Ein I2C-Scanner

von Michael Moske

Elektronik-Labor  Projekte  Mikrocontroller  TLScript  




Download: I2C_Scanner.tls

Kann man mit TLScipt eine I2C-Verbindung aufbauen? Das Fernziel könnte sein, ein OLED anzusprechen, und es gibt ja eine Unmenge anderer ICs, für die sich das lohnen würde. Für den Anfang reicht es, am Bus angeschlossene ICs und ihre Adressen zu finden. Fast alle wesentlichen Funktionen am I2C-Bus sind dafür schon nötig. Für den Bus braucht man zwei Leitungen, die abwechselnd als Eingänge und als Ausgänge arbeiten müssen. Hier wurde C1 als Datenleitung SDA und C2 als Taktleitung SCL festgelegt.


Das Programm I2C_Scanner.tls wird geladen und gestartet. Und siehe da, die I2C-Adresse 60 (0x3C) des OLED-Displays wird gefunden und ausgegeben. Wer die I2C-Grundfunktionen kennt, wird sich schnell im Quelltext zurechtfinden. Das Entscheidende zur Kommunikation mit dem Display ist das I2C-Protokoll. Im Programm kann die Steuerung der SDA und SCL Leitungen Bit für Bit nachvollzogen werden, wobei die 4 möglichen Zustände von High/Low-Kombinationen für Start, Datenbit, Acknowledge und Stop genutzt werden.


              Rem ************
              Rem I2C Scanner
              Rem ************
              Rem
              Rem ************
              Rem Init SDA/SCL
              Rem ************
0x0906  Pdir = 0x06
              Rem
              Rem ************
              Rem Main Loop
              Rem ************
              L1:
0x037F  C = 0x7f
              L2:
0x2128  Call L110:
0x3700  A = C
0x3100  A = A Shl 1
0x2131  Call L112:
0x0200  B = 0
0x220A  If A=B Jmp L3:
0x212D  Call L111:
0x2502  C*Jmp L2:
              L3:
0x212D  Call L111:
0x3700  A = C
0x4200  Print A
0x1A01  Delay s = 1
0x2001  Jmp L1:
              Rem ************
              Rem End of Loop
              Rem ************
              Rem
              Rem ************
              Rem Set_SDA
              Rem ************
              L100:
0x3F00  A = Pin
0x1302  A = A OR 0x02
0x4500  Pout = A
              Rem PC1 = 1
0x4800  Ret
              Rem ************
              Rem Reset_SDA
              Rem ************
              L101:
0x3F00  A = Pin
0x12FD  A = A AND 0xfd
0x4500  Pout = A
              Rem PC1 = 0
0x4800  Ret
              Rem ************
              Rem Read_SDA
              Rem ************
              L102:
0x3F00  A = Pin
0x1202  A = A AND 0x02
0x3200  A = A Shr 1
0x4800  Ret
              Rem ************
              Rem Set_SCL
              Rem ************
              L103:
0x3F00  A = Pin
0x1304  A = A OR 0x04
0x4500  Pout = A
              Rem PC2 = 1
0x4800  Ret
              Rem ************
              Rem Reset_SCL
              Rem ************
              L104:
0x3F00  A = Pin
0x12FB  A = A AND 0xfb
0x4500  Pout = A
              Rem PC2 = 0
0x4800  Ret
              Rem ************
              Rem Read_SCL
              Rem ************
              L105:
0x3F00  A = Pin
0x1204  A = A AND 0x04
0x3200  A = A Shr 1
0x3200  A = A Shr 1
0x4800  Ret
              Rem ************
              Rem Start
              Rem ************
              L110:
0x210F  Call L100:
0x211B  Call L103:
0x2113  Call L101:
0x211F  Call L104:
0x4800  Ret
              Rem ************
              Rem Stop
              Rem ************
              L111:
0x2113  Call L101:
0x211B  Call L103:
0x210F  Call L100:
0x4800  Ret
              Rem ************
              Rem Write byte
              Rem ************
              L112:
              Rem Save byte
0x0201  B = 1
0x3B00  [B+] = A
0x0407  D = 0x07
              Rem TX Loop
              L113:
0x0201  B = 1
0x3A00  A = [B+]
              Rem Check bit 7
0x1280  A = A AND 0x80
0x0200  B = 0
0x223B  If A=B Jmp L114:
              Rem Bit found
0x210F  Call L100:
0x203C  Jmp L115:
              L114:
              Rem Bit not found
0x2113  Call L101:
              L115:
              Rem Reload byte
0x0201  B = 1
0x3A00  A = [B+]
0x3100  A = A Shl 1
              Rem Save shifted byte
0x0201  B = 1
0x3B00  [B+] = A
0x211B  Call L103:
0x211F  Call L104:
0x2634  D*Jmp L113:
              Rem Byte was sent
0x210F  Call L100:
0x211B  Call L103:
              Rem Read ACK
0x2117  Call L102:
0x3800  D = A
0x211F  Call L104:
0x3900  A = D
              Rem Return ACK
0x4800  Ret


Erweiterung: I2C mit LEDs 


Video: https://www.youtube.com/shorts/MJ7NsHvPueg

Download: I2C_Scanner_mit_LEDs.tls

Ich hatte mir überlegt, dass man doch die Schaltzustände der I2C-Programme, exemplarisch für den I2C-Scanner, auch direkt mit LEDs anzeigen kann. Das I2C-Scanner TLScript-Programm habe ich in einer neuen Version erweitert zur synchronen Ausgabe der Schaltzustände mittels Status-LEDs.  Zu den LEDs: linke blaue LED -> SCL, rechte blaue LED -> SDA, gelb -> Schreiben, grün -> ACK, rot -> NACK. Im Programm sind Call-Befehle für die Zeitverzögerung eingesetzt, die ganz am Ende steht und zentral geändert werden kann. Die Pausen zwischen Start, Write, Stop und ACK-Abfrage sind mit einer Sekunde festgelegt. Die Befehle zum Schalten der gelb/grün/roten Status-LEDs sind im Programm integriert und am Ende der Stop-Sequenz wurde noch zur besseren Erkennung das Zurückschalten auf Low-Pegel angefügt. Zum Unterstreichen einer gefundenen Adresse habe ich noch eine Blink-Sequenz eingefügt, die nicht eigentlich zum I2C-Protokoll gehört. Und in der IDE wird in der Ausgabezeile jeweils die gerade in Arbeit befindliche Adresse angezeigt und eine gefundene Adresse zur besseren Visualisierung mit Nullen eingerahmt.

Damit nicht zu lange zu viele I2C-Adressen abgearbeitet werden, startet das Programm bei Adresse 62 absteigend bis eine positive Rückmeldung (ACK) von einem I2C-Slave erfolgt. Dies kann natürlich frei geändert werden. Die Adresse 60 (0x3C) gilt für das OLED-Display. Für BME280-Wettersensoren gelten z.B Adressen im Bereich 118 (0x76).



Elektronik-Labor  Projekte  Mikrocontroller  TLScript