rogerberglen
20.08.2007, 12:57
Ich habe wie schon geschrieben ein Programm erstellt, daß eine Spannung misst und auf 4 LED's ausgeben soll.
Im AVR Simulator läuft das Ganze allerbest. Nun habe ich das Programm in den ATtiny15 geschrieben mit den passenden EEprom-Werten.
Nach dem Einschalten wird auf den LED's zufällig was angezeigt. Wenn man dann von Hand einen RESET macht dann leuchtet die richtige LED. Leider ändert sich aber an den LED's nichts wenn man die Analogspannung variiert. Es wird aber jeweils nach dem RESET die passende LED angezeigt.
Warum wird anscheinend die AD-Wandlung nicht vom Timer aufgerufen???
Auch sollten nach einem RESET die LED's so ca. 1/2 Sekunde lang leuchten. Diese blitzen aber nur kaum merklich auf. Daran ändert sich auch nichts wenn man den Prescaler Wert des Timers ändert.
Ich bin jetzt ziemlich ratlos denn eigentlich sollte das Ganze funktionieren.
Hier das Programm:
; ************************************************** ********
; * Prozessor Attiny15 *
; ************************************************** ********
; * Temperaturüberwachung über einen NTC *
; ************************************************** ********
; * Dazu wird ein Analogsignal über einen AD-Wandler in *
; * einen Digitalen Zahlenwert übersetzt. *
; * Die Abfrage findet in etwa im Sekundentakt statt. Dazu *
; * wird über den Timer0 ein Interrupt generiert. *
; * Die Vergleichswerte für die einzelnen Temperaturberei- *
; * che werden in der EEprom Sektion des ATtiny15 hinter- *
; * legt. Dadurch sind Anpassungen einfach an den jeweili- *
; * gen Meßfühler möglich. *
; * Das Ergebnis wird mit 4 LED's verschiedener Farben an- *
; * gezeigt: *
; * *
; * LED1 (blau) = Temperatur ist niedriger als 60°C *
; * LED2 (grün) = Temperatur befindet sich 60°C - 100°C *
; * LED3 (gelb) = Temperatur befindet sich 100°C - 115°C *
; * LED4 (rot) = Temperatur ist höher als 115°C *
; ************************************************** ********
; * (RESET/ADC0) PB5 = Pin1 Pin8 = Vcc *
; * (ADC3) PB4 = Pin2 Pin7 = PB2 (ADC1/SCK/T0/INT0) *
; * (ADC2) PB3 = Pin3 Pin6 = PB1 (AIN1/ MISO/OC1A) *
; * GND = Pin4 Pin5 = PB0 (AIN0/AREF/MOSI) *
; ************************************************** ********
.include "TN15def.inc" ; Prozessor ATtiny15
.eseg ; Kennung für EEprom
; ************************************************** ********
; * Temperaturvergleichswerte noch anpassen !!! *
; ************************************************** ********
TempKalt: .dw 0x5555 ; Wert für Temperatur bis 60°C
TempWarm: .dw 0x7777 ; Wert für Temperatur 60°C - 100°C
TempHoch: .dw 0x9999 ; Wert für Temperatur 100°C-115°C
TempKrit: .dw 0xBBBB ; Wert für Temperatur über 115°C
.cseg ; Kennung für Programmcode
.def TMP1 = R16 ; Allgemeine Variable
.def LEDStat = R17 ; LED-Register
.def Prescaler = R18 ; Timer0 Startwert
.def ADHigh = R19 ; High-Byte Analogwandler
.def ADLow = R20 ; Low-Byte Analogwandler
.def EEprom = R21 ; EEprom Adresse
.def EEData = R22 ; EEprom Daten
.def TPHigh = R23 ; Temperaturvergleich High-Byte
.def TPLow = R24 ; Temperaturvergleich Low-Byte
.def SCount = R25 ; Schleifenzähler
.def Vergleich = R26 ; Vergleichsergebnis
.def LEDWert = R27 ; Übergabevariable (Unterprogramm)
.org 0x0000 ; Programm Startadresse $0000
rjmp Init ; Einsprung ins Hauptprogramm
.org 0x0005 ; Interrupt Timer0
rjmp Led ; Led im Sekundentakt blinken
.org 0x0008 ; Interrupt AD-Wandler
rjmp ADFertig ; Ergebnis von AD holen
.org 0x0009 ; Programmstart bei $0009
Init:
ldi TMP1,0b00010111 ; Pin 2,5,6 und 7 auf Ausgabe
out DDRB,TMP1 ; schalten und alle LED's
ldi TMP1,0x00
mov Vergleich,TMP1 ; Vergleichsregister löschen
out PORTB,TMP1 ; einschalten.
sbr LEDStat,0b11000000 ; LED-Status (alle an) speichern
ldi TMP1,0x01
rol TMP1
out TIMSK,TMP1 ; Timer0 Interrupt freigeben
ldi TMP1,0x02 ; Teilerfaktor 8
out TCCR0,TMP1 ; für Timer0 einstellen.
ldi TMP1,0x0 ; Timer0 mit Startwert
out TCNT0,TMP1 ; vorladen und Startwert
mov Prescaler,TMP1 ; speichern.
ldi TMP1,0x82 ; Interne Referenzspannung
out ADMUX,TMP1 ; einschalten und Pin3 Analogeingang
ldi TMP1,0x8F ; AD-Wandler einschalten und
out ADCSR,TMP1 ; Interrupt für AD freigeben.
ldi TMP1,0x00 ; Schleifendurchläufe festlegen
mov SCount,TMP1
sei ; Interrupts freigeben
Start:
; **********************************************
; * Hauptprogramm für Temperaturauswertung *
; **********************************************
Schleife:
sbrc LEDStat,7
rjmp Schleife
LED1:
ldi EEprom,0x00 ; Vergleichswertadresse vorgeben
rcall LeseEEprom ; und Wert aus EEprom holen.
cp ADLow,TPLow ; 16-Bit Vergleich vornehmen.
cpc ADHigh,TPHigh ; Meßwert > Vorgabewert?
brcc LED2 ; Ja, dann zur nächsten LED
ldi LEDStat,0b00010110 ; sonst LED1 einschalten.
rcall LEDAkt
rjmp LEDEnde
LED2:
ldi EEprom,0x01 ; Vergleichswertadresse vorgeben
rcall LeseEEprom ; und Wert aus EEprom holen.
cp ADLow,TPLow ; 16-Bit Vergleich vornehmen.
cpc ADHigh,TPHigh ; Meßwert > Vorgabewert?
brcc LED3 ; Ja, dann zur nächsten LED
ldi LEDStat,0b00010101 ; sonst LED2 einschalten.
rcall LEDAkt
rjmp LEDEnde
LED3:
ldi EEprom,0x02 ; Vergleichswertadresse vorgeben
rcall LeseEEprom ; und Wert aus EEprom holen.
cp ADLow,TPLow ; 16-Bit Vergleich vornehmen.
cpc ADHigh,TPHigh ; Meßwert > Vergleichswert?
brcc LED4 ; Ja, dann zur nächsten LED
ldi LEDStat,0b00010011 ; sonst LED3 einschalten.
rcall LEDAkt
rjmp LEDEnde
LED4:
ldi EEprom,0x03 ; Vergleichswertadresse vorgeben
rcall LeseEEprom ; und Wert aus EEprom holen.
cp ADLow,TPLow ; 16-Bit Vergleich vornehmen.
cpc ADHigh,TPHigh ; Meßwert > Vergleichswert
;brcc LED4 ; Ja, dann LED4 eingeschaltet lassen
;sbr LEDStat,0b00010111 ; sonst alle LED's ausschalten
;out PORTB,LEDStat ; und LED4
;cbr LEDStat,0b00010000 ; einschalten
;out PORTB,LEDStat
ldi LEDStat,0b00000111
rcall LEDAkt
LEDEnde:
sbr LEDStat,0b10000000
rjmp start ; Hauptprogrammende
; >>>>>>>>>> INTERRUPTPROGRAMME <<<<<<<<<<
; ****************************************
; * Interrupt LED An/Aus Timer0 *
; ****************************************
Led:
out TCNT0,Prescaler ; Timer mit Startwert laden
sbrs LEDStat,6 ; Startbit LED löschen gesetzt?
rjmp Tim0
cbr LEDStat,6
andi LEDStat,0b10111111
ori LEDStat,0b00010111
out PORTB,LEDStat
Tim0:
sbi ADCSR,ADSC ; AD-Wandlung starten.
reti ; Rücksprung zum Hauptprogramm
; ****************************************
; * Interrupt AD-Wandler *
; ****************************************
ADFertig:
cbr LEDStat,0b10000000 ; Kennung (alle Led an) löschen
in ADHigh,ADCH ; High-Byte AD speichern
in ADLow,ADCL ; Low-Byte AD speichern
reti
; >>>>>>>>>> UNTERPROGRAMME <<<<<<<<<<
; ****************************************
; * EEprom Werte Lesen *
; ****************************************
LeseEEprom:
lsl EEprom ; Adresse *2 für 2-Byte Sprung
out EEAR,EEprom ; Adresse in EEprom schreiben.
ldi TMP1,0x01 ; Dazu Lesefreigabe ins
out EECR,TMP1 ; EEprom-Steuerregister schreiben.
in TPHigh,EEDR ; EEprom-Daten in High-Byte.
inc EEprom ; Low-Byte des Vergleichswert
out EEAR,EEprom ; aus dem EEprom holen.
out EECR,TMP1 ; Lesefreigabe schreiben und
in TPLow,EEDR ; EEprom-Daten holen.
ret
; *****************************************
; * LED's aktualisieren *
; *****************************************
LEDAkt:
mov LEDWert,LEDStat ; Wert übergeben und
out PORTB,LEDStat ; auf Port ausgeben.
ret
Im AVR Simulator läuft das Ganze allerbest. Nun habe ich das Programm in den ATtiny15 geschrieben mit den passenden EEprom-Werten.
Nach dem Einschalten wird auf den LED's zufällig was angezeigt. Wenn man dann von Hand einen RESET macht dann leuchtet die richtige LED. Leider ändert sich aber an den LED's nichts wenn man die Analogspannung variiert. Es wird aber jeweils nach dem RESET die passende LED angezeigt.
Warum wird anscheinend die AD-Wandlung nicht vom Timer aufgerufen???
Auch sollten nach einem RESET die LED's so ca. 1/2 Sekunde lang leuchten. Diese blitzen aber nur kaum merklich auf. Daran ändert sich auch nichts wenn man den Prescaler Wert des Timers ändert.
Ich bin jetzt ziemlich ratlos denn eigentlich sollte das Ganze funktionieren.
Hier das Programm:
; ************************************************** ********
; * Prozessor Attiny15 *
; ************************************************** ********
; * Temperaturüberwachung über einen NTC *
; ************************************************** ********
; * Dazu wird ein Analogsignal über einen AD-Wandler in *
; * einen Digitalen Zahlenwert übersetzt. *
; * Die Abfrage findet in etwa im Sekundentakt statt. Dazu *
; * wird über den Timer0 ein Interrupt generiert. *
; * Die Vergleichswerte für die einzelnen Temperaturberei- *
; * che werden in der EEprom Sektion des ATtiny15 hinter- *
; * legt. Dadurch sind Anpassungen einfach an den jeweili- *
; * gen Meßfühler möglich. *
; * Das Ergebnis wird mit 4 LED's verschiedener Farben an- *
; * gezeigt: *
; * *
; * LED1 (blau) = Temperatur ist niedriger als 60°C *
; * LED2 (grün) = Temperatur befindet sich 60°C - 100°C *
; * LED3 (gelb) = Temperatur befindet sich 100°C - 115°C *
; * LED4 (rot) = Temperatur ist höher als 115°C *
; ************************************************** ********
; * (RESET/ADC0) PB5 = Pin1 Pin8 = Vcc *
; * (ADC3) PB4 = Pin2 Pin7 = PB2 (ADC1/SCK/T0/INT0) *
; * (ADC2) PB3 = Pin3 Pin6 = PB1 (AIN1/ MISO/OC1A) *
; * GND = Pin4 Pin5 = PB0 (AIN0/AREF/MOSI) *
; ************************************************** ********
.include "TN15def.inc" ; Prozessor ATtiny15
.eseg ; Kennung für EEprom
; ************************************************** ********
; * Temperaturvergleichswerte noch anpassen !!! *
; ************************************************** ********
TempKalt: .dw 0x5555 ; Wert für Temperatur bis 60°C
TempWarm: .dw 0x7777 ; Wert für Temperatur 60°C - 100°C
TempHoch: .dw 0x9999 ; Wert für Temperatur 100°C-115°C
TempKrit: .dw 0xBBBB ; Wert für Temperatur über 115°C
.cseg ; Kennung für Programmcode
.def TMP1 = R16 ; Allgemeine Variable
.def LEDStat = R17 ; LED-Register
.def Prescaler = R18 ; Timer0 Startwert
.def ADHigh = R19 ; High-Byte Analogwandler
.def ADLow = R20 ; Low-Byte Analogwandler
.def EEprom = R21 ; EEprom Adresse
.def EEData = R22 ; EEprom Daten
.def TPHigh = R23 ; Temperaturvergleich High-Byte
.def TPLow = R24 ; Temperaturvergleich Low-Byte
.def SCount = R25 ; Schleifenzähler
.def Vergleich = R26 ; Vergleichsergebnis
.def LEDWert = R27 ; Übergabevariable (Unterprogramm)
.org 0x0000 ; Programm Startadresse $0000
rjmp Init ; Einsprung ins Hauptprogramm
.org 0x0005 ; Interrupt Timer0
rjmp Led ; Led im Sekundentakt blinken
.org 0x0008 ; Interrupt AD-Wandler
rjmp ADFertig ; Ergebnis von AD holen
.org 0x0009 ; Programmstart bei $0009
Init:
ldi TMP1,0b00010111 ; Pin 2,5,6 und 7 auf Ausgabe
out DDRB,TMP1 ; schalten und alle LED's
ldi TMP1,0x00
mov Vergleich,TMP1 ; Vergleichsregister löschen
out PORTB,TMP1 ; einschalten.
sbr LEDStat,0b11000000 ; LED-Status (alle an) speichern
ldi TMP1,0x01
rol TMP1
out TIMSK,TMP1 ; Timer0 Interrupt freigeben
ldi TMP1,0x02 ; Teilerfaktor 8
out TCCR0,TMP1 ; für Timer0 einstellen.
ldi TMP1,0x0 ; Timer0 mit Startwert
out TCNT0,TMP1 ; vorladen und Startwert
mov Prescaler,TMP1 ; speichern.
ldi TMP1,0x82 ; Interne Referenzspannung
out ADMUX,TMP1 ; einschalten und Pin3 Analogeingang
ldi TMP1,0x8F ; AD-Wandler einschalten und
out ADCSR,TMP1 ; Interrupt für AD freigeben.
ldi TMP1,0x00 ; Schleifendurchläufe festlegen
mov SCount,TMP1
sei ; Interrupts freigeben
Start:
; **********************************************
; * Hauptprogramm für Temperaturauswertung *
; **********************************************
Schleife:
sbrc LEDStat,7
rjmp Schleife
LED1:
ldi EEprom,0x00 ; Vergleichswertadresse vorgeben
rcall LeseEEprom ; und Wert aus EEprom holen.
cp ADLow,TPLow ; 16-Bit Vergleich vornehmen.
cpc ADHigh,TPHigh ; Meßwert > Vorgabewert?
brcc LED2 ; Ja, dann zur nächsten LED
ldi LEDStat,0b00010110 ; sonst LED1 einschalten.
rcall LEDAkt
rjmp LEDEnde
LED2:
ldi EEprom,0x01 ; Vergleichswertadresse vorgeben
rcall LeseEEprom ; und Wert aus EEprom holen.
cp ADLow,TPLow ; 16-Bit Vergleich vornehmen.
cpc ADHigh,TPHigh ; Meßwert > Vorgabewert?
brcc LED3 ; Ja, dann zur nächsten LED
ldi LEDStat,0b00010101 ; sonst LED2 einschalten.
rcall LEDAkt
rjmp LEDEnde
LED3:
ldi EEprom,0x02 ; Vergleichswertadresse vorgeben
rcall LeseEEprom ; und Wert aus EEprom holen.
cp ADLow,TPLow ; 16-Bit Vergleich vornehmen.
cpc ADHigh,TPHigh ; Meßwert > Vergleichswert?
brcc LED4 ; Ja, dann zur nächsten LED
ldi LEDStat,0b00010011 ; sonst LED3 einschalten.
rcall LEDAkt
rjmp LEDEnde
LED4:
ldi EEprom,0x03 ; Vergleichswertadresse vorgeben
rcall LeseEEprom ; und Wert aus EEprom holen.
cp ADLow,TPLow ; 16-Bit Vergleich vornehmen.
cpc ADHigh,TPHigh ; Meßwert > Vergleichswert
;brcc LED4 ; Ja, dann LED4 eingeschaltet lassen
;sbr LEDStat,0b00010111 ; sonst alle LED's ausschalten
;out PORTB,LEDStat ; und LED4
;cbr LEDStat,0b00010000 ; einschalten
;out PORTB,LEDStat
ldi LEDStat,0b00000111
rcall LEDAkt
LEDEnde:
sbr LEDStat,0b10000000
rjmp start ; Hauptprogrammende
; >>>>>>>>>> INTERRUPTPROGRAMME <<<<<<<<<<
; ****************************************
; * Interrupt LED An/Aus Timer0 *
; ****************************************
Led:
out TCNT0,Prescaler ; Timer mit Startwert laden
sbrs LEDStat,6 ; Startbit LED löschen gesetzt?
rjmp Tim0
cbr LEDStat,6
andi LEDStat,0b10111111
ori LEDStat,0b00010111
out PORTB,LEDStat
Tim0:
sbi ADCSR,ADSC ; AD-Wandlung starten.
reti ; Rücksprung zum Hauptprogramm
; ****************************************
; * Interrupt AD-Wandler *
; ****************************************
ADFertig:
cbr LEDStat,0b10000000 ; Kennung (alle Led an) löschen
in ADHigh,ADCH ; High-Byte AD speichern
in ADLow,ADCL ; Low-Byte AD speichern
reti
; >>>>>>>>>> UNTERPROGRAMME <<<<<<<<<<
; ****************************************
; * EEprom Werte Lesen *
; ****************************************
LeseEEprom:
lsl EEprom ; Adresse *2 für 2-Byte Sprung
out EEAR,EEprom ; Adresse in EEprom schreiben.
ldi TMP1,0x01 ; Dazu Lesefreigabe ins
out EECR,TMP1 ; EEprom-Steuerregister schreiben.
in TPHigh,EEDR ; EEprom-Daten in High-Byte.
inc EEprom ; Low-Byte des Vergleichswert
out EEAR,EEprom ; aus dem EEprom holen.
out EECR,TMP1 ; Lesefreigabe schreiben und
in TPLow,EEDR ; EEprom-Daten holen.
ret
; *****************************************
; * LED's aktualisieren *
; *****************************************
LEDAkt:
mov LEDWert,LEDStat ; Wert übergeben und
out PORTB,LEDStat ; auf Port ausgeben.
ret