; **************************************************** ; * Frequenzzaehler, Drehzahlmesser und Voltmeter * ; * fuer ATmega8 bei 16 MHz Taktfrequenz (Quarzosz.) * ; * Version 0.2 (C)2005 by info@avr-asm-tutorial.net * ; **************************************************** ; .INCLUDE "m8def.inc" ; .EQU debug = 0 .EQU debugpulse = 0 ; ; Switches for connected hardware ; .EQU cDisplay = 1 ; LCD display connected .EQU cDisplay8 = 0 ; displays 8 characters per line instead of 16 .EQU cDisplay2 = 1 ; two line LCD display connected .EQU cUart = 1 ; Uart active ; attached prescaler on port C .EQU pPresc = PORTC ; prescaler by 8 output attached to port C .EQU pPrescD = DDRC ; data direction of prescaler .EQU bPresc = 5 ; bit 5 enables prescaler by 8 ; ; ================================================ ; Other hardware depending stuff ; ================================================ ; .EQU cFreq = 16000000 ; Clock frequency processor in cycles/s .IF cUart .EQU cBaud = 9600 ; If Uart active, define Baudrate .ENDIF .EQU bLcdE = 5 ; LCD E port bit on Port B .EQU bLcdRs = 4 ; Lcd RS port bit on Port B ; ; ================================================ ; Constants for voltage measurement ; ================================================ ; ; Resistor network as pre-divider for the ADC ; -------------------------------------- ; R1 R2(k) Meas Accur. MaxVoltage ; kOhm kOhm Volt mV/dig Volt ; -------------------------------------- ; 1000 1000 5,12 5 10 ; 1000 820 5,68 6 11 ; 1000 680 6,32 6 12 ; 1000 560 7,13 7 14 ; 1000 470 8,01 8 15 ; 1000 330 10,32 10 20 ; 1000 270 12,04 12 23 ; 1000 220 14,20 14 27 ; 1000 180 16,78 16 32 ; 1000 150 19,63 19 38 ; 1000 120 23,98 23 46 ; 1000 100 28,16 28 55 ; .EQU cR1 = 1000 ; Resistor between ADC input and measured voltage .EQU cR2 = 1000 ; Resistor between ADC input and ground .EQU cRin = 8250 ; Input resistance ADC, experimental ; ; Other sSoft switches ; .EQU cNMode = 3 ; number o0f measurements before mode changes .EQU cDecSep = ',' ; decimal separator for numbers displayed .EQU c1kSep = '.' ; thousands separator .EQU nMeasm = 4 ; number of measurements per second .IF (nMeasm<4)||(nMeasm>7) .ERROR "Number of measurements outside acceptable range" .ENDIF ; ; ================================================ ; Hardware connections ; ================================================ ; ___ ___ ; RESET |1 |_| 28| Prescaler divide by 8 output ; RXD |2 A 27| ; TXD |3 T 26| ; Time inp |4 M 25| ; |5 E 24| Mode select input, 0..2.56 V ; Count in |6 L 23| Voltage input, 0..2.56 V ; VCC |7 22| GND ; GND |8 A 21| AREF (2.56 V output) ; XTAL1 |9 T 20| AVCC input ; XTAL2 |10 m 19| SCK/LCD-E ; |11 e 18| MISO/LCD-RS ; |12 g 17| MOSI/LCD-D7 ; |13 a 16| LCD-D6 ; LCD-D4 |14 8 15| LCD-D5 ; |_________| ; ; ; ================================================ ; Derived constants ; ================================================ ; .EQU cR2c = (cR2 * cRin) / (cR2+cRin) .EQU cMultiplier = (641 * (cR1+cR2c))/cR2c ; used for voltage multiplication .EQU cMaxVoltage = 1024*cMultiplier/256 ; in mV .EQU cSafeVoltage = (cMaxVoltage * 5000) / 2560 .EQU cTDiv = 1000/nMeasm ; interval per measurement update ; calculating the CTC and prescaler values for TC1 (frequency measurement) .SET cCmp1F = cFreq/32 ; CTC compare value with prescaler = 8 .SET cPre1F = (1<2097120 .SET cCmp1F = cFreq/256 ; CTC compare value with prescaler = 64 .SET cPre1F = (1<16776960 .SET cCmp1F = cFreq/1024 ; CTC compare value with prescaler = 256 .SET cPre1F = (1<2040000 .SET cCmp2 = cFreq/32000 .SET cPre2 = (1<8160000 .SET cCmp2 = cFreq/64000 .SET cPre2 = (1<16320000 .SET cCmp2 = cFreq/128000 ; prescaler = 128 .SET cPre2 = (1< Presc2 => TC2 => CTC => rTDiv => ; ADC0 conversion => ADC1 conversion => bAdc-flag ; ; Main interval timer TC2 ; - uses TC2 as 8-bit-CTC, with compare interrupt ; - starts a ADC conversion ; - on ADC conversion complete: ; * store ADC result ; * convert ADC result ; * if a new counter result: convert this ; * if Uart connected and monitoring f/U: display on Uart ; * if LCD connected and display mode: display f/U result ; ; Operation at 16 MHz clock: ; cFreq => Prescaler/128 => CTC(125) => rTDiv(250) ; 16MHz => 125 kHz => 1 kHz => 4 Hz ; ; Frequeny counting modes (Mode = 0 and 1) ; - uses TC0 as 8-bit-counter to count positive edges ; - uses TC1 as 16-bit-counter to time-out the counter after 250 ms ; ; Timer modes (Mode = 2 to 8) ; - uses edge detection on external INT0 for timeout ; - uses TC1 as 16-bit-counter to time-out from edge to edge ; ; Voltage only (Mode = 9) ; - Timers TC0 and TC1 off ; - Timer TC2 times interval ; ; ============================================== ; Reset and Interrupt Vectors starting here ; ============================================== ; .CSEG .ORG $0000 ; ; Reset/Intvectors ; rjmp Main ; Reset rjmp Int0Int; Int0 reti ; Int1 rjmp TC2CmpInt ; TC2 Comp reti ; TC2 Ovf reti ; TC1 Capt rjmp Tc1CmpAInt ; TC1 Comp A reti ; TC1 Comp B rjmp Tc1OvfInt ; TC1 Ovf rjmp TC0OvfInt ; TC0 Ovf reti ; SPI STC .IFDEF cUart rjmp SioRxcIsr ; USART RX .ELSE reti ; USART RX .ENDIF reti ; USART UDRE reti ; USART TXC rjmp AdcCcInt ; ADC Conv Compl reti ; EERDY reti ; ANA_COMP reti ; TWI reti ; SPM_RDY ; ; ============================================= ; ; Interrupt Service Routines ; ; ============================================= ; ; TC2 Compare Match Interrupt ; counts rTDiv down, if zero: starts an AD conversion ; TC2CmpInt: in rSreg,SREG ; save SREG dec rTDiv ; count down brne TC2CmpInt1 ; not zero, interval not ended ldi rimp,(1< 1000 brne CalcPwE tst rRes3 brne CalcPwE ldi rmp,LOW(1001) cp rRes1,rmp ldi rmp,HIGH(1001) cpc rRes2,rmp brcc CalcPwE clc ; no error ret CalcPwE: ; error sec ret ; ; Display the binary in R2:R1 in the form " 100,0%" ; DisplPw: ldi XH,HIGH(sResult) ldi XL,LOW(sResult) ldi rmp,' ' st X+,rmp st X+,rmp clr R0 ldi ZH,HIGH(1000) ldi ZL,LOW(1000) rcall DisplDecX2 ldi ZH,HIGH(100) ldi ZL,LOW(100) rcall DisplDecX2 ldi ZL,10 inc R0 rcall DisplDecX2 ldi rmp,cDecSep st X+,rmp ldi rmp,'0' add rmp,rRes1 st X+,rmp ldi rmp,'%' st X+,rmp .IF ! cDisplay8 ldi rmp,8 ldi ZL,' ' DisplPw1: st X+,ZL dec rmp brne DisplPw1 .ENDIF ret ; ; If the first characters in the result buffer are empty, ; place the character in ZL here and add equal, if possible ; DisplMode: ldi XH,HIGH(sResult+1) ; point to result buffer ldi XL,LOW(sResult+1) ld rmp,X ; read second char cpi rmp,' ' brne DisplMode1 ldi rmp,'=' st X,rmp DisplMode1: sbiw XL,1 ld rmp,X ; read first char cpi rmp,' ' brne DisplMode2 st X,ZL DisplMode2: ret ; ;================================================= ; Display binary numbers as decimal ;================================================= ; ; Converts a binary in R2:R1 to a digit in X ; binary in Z ; DecConv: clr rmp DecConv1: cp R1,ZL ; smaller than binary digit? cpc R2,ZH brcs DecConv2 ; ended subtraction sub R1,ZL sbc R2,ZH inc rmp rjmp DecConv1 DecConv2: tst rmp brne DecConv3 tst R0 brne DecConv3 ldi rmp,' ' ; suppress leading zero rjmp DecConv4 DecConv3: subi rmp,-'0' DecConv4: st X+,rmp ret ; ; Display fractional number in R3:R2:(Fract)R1 ; DisplFrac: ldi XH,HIGH(sResult) ldi XL,LOW(sResult) .IF ! cDisplay8 ldi rmp,' ' st X+,rmp st X+,rmp .ENDIF clr R0 ldi ZH,HIGH(10000) ldi ZL,LOW(10000) rcall DisplDecY2 ldi ZH,HIGH(1000) ldi ZL,LOW(1000) rcall DisplDecY2 .IF ! cDisplay8 ldi rmp,c1kSep tst R0 brne DisplFrac0 ldi rmp,' ' DisplFrac0: st X+,rmp .ENDIF ldi ZL,100 rcall DisplDecY1 ldi ZL,10 rcall DisplDecY1 ldi rmp,'0' add rmp,R2 st X+,rmp tst R1 ; fraction = 0? brne DisplFrac1 ldi rmp,' ' st X+,rmp ldi rmp,'H' st X+,rmp ldi rmp,'z' st X+,rmp .IF ! cDisplay8 ldi rmp,' ' st X+,rmp st X+,rmp st X+,rmp st X+,rmp .ENDIF ret DisplFrac1: ldi rmp,cDecSep st X+,rmp .IF cDisplay8 ldi ZL,2 .ELSE ldi ZL,3 .ENDIF DisplFrac2: clr rRes3 clr rRes2 mov R0,rRes1 ; * 1 lsl rRes1 ; * 2 adc rRes2,rRes3 lsl rRes1 ; * 4 rol rRes2 add rRes1,R0 ; * 5 adc rRes2,rRes3 lsl rRes1 ; * 10 rol rRes2 ldi rmp,'0' add rmp,rRes2 st X+,rmp dec ZL brne DisplFrac2 .IF ! cDisplay8 ldi rmp,' ' st X+,rmp ldi rmp,'H' st X+,rmp ldi rmp,'z' st X+,rmp ldi rmp,' ' st X+,rmp .ENDIF ret ; ; convert a decimal in R4:R3:R2, decimal in ZH:ZL ; DisplDecY2: clr rDiv1 ; rDiv1 is counter clr rDiv2 ; overflow byte DisplDecY2a: cp rRes2,ZL cpc rRes3,ZH cpc rRes4,rDiv2 brcs DisplDecY2b ; ended sub rRes2,ZL ; subtract sbc rRes3,ZH sbc rRes4,rDiv2 inc rDiv1 rjmp DisplDecY2a DisplDecY2b: ldi rmp,'0' add rmp,rDiv1 add R0,rDiv1 tst R0 brne DisplDecY2c ldi rmp,' ' DisplDecY2c: st X+,rmp ret ; ; convert a decimal decimal in R:R2, decimal in ZL ; DisplDecY1: clr rDiv1 ; rDiv1 is counter clr rDiv2 ; overflow byte DisplDecY1a: cp rRes2,ZL cpc rRes3,rDiv2 brcs DisplDecY1b ; ended sub rRes2,ZL ; subtract sbc rRes3,rDiv2 inc rDiv1 rjmp DisplDecY1a DisplDecY1b: ldi rmp,'0' add rmp,rDiv1 add R0,rDiv1 tst R0 brne DisplDecY1c ldi rmp,' ' DisplDecY1c: st X+,rmp ret ; ; Display a 4-byte-binary in decimal format on result line 1 ; 8-bit-display: "12345678" ; 16-bit-display: " 12.345.678 Hz " ; Displ4Dec: ldi rmp,BYTE1(100000000) ; check overflow cp rRes1,rmp ldi rmp,BYTE2(100000000) cpc rRes2,rmp ldi rmp,BYTE3(100000000) cpc rRes3,rmp ldi rmp,BYTE4(100000000) cpc rRes4,rmp brcs Displ4Dec1 rjmp CycleOvf Displ4Dec1: clr R0 ; suppress leading zeroes ldi XH,HIGH(sResult) ; X to result buffer ldi XL,LOW(sResult) .IF ! cDisplay8 ldi rmp,' ' ; clear the first two digits st X+,rmp st X+,rmp .ENDIF ldi ZH,BYTE3(10000000) ; 10 mio ldi ZL,BYTE2(10000000) ldi rmp,BYTE1(10000000) rcall DisplDecX3 ldi ZH,BYTE3(1000000) ; 1 mio ldi ZL,BYTE2(1000000) ldi rmp,BYTE1(1000000) rcall DisplDecX3 .IF ! cDisplay8 ldi rmp,c1kSep ; set separator tst R0 brne Displ4Dec2 ldi rmp,' ' Displ4Dec2: st X+,rmp .ENDIF ldi ZH,BYTE3(100000) ; 100 k ldi ZL,BYTE2(100000) ldi rmp,BYTE1(100000) rcall DisplDecX3 ldi ZH,HIGH(10000) ; 10 k ldi ZL,LOW(10000) rcall DisplDecX2 ldi ZH,HIGH(1000) ; 1 k ldi ZL,LOW(1000) rcall DisplDecX2 .IF ! cDisplay8 ldi rmp,c1kSep ; set separator tst R0 brne Displ4Dec3 ldi rmp,' ' Displ4Dec3: st X+,rmp .ENDIF ldi ZL,100 ; 100 rcall DisplDecX1 ldi ZL,10 rcall DisplDecX1 ldi rmp,'0' ; 1 add rmp,R1 st X+,rmp ret ; ; convert a decimal in R3:R2:R1, decimal in ZH:ZL:rmp ; DisplDecX3: clr rDiv1 ; rDiv1 is counter clr rDiv2 ; subtractor for byte 4 DisplDecX3a: cp rRes1,rmp ; compare cpc rRes2,ZL cpc rRes3,ZH cpc rRes4,rDiv2 brcs DisplDecX3b ; ended sub rRes1,rmp ; subtract sbc rRes2,ZL sbc rRes3,ZH sbc rRes4,rDiv2 inc rDiv1 rjmp DisplDecX3a DisplDecX3b: ldi rmp,'0' add rmp,rDiv1 add R0,rDiv1 tst R0 brne DisplDecX3c ldi rmp,' ' DisplDecX3c: st X+,rmp ret ; ; convert a decimal in R3:R2:R1, decimal in ZH:ZL ; DisplDecX2: clr rDiv1 ; rDiv1 is counter clr rDiv2 ; next byte overflow DisplDecX2a: cp rRes1,ZL cpc rRes2,ZH cpc rRes3,rDiv2 brcs DisplDecX2b ; ended sub rRes1,ZL ; subtract sbc rRes2,ZH sbc rRes3,rDiv2 inc rDiv1 rjmp DisplDecX2a DisplDecX2b: ldi rmp,'0' add rmp,rDiv1 add R0,rDiv1 tst R0 brne DisplDecX2c ldi rmp,' ' DisplDecX2c: st X+,rmp ret ; ; convert a decimal decimal in R2:R1, decimal in ZL ; DisplDecX1: clr rDiv1 ; rDiv1 is counter clr rDiv2 ; next byte overflow DisplDecX1a: cp rRes1,ZL cpc rRes2,rDiv2 brcs DisplDecX1b ; ended sub rRes1,ZL ; subtract sbc rRes2,rDiv2 inc rDiv1 rjmp DisplDecX1a DisplDecX1b: ldi rmp,'0' add rmp,rDiv1 add R0,rDiv1 tst R0 brne DisplDecX1c ldi rmp,' ' DisplDecX1c: st X+,rmp ret ; ;================================================= ; Delay routines ;================================================= ; Delay10ms: ldi rDelH,HIGH(10000) ldi rDelL,LOW(10000) rjmp DelayZ Delay15ms: ldi rDelH,HIGH(15000) ldi rDelL,LOW(15000) rjmp DelayZ Delay4_1ms: ldi rDelH,HIGH(4100) ldi rDelL,LOW(4100) rjmp DelayZ Delay1_64ms: ldi rDelH,HIGH(1640) ldi rDelL,LOW(1640) rjmp DelayZ Delay100us: clr rDelH ldi rDelL,100 rjmp DelayZ Delay40us: clr rDelH ldi rDelL,40 rjmp DelayZ ; ; Delays execution for Z microseconds ; DelayZ: .IF cFreq>18000000 nop nop .ENDIF .IF cFreq>16000000 nop nop .ENDIF .IF cFreq>14000000 nop nop .ENDIF .IF cFreq>12000000 nop nop .ENDIF .IF cFreq>10000000 nop nop .ENDIF .IF cFreq>8000000 nop nop .ENDIF .IF cFreq>6000000 nop nop .ENDIF .IF cFreq>4000000 nop nop .ENDIF sbiw rDelL,1 ; 2 brne DelayZ ; 2 ret ; ; ========================================= ; Main Program Start ; ========================================= ; main: ldi rmp,HIGH(RAMEND) ; set stack pointer out SPH,rmp ldi rmp,LOW(RAMEND) out SPL,rmp clr rFlg ; set flags to default ; .IF debug .EQU number = 100000000 ldi rmp,BYTE4(number) mov rRes4,rmp mov rDiv4,rmp ldi rmp,BYTE3(number) mov rRes3,rmp mov rDiv3,rmp ldi rmp,BYTE2(number) mov rRes2,rmp mov rDiv2,rmp ldi rmp,BYTE1(number) mov rRes1,rmp mov rDiv1,rmp rcall CycleM6 beloop: rjmp beloop .ENDIF .IF debugpulse .EQU nhigh = 100000000 .EQU nlow = 15000 ldi rmp,BYTE4(nhigh) sts sCtr+3,rmp ldi rmp,BYTE3(nhigh) sts sCtr+2,rmp ldi rmp,BYTE2(nhigh) sts sCtr+1,rmp ldi rmp,BYTE1(nhigh) sts sCtr,rmp ldi rmp,BYTE4(nlow) mov rRes4,rmp mov rDiv4,rmp ldi rmp,BYTE3(nlow) mov rRes3,rmp mov rDiv3,rmp ldi rmp,BYTE2(nlow) mov rRes2,rmp mov rDiv2,rmp ldi rmp,BYTE1(nlow) mov rRes1,rmp mov rDiv1,rmp sbr rFlg,1< 10 MHz ldi rmp,0 brcc CycleM1a tst rRes3 ; check smaller than 1 kHz brne CycleM1b tst rRes2 brne CycleM1b ldi rmp,2 ; switch to mode 2 CycleM1a: dec rNMode ; count modes brne CycleM1b ldi rNMode,cNMode sts sModeNext,rmp CycleM1b: clr rDiv1 ; detect overflow in rDiv1 lsl rRes1 ; * 2 rol rRes2 rol rRes3 rol rRes4 rol rDiv1 lsl rRes1 ; * 4 rol rRes2 rol rRes3 rol rRes4 rol rDiv1 tst rDiv1 ; check overflow breq CycleM1d ; no error rjmp CycleOvf CycleM1d: rcall Displ4Dec .IF ! cDisplay8 ldi rmp,' ' st X+,rmp ldi rmp,'H' st X+,rmp ldi rmp,'z' st X+,rmp ldi rmp,' ' st X,rmp .ENDIF ldi ZL,'f' rjmp DisplMode ; ; Mode 2: Time measured, prescale = 1, display frequency ; CycleM2: mov rmp,rDiv2 ; check too small andi rmp,0xC0 ; isolate upper six bits or rmp,rDiv3 or rmp,rDiv4 brne CycleM2a dec rNMode ; count mode change counter down brne CycleM2a ldi rNMode,cNMode ; restart counter ldi rmp,cModeFrequency ; switch to frequency mode sts sModeNext,rmp CycleM2a: rcall Divide tst rRes4 brne CycleM2e rcall DisplFrac ldi ZL,'v' rcall DisplMode ret CycleM2e: mov rRes1,rRes2 ; number too big, skip fraction mov rRes2,rRes3 mov rRes3,rRes4 clr rRes4 rcall Displ4Dec .IF ! cDisplay8 ldi rmp,' ' st X+,rmp ldi rmp,'H' st X+,rmp ldi rmp,'z' st X+,rmp ldi rmp,' ' st X,rmp .ENDIF ldi ZL,'v' rcall DisplMode ret ; ; Measure time, display rounds per minute ; CycleM3: rcall Divide clr R0 ; overflow detection clr rmp lsl rRes1 ; * 2 rol rRes2 rol rRes3 rol rRes4 adc R0,rmp lsl rRes1 ; * 4 rol rRes2 rol rRes3 rol rRes4 adc R0,rmp mov rDiv1,rRes1 ; copy mov rDiv2,rRes2 mov rDiv3,rRes3 mov rDiv4,rRes4 lsl rRes1 ; * 8 rol rRes2 rol rRes3 rol rRes4 adc R0,rmp lsl rRes1 ; * 16 rol rRes2 rol rRes3 rol rRes4 adc R0,rmp lsl rRes1 ; * 32 rol rRes2 rol rRes3 rol rRes4 adc R0,rmp lsl rRes1 ; * 64 rol rRes2 rol rRes3 rol rRes4 adc R0,rmp tst R0 ; overflow? breq CycleM3a rjmp CycleOvf CycleM3a: sub rRes1,rDiv1 sbc rRes2,rDiv2 sbc rRes3,rDiv3 sbc rRes4,rDiv4 mov rRes1,rRes2 mov rRes2,rRes3 mov rRes3,rRes4 clr rRes4 rcall Displ4Dec .IF ! cDisplay8 ldi rmp,' ' st X+,rmp ldi rmp,'r' st X+,rmp ldi rmp,'p' st X+,rmp ldi rmp,'m' st X+,rmp .ENDIF ldi ZL,'u' rcall DisplMode ret ; ; Measure time high+low, display time ; CycleM4: rcall Multiply rcall Displ4Dec rcall DisplSec ldi ZL,'t' rcall DisplMode ret ; ; Measure time high, display time ; CycleM5: sbrs rFlg,bEdge rjmp CycleM5a rcall Multiply rcall Displ4Dec rcall DisplSec ldi ZL,'h' rcall DisplMode CycleM5a: ret ; ; Measure time low, display time ; CycleM6: sbrc rFlg,bEdge rjmp CycleM6a rcall Multiply rcall Displ4Dec rcall DisplSec ldi ZL,'l' rcall DisplMode CycleM6a: ret ; ; Measure time high and low, display pulse width ratio high in % ; if the edge was negative, store the measured time, if positive calculate ; rRes and rDiv hold the active low time, sCtr the last active high time ; to CalcPw: rDelH:rDelL:R0:rmp = active high time ; CycleM7: sbrs rFlg,bEdge rjmp CycleM7a ldi ZH,HIGH(sCtr) ; edge is high, calculate ldi ZL,LOW(sCtr) ld rRes1,Z+ ; copy counter value ld rRes2,Z+ ld rRes3,Z+ ld rRes4,Z+ add rDiv1,rRes1 ; add to total time adc rDiv2,rRes2 adc rDiv3,rRes3 adc rDiv4,rRes4 brcs CycleM7b mov rmp,rRes1 ; copy high value to divisor mov R0,rRes2 mov rDelL,rRes3 mov rDelH,rRes4 rcall CalcPw ; calculate the ratio brcs CycleM7b ; error rcall DisplPw ; display the ratio ldi ZL,'P' rjmp DisplMode CycleM7a: ldi ZH,HIGH(sCtr) ldi ZL,LOW(sCtr) st Z+,rRes1 ; copy counter value st Z+,rRes2 st Z+,rRes3 st Z+,rRes4 ret CycleM7b: ; overflow ldi rmp,'P' rjmp PulseOvFlw ; ; Measure time high and low, display pulse width ratio low in % ; if the edge was negative, store the measured time, if positive calculate ; rRes and rDiv hold the active low time, sCtr the last active high time ; to CalcPw: rDelH:rDelL:R0:rmp = active low time ; CycleM8: sbrs rFlg,bEdge rjmp CycleM8a ldi ZH,HIGH(sCtr) ; edge is high, calculate ldi ZL,LOW(sCtr) ld rmp,Z+ ; read high-time ld R0,Z+ ld rDelL,Z+ ld rDelH,Z add rDiv1,rmp ; add to total time adc rDiv2,R0 adc rDiv3,rDelL adc rDiv4,rDelH mov rmp,rRes1 ; copy the active low time mov R0,rRes2 mov rDelL,rRes3 mov rDelH,rRes4 rcall CalcPw ; calculate the ratio brcs CycleM8b ; error rcall DisplPw ; display the ratio ldi ZL,'p' rjmp DisplMode CycleM8a: ldi ZH,HIGH(sCtr) ldi ZL,LOW(sCtr) st Z+,rRes1 ; copy counter value st Z+,rRes2 st Z+,rRes3 st Z+,rRes4 ret CycleM8b: ; overflow ldi rmp,'p' rjmp PulseOvFlw ; ; Converts an ADC value in R1:R0 to a voltage for display ; cAdc2U input: ADC value, output: Voltage in V for display ; cAdc2U: clr R2 ; clear the registers for left shift in R3:R2 clr R3 ldi rmp,HIGH(cMultiplier) ; Multiplier to R5:R4 mov R5,rmp ldi rmp,LOW(cMultiplier) mov R4,rmp clr XL ; clear result in ZH:ZL:XH:XL clr XH clr ZL clr ZH cAdc2U1: lsr R5 ; shift Multiplier right ror R4 brcc cAdc2U2 ; bit is zero, don't add add XL,R0 ; add to result adc XH,R1 adc ZL,R2 adc ZH,R3 cAdc2U2: mov rmp,R4 ; check zero or rmp,R5 breq cAdc2U3 ; end of multiplication lsl R0 ; multiply by 2 rol R1 rol R2 rol R3 rjmp cAdc2U1 ; go on multipying cAdc2U3: ldi rmp,$80 ; round up add XL,rmp ldi rmp,$00 adc XH,rmp adc ZL,rmp adc ZH,rmp tst ZH ; check overflow mov R1,XH ; copy result to R2:R1 mov R2,ZL ldi XH,HIGH(sResult+16) ; point to result ldi XL,LOW(sResult+16) ldi rmp,'U' st X+,rmp breq cAdc2U5 ldi ZH,HIGH(2*AdcErrTxt) ldi ZL,LOW(2*AdcErrTxt) cAdc2U4: lpm tst R0 breq cAdc2U6 sbiw ZL,1 st X+,R0 rjmp cAdc2U4 cAdc2U5: clr R0 ldi ZH,HIGH(10000) ldi ZL,LOW(10000) rcall DecConv inc R0 ldi ZH,HIGH(1000) ldi ZL,LOW(1000) rcall DecConv ldi rmp,cDecSep st X+,rmp clr ZH ldi ZL,100 rcall DecConv ldi ZL,10 rcall DecConv ldi rmp,'0' add rmp,R1 st X+,rmp ldi rmp,'V' st X,rmp lds rmp,sResult+17 cpi rmp,' ' brne cAdc2U6 ldi rmp,'=' sts sResult+17,rmp cAdc2U6: ret ; AdcErrTxt: .DB "overflw",$00 ; ; =========================================== ; Lcd display routines ; =========================================== ; .IF cDisplay ; if display connected ; ; LcdE pulses the E output for at least 1 us ; LcdE: sbi PORTB,bLcdE .IF cFreq>14000000 nop nop .ENDIF .IF cFreq>12000000 nop nop .ENDIF .IF cFreq>10000000 nop nop .ENDIF .IF cFreq>8000000 nop nop .ENDIF .IF cFreq>6000000 nop nop .ENDIF .IF cFreq>4000000 nop nop .ENDIF .IF cFreq>2000000 nop nop .ENDIF nop nop cbi PORTB,bLcdE ret ; ; outputs the content of rmp (temporary ; 8-Bit-Interface during startup) ; LcdRs8: out PORTB,rmp rcall LcdE ret ; ; write rmp as 4-bit-command to the LCD ; LcdRs4: mov R0,rmp ; copy rmp swap rmp ; upper nibble to lower nibble andi rmp,0x0F ; clear upper nibble out PORTB,rmp ; write to display interface rcall LcdE ; pulse E mov rmp,R0 ; copy original back andi rmp,0x0F ; clear upper nibble out PORTB,rmp ; write to display interface rcall LcdE mov rmp,R0 ; restore rmp ret ; ; write rmp as data over 4-bit-interface to the LCD ; LcdData4: push rmp ; save rmp mov rmp,R0 ; copy rmp swap rmp ; upper nibble to lower nibble andi rmp,0x0F ; clear upper nibble sbr rmp,1<elp",cCr,cLf txtUartCursor: .DB cCr,cLf,"i> ",cNul .ENDIF ; ; End of source code ;