| CODE |
;***** AtoD Test with interrupt driven timing ******** ;Timer 1 match function is used to take 1 sample/sec ; and display the top 8 bits on the LEDs. ;THIS HAS AREF AS 2.048 VOLTS ;You will need to CHANGE this path .include "c:\academic\476\8535def.inc" .device AT90S8535; specifies to the assembler which chip we are using .def save =r1;SREG temp reg .def temp =r16;temporary register .def maintenance =r17 .def Analo =r18;;A to D result .def butnum =r19 .def wreg =r20 .def longtime=r21 .def timeout =r22 ;.def charcnt =r23 .def objective=r23 ;.def auto =r24 .def one =r25 .def ten =r26 .def hundred =r24 .equ lcdrs =PD6 ;LCD rs pin connected to PD6 .equ lcdrw =PD5 ;LCD r/w pin connected to PD5 .equ lcde =PD4 ;LCD enable pin connected to PD4 ; Timer/Counter prescaler values .equ TSTOP =0 ;Stop Timer/Counter .equ TCK1 =1 ;Timer/Counter runs from CK .equ TCK8 =2 ;Timer/Counter runs from CK / 8 .equ TCK64 =3 ;Timer/Counter runs from CK / 64 .equ TCK256 =4 ;Timer/Counter runs from CK / 256 .equ TCK1024 =5 ;Timer/Counter runs from CK / 1024 .equ TEXF =6 ;Timer/Counter runs from external falling edge .equ TEXR =7 ;Timer/Counter runs from external rising edge .equ azero=0x30 .dseg tempthreshold: .byte 1 ; one bytes to store the threhold valu ;initialize to 01000111 for 25 celcius ;***** Initialization .cseg .org $0000 rjmp RESET;reset entry vector reti reti reti reti reti rjmp t1match reti reti rjmp t0int reti reti reti reti reti reti reti ;this table is rearranged so numbers will take up the first ten spaces in butnum ;A is 11, B is 12, C is 13, D is 14, * is 15, # is 16 ;keytbl: .db 0b11101110, 0b11101101, 0b11101011, 0b11100111 ; .db 0b11011110, 0b11011101, 0b11011011, 0b11010111 ; .db 0b10111110, 0b10111101, 0b10111011, 0b10110111 ; .db 0b01111110, 0b01111101, 0b01111011, 0b01110111 keytbl: .db 0b01111101, 0b11101110, 0b11101101, 0b11101011 .db 0b11011110, 0b11011101, 0b11011011, 0b10111110 .db 0b10111101, 0b10111011, 0b11100111, 0b11010111 .db 0b10110111, 0b01110111, 0b01111110, 0b01111011 temptable: .db 0b01111010, 0b01110010, 0b01100111, 0b01011011 .db 0b01001101, 0b01000111, 0b01000000, 0b00110100 .db 0b00101001, 0b00100000, 0b00011001, 0b00010011 RESET: ldi temp, LOW(RAMEND);setup stack pointer out SPL, temp ldi temp, HIGH(RAMEND) out SPH, temp ;************************************************initialize LCD************ loop: ldi wreg,TSTOP;Timer 0 off (just in case) out TCCR0,wreg;Stop timer clr temp out TCCR1B,temp;stop timer1 as well ldi wreg,0x05;Enable Timer 0 interrupt out TIMSK, wreg sei ;Enable interrupts ;power down the LCD ;ldi wreg, 0b11000000;LCD power connection ;out DDRA, wreg;power it down after reset ; power the LCD with PORTB 7 ;ser temp ;out DDRB, temp ;cbi PORTB, 7 ;ldi wreg, 0x00 ;out PORTA,wreg ldi longtime,100; then Wait 1.5 second with LCD power off ldi timeout,0;Delay 15 mS offwait: rcall delay dec longtime brne offwait ;now power up LCD ;ldi wreg, 0xff ;out PORTA, wreg ;SBI PORTB, 7 ldi longtime,100;Wait 1.5 second for LCD power up ldi timeout,0;Delay 15 mS puwait: rcall delay dec longtime brne puwait rcall lcdinit ;Initialize LCD module rcall lcdclr ;Clear LCD screen ;clr charcnt ;zero the character countv ;not neccessary since we don't plan to write more than 8 characters ;********************************finish initializing LCD************** ;********************************set up sampling specs**************** ;set up Timer 1 to interrupt on compare A match ;and set the compare time to 62500 ticks ldi temp,0b00010000;enable t1 matchA interrupt out TIMSK, temp ldi temp, 0xf4;set the match A register to out OCR1AH, temp;62500 since 62500*16microsec=sec ldi temp, 0x24;62500 = 0xf424 out OCR1AL, temp ldi temp,0b00001010;prescale timer by 8 (one tick=1.6E-5 /8 sec) out TCCR1B, temp;and clear-on-matchA ;*********************************finish set up sampling************** ;set PORTB to output port ser temp out DDRB, temp ;initiate maintenance sequence clr maintenance ;remember to initiate butnum ;actually turns out that butnum should be initiated to 0 ??? ;ldi butnum, 11 ; initial value set to button B for temperature ldi butnum, 0 ; initiate temperature threshold level at 25 celcius ldi ZL, LOW(tempthreshold);ptr to ram ldi ZH, HIGH(tempthreshold) ldi temp, 0b01000111 st Z,temp ;reads keypad preswait: rjmp keypad ;decide which operation by comparing value of butnum afterkey: cpi butnum, 11 ; display pressue loop breq pressure cpi butnum, 12; display temperature loop breq temperature cpi butnum, 14;threshchange breq thresh cpi butnum, 17 ;program initiated pressure callback breq pressure cpi butnum, 18 breq temperature ; if not a valid operation rcall keypad rjmp preswait pressure: ;set up analog converter to read channel zero ldi temp, 0 rjmp setadmux temperature: ;set up analog converter to read channel 4 ldi temp, 0x04 rjmp setadmux thresh: ldi temp, 0x55 out PORTB, temp ldi temp, 0x0f;set lower four lines to output out DDRC, temp ldi temp, 0xf0;and turn on the pullups on the inputs out PORTC, temp nop ;Need some time for the pullups to nop ;charge the port pins nop nop in temp, PINC;read the high nibble mov wreg, temp;and store it (with zeros in the low nibble) ldi temp, 0xf0;set upper four lines to outputs out DDRC, temp ldi temp, 0x0f;and turn on pullups on the inputs out PORTC, temp nop ;As before wait for the pin to charge nop nop nop in temp, PINC;read the low nibble or wreg, temp;combine to make key code ;At the point the raw key code should have exactly one zero each in ;the lower and upper nibbles. Any other number of zeros indicates ;either no-button pressed or multiple-button pressed. ;Now search the table for a match to the raw key code ;and exit with a button number ldi ZL, low(keytbl*2);table pointer in FLASH ldi ZH, high(keytbl*2);so convert from word to byte addr ldi one, 0 tbllp2: lpm ;get the table entry cp wreg, r0 ;match? breq foundit2 inc one ;if not, have we exhaused the cpi one, 0x0a;table breq thresh adiw ZL, 1 ;if not, get the next table entry rjmp tbllp2 foundit2: subi one, -1;add one for comparison rjmp changethreshold setadmux: out ADMUX, temp ;value of admux preloaded into temp sei ;enable all interrupts ;start timer1 ldi temp,0b00001010;prescale timer by 8 (one tick=1.6E-5sec/8) out TCCR1B, temp;and clear-on-matchA swait: in temp, ADCSR;wait for A to D start andi temp, 0b01000000;by checking if ADSC bit is set breq swait ;this bit is set by t1match interrupt await: in temp, ADCSR;wait for A to D done andi temp, 0b01000000;by checking ADSC bit brne await ;this bit is cleared by the AtoD hardware in AnaLo, ADCL;read the voltage in hundred, ADCH; using this to save register in temp, ADMUX andi temp, 0x07 cpi temp, 0 breq pressureproc cpi temp, 4 breq tempprocessing rjmp preswait pressureproc: ldi temp,0b00001000;stop the clock out TCCR1B, temp;and clear-on-matchA ; for pressure, each tick is equal to one PSI so simply display ;tare offset of 7mv first though clr ten clr one ldi hundred, 0x20 ;this is a null characters for the LCD ;out portb, AnaLo subi AnaLo, 7 ;offset ;only display if value is positive cpi AnaLo, 0 brge checkforten ldi AnaLo, 0 ;else assume zero since gauge is only 0-30 PSI ; only display when called upon checkforten: cpi butnum, 11 breq checkfortenII rjmp preswait checkfortenII: inc ten subi AnaLo, 10 brmi donetens rjmp checkforten donetens: subi ten, 1 subi AnaLo, -10 mov one, AnaLo ldi temp, azero add one, temp add ten, temp rcall displaylcd rjmp preswait changethreshold: ldi ZL, low(temptable*2) ldi ZH, high(temptable*2) adiw ZL,1 lookfor: dec one breq getval adiw ZL, 1 rjmp lookfor getval: lpm mov ten, r0 out portb, ten ldi ZL, LOW(tempthreshold);ptr to ram ldi ZH, HIGH(tempthreshold) st Z,ten ldi butnum, 11 rjmp afterkey tempprocessing: ldi temp,0b00001000;stop the clock out TCCR1B, temp;and clear-on-matchA ;just want 8 bit accuracy, refer to excel sheet ror hundred ; ror AnaLo ror hundred ; ror AnaLo mov wreg, AnaLo ; since this temperature call can be made by program instead of user we first see ; how the temperature processing is triggered. if temperature control is called ; bysetting butnum into 17 then that is a program hidden call. cpi butnum, 17 brne pretemptbllp rjmp tcontrol;if not called by program but by user then follow usual routine ; to determine what to display on LCD ; begin tracin range of temperature from -20 to 80 pretemptbllp: ldi ZL, low(temptable*2);table pointer in FLASH ldi ZH, high(temptable*2);so convert from word to byte addr ldi objective, 1;initialize the objective value to one (temp-range =-20) temptbllp: lpm ;get the table entry cp wreg, r0 ;match? ;now eliminate range by comparing and if greater than, then we know temprange. brge foundtemp ;this returns upper bound since this is a cooling system, it should maximum worst case ;according to binning inc objective;if not, have we exhaused the cpi objective, 0x0d;table (limited to N+1 since initial is 1) breq outofrange adiw ZL, 1 ;if not, get the next table entry rjmp temptbllp outofrange: rjmp preswait foundtemp: ldi ten, 0x30 ldi one, 0x30 ; most one digit will be zero except for 25 ldi hundred, 0x2b;load with a positive sign for +- temperature cpi objective, 5 breq range20 cpi objective, 6 breq range25 cpi objective, 7 breq range30 cpi objective, 8 breq range40 cpi objective, 9 breq range50 cpi objective, 10 breq range60 cpi objective, 11 breq range70 cpi objective, 4 ;put more typical number first breq range10 cpi objective, 1 breq rangen20 cpi objective, 2 breq rangen10 cpi objective, 3 breq check ; this case we have as initial value cpi objective, 12 breq range80 range20: ldi ten, 0x32 rjmp check range25: ldi one, 0x35 ldi ten, 0x32 rjmp check range30: ldi ten, 0x33 rjmp check range40: ldi ten, 0x34 rjmp check range50: ldi ten, 0x35 rjmp check range60: ldi ten, 0x36 rjmp check range70: ldi ten, 0x37 rjmp check range80: ldi ten, 0x38 rjmp check range10: ldi ten, 0x31 rjmp check rangen10: ldi hundred, 0x2d ;include a negative sign ldi ten, 0x31 rjmp check rangen20: ldi hundred, 0x2d ldi ten, 0x32 check: ; checks to see if temperature has passed a user set threshold level ; store in RAM ; but first display value on LCD rcall displaylcd ;load the threshold value from RAM tcontrol: ldi ZL, LOW(tempthreshold) ldi ZH, HIGH(tempthreshold) ld r0, Z mov temp, r0 ;this control is only for cooling of device but has two degrees of cooling at +4 or +8 ;which is about between 3 degrees and 10 degrees depending on which temperature range you are in ;but since this is a cooling system about 3 degree leniency will be observed for higher temp range ; >20 degrees subi temp, 2 mov one, temp subi temp, 6 mov ten, temp cp AnaLo, one brge controldone ;if not over temperature turn cooling device off ;relay is controlled by portb0 and b1 cp AnaLo, ten brge midfan highfan: cbi PORTB, 0 sbi PORTB, 1 clr temp out portb, temp ldi temp, 0b11110000 out portb, temp rjmp preswait midfan: cbi PORTB, 1 ;make sure the other relay is not on sbi PORTB, 0 clr temp out portb, temp ldi temp, 0b11011100 out portb,temp rjmp preswait controldone: clr temp out portb, temp ldi temp, 0b00011100; out portb,temp cbi PORTB, 0 cbi PORTB, 1 rjmp preswait ;*************************************displaylcd******************************* displaylcd: ldi wreg,0x80 ;Set address to first char (set to 0) rcall lcdcmd ldi wreg,TSTOP;Timer 0 off out TCCR0,wreg;Stop timer mov wreg, hundred rcall lcdput nop ldi wreg,TSTOP;Timer 0 off out TCCR0,wreg;Stop timer mov wreg, ten rcall lcdput nop ldi wreg,TSTOP;Timer 0 off out TCCR0,wreg;Stop timer mov wreg, one rcall lcdput ;don't need to keep track of char number because under 8 nop cpi butnum, 17 breq doneshow cpi butnum, 18 breq doneshow cpi butnum, 11 breq showpsi cpi butnum, 12 breq showC showpsi: ldi ZH, high(message1*2) ldi ZL, low(message1*2) rjmp showloop showC: ldi ZH, high(message2*2) ldi ZL, low(message2*2) rjmp showloop ;in case there are newer functions showloop: lpm tst R0 breq doneshow mov wreg, R0 rcall lcdput adiw ZL,1 rjmp showloop doneshow: ret ;*************************************reads keypad******************************************* keypad: ;increment the maintenance counter to see if hidden control should be performed ; however program only does hidden controls.ie, if the item is the currently selected ;(diplayed) item then no need to perform hidden callback. inc maintenance cpi maintenance, 40 ; if it is 200 then we perform temperature hidden call breq hiddentemp cpi maintenance,20; if it is 20 then we perform pressure hidden call breq hiddenpressure rjmp comingback hiddenpressure: push butnum ;push the current butnum so we kwnow where to go back to after ldi butnum, 17;hidden call rjmp afterkey ; by pushing here we have to ensure no other pushing will be done ;prior to the next pop. hiddentemp: ldi maintenance, 0x00 ;need to set to zero to ensure next hidden control will be called push butnum ldi butnum, 18 rjmp afterkey comingback: ; coming back checks if we came back from a hidden control call ;butnum values of 17 and 18 are computer triggered for hidden control purposes cpi butnum, 17 breq reading cpi butnum, 18 breq reading ;if it is neither 17 nor 18 for the last operation then we can push butnum value in push butnum reading: ldi temp, 0x0f;set lower four lines to output out DDRC, temp ldi temp, 0xf0;and turn on the pullups on the inputs out PORTC, temp nop ;Need some time for the pullups to nop ;charge the port pins nop nop in temp, PINC;read the high nibble mov wreg, temp;and store it (with zeros in the low nibble) ldi temp, 0xf0;set upper four lines to outputs out DDRC, temp ldi temp, 0x0f;and turn on pullups on the inputs out PORTC, temp nop ;As before wait for the pin to charge nop nop nop in temp, PINC;read the low nibble or wreg, temp;combine to make key code ;At the point the raw key code should have exactly one zero each in ;the lower and upper nibbles. Any other number of zeros indicates ;either no-button pressed or multiple-button pressed. ;Now search the table for a match to the raw key code ;and exit with a button number ldi ZL, low(keytbl*2);table pointer in FLASH ldi ZH, high(keytbl*2);so convert from word to byte addr ldi butnum, 0 tbllp: lpm ;get the table entry cp wreg, r0 ;match? breq foundit inc butnum ;if not, have we exhaused the cpi butnum, 0x10;table breq same adiw ZL, 1 ;if not, get the next table entry rjmp tbllp foundit: pop temp ;just to complement the push pop so stack doesn't overflow subi butnum, -1;add one for display rjmp afterkey same: ;obtain previous value of butnum from stack pop butnum rjmp afterkey ================================================ ; Clear entire LCD and delay for a bit lcdclr: ldi wreg,1 ;Clear LCD command rcall lcdcmd ldi timeout,256;Delay 15 mS for clear command rcall delay ret ================================================ ; Initialize LCD module lcdinit: ;cbi PORTB,0 ;Turn on LED 0 ldi wreg,0 ;Setup port pins out PORTD,wreg;Pull all pins low ldi wreg,0xff;All pins are outputs out DDRD,wreg ldi timeout,256;Wait at least 15 mS at power up rcall delay ; LCD specs call for 3 repetitions as follows ldi wreg,3 ;Function set out PORTD,wreg;to 8-bit mode nop ;nop is data setup time sbi PORTD,lcde;Toggle enable line cbi PORTD,lcde ldi timeout,256;Wait at least 15 mS rcall delay ldi wreg,3 ;Function set out PORTD,wreg nop sbi PORTD,lcde;Toggle enable line cbi PORTD,lcde ldi timeout,256;Wait at least 15 ms rcall delay ldi wreg,3 ;Function set out PORTD,wreg nop sbi PORTD,lcde;Toggle enable line cbi PORTD,lcde ldi timeout,256;Wait at least 15 ms rcall delay ldi wreg,2 ;Function set, 4 line interface out PORTD,wreg nop ; rcall strobe ;Toggle enable line sbi PORTD,lcde;Toggle enable line cbi PORTD,lcde ldi wreg,0b11110000;Make 4 data lines inputs out DDRD,wreg ; Finally, ; At this point, the normal 4 wire command routine can be used ldi wreg,0b00100000;Function set, 4 wire, 1 line, 5x7 font rcall lcdcmd ldi wreg,0b00001100;Display on, no cursor, no blink rcall lcdcmd ldi wreg,0b00000110;Address increment, no scrolling rcall lcdcmd ;sbi PORTB,0 ;Turn off LED 0 ret ============================================ ; Wait for LCD to go unbusy lcdwait: ;cbi PORTB,1 ;Turn on LED 1 ldi wreg,0xF0;Make 4 data lines inputs out DDRD,wreg sbi PORTD,lcdrw;Set r/w pin to read cbi PORTD,lcdrs;Set register select to command waitloop: sbi PORTD,lcde;Toggle enable line cbi PORTD,lcde ;in auto,PIND;Read busy flag in temp,PIND;Read busy flag ;Read, and ignore lower nibble sbi PORTD,lcde;Toggle enable line cbi PORTD,lcde ;sbrc auto,3;Loop until done sbrc temp,3;Loop until done rjmp waitloop ;sbi PORTB,1 ;Turn off LED 1 ret ============================================= ; Send command in wreg to LCD lcdcmd: push wreg ;Save character rcall lcdwait ;Wait for LCD to be ready ldi wreg,0xFF;Make all port D pins outputs out DDRD,wreg pop wreg ;Get character back push wreg ;Save another copy swap wreg ;Get upper nibble andi wreg,0x0F;Strip off upper bits out PORTD,wreg;Put on port nop ;wait for data setup time sbi PORTD,lcde;Toggle enable line cbi PORTD,lcde pop wreg ;Recall character andi wreg,0x0F;Strip off upper bits out PORTD,wreg;Put on port nop sbi PORTD,lcde;Toggle enable line cbi PORTD,lcde ldi wreg,0xF0;Make 4 data lines inputs out DDRD,wreg ret ============================================= ; Send character data in wreg to LCD lcdput: push wreg ;Save character rcall lcdwait ;Wait for LCD to be ready ldi wreg,0xFF;Make all port D pins outputs out DDRD,wreg pop wreg ;Get character back push wreg ;Save another copy swap wreg ;Get upper nibble andi wreg,0x0F;Strip off upper bits out PORTD,wreg;Put on port sbi PORTD,lcdrs;Register select set for data nop sbi PORTD,lcde;Toggle enable line cbi PORTD,lcde pop wreg ;Recall character andi wreg,0x0F;Strip off upper bits out PORTD,wreg;Put on port sbi PORTD,lcdrs;Register select set for data nop sbi PORTD,lcde;Toggle enable line cbi PORTD,lcde ;cbi PORTD,lcdrs;-- ldi wreg,0xF0;Make 4 data lines inputs out DDRD,wreg ret delay: in wreg,SREG;Save status register push wreg out TCNT0,timeout clt ;Clear T ldi wreg,TCK256;Timer 0 prescaler, CK / 256 out TCCR0,wreg;Run timer dwait: brtc dwait ;Wait for timer 0 interrupt to set T pop wreg ;Restore status register out SREG,wreg ret ============================================= ;***** Timer 0 overflow interrupt handler t0int: set ;Set T flag ;ldi wreg,0xFF;Turn off all LEDs ;out PORTB,wreg ldi wreg,TSTOP;Timer 0 off out TCCR0,wreg;Stop timer reti ;Done, return ;**** timer 1 compare A match 1/sec t1match:in save, SREG ldi temp, 0b11000101;start A to D conversion out ADCSR, temp out SREG, save reti message2: .db " C ", 0x00 message1: .db " PSI", 0x00 |