;----------------------------------------------------------------
; Titel : I2C Bus Slave - Adressenfinder
;----------------------------------------------------------------
; Funktion : Programm zählt die Adressen von 0 bis 255 hoch
; : und sucht so die Adresse des I2C Bausteins
; : Anzeige erfolgt in Dezimalzahlen
; : LCD Display 2 x 16 an Port B
; : LCD Display DB4 an Port B0
; : LCD Display DB5 an Port B1
; : LCD Display DB6 an Port B2
; : LCD Display DB7 an Port B3
; : LCD Display RS an Port B4
; : LCD Display E an Port B5
; : Taster an Port C0 (für weiter suchen oder neue Suche)
; : Bus an Port C4 SDA und Port C5 SCl
;----------------------------------------------------------------
; Prozessor : ATmega8
; Takt : 3686400 Hz
; Sprache : Assembler (GNU)
; Datum : 05.03.2020
; Autor : Ernst Preischl
;----------------------------------------------------------------
.include "avr.h"
.equ F_CPU,3686400
.equ TWI_CLOCK,100000 ; Geschwindigkeit des TWI-Busses
;----------------------------------------------------------------
; TWCR - Control-Register-Bits
.equ _TWINT,0b10000000
.equ _TWEA,0b01000000
.equ _TWSTA,0b00100000
.equ _TWSTO,0b00010000
.equ _TWWC,0b00001000
.equ _TWEN,0b00000100
.equ _TWIE,0b00000001
.equ Stelle,0x11 ;r17 = Stelle LCD
.equ Adresse,0x12 ;r18 = Adresse
.equ Zahl,0x13 ;r19 = Zahl
.equ ja_nein,0x14 ;r20 = ja/nein
begin: rjmp main ; 1 POWER ON RESET
reti ; 2 Int0-Interrupt
reti ; 3 Int1-Interrupt
reti ; 4 TC2 Compare Match
reti ; 5 TC2 Overflow
reti ; 6 TC1 Capture
reti ; 7 TC1 Compare Match A
reti ; 8 TC1 Compare Match B
reti ; 9 TC1 Overflow
reti ;10 TC0 Overflow
reti ;11 SPI, STC Serial Transfer Complete
reti ;12 UART Rx Complete
reti ;13 UART Data Register Empty
reti ;14 UART Tx Complete
reti ;15 ADC Conversion Complete
reti ;16 EEPROM Ready
reti ;17 Analog Comparator
reti ;18 TWI (I²C) Serial Interface
reti ;19 Store Program Memory Ready
;----------------------------------------------------------------
; Initialisierungen
;----------------------------------------------------------------
main:
;--- Stack Initialisierung ---
ldi r16,hi8(RAMEND)
out SPH,r16
ldi r16,lo8(RAMEND)
out SPL,r16
ldi r16,0b11111111
out DDRB,r16 ;Konfiguration PORT B für LCD
cbi DDRC,0 ;Port C0 = IN für Taster
sbi PORTC,0 ;Pullup
rcall lcdInit
rcall lcdClear
rcall twiInitMaster
;----------------------------------------------------------------
; Hauptprogramm-Schleife
;----------------------------------------------------------------
mainloop: wdr ;Watchdog reset
rcall Text_1 ;Text 1 ans Display
ldi Zahl,0 ;Zahl 0 laden
ldi Stelle,3 ;Stelle 3 Zeile 1 laden
rcall LCD_Aufbereitung ;für Display aufbereiten
rcall Anzeige_Z1 ;und anzeigen
ldi Zahl,0 ;Zahl 0 laden
ldi Stelle,11 ;Stelle 11 Zeile 1 laden
rcall LCD_Aufbereitung ;für Display aufbereiten
rcall Anzeige_Z1 ;und anzeigen
ldi Zahl,0 ;Zahl 0 laden
ldi Stelle,3 ;Stelle 3 Zeile 2 laden
rcall LCD_Aufbereitung ;für Display aufbereiten
rcall Anzeige_Z2 ;und anzeigen
ldi Adresse,0x00 ;Busadresse 0 laden
loop: ;Hauptschleife
mov Zahl,Adresse ;Busadresse zu Zahl kopieren
ldi Stelle,3 ;Stelle 3 Zeile 1 laden
rcall LCD_Aufbereitung ;für Display aufbereiten
rcall Anzeige_Z1 ;und anzeigen
rcall twiStart ;TWI starten
mov r16,Adresse ;Adresse ins TWI-Register
clr r15 ;kein ACKN
rcall twiWriteByte ;TWI schreiben
inc Adresse ;Adresse um 1 erhöhen
inc Adresse ;nochmal um 1 erhöhen
wdr ;Watchdog reset
rcall wait_10ms ;warten
rcall wait_10ms ;warten
rcall wait_10ms ;warten
rcall wait_10ms ;warten
rcall wait_10ms ;warten
rcall wait_10ms ;warten
rcall wait_10ms ;warten
rcall wait_10ms ;warten
rcall wait_10ms ;warten
rcall wait_10ms ;warten
rcall wait_10ms ;warten
cpi Adresse,254 ;Ende des Scanns?
brne loop ;nein dann zur Hauptschleife
cpi ja_nein,0 ;Slave gefunden ja/nein
brne nein ;ja
rcall Text_2 ;Text kein Slave gefunden
rjmp warte_2 ;zur Warteschleife 2
nein: rcall Text_3 ;Text Ende des Scanns
ldi ja_nein,0 ;Slave gefunden Register
;auf Null setzen
warte_2: wdr ;Warteschleife 2
sbic PINC,0 ;warte auf Taster
rjmp warte_2
rjmp mainloop ;dann zurück zum Start
;----- Unterprogramm Slave gefunden -----
Slave_gefunden:
ldi ja_nein,1 ;Slave gefunden Register
mov Zahl,Adresse ;Busadresse zu Zahl kopieren
ldi Stelle,11 ;Stelle 11 Zeile 1 laden
rcall LCD_Aufbereitung ;für Display aufbereiten
rcall Anzeige_Z1 ;und anzeigen
inc Zahl ;erhöhe Zahl um 1
ldi Stelle,3 ;Stelle 3 Zeile 2 laden
rcall LCD_Aufbereitung ;für Display aufbereiten
rcall Anzeige_Z2 ;und anzeigen
warte_1: wdr;Warteschleife 1
sbic PINC,0 ;warte auf Taster
rjmp warte_1
ret
;----------------------------------------------------------------
;----- Unterprogramm Aufbereitung von Zahlen für LCD Anzeige -----
LCD_Aufbereitung:
push r21
push r22
push r23
push r24
mov r23,Zahl
ldi r21,0
ldi r22,0
main1: cpi r23,10
brlo main2
subi r23,10
inc r21
rjmp main1
main2: cpi r21,10
brlo main4
subi r21,10
inc r22
rjmp main2
main4: ldi r24,0b00110000
add r23,r24
sts 0x70,r23
add r21,r24
sts 0x71,r21
add r22,r24
sts 0x72,r22
pop r24
pop r23
pop r22
pop r21
ret
;----------------------------------------------------------------
;----- Text Adresse, Read, Write am Display anzeigen ------
Text_1: push r16
rcall lcdClear ;Display löschen
ldi r16,0b10000000 ;0
rcall lcdCmd
ldi r16,'A' ;"A"
rcall lcdOut
ldi r16,0b10000001 ;1
rcall lcdCmd
ldi r16,':' ;":"
rcall lcdOut
ldi r16,0b10001000 ;2
rcall lcdCmd
ldi r16,'W' ;"W"
rcall lcdOut
ldi r16,0b10001001 ;2
rcall lcdCmd
ldi r16,':' ;":"
rcall lcdOut
ldi r16,0b11000000 ;3
rcall lcdCmd
ldi r16,'R' ;"R"
rcall lcdOut
ldi r16,0b11000001 ;4
rcall lcdCmd
ldi r16,':' ;":"
rcall lcdOut
ldi r16,0b11001111 ;5
rcall lcdCmd
ldi r16,'>' ;">"
rcall lcdOut
pop r16
ret
;----------------------------------------------------------------
;----- Text Error kein Slave gefunden am Display anzeigen ------
Text_2: push r16
rcall lcdClear ;Display löschen
ldi r16,0b10000000 ;0
rcall lcdCmd
ldi r16,'E' ;"E"
rcall lcdOut
ldi r16,0b10000001 ;1
rcall lcdCmd
ldi r16,'r' ;"r"
rcall lcdOut
ldi r16,0b10000010 ;2
rcall lcdCmd
ldi r16,'r' ;"r"
rcall lcdOut
ldi r16,0b10000011 ;3
rcall lcdCmd
ldi r16,'o' ;"o"
rcall lcdOut
ldi r16,0b10000100 ;4
rcall lcdCmd
ldi r16,'r' ;"r"
rcall lcdOut
ldi r16,0b10000101 ;5
rcall lcdCmd
ldi r16,' ' ;" "
rcall lcdOut
ldi r16,0b10000110 ;6
rcall lcdCmd
ldi r16,'k' ;"k"
rcall lcdOut
ldi r16,0b10000111 ;7
rcall lcdCmd
ldi r16,'e' ;"e"
rcall lcdOut
ldi r16,0b10001000 ;8
rcall lcdCmd
ldi r16,'i' ;"i"
rcall lcdOut
ldi r16,0b10001001 ;9
rcall lcdCmd
ldi r16,'n' ;"n"
rcall lcdOut
ldi r16,0b10001010 ;10
rcall lcdCmd
ldi r16,' ' ;" "
rcall lcdOut
ldi r16,0b10001011 ;11
rcall lcdCmd
ldi r16,'S' ;"S"
rcall lcdOut
ldi r16,0b10001100 ;12
rcall lcdCmd
ldi r16,'l' ;"l"
rcall lcdOut
ldi r16,0b10001101 ;13
rcall lcdCmd
ldi r16,'a' ;"a"
rcall lcdOut
ldi r16,0b10001110 ;14
rcall lcdCmd
ldi r16,'v' ;"v"
rcall lcdOut
ldi r16,0b10001111 ;15
rcall lcdCmd
ldi r16,'e' ;"e"
rcall lcdOut
ldi r16,0b11000000 ;0
rcall lcdCmd
ldi r16,'g' ;"g"
rcall lcdOut
ldi r16,0b11000001 ;1
rcall lcdCmd
ldi r16,'e' ;"e"
rcall lcdOut
ldi r16,0b11000010 ;2
rcall lcdCmd
ldi r16,'f' ;"f"
rcall lcdOut
ldi r16,0b11000011 ;3
rcall lcdCmd
ldi r16,'u' ;"u"
rcall lcdOut
ldi r16,0b11000100 ;4
rcall lcdCmd
ldi r16,'n' ;"n"
rcall lcdOut
ldi r16,0b11000101 ;5
rcall lcdCmd
ldi r16,'d' ;"d"
rcall lcdOut
ldi r16,0b11000110 ;6
rcall lcdCmd
ldi r16,'e' ;"e"
rcall lcdOut
ldi r16,0b11000111 ;7
rcall lcdCmd
ldi r16,'n' ;"n"
rcall lcdOut
ldi r16,0b11001000 ;8
rcall lcdCmd
ldi r16,' ' ;" "
rcall lcdOut
ldi r16,0b11001001 ;9
rcall lcdCmd
ldi r16,'!' ;"!"
rcall lcdOut
ldi r16,0b11001010 ;10
rcall lcdCmd
ldi r16,' ' ;" "
rcall lcdOut
ldi r16,0b11001011 ;11
rcall lcdCmd
ldi r16,' ' ;" "
rcall lcdOut
ldi r16,0b11001100 ;12
rcall lcdCmd
ldi r16,' ' ;" "
rcall lcdOut
ldi r16,0b11001101 ;13
rcall lcdCmd
ldi r16,' ' ;":"
rcall lcdOut
ldi r16,0b11001110 ;14
rcall lcdCmd
ldi r16,' ' ;" "
rcall lcdOut
ldi r16,0b11001111 ;15
rcall lcdCmd
ldi r16,'>' ;">"
rcall lcdOut
pop r16
ret
;----------------------------------------------------------------
;----- Text Ende des Scanns ------
Text_3: push r16
rcall lcdClear ;Display löschen
ldi r16,0b10000000 ;0
rcall lcdCmd
ldi r16,'E' ;"E"
rcall lcdOut
ldi r16,0b10000001 ;1
rcall lcdCmd
ldi r16,'n' ;"n"
rcall lcdOut
ldi r16,0b10000010 ;2
rcall lcdCmd
ldi r16,'d' ;"d"
rcall lcdOut
ldi r16,0b10000011 ;3
rcall lcdCmd
ldi r16,'e' ;"e"
rcall lcdOut
ldi r16,0b10000100 ;4
rcall lcdCmd
ldi r16,' ' ;" "
rcall lcdOut
ldi r16,0b10000101 ;5
rcall lcdCmd
ldi r16,'d' ;"d"
rcall lcdOut
ldi r16,0b10000110 ;6
rcall lcdCmd
ldi r16,'e' ;"e"
rcall lcdOut
ldi r16,0b10000111 ;7
rcall lcdCmd
ldi r16,'s' ;"s"
rcall lcdOut
ldi r16,0b10001000 ;8
rcall lcdCmd
ldi r16,' ' ;" "
rcall lcdOut
ldi r16,0b10001001 ;9
rcall lcdCmd
ldi r16,'S' ;"S"
rcall lcdOut
ldi r16,0b10001010 ;10
rcall lcdCmd
ldi r16,'c' ;"c"
rcall lcdOut
ldi r16,0b10001011 ;11
rcall lcdCmd
ldi r16,'a' ;"a"
rcall lcdOut
ldi r16,0b10001100 ;12
rcall lcdCmd
ldi r16,'n' ;"n"
rcall lcdOut
ldi r16,0b10001101 ;13
rcall lcdCmd
ldi r16,'n' ;"n"
rcall lcdOut
ldi r16,0b10001110 ;14
rcall lcdCmd
ldi r16,'s' ;"s"
rcall lcdOut
ldi r16,0b10001111 ;15
rcall lcdCmd
ldi r16,'!' ;"!"
rcall lcdOut
ldi r16,0b11000000 ;0
rcall lcdCmd
ldi r16,'N' ;"N"
rcall lcdOut
ldi r16,0b11000001 ;1
rcall lcdCmd
ldi r16,'e' ;"e"
rcall lcdOut
ldi r16,0b11000010 ;2
rcall lcdCmd
ldi r16,'u' ;"u"
rcall lcdOut
ldi r16,0b11000011 ;3
rcall lcdCmd
ldi r16,'s' ;"s"
rcall lcdOut
ldi r16,0b11000100 ;4
rcall lcdCmd
ldi r16,'t' ;"t"
rcall lcdOut
ldi r16,0b11000101 ;5
rcall lcdCmd
ldi r16,'a' ;"a"
rcall lcdOut
ldi r16,0b11000110 ;6
rcall lcdCmd
ldi r16,'r' ;"r"
rcall lcdOut
ldi r16,0b11000111 ;7
rcall lcdCmd
ldi r16,'t' ;"t"
rcall lcdOut
ldi r16,0b11001000 ;8
rcall lcdCmd
ldi r16,' ' ;" "
rcall lcdOut
ldi r16,0b11001001 ;9
rcall lcdCmd
ldi r16,'?' ;"?"
rcall lcdOut
ldi r16,0b11001010 ;10
rcall lcdCmd
ldi r16,' ' ;" "
rcall lcdOut
ldi r16,0b11001011 ;11
rcall lcdCmd
ldi r16,' ' ;" "
rcall lcdOut
ldi r16,0b11001100 ;12
rcall lcdCmd
ldi r16,' ' ;" "
rcall lcdOut
ldi r16,0b11001101 ;13
rcall lcdCmd
ldi r16,' ' ;" "
rcall lcdOut
ldi r16,0b11001110 ;14
rcall lcdCmd
ldi r16,' ' ;" "
rcall lcdOut
ldi r16,0b11001111 ;15
rcall lcdCmd
ldi r16,'>' ;">"
rcall lcdOut
pop r16
ret
;----- LCD Anzeige Zeile 1------
Anzeige_Z1: push r16
ldi r16,0b10000000 ;Register Zeile 1
add r16,r17
rcall lcdCmd
lds r16,0x72 ;Ziffer 1
rcall lcdOut
lds r16,0x71 ;Ziffer 2
rcall lcdOut
lds r16,0x70 ;Ziffer 3
rcall lcdOut
pop r16
ret
;----- LCD Anzeige Zeile 2------
Anzeige_Z2: push r16
ldi r16,0b11000000 ;Register Zeile 2
add r16,r17
rcall lcdCmd
lds r16,0x72 ;Ziffer 1
rcall lcdOut
lds r16,0x71 ;Ziffer 2
rcall lcdOut
lds r16,0x70 ;Ziffer 3
rcall lcdOut
pop r16
ret
;----------------------------------------------------------------
;----- Display inialisieren -----
myWait_ms:
push r16
ldi r16,1
myWait_ms_3:
push r16
ldi r16,5
myWait_ms_2:
push r16
ldi r16,255
myWait_ms_1:
dec r16
brne myWait_ms_1
pop r16
dec r16
brne myWait_ms_2
pop r16
dec r16
brne myWait_ms_3
pop r16
dec r16
brne myWait_ms
ret
;--------------------------------------------------------------------
lcdOut: push r16
push r17
push r18
ldi r18,0b00010000
mov r17,r16 ;"Sicherungskopie" für
; die Übertragung des 2.Nibbles
swap r16 ;Vertauschen
andi r16,0b00001111 ;oberes Nibble auf Null setzen
or r16,r18 ;entspricht 0b00010000
out PORTB,r16 ;ausgeben
rcall lcdEnable ;Enable-Routine aufrufen
; 2. Nibble, kein swap da es schon
; an der richtigen stelle ist
andi r17,0b00001111 ;obere Hälfte auf Null setzen
or r17,r18 ;entspricht 0b00010000
out PORTB,r17 ;ausgeben
rcall lcdEnable ;Enable-Routine aufrufen
rcall lcdWait ;Delay-Routine aufrufen
pop r18
pop r17
pop r16
ret
;--------------------------------------------------------------------
; Warte-Routine für 5 ms
; die Routine wartet inclusive Aufruf 5,031 ms
;--------------------------------------------------------------------
lcdWait: ldi r16,20
rcall myWait_ms
ret
;--------------------------------------------------------------------
lcdCmd: push r16
push r17
push r18
mov r17,r16 ;"Sicherungskopie" für
; die Übertragung des 2.Nibbles
swap r16 ;Vertauschen
andi r16,0b00001111 ;oberes Nibble auf Null setzen
out PORTB,r16 ;ausgeben
rcall lcdEnable ;Enable-Routine aufrufen
; 2. Nibble, kein swap da es schon
; an der richtigen stelle ist
andi r17,0b00001111 ;obere Hälfte auf Null setzen
out PORTB,r17 ;ausgeben
rcall lcdEnable ;Enable-Routine aufrufen
rcall lcdWait ;Delay-Routine aufrufen
pop r18
pop r17
pop r16
ret ;zurück zum Hauptprogramm
;--------------------------------------------------------------------
lcdClear: ldi r16,0b00000001 ;Display löschen
rcall lcdCmd
rcall lcdWait
ret
;---------------------------------------------------------------------
lcdEnable: sbi PORTB,5 ;Enable high
nop ;kurz warten
nop
nop
cbi PORTB,5 ;Enable wieder low
ret
;----------------------------------------------------------------------
lcdHome: ldi r16,0b00000010 ;Cursor Anfang Zeile1
rcall lcdCmd
rcall lcdWait
ret
;----------------------------------------------------------------
lcdLine1: ldi r16,0b10000000 ;DRAM auf Adresse 0x00
rcall lcdCmd
rcall lcdWait
ret
;----------------------------------------------------------------
lcdLine2: ldi r16,0b11000000 ;DRAM auf Adresse 0x00
rcall lcdCmd
rcall lcdWait
ret
;----------------------------------------------------------------
lcdInit: cbi PORTB,4 ; LDC RS = Low
ldi r18,20
powerUp: rcall lcdWait ;warte bis PowerUp
dec r18
brne powerUp ;Power-Up Wartezyklus min 30 ms
; sende Resetsequenz kompatibel zu HD44780 Industriestandard
ldi r16,0b00000011 ;Reset-Sequenz Teil 1
out PORTB,r16
rcall lcdEnable ;Enable-Impuls
rcall lcdWait
ldi r16,0b00000011 ;Reset-Sequenz Teil 2
out PORTB,r16
rcall lcdEnable ;Enable-Impuls
rcall lcdWait
ldi r18,100 ;Wartezyklus bei RESET LCD min 100 µs
resetLCD: nop
nop
nop
dec r18
brne resetLCD
ldi r16,0b00000011 ;Reset-Sequenz Teil 3
out PORTB,r16
rcall lcdEnable ;Enable-Impuls
rcall lcdWait
ldi r16,0b00000010 ;4 Bit Modus aktivieren
out PORTB,r16
rcall lcdEnable ;Enable-Impuls
rcall lcdWait
ldi r16,0b00101000
rcall lcdCmd ;Function Set 4 Bit, 2 Zeilen, 5x7
ldi r16,0b00001100
rcall lcdCmd
ldi r16,0b00000100
rcall lcdCmd ;Entry Mode Set, increase+shifted
ret
;----------------------------------------------------------------
; twiInitMaster (ohne Interrupt)
; gestattet die Benutzung von TWI und setzt die Master-Clock-Rate
;----------------------------------------------------------------
twiInitMaster:
push r16
ldi r16,((F_CPU/TWI_CLOCK)-16)*2 ; Clock
out TWBR,r16 ;TWI-Status-Register (Vorteiler)
ldi r16,0
out TWSR,r16 ;Enable
ldi r16,_TWINT|_TWEN
out TWCR,r16
pop r16
ret
;----------------------------------------------------------------
; Start TWI
;----------------------------------------------------------------
twiStart:
push r16
in r16,TWCR
andi r16,_TWEN|_TWIE ;nur Beibehalten von Enable und InterruptJ/N
ori r16,_TWINT|_TWSTA
out TWCR,r16
twiStartWait1:
in r16,TWCR
sbrs r16,7 ;TWINT
rjmp twiStartWait1
pop r16
ret
;----------------------------------------------------------------
; Stopp TWI
;----------------------------------------------------------------
twiStopp:
push r16
in r16,TWCR
andi r16,_TWEN|_TWIE ;nur Beibehalten von Enable und InterruptJ/N
ori r16,_TWINT|_TWSTO
out TWCR,r16
pop r16
ret
;----------------------------------------------------------------
; Write Byte per TWI (ohne Interrupt)
; PE: r16 = Data
; r15.0 = 1 -> Acknowledge (=TWEA) setzten für Datenanforderung
;----------------------------------------------------------------
twiWriteByte:
push r16
out TWDR,r16 ;Daten bereitlegen
in r16,TWCR
andi r16,_TWEN|_TWIE ;nur Beibehalten von Enable und InterruptJ/N
ori r16,_TWINT
sbrc r15,0
ori r16,_TWEA ;evt. TWEA setzen, für Datenanforderung
out TWCR,r16 ;senden
twiWriteByteWait2:
in r16,TWCR
push r16
in r16,TWSR
cpi r16,24 ;feststellen der Slaveadresse
brne weiter
rcall Slave_gefunden ;zum Unterprog Slave Adressen
weiter: pop r16
sbrs r16,7 ;Twint
rjmp twiWriteByteWait2
pop r16
ret
;----------------------------------------------------------------
; Read Byte per TWI (ohne Interrupt)
; PE: r15.0 = 1 -> Acknowledge (=TWEA) setzten für Datenanforderung
; PA: r16 = Data
;----------------------------------------------------------------
twiReadByte:
in r16,TWCR
andi r16,_TWEN|_TWIE
ori r16,_TWINT
sbrc r15,0
ori r16,_TWEA ;evt. TWEA setzen, für Datenanforderung
out TWCR,r16
twiReadByteWait2:
in r16,TWCR
sbrs r16,7 ;TWINT
rjmp twiReadByteWait2
in r16,TWDR
ret
;----------------------------------------------------------------
wait_10ms:
push r16
ldi r16,10
rcall myWait_ms
pop r16
ret
;----------------------------------------------------------------