;*************************************************** ; Test TWI via USI-Interface ; MCU: ATMEL ATtiny2313 ; Clock: 4 MHz ; TWI/I2C-PortB PB7=SCL; PB5=SDA ; LCD: 4x20 SainSmart2004; HD44780 compatible ; P7 P6 P5 P4 P3 P2 P1 P0 ; D7 D6 D5 D4 LED ENA R|W RS ; ;ATtiny2313 memory use summary [bytes]: ;Segment Begin End Code Data Used Size Use% ;[.cseg] 0x000000 0x0002f4 704 52 756 2048 36.9% ;[.dseg] 0x000060 0x000060 0 0 0 128 0.0% ;[.eseg] 0x000000 0x000000 0 0 0 128 0.0% ;Assembly complete, 0 errors. 0 warnings ; ; Rev.: 28032018 ;*************************************************** ; ;Assemblerdirektiven: ; .nolist .include "tn2313def.inc";"tn4313def.inc" .list ; ; ; SRAM Definitionen: ; .dseg ; Datensegment (SRAM) Start bei .org 0x0060 ; Adresse 0x0060 ; ; ; Konstanten: .equ daten = portb .equ zeit0 = 1000 .equ zeit1 = 65535 ; ; ; Registernamen: .def inttemp = r12 ; Temporaerregister fuer Interrupt-Routinen .def intreg = r14 ; Zwischenspeicher fuer SREG bei ISRs .def temp = r16 ; diverse Universalregister .def temp1 = r17 .def temp2 = r18 .def temp3 = r19 ; .cseg ; Codesegment .org 0x0000 ; Startadresse rjmp reset ; Interrupt Vektoren Einsprungadressen (default) ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - .org 0x0001 ; ext IRQ0 Flanke rjmp INT00 .org 0x0002 ; ext IRQ1 Flanke rjmp INT10 .org 0x0003 ; Timer 1 capt rjmp ICP10 .org 0x0004 ; Timer 1 comp match A rjmp OC100 .org 0x0005 ; Timer 1 overflow rjmp OVF10 .org 0x0006 ; Timer 0 overflow rjmp OVF00 .org 0x0007 ; UART Receive Complete rjmp URXC0 .org 0x0008 ; UART Data Register Empty rjmp UDRE0 .org 0x0009 ; UART Transmit Complete rjmp UTXC0 .org 0x000A ; Analog Comparator Interrupt rjmp ACI00 .org 0x000B ; Pin Change Interrupt Request B rjmp PCIBA .org 0x000C ; Timer 1 comp match B rjmp OC1BA .org 0x000D ; Timer 0 comp match A rjmp OC0AA .org 0x000E ; Timer 0 comp match B rjmp OC0BA .org 0x000F ; USI Start Condition rjmp USIST .org 0x0010 ; USI Overflow rjmp USIOV .org 0x0011 ; Eprom read ready rjmp ERDYA .org 0x0012 ; Watchdog Timer Overflow rjmp WDTAD .org 0x0013 ; Pin Change Interrupt Request A rjmp PCIAA .org 0x0014 ; Pin Change Interrupt Request D rjmp PCIDA ; ;Interrupt Service Routinen - Interrupt handler ;- - - - - - - - - - - - - - - - - - - - - - - - - INT00: ; ISR not in use reti INT10: ; ISR not in use reti ICP10: ; ISR not in use reti OC100: ; ISR not in use reti OVF10: ; ISR not in use reti OVF00: ; ISR not in use reti URXC0: ; ISR not in use reti UDRE0: ; ISR not in use reti UTXC0: ; ISR not in use reti ACI00: ; ISR not in use reti PCIBA: ; ISR not in use reti OC1BA: ; ISR not in use reti OC0AA: ; ISR not in use reti OC0BA: ; ISR not in use reti USIST: ; ISR not in use reti USIOV: ; ISR not in use reti ERDYA: ; ISR not in use reti WDTAD: ; ISR not in use reti PCIAA: ; ISR not in use reti PCIDA: ; ISR not in use reti ; reset: cli ; Interrupts sperren ldi temp, low(ramend) ; Stackpointer setzen out spl, temp ;ldi temp, high(ramend) ; fuer ATtiny4313 ;out sph, temp rcall regclr ; Registerreset rcall portinit ; Init I/O-Ports rcall twimain ; TWI/I2C-Setup rcall lcdinit ; LCD-Initialisierung sei ; generelle Interruptfreigabe rjmp main ; Sprung zum Hauptprogramm ; regclr: ; Registerreset clr inttemp clr intreg ldi temp, 0x00 ldi temp1, 0x00 ldi temp2, 0x00 ldi temp3, 0x00 ret ; portinit: ; Init I/O-Ports ldi temp, 0xFF ; PortB Ausgang TWI out ddrb, temp out portb, temp out ddrd, temp ldi temp, 0xFF out portd, temp ret ; main: ; Hauptprogramm rcall text_1 rcall text_2 rcall text_3 rjmp endlos ; endlos: ; Endlosschleife rjmp endlos ; text_1: ; Text1 Tabellenaufruf ldi temp, 0x82 ; Positionierung Anfang rcall cmd2lcd ; Zeile 1, Spalte 3 rcall wait2 ldi ZL, LOW(text1*2) ; Adresse des Strings in den ldi ZH, HIGH(text1*2) ; Z-Pointer laden rcall print ; Funktion print aufrufen rcall wait2 ret ; text_2: ; Text2 Tabellenaufruf ldi temp, 0xC2 ; Positionierung Anfang rcall cmd2lcd ; Zeile 1, Spalte 3 rcall wait2 ldi ZL, LOW(text2*2) ; Adresse des Strings in den ldi ZH, HIGH(text2*2) ; Z-Pointer laden rcall print ; Funktion print aufrufen rcall wait2 ret ; text_3: ; Text3 Tabellenaufruf ldi temp, 0xD6 ; Positionierung Anfang rcall cmd2lcd ; Zeile 1, Spalte 3 rcall wait2 ldi ZL, LOW(text3*2) ; Adresse des Strings in den ldi ZH, HIGH(text3*2) ; Z-Pointer laden rcall print ; Funktion print aufrufen rcall wait2 ret print: lpm ; erstes Byte des Strings nach R0 lesen mov temp, r0 ; R0 auf 0 testen cpi temp, 0x00 ; alternativer Befehl -> "tst" breq print_end ; wenn 0, dann zu print_end mov temp1, temp ; Datenausgabe hier nur ueber temp1 rcall char2lcd adiw ZL:ZH, 1 ; Adresse des Z-Pointers um 1 erhoehen rjmp print ; zum Anfang springen, um naechstes ; ; Byte aus der Tabelle ;zu holen print_end: rcall wait3 ret ; text1: .db "ATMEL ATtiny2313 ",0 ; text2: .db "an SainSmart2004 ",0 ; text3: .db "TWI/I2C via USI",0 ; ; ;- - - - Verzoegerungsschleifen - - - - - - - wait1: rcall wait3 nop rcall wait3 nop rcall wait3 nop rcall wait3 nop ret ; wait2: ; Verzoegerungsschleife 2: push yl ; Register sichern auf Stapel push yh push temp ; Sicherung von Temporaerregistern... push temp1 ; und Statusregister auf Stapel push temp2 in temp2, SREG ; (bei Interrupts notwendig) push temp2 ldi yl, low(zeit0) ; laedt Zaehlregisterpaar ldi yh, high(zeit0) ; mit oben deklariertem Wert... rjmp repeatx ; ..."zeit0" ; wait3: ; Verzoegerungsschleife 3: push yl ; Register sichern auf Stapel push yh push temp ; Sichern von Temporaerregistern push temp1 ; und Statusregister auf Stapel push temp2 in temp2, SREG push temp2 ldi yl, low(zeit1) ; laedt Zaehlregisterpaar ldi yh, high(zeit1) ; mit oben deklariertem Wert... rjmp repeatx ; ..."zeit1" ; repeatx: ; 16-Bit-Subtraktionsschleife: sbiw yl:yh, 1 ; decrementiert Doppelregister brne repeatx ; zaehlt bis Null pop temp2 ; Wiederherstellung out SREG, temp2 ; von "geretteten" Registern etc. pop temp2 pop temp1 pop temp pop yh pop yl ret ; ; TWI/I2C Routinen via USI Interface (ATtiny2313/4313) ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - twimain: cli rcall twiinit rcall twistart ldi temp, 0x70 ; Adresse A0,A1,A2=GND + R/W-Bit (W=0; R=1) rcall twiout brts end ; Wenn NACK (Speicherbit in SREG gesetzt), ret ; dann Sprung zum Ende ; end: rjmp endlos ; twiinit: sbi portb, 7 ; SCL high sbi portb, 5 ; SDA high sbi ddrb, 7 ; PortB7 (SCL) als Ausgang sbi ddrb, 5 ; PortB5 (SDA) als Ausgang ldi temp, 0xFF out USIDR, temp ; Datenregister mit Einsen auffuellen ldi temp, 0x20 ; (1<no TWI clock out USICR,temp ret ; twidown: clr temp out USICR, temp ; USI-Funktion abschalten,PortB5, PortB7 wieder normal ret ; twistop: cbi portb, 5 ; SDA->L cbi USIDR, 7 ; Datenregister MSB->L nop nop nop nop nop sbi portb, 7 ; SCL->H ; twistop1: sbis pinb, 7 ; SCL H abwarten rjmp twistop1 sbi portb, 5 sbi USIDR, 7 ; SDA->H ret ; twistart: sbi portb, 5 ; SDA->H sbi USIDR, 7 ; Datenregister MSB->H nop nop nop sbi portb, 7 ; SCL->H ; twistart1: sbis pinb, 7 ; warten auf SCL=H rjmp twistart1 ; cbi USIDR, 7 ; Datenregister MSB->L nop nop nop cbi portb, 7 ; SCL->L nop nop nop nop nop ret ; twiout: ; Slaveadresse zusammen mit R/W-Bit in temp senden push temp push temp1 out USIDR, temp ; Adresse/Daten in Datenregister ldi temp, 0xF8 ; Im USI-Statusregister IR-Flags resetten, Counter auf 8 out USISR,temp ; (1<H (USI clock toggle mode) ; twiout2: sbis pinb, 7 ; SCL H abwarten rjmp twiout2 nop nop nop nop sbi USICR, USITC ; SCL H->L (USI clock toggle mode) nop nop nop nop sbi USICR, USICLK ; Datenregister schiebt+1 und Zaehler+1 nop dec temp1 ; Zaehler fuer restliche Bits erniedrigen cpi temp1, 0x00 brne twiout1 ; Schleife, bis Null erreicht ldi temp, 0xFF ; alle Flags im USI-Statusregister resetten out USISR, temp cbi ddrb, 5 ; SDA -> Eingang sbi USICR, USITC ; SCL L->H (USI clock toggle mode;ACK/NACK lesen) nop nop nop nop nop set ; Speicherbit im SREG setzen sbis pinb, 5 ; SDA auf H (NACK)? clt ; nein-> Speicherbit im SREG loeschen sbi USICR, USITC ; SCL H->L (USI clock toggle mode) sbi ddrb, 5 ; SDA auf Ausgang nop nop nop pop temp1 pop temp ret ; lcdinit: ;LCD-Port: D0-D3=n.c.; D4-D7=Daten; ; ; ; P7 | P6 | P5 | P4 | P3 | P2 | P1 | P0 ; ; D7 | D6 | D5 | D4 | LED| ENA| R|W| RS ; ;======================================= rcall wait1 ; LCD Self-Reset abwarten rcall twistart ldi temp, 0x70 ; Slave Startadresse + RW-Bit rcall twiout ; PCF8574->0x40; PCF8574A->0x70 rcall lcd_achtbitinit ; LCD-Init: acht Bit rcall lcd_acht_vier ; LCD-Init: acht zu vier Bit rcall lcd_vier_zwei_z ; LCD-Init: vier Bit, 2 Zeilen rcall lcd_on_off ; LCD-Init: Displaypuffer aus rcall lcd_clear ; LCD-Init: Anzeige loeschen rcall lcd_entrymode ; LCD-Init: Entry Mode Set ret ; lcd_achtbitinit: ; noetiger erster LCD-Software-Init ldi temp, 0b00001000 ; LED-Hintergrundlicht ein rcall twiout ldi temp, 0b00110000 ; 0x30 rcall twiout rcall enable rcall wait1 ldi temp, 0b00110000 ; 0x30 rcall twiout rcall enable rcall wait1 ldi temp, 0b00110000 ; 0x30 rcall twiout rcall enable rcall wait1 ret ; lcd_acht_vier: ; Acht-zu-Vierbitmodus-Wechsel push temp ldi temp, 0b00001000 ; LED-Hintergrundlicht ein rcall twiout ldi temp, 0b00100000 ; zunaechst nur 4-Bit-Modus, rcall twiout rcall enable rcall wait2 ; noch 8-Bit-Befehlsbreite pop temp ret ; lcd_vier_zwei_z: ; Vierbitmodus; zwei Zeilen push temp ; Vierbitmodus ldi temp, 0b00101000 ; und zweizeilig, rcall cmd2lcd ; ab hier Steuerwort auch rcall wait2 ; im Vierbit-Modus senden pop temp ret ; lcd_on_off: ; On Off Control, Display ein/ausschalten: push temp ldi temp, 0b00001000 ; Display ausschalten, rcall cmd2lcd ; Cursor aus, Blinken aus rcall wait1 pop temp ret ; lcd_clear: ; Anzeigepuffer loeschen: push temp ldi temp, 0b00000001 rcall cmd2lcd rcall wait1 pop temp ret ; lcd_entrymode: ; Entry/Shift Mode Set: push temp ldi temp, 0b00000110 ; Cursor von links nach rechts rcall cmd2lcd ; kein Schieben rcall wait2 ldi temp, 0b00010000 ; kein Schieben, Cursorbewegung rcall cmd2lcd ; nach rechts rcall wait2 ldi temp, 0b00001100 ; Anzeige wieder einschalten rcall cmd2lcd ; Cursor aus, Blinken aus rcall wait2 ldi temp, 0b00000001 ; Anzeige nochmals loeschen rcall cmd2lcd rcall wait2 pop temp ret ; char2lcd: ; gibt Charakter via TWI auf LCD aus push temp ; rettet temps auf Stapel push temp1 mov temp1, temp ; Kopie des Wertes fuer weitere; ; ; Operation unten andi temp, 0b11110000 ; D0-D3-Daten-Nibble ausblenden ori temp, 0b00000001 ; RS=H maskieren rcall twiout ; Ausgabe D4-D7 auf B4-B7 rcall enable ; ersten Enableimpuls senden swap temp1 ; Daten-Nibble vertauschen andi temp1, 0b11110000 ; unteres Port-Nibble ausblenden ori temp1, 0b00001001 ; RS=H; LED-Hintergrundlicht ein mov temp, temp1 ; auf Ausgaberegister "temp" kopieren rcall twiout ; Ausgabe D0-D3 auf Port B4-B7 rcall enable ; zweiten Enableimpuls senden rcall wait2 ; LCD-Verarbeitungszeit abwarten pop temp1 ; Wiederherstellung von temps pop temp ret ; cmd2lcd: ; sendet Steuerzeichen via TWI an LCD push temp ; rettet temps auf Stapel push temp1 mov temp1, temp ; Kopie des Wertes fuer weitere; ; ; Operation unten andi temp, 0b11110000 ; RS=L; D0-D3-Daten-Nibble ausblenden rcall twiout ; Ausgabe D4-D7 auf B4-B7 rcall enable ; ersten Enableimpuls senden swap temp1 ; Nibble-Vertauschen, Wert aus temp; ; ; kopiert, siehe oben andi temp1, 0b11110000 ; unteres Port-Nibble ausblenden mov temp, temp1 ; auf Ausgaberegister "temp" kopieren rcall twiout ; Ausgabe D0-D3 auf Port B4-B7 rcall enable ; zweiten Enableimpuls senden rcall wait2 ; LCD-Verarbeitungszeit abwarten pop temp1 ; Wiederherstellung von temps pop temp ret ; enable: nop ori temp, 0b00000100 ; Enable-Bit ->H maskieren rcall twiout ; Ausgabe nop nop nop nop nop nop nop nop andi temp, 0b11111011 ; Enable-Bit ->L maskieren rcall twiout ; Ausgabe nop ret ;