A nice book for ideas


Work document for friends
A nice book for ideas


Work document for friends
These tiny modules use a Clock and Data signal.
The rest of the pins are for 3.3V and Gnd.
There are many libraries you can choose from, i’ve tried several.
For now, i ended up with this one.
Another promising one is https://github.com/AKJ7/TM1637
Another one i’ve tested https://github.com/bxparks/AceSegment
Now i have to add Wifi and Mqtt so it can remotely controlled.
Connected like this
Code with Wifi/Mqtt
#include <Arduino.h>
#include <TM1637Display.h>
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
const char* ssid = "MYSSID";
const char* password = "MYSSIDPASS";
const char* mqtt_server = "MQTT-SERVER-IP";
const int CLK = D6; //Set the CLK pin connection to the display
const int DIO = D5; //Set the DIO pin connection to the display
int numCounter = 0;
int mydata = 0;
// The amount of time (in milliseconds) between tests
#define TEST_DELAY 2000
const uint8_t SEG_DONE[] = {
SEG_B | SEG_C | SEG_D | SEG_E | SEG_G, // d
SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F, // O
SEG_C | SEG_E | SEG_G, // n
SEG_A | SEG_D | SEG_E | SEG_F | SEG_G // E
};
TM1637Display display(CLK, DIO);
WiFiClient espClient;
PubSubClient client(espClient);
unsigned long lastMsg = 0;
#define MSG_BUFFER_SIZE (50)
char msg[MSG_BUFFER_SIZE];
int value = 0;
void setup()
{
display.setBrightness(0x0a); //set the diplay to maximum brightness
Serial.begin(115200);
setup_wifi();
client.setServer(mqtt_server, 1883);
client.setCallback(callback);
}
void setup_wifi() {
delay(10);
// We start by connecting to a WiFi network
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
client.setServer(mqtt_server, 1883);
client.setCallback(callback);
randomSeed(micros());
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
}
void callback(char* topic, byte* payload, unsigned int length) {
char buffer[4];
Serial.print("Message arrived [");
Serial.print(topic);
Serial.print("] ");
for (int i = 0; i < length; i++) {
Serial.print((char)payload[i]);
buffer[i] = int(payload[i]);
}
Serial.println();
// mydata=int(payload[0])+int(payload[1]*10);
int n;
n = atoi(buffer);
display.showNumberDec(n); //Display the numCounter value;
}
void reconnect() {
// Loop until we're reconnected
while (!client.connected()) {
Serial.print("Attempting MQTT connection...");
// Create a random client ID
String clientId = "ESP8266Client-";
clientId += String(random(0xffff), HEX);
// Attempt to connect
if (client.connect(clientId.c_str())) {
Serial.println("connected");
// Once connected, publish an announcement...
client.publish("escape/seg1ping", "seg1alive");
// ... and resubscribe
client.subscribe("escape/seg1data");
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
// Wait 5 seconds before retrying
delay(5000);
}
}
}
void loop() {
if (!client.connected()) {
reconnect();
}
client.loop();
unsigned long now = millis();
if (now - lastMsg > 2000) {
lastMsg = now;
++value;
snprintf (msg, MSG_BUFFER_SIZE, "seg1alive #%ld", value);
Serial.print("Publish message: ");
Serial.println(msg);
client.publish("escape/seg1ping", msg);
}
}
As part of my internet based escape room.
I took the idea from the Keep-talking-and-nobody-explodes game.

When starting up, is gets the configuration from a Mqtt Topic.
So i can create a different setup over the internet.
The result is also send back via MQTT.
(example play, all players are on different locations)
I used a wire with a line. Multiple colors for jacks and sockets.
It’s also possible to connect a jack to a jack.
Loads of possibilities.
Todo:
Wifi and Mqtt part
Debounce software or hardware
Lets try to make a Electronic Concertina
UPDATE:
https://www.henriaanstoot.nl/2023/01/10/arduino-concertina-poc/
https://www.henriaanstoot.nl/2023/01/17/arduino-concertina-poc-2/
So we need some pushbuttons … at least 14 .. for the most simple tunes.
A sensor for push and pull.
A buzzer or better yet .. a jack for earphones.
Arduino with enough pins to connect a keyboard matrix.
When using a keyboard matrix only single keypresses are detected.
So we cant do chords!
Last year i was playing with this radar module also, but today i made a version with MQTT and a linux client.
(There is a project on the internet which uses a HC-SR04, and a arduino connected to the Laptop. This setup is more sensitive and no need for a usb thinghy.)

