;********************************* ;Copyright(C)2002,2003, 2004, 2008 by Richard Cappels projects@cappels.org ;http://www.projects.cappels.org ; ;Uses ATTINY2313 operating at 4 MHz. ; ; ;******************************** ; ; ; The purpose of this code is to simulate a Princeton Technology Corp. PT2264 with a single fixed address and data. ; In the PT2264 datashet, time is denoted in clock periods of the PT2264's oscillator. These clock periods are ; referred to with the Greek leter alpha. Since the minimum time period in the coded address and data is 4 alpha, ; this code generates output data based on minimum time slices of 4 clocks. ; ; Geneartion of the "4 clock time slice: ; The 16 bit timer, timer1 in the AT90S2313/ATTINY2313, is used what some manufacturers call the free run mode. ; A count compare register is loaded with a number which is = (crystal frequency/(PT2264 clock frequency/4),and ; Whenever the timer counts up to that number of microcontroller clocks, the counter is reset and an interrupt ; occurs. When the interrupts are serviced, the contents of PORTD is updated to reflect the data stored in a ; register, called dout, for that purpose. In other words, output data for PORTD is written to dout and then ; once interrupt, the data is copied from dout to PORTD. This assures that the output data is synchronous with ; the interrupts. ; ; To assure that interrupts are equally spaced, and thus there is minmum jitter in the data being sent, the ; microcontroller sleeps and waits for an interrupt after each change in the data output, This assures ; that interrupt latency is consistent. ; ; Note: When programming the chip, set Browout detectiion OFF, and the watchdog timer OFF to save power. ; ; ; ; pt2264i081004A Verson. .include "tn2313def.inc" .equ clock = 4000000 ; Clock frequency .def temp = r16 ; General purpose scratch register. .def intcounter = r17 ; Counter used to test interrupt timing. .def dout = r18 ; Data output to PORTD every T1_compare_int. .def delay = r19 ; Delay counter. .def hundelay = r20 ; Dedicated register for timing 100 millisecond delay.. ;Definition of PORTB bits: ;0 ;1 ;2 Motorcycle_Entrance input with pullup ;3 Test input with pullup ;4 Manual input with pullup ;5 Motorcycle_Exit input with pullup ;6 Pedestrian Open input with pullup ;7 Pedestrian Close input with pullup ;Definition of PORTD bits: ;0 input with pullup ;1 input with pullup ;2 input with pullup ;3 input with pullup ;4 input with pullup ;5 Data output ;6. Data output ;7 Not present on AT90S2313/ATTINY2313 .org $00 rjmp reset ; Power-on and reset vector. .org $04 rjmp T1_compare_int ; 16 Bit timer overflow. .org $0B ; Pin Chance interrupt. rjmp reset T1_compare_int: ; The purpose is to wake the CPU every 301.75 us. out PORTD,dout ; Update PORTD otuput pins. No flags affected by this instruction. reti Sleep_now: ; Sleep until interrupt. sei ; Assure interrupts are enabled. ldi temp,0b00100000 ; Enable sleep mode (idle). out MCUCR,temp sleep ret delay_3: ; Delay 3 minimum time slices. ldi delay,3 delay_3_loop: rcall Sleep_now ; Wait one minimum time slice. dec delay brne delay_3_loop ret delay_31: ldi delay,31 ; Delay 31 minimum time slices. delay_31_loop: rcall Sleep_now ; Wait one minimum time slice. dec delay brne delay_31_loop ret send_0: ; Send a logic zero. 1 interrupt high, 4 low,two times. ori dout,0b01100000 ; Set bit 6 high for one minimum slice. rcall Sleep_now ; Wait one minimum time slice. andi dout,0b10011111 ; Set bit 6 low for three minimum slices. rcall delay_3 ori dout,0b01100000 ; Set bit 6 high for one minimum slice.. rcall Sleep_now ; Wait one minimum time slice. andi dout,0b10011111 ; Set bit 6 low for three minimum slices. rcall delay_3 ret send_1: ori dout,0b01100000 ; Set bit 6 high for three minimum slices. rcall delay_3 andi dout,0b10011111 ; Set bit 6 low for one minimum slice. rcall Sleep_now ori dout,0b01100000 ; Set bit 6 high for three minimum slices. rcall delay_3 andi dout,0b10011111 ; Set bit 6 low for one minimum slice. rcall Sleep_now ; Wait one minimum time slice. ret send_F: ; 1 high, 3 low, 3 high, 1 low ori dout,0b01100000 ; Set bit 6 high for one minimum slice. rcall Sleep_now ; Wait one minimum time slice. andi dout,0b10011111 ; Set bit 6 low for three minimum slices. rcall delay_3 ori dout,0b01100000 ; Set bit 6 high for three minimum slices. rcall delay_3 andi dout,0b10011111 ; Set bit 6 low for one minimum slice. rcall Sleep_now ret send_sync: ; 1 high, 31 low. ori dout,0b01100000 ; Set bit 6 high for one minimum slice. rcall Sleep_now ; Wait one minimum time slice. andi dout,0b10011111 ; Set bit 6 low for 31 minimum slices. rcall delay_31 ret interword_delay: ; Delay for 32 minimum time slices. rcall delay_31 rcall Sleep_now ret send_interframe_delay: ; Delay by 94 minimum time slices = 442.75 us. rcall delay_31 rcall delay_31 rcall delay_31 rcall delay_31 ret delay_2s: ; Delay 2 seconds. delay_2s_loop: rcall send_interframe_delay dec hundelay brne delay_2s_loop ret send_code_word: ; Code: L H F H F H H L H L F L rcall send_0 rcall send_1 rcall send_F rcall send_1 rcall send_F rcall send_1 rcall send_1 rcall send_0 rcall send_1 rcall send_0 rcall send_F rcall send_0 rcall send_sync ret send_code_frame: rcall send_code_word rcall send_code_word rcall send_code_word rcall send_code_word ret reset: cli ; Assure interrupts are off for now. ldi temp,low(ramend) out spl,temp ; Set stack pointer. ldi temp,0b00000000 ; Set PORTB Data Direction Register out DDRB,temp ldi temp,0b11111111 ; Set PORTB Data Register out PORTB,temp ldi temp,0b11111111 ; Set PORTD Data Direction Register out DDRD,temp ldi temp,0b00000000 ; Set PORTD Data Register out PORTD,temp ldi dout,0b00000000 ; Set update data for PORTD. ldi temp,0b10000000 out ACSR,temp ldi temp,$00 ; Don't really need to do this, but it shows TCCR1A as zeros. out TCCR1A,temp ldi temp,$00 ; Clear 16 bit counter. out TCNT1H,temp out TCNT1L,temp ldi temp,$04 ; Set value of compare match register -high register. out OCR1AH,temp ldi temp,$B7 ; Set value of compare match register -low register.. out OCR1AL,temp ldi temp,0b00001001 ; Enable input to Timer/Counter 1 (16 bit counter) clock/1. out TCCR1B,temp ldi temp,0b01000000 ; Enable Timer 1 (16 bit timer) compare match interrupts. out TIMSK,temp ldi temp,0b00000000 ; Disable pin change interrupts. out GIMSK,temp rjmp Main ; Go off and execute the main loop. test: ; Switch the code outputs high and keep it there until reset. ldi temp,0b01100000 out PORTD,temp rjmp test manual: rcall send_code_frame; rcall send_code_frame; rcall send_code_frame; rcall send_code_frame rjmp switch_off switch_off: ; Stop timer 1 interrupts, make sure buttons are up, and go to Power Down mode.. in temp,PINB andi temp,0b11111100 subi temp,0b11111100 brne switch_off ldi hundelay,2 ; About 27 counts per second. rcall delay_2s in temp,PINB andi temp,0b11111100 subi temp,0b11111100 brne switch_off ldi temp,0b00000000 ; Disable Timer 1 (16 bit timer) compare match interrupts. out TIMSK,temp ldi temp,0b00100000 ; Enable pin change interrupts. out GIMSK,temp ldi temp,0b00100000 out EIFR,temp ldi temp,0b11111100 ; Enable interrupts from bits on PORTB. out PCMSK,temp sei ; Assure interrupts are enabled. ldi temp,0b01110000 ; Enable Power Down sleep mode. out MCUCR,temp sleep ; After restart, the program runs to here, but no interrputs. motorcycle_exit: ; Open the gate for 30 seconds, then close it, then shut down.. rcall send_code_frame; rcall send_code_frame; rcall send_code_frame; rcall send_code_frame; ldi hundelay,255 ; Delay about 40 seconds. rcall delay_2s ldi hundelay,255 ; About 27 counts per second. For 5 seconds, use 135 rcall delay_2s ldi hundelay,255 ; About 27 counts per second. For 5 seconds, use 135 rcall delay_2s ldi hundelay,100 ; About 27 counts per second. For 5 seconds, use 135 rcall delay_2s rcall send_code_frame; rcall send_code_frame; rcall send_code_frame; rcall send_code_frame rjmp switch_off motorcycle_enter: ; Open the gate for 30 seconds, then close it, then shut down.. rcall send_code_frame; ; First series of commands starts to open again rcall send_code_frame; ; The motorcyle enters while gate is moving. rcall send_code_frame; rcall send_code_frame; ldi hundelay,255 ; Delay about 1 1/2 seconds. rcall delay_2s rcall send_code_frame; ; Second series of command pulses stops the gate rcall send_code_frame; rcall send_code_frame; rcall send_code_frame ldi hundelay,55 ; Delay about 2 seconds. rcall delay_2s rcall send_code_frame; ; Third series of command pulses closes the gate rcall send_code_frame; rcall send_code_frame; rcall send_code_frame rjmp switch_off Pedestrian_Close: ; Close the gate after a pedestrian has gone through. If gate is not all the way open. rcall send_code_frame; ; First series of commands starts to open again rcall send_code_frame; rcall send_code_frame; rcall send_code_frame; ldi hundelay,40 ; Delay about 1 1/2 seconds. rcall delay_2s rcall send_code_frame; ; Second series of command pulses stops the gate rcall send_code_frame; rcall send_code_frame; rcall send_code_frame ldi hundelay,55 ; Delay about 2 seconds. rcall delay_2s rcall send_code_frame; ; Third series of command pulses closes the gate rcall send_code_frame; rcall send_code_frame; rcall send_code_frame rjmp switch_off Pedestrian_Open: ; Close the gate after a pedestrian has gone through. If gate is not all the way open. rcall send_code_frame; ; First series of commands starts to open again rcall send_code_frame; rcall send_code_frame; rcall send_code_frame; ldi hundelay,165 ; Delay about 6 seconds. rcall delay_2s rcall send_code_frame; ; Second series of command pulses stops the gate rcall send_code_frame; rcall send_code_frame; rcall send_code_frame rjmp switch_off Main: ; Program's main loop. sei ; Allow interrupts so the delay routine canwork. ldi hundelay,6 ; About 27 counts per second. For 5 seconds, use 135 rcall delay_2s sbis PINB,7 rjmp Pedestrian_Close sbis PINB,6 rjmp Pedestrian_Open sbis PINB,5 rjmp motorcycle_exit sbis PINB,4 rjmp manual sbis PINB,3 rjmp test sbis PINB,2 rjmp motorcycle_enter rjmp switch_off .exit