; ; i0.14.byte.asm ; ; Neil Gershenfeld CBA MIT 11/23/06 ; (c) Massachusetts Institute of Technology 2006 ; Permission granted for experimental and personal use; ; license for commercial use available from MIT ; .include "tn45def.inc" .equ buttonbit = 2 ; pushbutton bit .equ buttonpin = PB2 ; pushbutton pin .equ lightpin = PB0 ; light pin .equ clickbit = 4 ; click bit .equ clickpin = PB4 ; click pin .equ settle_count = 10 ; counts to wait for click to settle .equ char = 'I' ; character to send/receive .def temp = R16 ; temporary register .def temp1 = R17 ; temporary register .def txbyte = R18 ; byte to transit .def rxbyte = R19 ; receive byte .def bitcount = R20 ; bit counter .def clickspace = R21 ; click spacing .def triplespace = R22 ; triple click spacing .def count = R23 ; loop counter .def doublecount = R24 ; double loop count .cseg .org 0 rjmp reset ; ; click_duration ; click_duration: ldi temp, 2 click_duration_loop: dec temp brne click_duration_loop ret ; ; click_delay ; click_delay: ldi temp, 15 click_delay_loop: dec temp brne click_delay_loop ret ; ; char_delay ; delay after sending a character ; char_delay: ldi temp, 255 char_delay_loop: dec temp brne char_delay_loop ret ; ; putclick ; send char in txbyte clicks ; putclick: ldi bitcount, 8 sec; set start bit ; ; get click pin ready for output ; cbi PORTB, clickpin ; ; send start clicks ; sbi DDRB, clickpin rcall click_duration cbi DDRB, clickpin rcall click_delay sbi DDRB, clickpin rcall click_duration cbi DDRB, clickpin rcall click_delay ; ; send data clicks ; putclick0: lsr txbyte; get next bit brcc putclick1 ; if carry set, send a 1 click sbi DDRB, clickpin rcall click_duration cbi DDRB, clickpin rcall click_delay cbi DDRB, clickpin rcall click_duration cbi DDRB, clickpin rcall click_delay rjmp putclick2; otherwise ... putclick1: cbi DDRB, clickpin ; ... send a 0 click rcall click_duration cbi DDRB, clickpin rcall click_delay sbi DDRB, clickpin rcall click_duration cbi DDRB, clickpin rcall click_delay putclick2: dec bitcount; if not all bits sent brne putclick0; send next bit ; ; send stop clicks ; sbi DDRB, clickpin rcall click_duration cbi DDRB, clickpin rcall click_delay sbi DDRB, clickpin rcall click_duration cbi DDRB, clickpin rcall click_delay ; ; return to pull-up on click pin and return ; sbi PORTB, clickpin ret ; ; getclick ; input an I0 byte following first click ; getclick: ; ; delay for first click to settle ; ldi count, settle_count getclick_settle_start: dec count nop ; to even out timing for breq brne getclick_settle_start ; ; time arrivial of second start click ; ldi clickspace, settle_count getclick_time_start: inc clickspace breq getclick_timeout ; check for overflow sbic PINB, clickpin ; check for click rjmp getclick_time_start mov triplespace, clickspace add triplespace, clickspace add triplespace, clickspace ; ; decode data clicks ; clr rxbyte ldi bitcount, 8 getclick_bitloop: ; ; delay for click to settle ; ldi count, settle_count getclick_settle: dec count nop ; to even out timing for breq brne getclick_settle ; ; time arrivial of next click ; ldi count, settle_count getclick_time: inc count breq getclick_timeout ; check for overflow sbic PINB, clickpin ; check for click rjmp getclick_time ; ; determine bit delay ; mov doublecount, count add doublecount, count cp doublecount, triplespace brsh getclick_zero ; ; one bit ; sec ; set carry ror rxbyte ; shift in carry ; ; even out 0/1 timing ; mov count, clickspace getclick_space: dec count nop ; to even out timing for breq brne getclick_space ; ; decrement counter and output if byte received ; dec bitcount brne getclick_bitloop rjmp getclick_end getclick_zero: ; ; zero bit ; clc ; clear carry ror rxbyte ; shift in carry ; ; decrement counter and output if byte received ; dec bitcount brne getclick_bitloop getclick_end: ; ; delay for stop clicks ; mov count, clickspace getclick_stop1: dec count nop ; to even out timing for breq brne getclick_stop1 mov count, clickspace getclick_stop2: dec count nop ; to even out timing for breq brne getclick_stop2 ret getclick_timeout: ldi rxbyte, 0 ret ; ; blink ; blink the LED ; blink: cbi PORTB, lightpin ldi temp, 255 blink_loop: ldi temp1, 100 blink_loop1: dec temp1 brne blink_loop1 dec temp brne blink_loop sbi PORTB, lightpin ret reset: ; ; set clock divider ; ldi temp, (1 << CLKPCE) ldi temp1, (0 << CLKPS3) | (0 << CLKPS2) | (0 << CLKPS1) | (0 << CLKPS0) ; /1 out CLKPR, temp out CLKPR, temp1 ; ; init microcontroller ; ldi temp, high(RAMEND) ; set stack pointer to top of RAM out SPH, temp ; " ldi temp, low(RAMEND) ; " out SPL, temp ; " sbi PORTB, lightpin ; init light pin for output sbi DDRB, lightpin ; " sbi PORTB, buttonpin ; init pushbutton pin for input with pull-up cbi DDRB, buttonpin ; " sbi PORTB, clickpin ; init click pin for input with pull-up cbi DDRB, clickpin ; " ; ; main loop ; mainloop: ; ; wait for the button to be pressed or a click to arrive ; waitloop: sbis PINB, buttonbit ; check for button press rjmp button_pressed sbic PINB, clickpin ; check for click rjmp waitloop click_received: ; ; click received, blink the light if char matches ; rcall getclick cpi rxbyte, char brne mainloop rcall blink rjmp mainloop button_pressed: ; ; button pressed, send char ; ldi txbyte, char rcall putclick rcall char_delay rjmp mainloop