Dim Adc_flag As Byte ' Flag fuer ADC fertig
Adc_flag = 0
Dim Adc_delay_cnt As Byte ' Zaehler fuer ADC-Rhythmus
' PA7 ------- VBat-ADC
'
' A=7= O=6= O=5= O=4= O=3= O=2= O=1= O=0= => 01111111 => DDRB
' VBat Tim1 ws3 ws2 ws1 bl3 bl2 bl1 => 00000000 => PORTB (init)
' | | | | | | | |
'
Ddra = &B0111_1111
Porta = &B0000_0000
' =============================================================================
' ===== ADC7 Initialisieren ===================================================
' =============================================================================
' ADC-Kanal 7 (PA7) misst die Akkuspannung (10 Zellen NiMh, 2100mAh)
' Die Messung soll soweit moeglich hardwareunterstuetzt ablaufen und dadurch moeglichst
' wenig Prozessorzeit verbrauchen. Als Referenz wird die interne 2,56V Bandgapquelle
' verwendet weil AVcc zu stark schwanken kann. Da die Timer 0+1 bereits belegt sind und
' Timer2 keine Wandlung ausloesen kann sowie ein 8Bit-Timer eine zu hohe Wandelrate liefern
' wuerde, wird der Start manuell ueber Software gestartet und dann das Ergebnis ueber ISR
' abgefragt. Eine Wandelrate von 1-2Hz reicht absolut aus.
'
' Spannungsteiler: Vbat---39k---ADC7---6k8---GND
'
' Berechnung der Akkuspannung aus dem gemessenen ADC-Registerinhalt:
'
' Vbat / (39k + 6k8) = Vadc / 6k8 ...=>... Vbat = ((39k + 6k8) / 6k8) * Vadc
' Vref / 1024steps = Vadc / ADCsteps ...=>... Vadc = (Vref / 1024steps) * ADCsteps
'
' ( ((39k + 6k8) * Vref) / (6k8 * 1024steps) ) *ADCsteps = Vbat
'
' 0,016838235 * ADCsteps = Vbat ...=>... Vbat = ADCsteps / 59,38864733
'
' ADC-Messzyklus: Software -> ADSC=1 .. ADC-ISR(read) .. Anzeige der letzten Mesung
'
Config Adc = Single , Prescaler = 128 , Reference = Internal
' ===== ADC Multiplexer Selection Register =====
'Bit --7-- --6-- --5-- --4-- --3-- --2-- --1-- --0-- ADMUX
' REFS1 REFS0 ADLAR MUX4 MUX3 MUX2 MUX1 MUX0
' R/W R/W R/W R/W R/W R/W R/W R/W
' | | |
' | | \ADC Left Adjust Result (Write one to ADLAR to left adjust the result)
' \ /
' 0 0 AREF, Internal Vref turned off
' 0 1 AVCC with external capacitor at AREF pin
' 1 0 Reserved
' 1 1 Internal 2.56V Voltage Reference with external capacitor at AREF pin
'
' MUX4:0 Single Ended Input
' 00111 ADC7
'
Admux = &B1100_0111
' ===== ADC Control and Status Register A =====
'Bit --7-- --6-- --5-- --4-- --3-- --2-- --1-- --0-- ADCSRA
' ADEN ADSC ADATE ADIF ADIE ADPS2 ADPS1 ADPS0
' R/W R/W R/W R/W R/W R/W R/W R/W
' | | | | |
' | | | | \ADC Interrupt Enable
' | | | \ADC Interrupt Flag
' | | \ADC Auto Trigger Enable
' | \ADC Start Conversion
' \ADC Enable
'
' ADPS2:0 - ADC Prescaler Select Bits => Division Factor
' 000 = 2 , 001 = 2 , 010 = 4 , 011 = 8 , 100 = 16 , 101 = 32 , 110 = 64 , 111 = 128
' Prescaler von 128 wuerde bei 16MHz etwa 96kHz Wandelrate ergeben. Reicht absolut.
'
Adcsra = &B1100_1111
' ===== Special FunctionIO Register =====
'Bit --7-- --6-- --5-- -4- --3-- -2- --1-- --0-- SFIOR
' ADTS2 ADTS1 ADTS0 - ACME PUD PSR2 PSR1
' R/W R/W R/W R R/W R/W R/W R/W
' | | | |
' | __/ | \_ W=0 !
' | / _______/
' || /
' ||| ADTS2:0: ADC Auto Trigger Source
' 000 Free Running mode
' 001 Analog Comparator
' 010 External Interrupt Request 0
' 011 Timer/Counter0 Compare Match
' 100 Timer/Counter0 Overflow
' 101 Timer/Counter1 Compare Match B
' 110 Timer/Counter1 Overflow
' 111 Timer/Counter1 Capture Event
'
'SFIOR = &B0000_xxxx
'Vbat_adc = Getadc(7) ==> selber auslesen ist resourcenschonender
'
On Adcc Adc_isr ' Interrupt-Vektor einstellen
' Enable ADC-Interrupt wird direkt im Register erledigt.
.......
Gosub Akku_mess ' Akkuspannungsmessung und Anzeige
........
' ================================================
' ===== ISR fuer ADC Conversion Complete =========
' ================================================
' ADC-Wandlung fuer Akkuspannungsmessung beendet
' 10Bit-Wert abholen
Adc_isr:
' Bei 10Bit UNBEDINGT erst das Low-Byte lesen damit
' dadurch das High-Byte in TEMP gelegt wird. Sonst ... RaceCondition!!
Adc_l = Adcl ' ZUERST Low-Byte holen
Adc_h = Adch ' Dann High-Byte aus TEMP lesen
Adc_flag = 1 ' Flag setzen als Info das Wert neu ist
Return
' ================================================
' ===== Akkuspannungsmessung und Anzeige =========
' ================================================
' Anzeige des aktuellen Modus auf den 3 LEDs der
' Modusanzeige und auf dem Debug-LCD im Steuergerät
Akku_mess:
If Adc_delay_cnt > 20 Then ' Anzeige und neue Messung starten
Adc_delay_cnt = 0 ' Verzoegerungszaehler neu starten
' DVM = 12,916 , ADC = 13,370 => +3,51502% Meßfehler => neuer Faktor 61,47617199
' Vbat = Adc_read / 59.38864733 ' gemessenen ADC-Wert holen und umrechnen
Vbat = Adc_read / 61.476171 ' kalibrierte Umrechnung
Vbatstr = Fusing(vbat , "#.##") ' Single-Wert formatieren
Locate 1 , 1
Lcd Vbatstr ' Spannung anzeigen
Set Adcsra.6 'adsc setzen - Start neue Conversion
End If
Incr Adc_delay_cnt ' Verzoegerungzaehler fuer ADC-Messung
Return