When using MQTT i can integrate this in HomeAssistant, Domoticz, NodeRed and more.
But i’ve written a python script which runs on my Laptop.
For example i can: Kill vlc, change to my work desktop, stop sound output and lock the screen. (everything you can script)
I wanted to have a “mobile” version of the sensor so i can place it anywhere. (Frontdoor, gardengate, candydrawer 🙂 )
These modules are very cheap, but do their job well!
I’ve used a Wroom ESP32 and a BattBorg together with the module, that’s it.
Simplified schematic (without the battborg)
I’m using PIN34 as an analog input.
Radar module pins:
Arduino sketch
#include <WiFi.h>
#include <PubSubClient.h>
#include <Wire.h>
const char* ssid = "MYSSID";
const char* password = "MYPASS";
const char* mqtt_server = "IP-MQTT-SERVER";
const char* mqtt_username = "";
const char* mqtt_password = "";
const char* clientID = "radar";
const int tiltPin = 34;
int tiltState = 0;
int previousState = 0;
WiFiClient espClient;
PubSubClient client(espClient);
String translateEncryptionType(wifi_auth_mode_t encryptionType) {
switch (encryptionType) {
case (WIFI_AUTH_OPEN):
return "Open";
case (WIFI_AUTH_WEP):
return "WEP";
case (WIFI_AUTH_WPA_PSK):
return "WPA_PSK";
case (WIFI_AUTH_WPA2_PSK):
return "WPA2_PSK";
case (WIFI_AUTH_WPA_WPA2_PSK):
return "WPA_WPA2_PSK";
case (WIFI_AUTH_WPA2_ENTERPRISE):
return "WPA2_ENTERPRISE";
}
}
void scanNetworks() {
int numberOfNetworks = WiFi.scanNetworks();
Serial.print("Number of networks found: ");
Serial.println(numberOfNetworks);
for (int i = 0; i < numberOfNetworks; i++) {
Serial.print("Network name: ");
Serial.println(WiFi.SSID(i));
Serial.print("Signal strength: ");
Serial.println(WiFi.RSSI(i));
Serial.print("MAC address: ");
Serial.println(WiFi.BSSIDstr(i));
Serial.print("Encryption type: ");
String encryptionTypeDescription = translateEncryptionType(WiFi.encryptionType(i));
Serial.println(encryptionTypeDescription);
Serial.println("-----------------------");
}
}
void connectToNetwork() {
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("Establishing connection to WiFi..");
}
Serial.println("Connected to network");
}
void reconnect() {
while (!client.connected()) {
if (client.connect(clientID, mqtt_username, mqtt_password)) {
} else {
delay(2000);
}
}
}
void setup()
{
{
Serial.begin(115200);
scanNetworks();
connectToNetwork();
Serial.println(WiFi.macAddress());
Serial.println(WiFi.localIP());
client.setServer(mqtt_server, 1883);
pinMode(tiltPin, INPUT);
}
}
void loop() {
tiltState = analogRead(tiltPin);
if (tiltState < 3048) {
client.publish("radar/state", "0"); //
} else {
client.publish("radar/state", "1"); //
}
delay(100);
{
if (!client.connected()) {
reconnect();
}
client.loop();
}
}
Lockscreen!
Below shows the speed of detection, and sending though the network
Python script which does a lock-screen using XDOTOOL
from paho.mqtt import client as mqtt_client
import subprocess
import time
broker = 'MQTT-SERVER'
port = 1883
topic = "radar/state"
client_id = "radarclient"
def connect_mqtt() -> mqtt_client:
def on_connect(client, userdata, flags, rc):
if rc == 0:
print("Connected to MQTT Broker!")
else:
print("Failed to connect, return code %d\n", rc)
client = mqtt_client.Client(client_id)
client.on_connect = on_connect
client.connect(broker, port)
return client
def subscribe(client: mqtt_client):
def on_message(client, userdata, msg):
state = msg.payload.decode()
print (state)
if state == "1":
subprocess.Popen(["xdotool","key","Super_L+l"])
time.sleep(30)
client.subscribe(topic)
client.on_message = on_message
def run():
client = connect_mqtt()
subscribe(client)
client.loop_forever()
if __name__ == '__main__':
run()
change
subprocess.Popen([“xdotool”,”key”,”Super_L+l”])
into
subprocess.Popen([“switchdesktop”])
to run a script named switchdesktop
#!/bin/bash # This is the switchdesktop script, it goes to the next screen using winows-page-down combo xdotool key "Super_L+Page_Down"
Todo:
3D print a case
Make a version which becomes a Access Point.
Then make another arduino setup which controls my Nikon.
So it can act like a wildcam (offline)
Something like below, using a optocoupler ( i still got some leftovers from my doorbell to gpio-pin project.)
I started to get some composite video generated with a arduino for my 6502 project.
UPDATE: 20221021
It is based on Grant Searle’s design, and yesterday I had some signals on my scope which looked like a screen with a character. But my monitor would not recognize a usable signal.
Today I tried a second version and another set of chips and crystals.

