;*************************************************** ; Test TWI ; MCU: ATMEL ATmega8535 ; Clock: 4 MHz (3.686 MHZ) ; TWI/I2C-PortB PC0=SCL; PC1=SDA ; LCD: 4x20 SainSmart2004; HD44780 compatible ; P7 P6 P5 P4 P3 P2 P1 P0 ; D7 D6 D5 D4 LED ENA R|W RS ; Device slave address: $38 (PCF8574A) 0x70 ; ATmega8535 memory use summary [bytes]: ; Segment Begin End Code Data Used Size Use% ;[.cseg] 0x000000 0x000362 760 106 866 8192 10.6% ;[.dseg] 0x000060 0x000060 0 0 0 512 0.0% ;[.eseg] 0x000000 0x000000 0 0 0 512 0.0% ;Assembly complete, 0 errors. 0 warnings ; ; Rev.: 04102026 ;*************************************************** ; ;Assembler direktives: ; .nolist .include "m8535def.inc" .list ; ; ; SRAM Definitions: ; .dseg ; Datasegment (SRAM) Start on .org 0x0060 ; address 0x0060 ; ; ; Constants: .equ delay0 = 1023 .equ delay1 = 65535 .equ taste = pind ;.equ comp = 36859 ; timer compare at 10 ms {MCUfreq/(40960-1)} ; ; (STK500=36859;at 4 MHz=39999) ; ; ; Register definitions: .def inttemp = r12 ; backup register for Interrupt-Routines .def intreg = r14 ; backup register for SREG on ISRs .def temp = r16 ; universal register for arithmetics .def temp1 = r17 .def temp2 = r18 .def temp3 = r19 ; .cseg ; Codesegment .org 0x0000 ; Start address rjmp reset ; Interrupt vektors addresses (default) ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - .org 0x0001 rjmp INT0adr ; External Interrupt 0 .org 0x0002 rjmp INT1adr ; External Interrupt 1 .org 0x0003 rjmp OC2adr ; Timer/Counter2 Compare Match .org 0x0004 rjmp OVF2adr ; Timer/Counter2 Overflow .org 0x0005 rjmp ICP1adr ; Timer/Counter1 Capture Event .org 0x0006 rjmp OC1Aadr ; Timer/Counter1 Compare Match A .org 0x0007 rjmp OC1Badr ; Timer/Counter1 Compare Match B .org 0x0008 rjmp OVF1adr ; Timer/Counter1 Overflow .org 0x0009 rjmp OVF0adr ; Timer/Counter0 Overflow .org 0x000A rjmp SPIadr ; SPI Serial Transfer Complete .org 0x000B rjmp URXCadr ; USART, RX Complete .org 0x000C rjmp UDREadr ; USART Data Register Empty .org 0x000D rjmp UTXCadr ; USART, TX Complete .org 0x000E rjmp ADCCadr ; ADC Conversion Complete .org 0x000F rjmp ERDYadr ; EEPROM Ready .org 0x0010 rjmp ACIadr ; Analog Comparator .org 0x0011 rjmp TWIadr ; Two-wire Serial Interface .org 0x0012 rjmp INT2adr ; External Interrupt Request 2 .org 0x0013 rjmp OC0adr ; TimerCounter0 Compare Match .org 0x0014 rjmp SPMRadr ; Store Program Memory Read ; ;Interrupt Service Routines - Interrupt Handler ;- - - - - - - - - - - - - - - - - - - - - - - - - INT0adr: ; ISR not in use reti INT1adr: ; ISR not in use reti OC2adr: ; ISR not in use reti OVF2adr: ; ISR not in use reti ICP1adr: ; ISR not in use reti OC1Aadr: ; ISR not in use ;rjmp timer_interrupt reti OC1Badr: ; ISR not in use reti OVF1adr: ; ISR not in use reti OVF0adr: ; ISR not in use rjmp switches SPIadr: ; ISR not in use reti URXCadr: ; ISR not in use reti UDREadr: ; ISR not in use reti UTXCadr: ; ISR not in use reti ADCCadr: ; ISR not in use reti ERDYadr: ; ISR not in use reti ACIadr: ; ISR not in use reti TWIadr: ; ISR not in use reti INT2adr: ; ISR not in use reti OC0adr: ; ISR not in use reti SPMRadr: ; ISR not in use reti ; reset: cli ; disable all interrupts ldi temp, low(ramend) ; Stackpointer set up out spl, temp ldi temp, high(ramend) out sph, temp ldi yl, low(0x0060) ; <<8 start SRAM low(0x0060) ldi yh, high(0x0060); &255 start SRAM high(0x0000) ldi temp, 0x00 init10x: ; clear SRAM st y+, temp cpi yl, low(ramend+1) ; ram end (low) reached? brne init10x ; no => loop cpi yh, high(ramend+1) ; ram end (high) reached? brne init10x ; no => loop rcall regclr ; register cleanup rcall portinit ; init I/O-ports rcall timerinit ; Timer setup rcall twiinit ; TWI/I2C setup rcall lcdinit ; LCD-initialization sei ; enable all interrupts rjmp main ; jump to main program ; regclr: ; set all registers to zero 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 ; Port A,B output/pullups out ddra, temp out porta, temp out ddrb, temp out portb, temp ldi temp, 0x00 ; Port D input switches out ddrd, temp ldi temp, 0xFF ; pullups out portd, temp ldi temp, 0x00 out ddrc, temp ; input i2c ldi temp, 0xFF ; pullups out portc, temp ret ; timerinit: ; Timer0 configuration ; ; Prescaler setup for instance clock/1024 ; ; CS02=1, CS01=0, CS00=1 normal timer mode ldi temp, 0x05 ; (1<0x40; PCF8574A->0x70 rcall lcd_eight_bit ; LCD-Init: eight bit rcall lcd_eight_four ; LCD-Init: eight to four bit change rcall lcd_four_two_r ; LCD-Init: four bit, 2 rows rcall lcd_on_off ; LCD-Init: display buffer off rcall lcd_clear ; LCD-Init: clear display rcall lcd_entrymode ; LCD-Init: Entry Mode Set ret ; lcd_eight_bit: ; first LCD synchronizing init ldi temp, 0b00001000 ; LED-backlight on rcall i2c_write rcall wait3 ldi temp, 0b00110000 ; 0x30 rcall i2c_write ; output via TWI subroutine rcall enable ; call enable impuls subroutine rcall wait3 ; wait for lcd processing ldi temp, 0b00110000 ; 0x30 rcall i2c_write rcall enable rcall wait3 ldi temp, 0b00110000 ; 0x30 rcall i2c_write rcall enable rcall wait2 ret ; lcd_eight_four: ; eight to four bit change push temp ldi temp, 0b00001000 ; LED-backlight on rcall i2c_write ldi temp, 0b00100000 ; first, four bit mode, only rcall i2c_write rcall enable rcall wait2 ; still lcd remains on 8 bit frame pop temp ; when accepting command lines ret ; lcd_four_two_r: ; four bit modus; two rows push temp ldi temp, 0b00101000 rcall cmd2lcd ; from now on lcd accepts rcall wait2 ; commands in a four bit frame, only pop temp ; do with call cmd2lcd subroutine ret ; lcd_on_off: ; On Off Control, swith display on/off: push temp ldi temp, 0b00001000 ; switch off display rcall cmd2lcd ; no cursor, no blinking pop temp ret ; lcd_clear: ; clear entire display buffer: push temp ldi temp, 0b00000001 rcall cmd2lcd rcall wait3 pop temp ret ; lcd_entrymode: ; Entry/Shift Mode Set: push temp ldi temp, 0b00000110 ; cursor move direction from left to right rcall cmd2lcd ; no display shifting ldi temp, 0b00010000 ; no display shifting, cursor move rcall cmd2lcd ; from left to right ldi temp, 0b00001100 ; display on again rcall cmd2lcd ; no cursor, blinking off ldi temp, 0b00000001 ; clearing display once more rcall cmd2lcd pop temp ret ; lcd_entrymode_01: push temp ldi temp, 0b00000110 ; cursor move direction from left to right rcall cmd2lcd ; no display shifting ldi temp, 0b00011100 ; display shifting, cursor move rcall cmd2lcd ; from left to right ldi temp, 0b00001111 ; display on again rcall cmd2lcd ; cursor, blinking on ldi temp, 0b00000001 ; clearing display once more rcall cmd2lcd pop temp ret ; char2lcd: ; charakter output "temp" on LCD via TWI: push temp ; saves "temps" on stack push temp1 mov temp1, temp ; content's copy for further actions below; andi temp, 0b11110000 ; blanking out D0-D3 data nibble ori temp, 0b00000001 ; RS=H masking rcall i2c_write ; output D4-D7 on B4-B7 rcall enable ; output first enable impuls swap temp1 ; swapping nibbles, uses copy of temp to temp1 andi temp1, 0b11110000 ; blanking out LSB port nibble ori temp1, 0b00001001 ; RS=H; LED-backlight on mov temp, temp1 ; copy temp1 to output register in use temp rcall i2c_write ; output D0-D3 on Port B4-B7 rcall enable ; output second enable impuls rcall wait2 ; wait for LCD processing pop temp1 ; reestablishing temps ... pop temp ; ...previous saved on stack ret ; cmd2lcd: ; transmitting instructions "temp" towards LCD via TWI push temp ; saves "temps" on stack push temp1 mov temp1, temp ; content's copy for further actions below andi temp, 0b11110000 ; RS=L; blanking out D0-D3 data nibble rcall i2c_write ; output D4-D7 on B4-B7 rcall enable ; output first enable impuls swap temp1 ; swapping nibbles, uses copy of temp to temp1 andi temp1, 0b11110000 ; blanking out LSB port nibble mov temp, temp1 ; copy temp1 to output register in use temp rcall i2c_write ; output D0-D3 on Port B4-B7 rcall enable ; output second enable impuls rcall wait2 ; wait for LCD processing pop temp1 ; reestablishing temps ... pop temp ; ...previous saved on stack ret ; enable: ori temp, 0b00000100 ; H-masking enable bit rcall i2c_write ; output via subroutine "i2c_write" andi temp, 0b11111011 ; L-masking enable bit rcall i2c_write ; output via subroutine "i2c_write" ret ; ;************** ; converting binary to decimal (ASCII) bin2dec: ; "temp1" 8 bit binary to 3 digit numbers push temp ; with leading zeros push temp1 push temp2 mov temp3, temp1 ; counts amount of hundreds ldi temp2, 0x30 ; adding ASCII code offset ; num_1: subi temp3, 100 ; subtracts value 100 from "temp3" brcs num_2 ; jump to output, if negative flag "overflow" set inc temp2 rjmp num_1 ; output amount of loops for "hundreds" ; num_2: mov temp, temp2 rcall char2lcd subi temp3, -100 ; adding "100" again, due previous loop ldi temp2, 0x30 ; subracted "100" too much ; num_3: ; counting amount of tens subi temp3, 10 ; subtracts value 10 brcs num_4 ; jump to output, if negative flag "overflow" set inc temp2 rjmp num_3 ; output amount of loops for "tens" ; num_4: mov temp, temp2 rcall char2lcd subi temp3, -10 ; adding "10" again, due previous loop ; ; subracted "10" too much ldi temp2, 0x30 ; adding ASCII code offset add temp2, temp3 mov temp, temp2 rcall char2lcd ; output amount of reamining "ones" rcall i2c_stop pop temp2 pop temp1 pop temp ret ;***************************************************** ;- FIN -