;ATMEGA8 10 BIT DPM ;M8DPM091109A .include "m8def.inc" ;Include file is in the same directory as the project. ; I/O Assignment ; PORTB ;B0 Range control output ;B1 Input with weak pullup ;B2 Input with weak pullup ;B3 Input with weak pullup ;B4 Input with weak pullup ;B5 Input with weak pullup ;B6 Input with weak pullup ;B7 Input with weak pullup .equ PORTBdata =0b11111110 ;Initial data .equ DDRBdata =0b00000000 ;Initial data ; PORTC Bits 1 - are cathodes for four digit common cathod LED display. ;C0 ;C1 Digit 1 (right-most digit) ;C2 Digit 2 ;C3 Digit 3 ;C4 Digit 4 (left-most digit) ;C5 ;C6 ;C7 .equ PORTCdata =0b11100000 ;Initial data .equ DDRCdata =0b11111110 ;Initial data ;LED display segment definition is below: ; AAAAAA ; F B ; F B ; GGGGGG ; E C ; E C ; DDDDDD DP ledlut: ;LED Look-Up Table, Segent codes for 0..9 on 7 segment display ; 0 1 2 3 4 5 6 7 8 9 blank minus ;.db $3F,$06,$5B,$4F,$66,$6D,$7d,$07,$7F, $6F, $00, $40 ;The look-up table above is only used as a reference. ; PORTD Anodes for a four digit common cathode diapls ;D0 Segment a, driven through a resistor. ;D1 Segment b, driven through a resistor ;D2 Segment c, driven through a resistor ;D3 Segment d, driven through a resistor ;D4 Segment e, driven through a resistor ;D5 Segment f, driven through a resistor ;D6 Segment g, driven through a resistor ;D7 Segment decimal point .equ PORTDdata =0b10000000 ;Initial data .equ DDRDdata =0b11111111 ;Initial data .equ number_of_tasks = 5; Number of tasks handled during interrupt. .equ Scanspeed = 252 ; Timer 0 reload value. Sets multitasking frequency. . .equ Measurements_to_skip = 80 ; The number of display cycles per measuremnt ; Register assignments .def temp = r16 ;General purpose scratch register. .def segval = r17 ;General purpoe scratch register .def innum = r18 .def digit1 = r19 ;Images of the 7 segments + decimal point .def digit2 = r20 ;which are to be written to the four digits. .def digit3 = r21 .def digit4 = r22 .def interruptcounter = r23 ;Counts interrupts for multitasker. .def Measurement_counter = r24; number of display refresh cycles per measurement. .def flagreg = r25; Flags for intraprocess signaling ;flagregister bit assignments ;0 Range mode 0 = in low range, 1 = in high range ;1 ;2 ;3 ;4 ;5 ;6 ;7 .equ FlagretInitial =0b10000000 ;Initial data for flag register .cseg .ORG $0000 rjmp start .org $0009 rjmp timer0service ;Initializaton code .org $000E ;ADC_complete interrupt reti start: ;Entry point after reset -initialize everything ldi temp,high(ramend) ;Initialize 16 bit Stack Pointer out sph,temp ldi temp,low(ramend) out spl,temp ldi temp,DDRBdata out DDRB,temp ldi temp,PORTBdata out PORTB,temp ldi temp,DDRCdata out DDRC,temp ldi temp,PORTCdata out PORTC,temp ldi temp,DDRDdata out DDRD,temp ldi temp,PORTDdata out PORTD,temp ldi temp,DDRCdata out DDRC,temp ldi temp,PORTCdata out PORTC,temp ;8 BIT TIMER 0 SETUP ldi temp,0b00000101 ;Set prescaler for clk/8 out TCCR0,temp out TCNT0,temp in temp,TIMSK ori temp,0b00000001 ;Enable timer 0 oveflow interrupt. out TIMSK,temp ;ITINITALIZE A TO D CONVERTER ldi temp,0b00010101 ;Set control and status register. 4 MHz clock.Clear int flag. out ADCSR,temp ldi interruptcounter,number_of_tasks ldi flagreg,FlagretInitial ldi Measurement_counter,0 sei ;Enable interrupts. spin: ;No foreground tasks; everythign happens durring the timer interrupt. rjmp spin ;/////////////////////////////Interrupt 0 multitasker\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ timer0service: push temp in temp,sreg push temp ldi temp, Scanspeed ;Set number of pulses to count up after division by prescaler out TCNT0,temp dec interruptcounter brne select_task ldi interruptcounter,number_of_tasks select_task: cpi interruptcounter,1 brne not1 rcall dodigit1 not1: cpi interruptcounter,2 brne not2 rcall dodigit2 not2: cpi interruptcounter,3 brne not3 rcall dodigit3 not3: cpi interruptcounter,4 brne not4 rcall dodigit4 not4: cpi interruptcounter,5 brne not5 rcall doblank inc Measurement_counter ;Make measurements only evey Measurements_to_skip cycles. cpi Measurement_counter ,Measurements_to_skip breq Take_a_measurement rjmp not5 Take_a_measurement: clr Measurement_counter ;A/D measurement /////////////////////////////////////////////////// ;Take 8 measurments and add them in X register, then shift to divide by 8. ldi temp,0 ;Set A/D converter channel to channel 0. rcall Measure ;Go get the measurement, results are in YH,YL. mov XH,YH mov XL,YL ldi temp,0 ;Set A/D converter channel to channel 0. rcall Measure ;Go get the measurement, results are in YH,YL. clc adc XL,YL adc Xh,Yh ldi temp,0 ;Set A/D converter channel to channel 0. rcall Measure ;Go get the measurement, results are in YH,YL. clc adc XL,YL adc Xh,Yh ldi temp,0 ;Set A/D converter channel to channel 0. rcall Measure ;Go get the measurement, results are in YH,YL. clc adc XL,YL adc Xh,Yh ldi temp,0 ;Set A/D converter channel to channel 0. rcall Measure ;Go get the measurement, results are in YH,YL. clc adc XL,YL adc Xh,Yh ldi temp,0 ;Set A/D converter channel to channel 0. rcall Measure ;Go get the measurement, results are in YH,YL. clc adc XL,YL adc Xh,Yh ldi temp,0 ;Set A/D converter channel to channel 0. rcall Measure ;Go get the measurement, results are in YH,YL. clc adc XL,YL adc Xh,Yh ldi temp,0 ;Set A/D converter channel to channel 0. rcall Measure ;Go get the measurement, results are in YH,YL. clc adc XL,YL adc Xh,Yh ;Shift right three times to divide by 8. clc ror XH ror XL clc ror XH ror XL clc ror XH ror XL mov YH,XH mov YL,XL andi YH,0b0000011 ;Mask off bits that should be low -its only a 10 bit A/D converter. rcall Adjust_range rcall volts_to_decimal ;Value in YH,YL made into numbers not5: pop temp out sreg,temp pop temp reti ;Return from interrupt. ;******************** INTERRUPT TASKS CALLED BY MULTITASKER ********** dodigit1: rcall doblank mov temp,digit1 rcall number_to_7_seg out PORTD,temp cbi PORTC,1 ret dodigit2: rcall doblank mov temp,digit2 rcall number_to_7_seg out PORTD,temp sbrc flagreg,0 sbi PORTD,7 cbi PORTC,2 ret dodigit3: rcall doblank mov temp,digit3 rcall number_to_7_seg out PORTD,temp sbrs flagreg,0 sbi PORTD,7 cbi PORTC,3 ret dodigit4: rcall doblank mov temp,digit4 rcall number_to_7_seg out PORTD,temp cbi PORTC,4 ret doblank: sbi PORTC,1 sbi PORTC,2 sbi PORTC,3 sbi PORTC,4 ret Adjust_range: ;If in low range mode, and if over 1020 ($03FC), switch to high mode ;If in high range mode, and if under 100 ($64), switch to low mode. sbrc flagreg,0 rjmp in_high_range ;Must be in low range to be here. cpi YH,$03 brne Leave_Adjust_range cpi YL,$FC brlo Leave_Adjust_range sbr flagreg,0b00000001 ;Switch to high range mode. sbi DDRB,0 rjmp Leave_Adjust_range in_high_range: ;Must be in high range to be here. cpi YH,0 brne Leave_Adjust_range cpi YL,$64 brlo set_to_low rjmp Leave_Adjust_range set_to_low: cbr flagreg,0b00000001 cbi DDRB,0 Leave_Adjust_range: ret ;***************** convert 16 bit number to values for digits 1 through 4 ************ volts_to_decimal: ;Enter with input value in YH:YL. YH,YL,a1,a2,a3,temp,digit1, digit2, digit3, digit4 ; modified. The contents of digit1, digit2, digit3, and digit4 are the values for ; each digit, each with a range corresponding to the acceptable input vlaues of ; the number_to_7_seg routine. Values in Y register are preerved. ;If in high range mode, If YH,YL is at $03FF, then declare overflow. sbrc flagreg,0 rjmp no_overflow cpi YH,$03 brne no_overflow cpi YL,$FF brne no_overflow ldi digit4,0 ;Number corresponding to the letter "O",actually a zero. ldi digit3,11 ;Number corresponding to the letter "F" ldi digit2,12 ;Number corresponding to the letter "L" ldi digit1,13 ;Number corresponding to the letter "o" rjmp conversiondone no_overflow: ; countdone: clr digit4 clr digit3 clr digit2 clr digit1 MoreK: inc digit4 subi YL,$E8 ;Find out how many 1000's sbci YH,$03 brcc MoreK ldi temp,$E8 ;Subtracted one too many, add back on. add YL,temp ldi temp,$03 adc YH,temp; dec digit4 MoreH: inc digit3 subi YL,100 ;Find out how many 100's sbci YH,0 brcc MoreH ldi temp,100 ;Subtracted one too many, add back on. add YL,temp ldi temp,0 adc YH,temp; dec digit3 MoreT: inc digit2 subi YL,10 ;Find out how many 10's sbci YH,$0 brcc moreT ldi temp,10 ;Subtracted one too many, add back on. add YL,temp ldi temp,0 adc YH,temp dec digit2 MoreU: inc digit1 subi YL,1 ;Find out how many 1's sbci YH,0 brcc moreT ldi temp,1 ;Subtracted one too many, add back on. add YL,temp ldi temp,0 adc YH,temp dec digit1 conversiondone: ret number_to_7_seg: ;Enter with number in temp, extis with the 7 segment pattern in temp. ldi segval,$3F ;0 cpi temp,0 breq segments_set ldi segval,$06 ;1 cpi temp,1 breq segments_set ldi segval,$5B ;2 cpi temp,2 breq segments_set ldi segval,$4F ;3 cpi temp,3 breq segments_set ldi segval,$66 ;4 cpi temp,4 breq segments_set ldi segval,$6D ;5 cpi temp,5 breq segments_set ldi segval,$7d ;6 cpi temp,6 breq segments_set ldi segval,$07 ;7 cpi temp,7 breq segments_set ldi segval,$7F ;8 cpi temp,8 breq segments_set ldi segval,$6F ;9 cpi temp,9 breq segments_set ldi segval,$40 ;Negative sign cpi temp,10 breq segments_set ldi segval,0b01110001 ;Letter "F" cpi temp,11 breq segments_set ldi segval,0b00111000 ;Letter "L" cpi temp,12 breq segments_set ldi segval,0b01011100 ;Lower case letter "o" cpi temp,13 breq segments_set ldi segval,$00 ; Blank (default) segments_set: mov temp,segval ret Measure: ;Measure A/D channel. Enter with channel number in temp. Exit with data in YH:YL ;Allowed range is 0..5 push temp sbi ADCSR,ADEN ;Enable A/D converter. andi temp,0b00000111 ;Mask off upper bits to restrict range of channel selction. ori temp,0b11000000 ;Set reference voltage bit to use internal bandgap reference out ADMUX,temp ;Select channel. sei sbi ADCSRA,3 ;Enable ADC interrupts ldi temp,0b10010000 out mcucr,temp sleep sbi ADCSR,ADIF ;Clear interrupt flag. in YL,ADCL ;Get data into Y register. in YH,ADCH pop temp ret .exit /* ;flooby not used? set_decimal_point: cbr digit3,0b10000000 ;Set the decimal point according to range flag (flagreg,0). cbr digit4,0b10000000 sbrs flagreg,0 sbr digit3,0b10000000 sbrc flagreg,0 sbr digit4,0b10000000 ret */