It looks like a signal, but I can’t see a clock pulse from the crystal?! So .. how?

Maybe I used a bad power supply. And killed something?
UPDATE: 20221021
After switching to another power supply, and checking the atmega328p fuses again (also wrong) .. at least SOME success!
Some minipro info #Erase minipro -p ATMEGA328P@DIP28 -E #Flash hex code minipro -p ATMEGA328P@DIP28 -w SBCVideo.hex #Flash fuses minipro -p ATMEGA328P@DIP28 -e -c config -w fuses #Used fuses file lfuse = 0xf7 hfuse = 0xd9 efuse = 0xfc lock = 0xff lfuse = 0xff hfuse = 0xff efuse = 0xff user_id0 = 0xff user_id1 = 0xff user_id2 = 0xff user_id3 = 0xff user_id4 = 0x37 user_id5 = 0x37 user_id6 = 0x39 user_id7 = 0x36 #Dump all from atmega328p minipro -p ATMEGA328P@DIP28 -r dump -f ihex
Some info about the fuses:
https://www.allaboutcircuits.com/projects/atmega328p-fuse-bits-and-an-external-crystal-oscillator
Work in progress code
PORT2B = $5000 ; VIA PORTB PORT2A = $5001 ; VIA PORTA DDR2B = $5002 ; Data direction register DDR2A = $5003 ; Data direction register PORTB = $6000 ; display PORTA = $6001 ; control display + matrix keyboard DDRB = $6002 ; data direction register DDRA = $6003 ; data direction register SID = $7000 ; sid base address E = %10000000 ; enable bit RW = %01000000 ; RW bit RS = %00100000 ; Register Select bit HOME = %00000010 ; VIA PORTB HOME command DADDR = %00010000 ; VIA DADDRESS LINENO = $0200 ; temp address linenumber (move to other location) NEXTLINE = 40 ; 2x16 Chars but internally 40 .org $8000 reset: ldx #$ff txs ; reset stack ; ################################################### ; # DISPLAY CONTROL # ; ################################################### ; VIA Setup lda #%11111111 ; Set all pins on port B to output sta DDRB lda #%11100000 ; Set top 3 pins on port A to output sta DDRA ; DISPLAY Setup lda #%00111000 ; Set 8-bit mode; 2-line display; 5x8 font jsr lcd_instruction lda #%00001110 ; Display on; cursor on; blink off jsr lcd_instruction lda #%00000110 ; Increment and shift cursor; don't shift display jsr lcd_instruction lda #$00000001 ; Clear display jsr lcd_instruction ; ################################################### ; # PRINT MESSAGE LINE NO 0 # ; ################################################### lda #0 ; set line number sta LINENO ; store for subroutine jsr gotoline ; move cursor ldx #0 ; message index pointer print: lda message0,x ; start of message beq nextprint ; stop when null in message (asciiz <- Zero padded) jsr print_char ; print char inx ; incr index jmp print ; resume print ; ################################################### ; # PRINT MESSAGE LINE NO 1 # ; ################################################### nextprint: lda #1 ; set line number sta LINENO ; store jsr gotoline ldx #0 ; index pointer print2: lda message1,x ; absolute address message + x in A beq sidsound ; if x is 0, end of message jsr print_char ; jump subroutine inx ; increment x jmp print2 ; loop print2 ; ################################################### ; # SID SOUND # ; ################################################### sidsound: lda #0 sta SID+$5 ; attack/decay duration lda #250 sta SID+$6 ; sustain level/release duration lda #$95 ; frequency voice 1 low byte sta SID+$0 lda #$44 ; frequency voice 1 high byte sta SID+$1 lda #%00100001 ; sawtooth + gate sta SID+$4 ; control register voice 1 lda #$0f ; filter mode and volume (bits 3-0 main volume) sta SID+$18 ; filter mode and volume ; ################################################### ; # 2ND VIA # ; ################################################### lda #%11111111 ; set port A output sta DDR2A lda #%11111111 ; all ones! sta PORT2A ; ################################################### lda #%11111111 ; set port A output sta DDR2A lda #%11111111 ; all ones! sta PORT2A ; ################################################### ; # MAIN PROGRAM LOOP # ; ################################################### loop: jmp loop ; 1234567812345678 message0: .asciiz "VIA 1,2 SID TEST" message1: .asciiz " FASH 2022 " ; ################################################### ; # ONLY SUBROUTINES # ; ################################################### ; ################################################### ; # Subroutine gotoline # ; # Moves character placement position on display # ; # Needs : $LINENO ADDRESS # ; # Exit values : - # ; # Destroys registers: - # ; ################################################### gotoline: pha ; store a txa pha ; store x ldx LINENO lda #HOME ; cursor down jsr lcd_instruction lda #$80 nextline: ldx LINENO cpx #00 beq endnextlines loopline: adc #40 jsr lcd_instruction dex stx LINENO jmp nextline endnextlines: pla ; pop a tax ; a to x pla ; pop a rts ; ################################################### ; # LCD SUBROUTINES # ; ################################################### lcd_wait: pha lda #%00000000 ; Port B is input sta DDRB lcdbusy: lda #RW sta PORTA lda #(RW | E) sta PORTA lda PORTB and #%10000000 bne lcdbusy lda #RW sta PORTA lda #%11111111 ; Port B is output sta DDRB pla rts lcd_instruction: jsr lcd_wait sta PORTB lda #0 ; Clear RS/RW/E bits sta PORTA lda #E ; Set E bit to send instruction sta PORTA lda #0 ; Clear RS/RW/E bits sta PORTA rts print_char: jsr lcd_wait sta PORTB lda #RS ; Set RS; Clear RW/E bits sta PORTA lda #(RS | E) ; Set E bit to send instruction sta PORTA lda #RS ; Clear E bits sta PORTA rts nmi: rti irq: rti .org $fffa .word nmi .word reset .word irq ; .word $0000
In this case designed for my 6502, but it is a generic setup.
I it just a dual 16key matrix decoder merged together. You can probably use this with raspberries, arduinos etc.
I wanted to use 74C923 but these are nowhere to be found. And even then, the number of keys wil be 20.
So i am tying together two 74C922 using some logic in a PLD.
It wil be something like above. Using the data availabe signal i can combine both 16key matrixes. (In theory .. it is all untested)
PLD Code
GAL22V10 Address Decoder PHI2 DA0 DA1 D01 D02 D03 D04 D11 D12 D13 D14 GND NC D0 D1 D2 D3 D4 DA NC NC NC NC VCC DA = DA0 + DA1 D0 = D01 & DA0 + D11 & DA1 D1 = D02 & DA0 + D12 & DA1 D2 = D03 & DA0 + D13 & DA1 D3 = D04 & DA0 + D14 & DA1 D4 = DA1 DESCRIPTION Key matrix merger
I’ve got my new keys of the keyboard in today!
My inkscape template (keys are 10/10mm)
Printed on white and red paper
https://media.henriaanstoot.nl/keyboardmatrix.svg
UPDATE: 20220815, 20220814, 20220815, 20230202
Flashing ROMs .. (eeproms). It used to be a pain in the *$$.
Burning took a looong time. But clearing one with UV took .. 20 minutes or so. Using one of these:
Altered clock module
Changed Rom/Ram
VIC 6522
Display
Generic improvements
To do’s or ‘have to look into’s’
Notes about the movie:
Left side is Arduino IDE monitor reading Addressbus and Databus.
(I’m going to try to rewrite this to realtime disassemble)
Resetting system.
Stepping CPU with manual clock pulses.
Start vector being read at $FFFC/$FFFD.
Program being run from $8000.
Set clock on automatic ( ~ about 150 Hz )
Last opcodes you see a JMP loop 4C 2F 80, that is JMP $802F
Display enlarged on video, was not visible on movie i took on mobile.
(Wrong angle?)
Breadboard overview
| Clock module | Reset module + Crystal |
| CPU + nmi/int buttons | RAM and ROM |
| Address decode + Bus divide | Addres/Data bus leds |
| 6522 VIA + Display | 2nd via + Buttons |
| ? | (sound board) |
TIL: 6502 can run without ram only rom,expect when using JSR … which uses a program stack in RAM
TODO:
After a whole day soldering yesterday, ending up with a wire mess.
Which didn’t work at the end…
Starting measuring some things, and create some test sketches (led blinky tests)
I found out that the main problem was not having the red switches connected to GND.
Blue switches where upside down, this was a easy fix. Because these are ON-ON switches, and where already connected to a common line.
Then a mixup between D0 and D6 (wires crossed)
And it is working! Made some lines and lettering on the frontplate after some playing around.
Weird to input stuff in octal (group of 3 bits)