;***** COM Relay Controller ;(c) 2003 Chris L Peterson, Cloudbait Observatory ; ; Uses Maxim/Mt Stromlo Protocol: ; M [-]X.XX [-]Y.YY ; X and Y times in seconds, resolution 10mS ; ; Alternate function uses Starlight Express protocol: ; 0x01 = west ; 0x02 = south ; 0x04 = north ; 0x08 = east ; 0x00 = off .include "4433def.inc" .def timel = r2 .def timeh = r3 .def fgtemp = r16 ;foreground temporary register .def ttemp1 = r17 ;temp register for timer interrupt routine .def ttemp2 = r18 ;temp register for timer interrupt routine .def utemp1 = r19 ;temp register for rx data interrupt routine .def utemp2 = r20 ;temp register for rx data interrupt routine .def xdir = r21 ;x axis direction .def ydir = r22 ;y axis direction .def xtimel = r28 ;x axis timer (low) .def xtimeh = r29 ;x axis timer (high) .def ytimel = r30 ;y axis timer (low) .def ytimeh = r31 ;y axis timer (high) .equ TBASE = 217 ;10mS counter value for 4.00 MHz clock .equ B9600 = 25 ;9600 baud for 4.00 MHz clock .equ BFR = $60 ;char buffer = start of ram ;***** Initialization rjmp reset ;Reset Handler rjmp reset ;IRQ0 Handler rjmp reset ;IRQ1 Handler rjmp reset ;Timer1 Capture Handler rjmp reset ;Timer1 compare Handler rjmp reset ;Timer1 Overflow Handler rjmp t0over ;Timer0 Overflow Handler rjmp reset ;SPI Transfer Complete Handler rjmp rxdata ;UART RX Complete Handler rjmp reset ;UDR Empty Handler rjmp reset ;UART TX Complete Handler rjmp reset ;ADC Conversion Complete Interrupt Handler rjmp reset ;EEPROM Ready Handler rjmp reset ;Analog Comparator Handler reset: ldi fgtemp,$df out SP,fgtemp ;init stack pointer ser fgtemp out DDRC,fgtemp ;set PORTC to outputs out DDRB,fgtemp ;set PORTB to outputs out PORTC,fgtemp ;all relays off out PORTB,fgtemp ;all indicators off ;*** initialize timer 0 ldi fgtemp,TBASE out TCNT0,fgtemp ;setup 10mS count ldi fgtemp,0b00000101 out TCCR0,fgtemp ;prescale clock by 1024 ldi fgtemp,0b00000010 out TIMSK,fgtemp ;enable timer 0 overflow interrupt clr xtimel clr xtimeh clr xdir clr ytimel clr ytimeh clr ydir ;*** initialize uart ldi fgtemp,0b10011000 out UCSRB,fgtemp ;enable rx,tx, rx interrupt clr fgtemp out UBRRH,fgtemp ldi fgtemp,B9600 ;9600 baud out UBRR,fgtemp sei ;enable interrupts norm: ldi xtimel,1 ldi ytimel,1 ;make sure relays get turned off sei ;enable interrupts loop: sbis PIND,7 ;exit if alternate mode rjmp loop ;else, remain in idle loop alt: cli ;disable interrupts altlp: sbis PIND,7 ;continue if in alternate mode rjmp norm ;else, exit to normal mode rcall getc ;wait for a char ldi fgtemp,$0f and fgtemp,r0 ;isolate lower nibble com fgtemp ;invert logic out PORTC,fgtemp ;send to relays out PORTB,fgtemp ;send to indicators rjmp altlp getc: sbis UCSRA,7 ;got a char? rjmp getc ;no in r0,UDR ;else, get data ret ;*** rx data interrupt handler rxdata: in utemp1,sreg push utemp1 ;save status in utemp1,UDR ;get data ; out UDR,utemp1 ;DIAGNOSTIC: echo cpi utemp1,'.' ;dp? breq rxx ;b/yes (ignore) cpi utemp1,'M' ;start code? brne rx2 ;b/no ldi r26,BFR ;else, reset char pointer rjmp rxx ;and exit rx2: cpi utemp1,$0a ;line feed? breq rx3 ;b/yes (process buffer) st x+,utemp1 ;else, buffer the char cpi r26,BFR+16 ;buffer overflow? brlo rxx ;b/no ldi r26,BFR ;else, reset char pointer rjmp rxx ;and exit rx3: rcall procb ;process buffer rxx: pop r0 out sreg,r0 ;restore status reti ;*** process buffer and extract x,y times and directions procb: clr xdir clr ydir ;clear direction flags clr xtimel clr xtimeh clr ytimel clr ytimeh ;clear timers in utemp1,PORTC ori utemp1,$0f out PORTC,utemp1 ;turn off all relays in utemp1,PORTB ori utemp1,$0f out PORTB,utemp1 ;turn off all indicators clr XH ldi XL,BFR+1 ;reset char pointer ld utemp1,x+ ;get char cpi utemp1,'-' ;-x? brne prb1 ;b/no inc xdir ;else, set x direction flag ld utemp1,x+ ;and get next char prb1: rcall m10x ;multiply and accumulate x ld utemp1,x+ ;get next char cpi utemp1,' ' ;end of x field? brne prb1 ;b/no ld utemp1,x+ ;get next char cpi utemp1,'-' ;-y? brne prb2 ;b/no inc ydir ;else, set y direction flag ld utemp1,x+ ;and get next char prb2: rcall m10y ;multiply and accumulate y ld utemp1,x+ ;get next char cpi utemp1,$0d ;end of y field? brne prb2 ;b/no mov utemp1,xtimel or utemp1,xtimeh breq rx7 ;b/xtime=0 tst xdir ;+x? breq rx6 ;b/yes cbi PORTC,0 ;enable -x relay cbi PORTB,0 ;enable -x indicator rjmp rx7 rx6: cbi PORTC,3 ;enable +x relay cbi PORTB,3 ;enable +x indicator rx7: mov utemp1,ytimel or utemp1,ytimeh breq procbx ;b/ytime=0 tst ydir ;+y? breq rx8 ;b/yes cbi PORTC,1 ;enable -y relay cbi PORTB,1 ;enable -y indicator rjmp procbx rx8: cbi PORTC,2 ;enable +y relay cbi PORTB,2 ;enable +y indicator procbx: ret ;*** calculate (xtime * 10) * val(utemp1) m10x: andi utemp1,$0f ;isolate numeric part of utemp1 mov timel,xtimel mov timeh,xtimeh lsl xtimel rol xtimeh lsl xtimel rol xtimeh lsl xtimel rol xtimeh ;xtime*8... lsl timel rol timeh ;xtime*2... add xtimel,timel adc xtimeh,timeh ;=xtime*10 add xtimel,utemp1 clr utemp1 adc xtimeh,utemp1 ;+utemp1 reti ;*** calculate (ytime * 10) * utemp1 m10y: andi utemp1,$0f ;isolate numeric part of utemp1 mov timel,ytimel mov timeh,ytimeh lsl ytimel rol ytimeh lsl ytimel rol ytimeh lsl ytimel rol ytimeh ;ytime*8... lsl timel rol timeh ;ytime*2... add ytimel,timel adc ytimeh,timeh ;=ytime*10 add ytimel,utemp1 clr utemp1 adc ytimeh,utemp1 ;+utemp1 reti ;*** timer 0 overflow interrupt handler t0over: in ttemp1,sreg push ttemp1 ;save status ldi ttemp1,TBASE out TCNT0,ttemp1 ;set 10mS count mov ttemp1,xtimel or ttemp1,xtimeh ;x time at zero? breq t0xz ;b/yes subi xtimel,1 sbci xtimeh,0 ;else, decrement timer mov ttemp1,xtimel or ttemp1,xtimeh ;x time at zero? brne t0xz ;b/not zero in ttemp1,PORTC ldi ttemp2,0b00001001 or ttemp1,ttemp2 out PORTC,ttemp1 ;turn off x relays in ttemp1,PORTB ldi ttemp2,0b00001001 or ttemp1,ttemp2 out PORTB,ttemp1 ;turn off x indicators t0xz: mov ttemp1,ytimel or ttemp1,ytimeh ;y time at zero? breq t0x ;b/yes subi ytimel,1 sbci ytimeh,0 ;else, decrement timer mov ttemp1,ytimel or ttemp1,ytimeh ;y time at zero? brne t0x ;b/not zero in ttemp1,PORTC ldi ttemp2,0b00000110 or ttemp1,ttemp2 out PORTC,ttemp1 ;turn off y relays in ttemp1,PORTB ldi ttemp2,0b00000110 or ttemp1,ttemp2 out PORTB,ttemp1 ;turn off y indicators t0x: pop r0 out sreg,r0 ;restore status reti