;Display-Routine. Liest ab "String" das SRAM aus und gibt es auf dem Display aus. .EQU String=0x60 ;SRAM-Location .EQU Stringlength=8 .EQU Symbol=0x6A ;SRAM-Location für Symbole .EQU Symbollength=2 .EQU SlaveAddress=0x4A ;TID-Addresse ;************* .EQU SCL_OUT=0 .EQU MRQ_OUT=1 .EQU SDA_OUT=2 ;************* .EQU Sendtimeout=250 .EQU Retries=3 ;Wie oft wird versucht ein Byte zu senden? Display: PUSH u1 PUSH u2 PUSH u3 PUSH YL PUSH YH ;*******Init********** LDI u1,200 ;Pause vor dem Senden machen um nicht zu viele Daten zu senden PUSH u1 RCALL XDelay POP u1 ;**********Transfer-Init******* SBI DDRB, MRQ_OUT ;MRQ auf LOW ziehen; Transfer wird initiiert. LDI u1,150 ;Maximal 15000µs auf Reaktion vom TID warten WaitforSDALow: SBIS PINB,SDA_OUT ;Schaue ob das TID die Leitung auch auf 0 zieht, also reagiert. Falls nicht, verlängere die Pause RJMP SDAIsLow RCALL Delay DEC u1 BRNE WaitforSDALow RJMP Endtrans ;Transfer Failed, exit SDAIsLow: RCALL Delay ;100µs warten, dann CBI DDRB, MRQ_OUT ;MRQ wieder HIGH LDI u1,30 WaitforSDAHigh: SBIC PINB,SDA_OUT ;Warten bis SDA vom Slave wieder auf High gesetzt wird RJMP SDAIsHigh RCALL Delay DEC u1 BRNE WaitforSDAHigh RJMP Endtrans ;Transfer Failed, exit SDAIsHigh: RCALL Delay ;100 Mikrosekunden warten SBI DDRB, SDA_OUT ;SDA auf LOW setzen RCALL Delay ;100 Mikrosekunden warten SBI DDRB, SCL_OUT ;Clock Leitung auf 0 ziehen RCALL Delay ;*********Slave-Addresse senden********* LDI u1,SlaveAddress ;Slave Addresse senden PUSH u1 RCALL Send POP u1 ;Anzahl der Versuche checken CPI u1,Retries+1 BRSH Endtrans ;falls 4 Versuche gebraucht wurden dann beende das Senden ;*****Symbole senden****** SBI DDRB, MRQ_OUT ;MRQ auf LOW setzen ==> Beginn der Zeichensendungen CLR u2 LDI YL,LOW(Symbol) ;Den Pointer auf die Symbole pointen lassen LDI YH,HIGH(Symbol) SendSymbolLoop: LD u1,Y ;Stelle lesen ST Y+, Null ;Stelle löschen (Register leeren) PUSH u1 ;auf den Stack schieben RCALL Send POP u1 CPI u1, Retries+1 ;s.o. BREQ Endtrans INC u2 CPI u2, Symbollength BRNE SendSymbolLoop ;*****Zeichen senden******* CLR u2 LDI YL,LOW(String) ;Den Pointer auf die Zeichen pointen lassen LDI YH,HIGH(String) SendStringLoop: LD u1,Y ;Stelle lesen LDI u3,' ' ;Leerzeichen laden ST Y+, u3 ;Stelle löschen (Mit Leerzeichen füllen) PUSH u1 ;auf den Stack schieben RCALL Send POP u1 CPI u1, Retries+1 ;s.o. BREQ Endtrans INC u2 CPI u2, Stringlength BRNE SendStringLoop ;********Stop-Condition erzeugen********* Endtrans: CBI DDRB, SDA_OUT CBI DDRB, SCL_OUT SBI DDRB, MRQ_OUT RCALL DELAY SBI DDRB, SDA_OUT RCALL DELAY CBI DDRB, SCL_OUT RCALL DELAY CBI DDRB, SDA_OUT RCALL Delay CBI DDRB, MRQ_OUT ;*************************************** POP YH POP YL POP u3 POP u2 POP u1 RET Subroutinen: ;=========== Send: PUSH u1 PUSH u2 PUSH u3 PUSH u4 PUSH YL PUSH YH IN YL, SPL ;Stackpointer in u2 schieben IN YH, SPH ADIW YL, 9 ;auf das Zeichen im SRAM zeigen ;****************** CLR u4 ;Send-Retry-Counter GenerateParity: LD u1,Y ;Parameter aus dem SRAM holen LDI u3,8 ;Länge eines Datenbits wird pauschal auf 8 gesetzt. LSL u1 ;Das überflüssige Bit rausschieben. CLR u2 ;"Parity-Counter" SBRC u1,7 ;Ok - Ich geb zu dass dieses Modul nicht gerade die Perle der Programmierkunst ist, INC u2 ;Aber es funzt => Schöön :) SBRC u1,6 INC u2 SBRC u1,5 INC u2 SBRC u1,4 INC u2 SBRC u1,3 INC u2 SBRC u1,2 INC u2 SBRC u1,1 INC u2 SBRS u2,0 SBR u1,1 Sendbyte: SBI DDRB, SDA_OUT ;Die SDA-Leitung wird auf LOW gezogen. SBRC u1,7 ;Wenn das 7.Bit eine 0 ist, dann wird der nächste Befehl übersprungen CBI DDRB, SDA_OUT ;Ist er eine eins, dann wird der Befehl nicht übersprungen und die Leitung auf "High" RCALL Clkgen ;Die Uhr wird jetzt einmal fallen, einmal steigen und wieder einmal fallen lassen. ;Wenn das SCL-Signal HIGH ist, dann müssen laut I2C-Specs die Daten auf SDA gültig sein. LSL u1 ;Logical Shift left: Das 8. Bit wird rausgeschmissen und durch das folgende ersetzt. DEC u3 ;length zählt mit wie oft sich die Sendeschleife wiederholen muss! BRNE Sendbyte ;Solange zu SendAddress springen bis length=0 CBI DDRB, SDA_OUT ;SDA auf "High" setzen => Ack abwarten RCALL Delay CBI DDRB, SCL_OUT CLR u3 ;u3 wird "Timeout-Counter" WaitforAcklow: INC u3 ;Wenn innerhalb einer bestimmten Zeitspanne nicht geantwortet wird dann CPI u3,Sendtimeout ;wiederhole die Übertragung BREQ RetrySendByte SBIC PINB,SDA_OUT ;Auf das Ack vom TID warten RJMP WaitforAcklow RCALL Delay SBI DDRB, SCL_OUT RCALL Delay RJMP Bytesent RetrySendByte: INC u4 CPI u4,Retries+1 ;Anzahl der Versuche überprüfen BRNE GenerateParity ;Wenn 4 Versuche dann gib auf ;************** ByteSent: ST Y,u4 ;u4 wieder auf den Stack als Übergabeparameter schieben POP YH POP YL ;Werte wieder vom Stack holen POP u4 POP u3 POP u2 POP u1 RET Clkgen: SBI DDRB, SCL_OUT ;Die Uhr fängt mit LOW an RCALL Delay ;200us Low-Clock RCALL Delay CBI DDRB, SCL_OUT ;Clock auf High RCALL Delay ;100us warten SBI DDRB, SCL_OUT ;Clock wieder low RCALL Delay ;200us warten RCALL Delay RET