|
;--------------------------------------------------------
;
; Developed by Claes Sundman , menola@home.se
;
; Version 0.1
;
; Alarmclock with calender and temp. and humidity sensor
;
; AT90S4433 PIN Project PIN Project
;
; RESET 1 Resetbutton 28 PC5 Button1
; PD0 2 - 27 PC4 Button2
; PD1 3 RS 26 PC3 Button3
; PD2 4 R/W 25 PC2 Button4
; PD3 5 E 24 PC1
; PD4 6 D4 23 PC0 LED
; VCC 7 22 AGND
; GND 8 21 AREF +5.0V
; X1 9 20 AVCC
; X2 10 19 PB5
; PD5 11 D5 18 PB4 I2C_SDA
; PD6 12 D6 17 PB3 I2C_SCL
; PD7 13 D7 16 PB2 SCLK DS1302
; PB0 14 I/0 DS1302 15 PB1 TST DS1302
;
;--------------------------------------------------------
.include "4433def.inc"
;.include "i2c.inc"
;--------------------------------------------------------
.DSEG
.def tmp1 = r16
.def tmp2 = r17
.def tmp3 = r18
.def tmp4 = r19
.def tmp5 = r20
.def tmp6 = r21 ; Delay loop variable
.equ b_dir = 0 ; transfer direction bit in TWIadr
.equ TWIrd = 1 ; write bit
.equ TWIwr = 0 ; write bit
.equ SCLP = 3 ; SCL Pin number (port B)
.equ SDAP = 4 ; SDA Pin number (port B)
.def TWIdelay = r22 ; Delay loop variable
.def TWIdata = r23 ; TWI data transfer register
.def TWIadr = r24 ; TWI address and direction register
.def TWIstat = r25 ; TWI bus status register
; SHT11 needs 11ms of delay after power up!
; SoftReset then wait 11ms
; .equ ADDR_SHT11_temp = 0x01 ; SHT11 address byte Temp. read (00000011)
; .equ ADDR_SHT11_humi = 0x02 ; SHT11 address byte Humidity read (00000101)
; .equ ADDR_SHT11_status_read = 0x03 ; SHT11 address byte Status read (00000111)
; .equ ADDR_SHT11_status_write = 0x07 ; SHT11 address byte Status write (00000110)
; .equ ADDR_SHT11_softreset = 0x0F ; SHT11 address byte SoftReset write(00011110)
; .equ ADDR_24LC16 = 0x50 ; 24LC16, EEPROM address (10100000)
; .equ 24LC16_memsize = 16384 ; 2048x8, EEPROM size
; M24C16B Microchip max 400khz and 5ms to write.
; Address: 000 - 7FF = 24LC26B
;--------------------------------------------------------
.cseg
.org $000
rjmp reset
;rjmp INT_0 ; Ext. Interrupt 0
;rjmp INT_1 ; Ext. Interrupt 1
;reti TIMER1_CAPT ; Timer/Counter1 Capture
;reti TIMER1_COMP ; Timer/Counter1 Overflow
;reti TIMER1_OVF ; Timer/Counter1 Overflow
;reti TIMER0_OVF ; Timer/Counter0 Overflow
;reti SPI_STC ; SPI Transfer Complete
;rjmp UART_RX ; UART Receive, serial data in
;reti UART_UDRE ; UART empty
;reti UART_TX ; UART Transmit
;reti ADAC ; ADC Ready
;reti EEE_RDY ; EE2 Ready
;reti ANA_COMP ; Analog comparator
;--------------------------------------------------------
; Program memory starts here
reset:
ldi tmp1, low(RAMEND)
out SPL, tmp1
ldi tmp1, 0xFF ; Init keys
out PORTC, tmp1 ; -"-
out DDRC, tmp1 ; -"-
out DDRB, tmp1
ldi tmp1, 0x00
out PORTB, tmp1
CLR tmp1
CLR tmp2
CLR tmp3
;--------------------------------------------------------
main:
rcall init_port
rcall lcd_init
; rcall lcd_ready
; rcall alarm_led_off
rcall ds1302_init
; rcall i2c
rcall loop
loop:
;rcall keys
rcall ds1302_read_to_lcd
rcall ds1302_days_to_lcd
;rcall temp
rjmp loop
;--------------------------------------------------------
alarm_led_on:
sbi portc, 0
ret
alarm_led_off:
cbi portc, 0
ret
;--------------------------------------------------------
keys:
push tmp1
in tmp1, PORTC
pop tmp1
ret
;--------------------------------------------------------
temp:
ldi tmp1, 0x8E
rcall lcd_cmd
ldi tmp1, 0b11011111
rcall lcd_char
ldi tmp1, 'C'
rcall lcd_char
ret
;--------------------------------------------------------
; Initial date/time code for lcd stored in format
mon_day: .db "Monday *C";,0xA9
tues_day: .db "Tuesday *C";,0xA9
wednes_day: .db "Wednesday *C";,0xA9
thurs_day: .db "Thursday *C";,0xA9
fri_day: .db "Friday *C";,0xA9
satur_day: .db "Saturday *C";,0xA9
sun_day: .db "Sunday *C";,0xA9
ds1302_days_to_lcd:
ldi tmp1, 0x80 ; first line
rcall lcd_cmd
ldi tmp1, $8B ; read days
rcall RdCmd
ldi tmp2, 0b00000001 ; test days...
cp tmp1, tmp2
breq monday
ldi tmp2, 0b00000010
cp tmp1, tmp2
breq tuesday
ldi tmp2, 0b00000011
cp tmp1, tmp2
breq wednesday
ldi tmp2, 0b00000100
cp tmp1, tmp2
breq thursday
ldi tmp2, 0b00000101
cp tmp1, tmp2
breq friday
ldi tmp2, 0b00000110
cp tmp1, tmp2
breq saturday
ldi tmp2, 0b00000111
cp tmp1, tmp2
breq sunday
ret
monday:
ldi tmp1, 0x00
rcall lcd_cmd
ldi r30, low (mon_day*2)
ldi r31, high(mon_day*2)
ldi tmp2, 16
rcall LCD_PrintPM
ret
tuesday:
ldi r30, low (tues_day*2)
ldi r31, high(tues_day*2)
ldi tmp2, 16
rcall LCD_PrintPM
ret
wednesday:
ldi r30, low (wednes_day*2)
ldi r31, high(wednes_day*2)
ldi tmp2, 16
rcall LCD_PrintPM
ret
thursday:
ldi r30, low (thurs_day*2)
ldi r31, high(thurs_day*2)
ldi tmp2, 16
rcall LCD_PrintPM
ret
friday:
ldi r30, low (fri_day*2)
ldi r31, high(fri_day*2)
ldi tmp2, 16
rcall LCD_PrintPM
ret
saturday:
ldi r30, low (satur_day*2)
ldi r31, high(satur_day*2)
ldi tmp2, 16
rcall LCD_PrintPM
ret
sunday:
ldi r30, low (sun_day*2)
ldi r31, high(sun_day*2)
ldi tmp2, 16
rcall LCD_PrintPM
ret
;--------------------------------------------------------
; Init the LCD in 4-bit mode BEGINNING
lcd_init:
push tmp1
ldi tmp1, 0x30
out portd, tmp1
rcall enable
rcall wait
rcall wait
ldi tmp1, 0x30
out portd, tmp1
rcall enable
rcall wait
ldi tmp1, 0x30
out portd, tmp1
rcall enable
rcall wait
ldi tmp1, 0x20
rcall lcd_cmd
ldi tmp1, 0x28
rcall lcd_cmd
ldi tmp1, 0x14
rcall lcd_cmd
ldi tmp1, 0x0c
rcall lcd_cmd
ldi tmp1, 0x06
rcall lcd_cmd
ldi tmp1, 0x01
rcall lcd_cmd
ldi tmp1, 0x80
rcall lcd_cmd
pop tmp1
ret
;--------------------------------------
; Init the LCD in 4-bit mode READY
lcd_ready:
ldi tmp1, 'L'
rcall lcd_char
ldi tmp1, 'C'
rcall lcd_char
ldi tmp1, 'D'
rcall lcd_char
ldi tmp1, ' '
rcall lcd_char
ldi tmp1, 'T'
rcall lcd_char
ldi tmp1, 'e'
rcall lcd_char
ldi tmp1, 's'
rcall lcd_char
ldi tmp1, 't'
rcall lcd_char
ldi tmp1, '!'
rcall lcd_char
ret
;--------------------------------------------------------
init_port:
ldi tmp1, 0xff
out ddrd, tmp1
ret
;--------------------------------------------------------
lcd_cmd:
push tmp1
push tmp2
rcall lcd_busyread
mov tmp2, tmp1 ;Load the value to the tmp2 also.
andi tmp2, 0xf0 ;select the upper 4bits of the sent byte
ori tmp2, 0x00 ;mask the tmp2 RS=0
out portd, tmp2 ;put result out to portc
rcall enable
mov tmp2, tmp1 ;load sent value to tmp2
andi tmp2, 0x0f ;select the 4 lower bits
swap tmp2 ;swap the lower D3-D0 bits to D7-D4
ori tmp2, 0x00 ;mask the tmp2 RS=0
out portd, tmp2 ;put result out to portc
rcall enable
pop tmp2
pop tmp1
rcall wait_short
ret
;--------------------------------------------------------
lcd_char:
push tmp1
push tmp2
rcall lcd_busyread
mov tmp2, tmp1 ;Load the value to the tmp2 also.
andi tmp2, 0xf0 ;select the upper 4bits of the sent byte
ori tmp2, 0x02 ;mask the tmp2 RS=1
out portd, tmp2 ;put result out to portc
rcall enable
mov tmp2, tmp1 ;load sent value to tmp2
andi tmp2, 0x0f ;select the 4 lower bits
swap tmp2 ;swap the lower D3-D0 bits to D7-D4
ori tmp2, 0x02 ;mask the tmp2 and RS=1
out portd, tmp2 ;put result out to portc
rcall enable
pop tmp2
pop tmp1
ret
;--------------------------------------------------------
lcd_busyread:
push tmp1
ldi tmp1, 0x00 ;clear portC
out portd, tmp1 ;make it happen
ldi tmp1, 0x0f ;turn D7-D4 to inputs
out ddrd, tmp1 ;make it happen
lcd_busyread_wait:
sbi portd, 2 ;R/W = 1
sbi portd, 3 ;Enable = 1
nop
nop
nop
nop
nop
nop
nop
in tmp1, pind ;read from LCD
cbi portd, 3 ;Enable = 0
nop
nop
nop
nop
rcall enable ;to complete reading the byte
andi tmp1, 0x80 ;want only D7
cpi tmp1, 0x00 ;is it zero ?
brne lcd_busyread_wait ;jump if not equal to zero
ldi tmp1, 0xff ;make portC to output
out ddrd, tmp1 ;make it happen
pop tmp1
ret
;--------------------------------------------------------
; Toggle the Enable on the LCD
enable:
sbi portd, 3 ;pin D3 = 1
push tmp1
ldi tmp1, 10
enable_loop:
dec tmp1
brne enable_loop
pop tmp1
cbi portd, 3 ;pin D3 = 0
ret
;--------------------------------------------------------
wait_short:
push tmp1
ldi tmp1, 0x80
wait_short_loop:
dec tmp1
brne wait_short_loop
pop tmp1
ret
wait:
push tmp2
ldi tmp2, 0xff
wait_loop:
rcall wait_short
dec tmp2
brne wait_loop
pop tmp2
ret
;--------------------------------------------------------
; LCD_PrintMem. Prints from memory. Put the starting,
; memory location in Z (r31:r30). Put the number of
; characters to print in tmp2. After execution,
; Z is at the character AFTER the last to be
; printed and tmp2 is zero. This function will
; not wrap if you the string is bigger than the LCD.
LCD_PrintMem:
push tmp1
LCD_MemRead:
ld tmp1, Z+
rcall lcd_char
dec tmp2
brne LCD_MemRead
pop tmp1
ret
;--------------------------------------------------------
; LCD_PrintPM. Prints from program memory
LCD_PrintPM:
push r0
push tmp1
LCD_PMRead:
lpm
mov tmp1, r0
rcall lcd_char
adiw r30, 1
dec tmp2
brne LCD_PMRead
pop tmp1
pop r0
ret
;--------------------------------------------------------
; Macros, delay 0.125 x 40 = 5us 200khz and max are 400khz
;.MACRO
rtc_delay:
push tmp1
ldi tmp1, 0xFF;40 Load with 4 to generate 2MHz to DS1302
rtc_delay_2:
dec tmp1
brne rtc_delay_2
pop tmp1
ret
;.ENDMACRO
;--------------------------------------------------------
; DS1302 macro
.MACRO IO_in
cbi DDRB, 0 ; Make I/O line input.
.ENDMACRO
.MACRO IO_out
sbi DDRB, 0 ; Make I/O line output.
.ENDMACRO
.MACRO SCLK_high
nop
nop
nop
nop
nop
sbi PORTB, 2 ; Set SCLK output.
nop
nop
nop
nop
nop
.ENDMACRO
.MACRO SCLK_low
nop
nop
nop
nop
nop
cbi PORTB, 2
nop
nop
nop
nop
nop
.ENDMACRO
.MACRO IO_high
sbi PORTB, 0
.ENDMACRO
.MACRO IO_low
cbi PORTB, 0
.ENDMACRO
.MACRO RST_high
nop
nop
nop
nop
nop
sbi PORTB, 1
nop
nop
nop
nop
nop
.ENDMACRO
.MACRO RST_low
nop
nop
nop
nop
nop
cbi PORTB, 1
nop
nop
nop
nop
nop
.ENDMACRO
;--------------------------------------------------------
; Write a cmd / data combo from tmp1 / tmp2 to the RTC.
WrtCmd:
RST_high
mov tmp3, tmp1 ; write command to RTC
rcall WrtByte
mov tmp3, tmp2 ; write data to RTC
rcall WrtByte
RST_low
ret
; Clock out the byte in tmp3 to the RTC.
; Data is clocked out starting with bit 0.
; Data is clocked into the RTC on the rising edge.
WrtByte:
ldi tmp1, 8 ; 8 bits to clock out.
WrtByte1:
lsr tmp3 ; rotate.............bit 0 into C
brcc WrtByte2 ; skip if bit = 0
IO_high
rjmp WrtByte3
WrtByte2:
IO_low
WrtByte3:
SCLK_high
dec tmp1
breq WrtByte4
SCLK_low ; Clock it out.
rjmp WrtByte1 ; Do all the bits.
WrtByte4:
IO_high ; turn on pull up.
SCLK_low ; Clock data in (if applicable). @@ Claes , last bit is still here after last clock
clc
ret
; Read a byte following write of command byte.
RdCmd:
RST_high
IO_out
mov tmp3, tmp1
rcall WrtByte
IO_in
rcall RdByte
mov tmp1, tmp3
RST_low
IO_out
ret
; Clock in a byte from the RTC to tmp3
RdByte:
ldi tmp3, 0 ; Empty register for data
ldi tmp1, 8 ; 8 bits to clock in.
RdByte1:
clc ; Clear carry.
sbic PINB, 0 ; Jump if I/O = 0.
sec ; Set Carry Flag
ror tmp3 ; Rotate data into bit.
SCLK_high ; clock in next bit.
SCLK_low
dec tmp1 ; more bits ?
brne RdByte1
ret
;--------------------------------------------------------
ds1302_init:
ldi tmp1, $8E ; remove write protection
ldi tmp2, $00 ;
rcall WrtCmd
ldi tmp1, $80 ; write seconds
ldi tmp2, 0x55 ; 00; 0xxx xxxx
rcall WrtCmd
ldi tmp1, $82 ; write minutes
ldi tmp2, 0x59 ; 00; 0xxx xxxx
rcall WrtCmd
ldi tmp1, $84 ; write hours, 24h mode
ldi tmp2, 0x23 ; 00xx xxxx
rcall WrtCmd
ldi tmp1, $8A ; write day
ldi tmp2, 0x01 ; monday 01 - 07
rcall WrtCmd
ldi tmp1, $86 ; write date for day
ldi tmp2, 0x27 ; 00xx xxxx
rcall WrtCmd
ldi tmp1, $88 ; write month
ldi tmp2, 0x02 ; 000x xxxx
rcall WrtCmd
ldi tmp1, $8C ; write year
ldi tmp2, 0x03 ; xxxx xxxx
rcall WrtCmd
ret
; Info: BCD BCD
; sec. 0xxx xxxx
; min. 0xxx xxxx
; hour 00xx xxxx
; days 0000 0xxx
ds1302_read_to_lcd:
ldi tmp1, 0xC0
rcall lcd_cmd
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
ldi tmp1, $85 ; read 10 hour.
rcall RdCmd
swap tmp1
andi tmp1, 0x3F
ori tmp1, 0x30
rcall lcd_char
ldi tmp1, $85 ; read 1 hour.
rcall RdCmd
andi tmp1, 0x3F
ori tmp1, 0x30
rcall lcd_char
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
ldi tmp1, 0xC2 ; colon
rcall lcd_cmd
ldi tmp1, ':'
rcall lcd_char
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
ldi tmp1, $83 ; read 10 minutes.
rcall RdCmd
swap tmp1
andi tmp1, 0x3F
ori tmp1, 0x30
rcall lcd_char
ldi tmp1, $83 ; read 1 minutes.
rcall RdCmd
andi tmp1, 0x3F
ori tmp1, 0x30
rcall lcd_char
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
ldi tmp1, 0xC5 ; colon
rcall lcd_cmd
ldi tmp1, ':'
rcall lcd_char
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
ldi tmp1, $81 ; read seconds.
rcall RdCmd
swap tmp1
andi tmp1, 0x3F
ori tmp1, 0x30
rcall lcd_char
ldi tmp1, $81
rcall RdCmd
andi tmp1, 0x3F
ori tmp1, 0x30
rcall lcd_char
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
ldi tmp1, 0xCB ; date@lcd
rcall lcd_cmd
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
ldi tmp1, $87 ; read date.
rcall RdCmd
swap tmp1
andi tmp1, 0x3F
ori tmp1, 0x30
rcall lcd_char
ldi tmp1, $87
rcall RdCmd
andi tmp1, 0x3F
ori tmp1, 0x30
rcall lcd_char
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
ldi tmp1, '/'
rcall lcd_char
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
ldi tmp1, $89 ; read month.
rcall RdCmd
swap tmp1
andi tmp1, 0x3F
ori tmp1, 0x30
rcall lcd_char
ldi tmp1, $89
rcall RdCmd
andi tmp1, 0x3F
ori tmp1, 0x30
rcall lcd_char
ret
;***************************************************************************
;* Supports both 7-bit and 10-bit addressing.
;* TWI functions :
;* 'TWI_start' - Issues a start condition and sends address
;* and transfer direction.
;* 'TWI_rep_start' - Issues a repeated start condition and sends
;* address and transfer direction.
;* 'TWI_do_transfer' - Sends or receives data depending on
;* direction given in address/dir byte.
;* 'TWI_stop' - Terminates the data transfer by issue a
;* stop condition.
;* Code Size : 81 words (maximum)
;* Register Usage : 4 High, 0 Low
;*
;* TWI_hp_delay:
;* TWI_qp_delay
;* hp - half TWI clock period delay (normal: 5.0us / fast: 1.3us)
;* qp - quarter TWI clock period delay (normal: 2.5us / fast: 0.6us)
;***************************************************************************
TWI_hp_delay:
ldi TWIdelay, 2
TWI_hp_delay_loop:
dec TWIdelay
brne TWI_hp_delay_loop
ret
TWI_qp_delay:
ldi TWIdelay, 1
TWI_qp_delay_loop:
dec TWIdelay
brne TWI_qp_delay_loop
ret
;***************************************************************************
;* TWI_rep_start Assert repeated start condition and sends slave address.
;* TWIadr - Contains the slave address and transfer direction.
;* Carry flag - Cleared if a slave responds to the address.
;* This funtion must be directly followed by TWI_start.
;***************************************************************************
TWI_rep_start:
sbi DDRB, SCLP ; force SCL low
cbi DDRB, SDAP ; release SDA
rcall TWI_hp_delay ; half period delay
cbi DDRB, SCLP ; release SCL
rcall TWI_qp_delay ; quarter period delay
;***************************************************************************
;* FUNCTION
;* TWI_start
;* DESCRIPTION
;* Generates start condition and sends slave address.
;* USAGE
;* TWIadr - Contains the slave address and transfer direction.
;* RETURN
;* Carry flag - Cleared if a slave responds to the address.
;* NOTE
;* IMPORTANT! : This funtion must be directly followed by TWI_write.
;***************************************************************************
TWI_start:
mov TWIdata,TWIadr ; copy address to transmitt register
sbi DDRB, SDAP ; force SDA low
rcall TWI_qp_delay ; quarter period delay
;***************************************************************************
;* FUNCTION
;* TWI_write
;* DESCRIPTION
;* Writes data (one byte) to the TWI bus. Also used for sending
;* the address.
;* USAGE
;* TWIdata - Contains data to be transmitted.
;* RETURN
;* Carry flag - Set if the slave respond transfer.
;* NOTE
;* IMPORTANT! : This funtion must be directly followed by TWI_get_ack.
;***************************************************************************
TWI_write:
sec ; set carry flag
rol TWIdata ; shift in carry and out bit one
rjmp TWI_write_first
TWI_write_bit:
lsl TWIdata ; if transmit register empty
TWI_write_first:
breq TWI_get_ack ; goto get acknowledge
sbi DDRB, SCLP ; force SCL low
brcc TWI_write_low ; if bit high
nop ; (equalize number of cycles)
cbi DDRB, SDAP ; release SDA
rjmp TWI_write_high
TWI_write_low: ; else
sbi DDRD, SDAP ; force SDA low
rjmp TWI_write_high ; (equalize number of cycles)
TWI_write_high:
rcall TWI_hp_delay ; half period delay
cbi DDRB, SCLP ; release SCL
rcall TWI_hp_delay ; half period delay
rjmp TWI_write_bit
;***************************************************************************
;* FUNCTION
;* TWI_get_ack
;* DESCRIPTION
;* Get slave acknowledge response.
;* USAGE
;* (used only by TWI_write in this version)
;* RETURN
;* Carry flag - Cleared if a slave responds to a request.
;***************************************************************************
TWI_get_ack:
sbi DDRB, SCLP ; force SCL low
cbi DDRB, SDAP ; release SDA
rcall TWI_hp_delay ; half period delay
cbi DDRB, SCLP ; release SCL
TWI_get_ack_wait:
sbis PINB, SCLP ; wait SCL high(In case wait states are inserted)
rjmp TWI_get_ack_wait
clc ; clear carry flag
sbic PINB,SDAP ; if SDA is high
sec ; set carry flag
rcall TWI_hp_delay ; half period delay
ret
;***************************************************************************
;* FUNCTION
;* TWI_do_transfer
;* DESCRIPTION
;* Executes a transfer on bus. This is only a combination of TWI_read
;* and TWI_write for convenience.
;* USAGE
;* TWIadr - Must have the same direction as when TWI_start was called.
;* see TWI_read and TWI_write for more information.
;* RETURN
;* (depends on type of transfer, read or write)
;* NOTE
;* IMPORTANT! : This funtion must be directly followed by TWI_read.
;***************************************************************************
TWI_do_transfer:
sbrs TWIadr, b_dir ; if dir = write
rjmp TWI_write ; goto write data
;***************************************************************************
;* TWI_reads data (one byte) from the TWI bus.
;* USAGE
;* Carry flag - If set no acknowledge is given to the slave
;* indicating last read operation before a STOP.
;* If cleared acknowledge is given to the slave
;* indicating more data.
;* TWIdata - Contains received data.
;* This funtion must be directly followed by TWI_put_ack.
;***************************************************************************
TWI_read:
rol TWIstat ; store acknowledge (used by TWI_put_ack)
ldi TWIdata, 0x01 ; data = 0x01
TWI_read_bit: ; do
sbi DDRD, SCLP ; force SCL low
rcall TWI_hp_delay ; half period delay
cbi DDRD, SCLP ; release SCL
rcall TWI_hp_delay ; half period delay
clc ; clear carry flag
sbic PIND,SDAP ; if SDA is high
sec ; set carry flag
rol TWIdata ; store data bit
brcc TWI_read_bit ; while receive register not full
;***************************************************************************
;* TWI_put_ack Put acknowledge.(used only by TWI_read in this version)
;***************************************************************************
TWI_put_ack:
sbi DDRD, SCLP ; force SCL low
ror TWIstat ; get status bit
brcc TWI_put_ack_low ; if bit low goto assert low
cbi DDRD, SDAP ; release SDA
rjmp TWI_put_ack_high
TWI_put_ack_low: ; else
sbi DDRD, SDAP ; force SDA low
TWI_put_ack_high:
rcall TWI_hp_delay ; half period delay
cbi DDRD, SCLP ; release SCL
TWI_put_ack_wait:
sbis PIND, SCLP ; wait SCL high
rjmp TWI_put_ack_wait
rcall TWI_hp_delay ; half period delay
ret
;***************************************************************************
;* TWI_stop Assert stop condition.
;***************************************************************************
TWI_stop:
sbi DDRB, SCLP ; force SCL low
sbi DDRB, SDAP ; force SDA low
rcall TWI_hp_delay ; half period delay
cbi DDRB, SCLP ; release SCL
rcall TWI_qp_delay ; quarter period delay
cbi DDRD, SDAP ; release SDA
rcall TWI_hp_delay ; half period delay
ret
;***************************************************************************
;* TWI_init Initialization of the TWI bus interface.
;* Call this function once to initialize the TWI bus. No parameters
;* are required. PORTD and DDRD pins not used by the TWI bus interface will be
;* set to Hi-Z (!). This function can be combined with other PORTD initializations.
;***************************************************************************
TWI_init:
clr TWIstat ; clear TWI status register (used as a temporary register)
out PORTB, TWIstat ; set TWI pins to open colector
out DDRB, TWIstat
ret
;***************************************************************************
;* main - Test of TWI master implementation
;* Initializes TWI interface and shows an example of using it.
;
; .equ ADDR_SHT11_temp = 0x01 ; (00000011)
; .equ ADDR_SHT11_humi = 0x02 ; (00000101)
; .equ ADDR_SHT11_status_read = 0x03 ; (00000111)
; .equ ADDR_SHT11_status_write = 0x07 ; (00000110)
; .equ ADDR_SHT11_softreset = 0x0F ; (00011110)
; .equ ADDR_24LC16 = 0x50 ; (10100000)
; .equ 24LC16_memsize = 16384 ; 2048x8, EEPROM size
;
;***************************************************************************
i2c:
rcall TWI_init ; initialize
ldi TWIadr,$A0+TWIwr ; Set device Adr(00) = 0x55 and write
rcall TWI_start ; start
ldi TWIdata,$00 ; Write word address (0x00)
rcall TWI_do_transfer ; transfer
ldi TWIdata,$55 ; Set write data to 01010101b
rcall TWI_do_transfer ; transfer
rcall TWI_stop ; stop
ldi TWIadr,$A0+TWIwr ; Set device TWIdata = Adr(00) and write
rcall TWI_start ; start
ldi TWIdata,$00 ; Write word address
rcall TWI_do_transfer ; transfer
ldi TWIadr,$A0+TWIrd ; Set device address and read
rcall TWI_rep_start ; repeated start
sec ; Set no acknowledge (read is followed by a stop condition)
rcall TWI_do_transfer ; transfer (read)
rcall TWI_stop ; stop - releases bus
ret
;**** End of File ****
|