PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Problem mit Mittelwertberechnung (Atmega8)



agent07
25.06.2007, 15:50
Hallo
Ich habe ein Programm für eine Temperatursteuerung (vier Regelkreise) geschrieben. Da das signal am ADC-Eingang wohl etwas unsauber ist hab ich versucht für jeden Kanal den Mittelwert aus mehreren Messungen zu berechnen. Bei einem Eingang funktioniert das auch aber bei dem zweiten kommt ein viel kleinerer Wert heraus. Leider hab ich noch nicht sehr viel Erfahrung mit Assembler. Im Anhang ist ein teil des codes. Vielleicht findet ja jemand etwas was ich übrsehen habe. Wenn jemand noch eine bessere Möglichkeit kennt um den Mittelwert zu berechnen wäre ich für jede Hilfe Dankbar!

Gruß, agent

wkrug
25.06.2007, 22:39
So ganz versteh ich nicht was Du da machst.
Zuerst schimpfst Du über die schlechte Präzision der 10Bit A/D Wandler und dann machst Du einen 8Bit Wert daraus?
Das geht auch eleganter, es gibt in den Konfigurationsregistern das ADLAR Bit, das einen Linksbündigen 8Bit Wert ermöglicht.
Ich hab auch den Eindruck, das deine /16 Routine irgendwie nicht stimmt.

clc ;Carry Flag loschen
ror r19 ;High Byte /2 Teilen Übertrag ins Carry
ror r18 ;Carry links einschieben und durch 2 Teilen
clc ;Carry für die nächste /2 Teilung löschen
ror r19
ror r18
clc
......

müsste richtiger sein.
Beim LSR wird das Carry Flag, soweit ich weiß, nicht übertragen.
Was sagt der Simulator dazu ?
Ich würd aber trotzdem die 10Bit Auflösung des A/D Wandlers verwenden.
Da ja "nur" 16 Werte mit max 1024 addiert werden, kann ein Word (max. 65536) nicht überlaufen.

agent07
25.06.2007, 23:06
Hi
ich meinte eigentlich nicht das der 10Bit AD zu ungenau ist, sondern dass die Spannung am Eingang "zuckt". Aber Wie gesagt ich bin neu auf dem Gebiet.
Was mich halt wundert ist das es ja auf einem "Kanal" funktioniert.
Ich werd das mal ausprobieren. Wenn noch jemand was hat...
Aber schon mal danke!

agent07
26.06.2007, 19:06
Hab es jetzt mal mit deinem Vorschlag versucht aber irgendwie ist das Ergebnis viel zu groß. Ich lasse mir die Werte am PC graphisch darstellen und da läuft der "Mittelwert" acht mal über.
Vier mal durch zwei teilen müsste doch stimmen.
Und noch eine Frage. Welcher Simulator? Ich benutze im moment das myAVR Workpad. Das war ein Einstiegerset mit Experimentierplatine.

Gruß, agent

Lektor
27.06.2007, 17:30
Gemeint wurde wohl der Simulator des AVR Studios von Atmel.

wkrug
29.06.2007, 18:26
Gemeint wurde wohl der Simulator des AVR Studios von Atmel
Richtig, der war gemeint.
Arbeitest Du in deinem Programm mit signed int Variablen (Temperatur)?
Das könnte auch ein Grund sein warum's nicht geht.

agent07
30.06.2007, 12:55
Also die Messwerte speicher ich einfach in ein Register im Sram und die für die Sollwerte habe ich r23,r24,r25 verwendet
.equ lotemp, 0x17
.equ midtemp, 0x18
.equ hitemp,0x19

Sonst habe ich nichts deklariert. So sieht es zur Zeit aus: (Anhang)
Mittelwertbildung ist im unteren teil, aber ich hab es erst mal nur mit den ersten zwei ADC-Kanälen versucht.

wkrug
01.07.2007, 22:40
Da Du in deinem Quellcode eine Zeilennummerierung drin hast, kann ich sie leider nicht ins AVR Studio Importieren zum austesten.

agent07
02.07.2007, 16:25
Hier nochmal ohne Zeilennummerierung.
Vielen Dank für die Bemühungen.

wkrug
02.07.2007, 20:39
Ich hab deinen Quellcode mal auf AVR Studio 4 umgedröselt.
Ich hab die Datenerfassung deines ersten A/D Kanals (16 Wandlungen + Teilung durch 16 + ummodeln auf 8Bit) nachverfolgt.
Das scheint zu stimmen.
Ein Fehler war noch bei deinem Schleifenzähler r20, da hast Du CP anstatt CPI verwendet.
War das vieleicht der Fehler ?
Ausserdem sendest Du deine Werte in Binärformat, hast Du am Rechner ein Terminalprogramm, das damit umgehen kann ? Ansonsten wird einfach irgendein Zeichen angezeigt, oder gar nichts.

Anbei noch der geänderte Code:


;+----------------------------------------------------------------------
;| Title : myAVR Grundgerüst für ATmega8
;+----------------------------------------------------------------------
;| Funktion : ...
;| Schaltung:
;eingänge: gehäuse temp portC5
; verdampfer temp 1 portC1
; verdampfer temp 2 portC2
; verdampfer temp 3 portC3
; verdampfer temp 4 portC4
; pumpsignal portC0
; leistungswahl 1 portB4
; leistungswahl 2 portB5
; fluidmangel portB3
;Ausgänge: pumpen1-2 portB1
; pumpen3-4 portB2
; lüfter portB0
; pumpen bereit1-2 portD2
; pumpen bereit3-4 portD3
; heizung 1 portD4
; heizung 2 portD5
; heizung 3 portD6
; heizung 4 portD7
;
;blinkreg: bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit
; "blinkbit" - - - - - - -
;
;heizreg: bit7 bit6 bit5 bit4 bit3 bit2
; - - - heizen m.4 heizen m.3 heizen m.2
;
;pumpreg: bit7 bit6 bit5 bit4 bit
; pumpen möglich 4 1.pumpen möglich 4 p.m.3 1.p.m.3 p.m
;+----------------------------------------------------------------------
;| Prozessor : ATmega8
;| Takt : 3,6864 MHz
;| Sprache : Assembler
;| Datum : 30.06.2007
;| Version : 1.5
;| Autor : Ulrich Betz
;+----------------------------------------------------------------------
;.include "AVR.H"
.include "m8def.inc"
.def blinkreg = r20 ;r20 als variable (register für bli
.def heizreg = r21 ;r21 als variable (register für hei
.def pumpreg = r22 ;r22 als variable (register für pum
.def lotemp = r23 ;r23 als variable (untere temperatu
.def midtemp = r24 ;r24 als variable (mitlere temperat
.def hitemp = r25 ;r25 als variable (obere temperatur
;------------------------------------------------------------------------
;Reset and Interrupt vector ;VNr. Beschreibung
rjmp main ;1 POWER ON RESET
reti ;2 Int0-Interrupt
reti ;3 Int1-Interrupt
reti ;4 TC2 Compare Match
reti ;5 TC2 Overflow
reti ;6 TC1 Capture
reti ;7 TC1 Compare Match A
reti ;8 TC1 Compare Match B
reti ;9 TC1 Overflow
rjmp ontimer ;10 TC0 Overflow
reti ;11 SPI, STC Serial Transfer Compl
reti ;12 UART Rx Complete
reti ;13 UART Data Register Empty
reti ;14 UART Tx Complete
reti ;15 ADC Conversion Complete
reti ;16 EEPROM Ready
reti ;17 Analog Comparator
reti ;18 TWI (I²C) Serial Interface
reti ;19 Store Program Memory Ready
;------------------------------------------------------------------------
;Start, Power ON, Reset
main: ;initialisiere stack
ldi r16,low(RAMEND)
out SPL,r16
ldi r16,high(RAMEND)
out SPH,r16
;initialsiere I/O Register
ldi r16, 0b00000111 ;portB5,B4,B3 als eingang portB2,B
out DDRB, r16
ldi r16, 0b00111000 ;pull up für portB5,B4,B3, ausgäng
out PORTB, r16
ldi r16, 0b11111100 ;portD7,D6,D5,D4,D3,D2 als ausgang
out DDRD, r16
;initialisierung timer0
ldi r16, 0b00000101 ;maskiere timer0
out TCCR0, r16
ldi r16, 0b00000001 ;konfiguriere
out TIMSK, r16 ;interrupt auslösen
;initialisierung ADC
ldi r16, 0b00000001 ;ADC channel 1
out ADMUX, r16 ;portC1 ADC channel 1
ldi r16, 0b10000101 ;ADC ein und 115KHz taktrate
out ADCSRA, r16 ;single step
;initialisierung UART
sbi UCSRB, 3 ;TX aktivieren
ldi r16, 23
out UBRRL, r16 ;baudrate 9600 einstellen
;Temperatur Vergleichswerte (Schaltpunkte)
ldi lotemp, 140 ;unterer schaltpunkt
ldi midtemp, 200 ;mitlerer schaltpunkt
ldi hitemp, 250 ;oberer schaltpunkt
ldi pumpreg, 0
ldi heizreg, 0
ldi r18, 0
ldi r19, 0
sei
;------------------------------------------------------------------------
mainloop: rcall luefter
sbis PINB, 4 ;skip wenn LWahl-1 nicht gewählt B4
rjmp tempabfr12
cbi PORTD, 4 ;heizen 1 off
cbi PORTD, 5 ;heizen 2 off
cbi PORTB, 1 ;pumpen 1-2 off
cbi PORTD, 2 ;pumpen 1-2 led off
rjmp LWahl2
tempabfr12: rcall tempabfrage12 ;unterprogrammaufruf
sbis PINB, 3 ;skip wenn kein fluidmangel B3=logi
rjmp pump12off
sbrs pumpreg, 0 ;skip wenn 1pumpen 1 möglich
rjmp pump12off
sbrs pumpreg, 1 ;skip wenn pumpen 1 möglich
rjmp pump12off
sbrs pumpreg, 2 ;skip wenn 1pumpen 2 möglich
rjmp pump12off
sbrs pumpreg, 3 ;skip wenn pumpen 2 möglich
rjmp pump12off
rcall pump12
rjmp LWahl2
pump12off: cbi PORTD, 2 ;portD2 logisch 0 , "1-2 bereit le
cbi PORTB, 1 ;pumpen 1-2 off
LWahl2: sbis PINB, 5 ;skip wenn LWahl-2 nicht gewählt B5
rjmp tempabfr34
cbi PORTD, 6 ;heizen 3 off
cbi PORTD, 7 ;heizen 4 off
cbi PORTB, 2 ;pumpen 3-4 off
cbi PORTD, 3 ;pumpen 3-4 led off
rjmp mainloop
tempabfr34: rcall tempabfrage34 ;unterprogrammaufruf
sbis PINB, 3 ;skip wenn kein fluidmangel B3=logi
rjmp pump34off
sbrs pumpreg, 4 ;skip wenn 1pumpen 3 möglich
rjmp pump34off
sbrs pumpreg, 5 ;skip wenn pumpen 3 möglich
rjmp pump34off
sbrs pumpreg, 6 ;skip wenn 1pumpen 4 möglich
rjmp pump34off
sbrs pumpreg, 7 ;skip wenn pumpen 4 möglich
rjmp pump34off
rcall pump34
rjmp mainloop
pump34off: cbi PORTD, 3 ;portD3 logisch 0 , "3-4 lereit led
cbi PORTB, 2 ;pumpen 3-4 off
rjmp mainloop
;------------------------------------------------------------------------
tempabfrage12:
push r16
push r17
lds r16, 0x61 ;Twert1 aus sram laden
lds r17, 0x62 ;Twert2 aus sram laden
cp r16, midtemp ;vergleiche Twert1 mit midtemp
brsh firstpump1 ;spring zu firstpump1 wenn Twert1 >
sbr heizreg, 0b00000010 ;heizen möglich 1 setzen
rjmp locompare1
firstpump1: sbr pumpreg, 0b00000001 ;1.pumpen möglich 1 setzen
locompare1: cp r16, lotemp ;vergleiche Twert1 mit lotemp
brsh pump1set ;spring zu pump1set wenn Twert1 >=l
cbr pumpreg, 0b00000010 ;pumpen möglich 1 löschen
rjmp hicompare1
pump1set: sbr pumpreg, 0b00000010 ;pumpen möglich 1 setzen
hicompare1: cp r16, hitemp ;vergleiche Twert1 mit hitemp
brlo heizenon1 ;spring zu heizenon1 wenn Twert1 <
cbr heizreg, 0b00000010 ;heizen möglich 1 löschen
cbi PORTD, 4 ;heizen 1 off
heizenon1: sbrc heizreg, 1 ;skip wenn heizen möglich 1 nicht g
sbi PORTD, 4 ;heizen 1 on
cp r17, midtemp ;vergleiche Twert2 mit midtemp
brsh firstpump2 ;spring zu firstpump2 wenn Twert2 >
sbr heizreg, 0b00000100 ;heizen möglich 2 setzen
rjmp locompare2
firstpump2: sbr pumpreg, 0b00000100 ;1.pumpen möglich 2 setzen
locompare2: cp r17, lotemp ;vergleiche Twert2 mit lotemp
brsh pump2set ;spring zu pump2set wenn Twert2 >=l
cbr pumpreg, 0b00001000 ;pumpen möglich 2 löschen
rjmp hicompare2
pump2set: sbr pumpreg, 0b00001000 ;pumpen möglich 2 setzen
hicompare2: cp r17, hitemp ;vergleiche Twert2 mit hitemp
brlo heizenon2 ;spring zu heizenon2 wenn Twert2 <
cbr heizreg, 0b00000100 ;heizen möglich 2 löschen
cbi PORTD, 5 ;heizen 2 off
heizenon2: sbrc heizreg, 2 ;skip wenn heizen möglich 2 nicht g
sbi PORTD, 5 ;heizen 2 on
pop r16
pop r17
ret
;-------------------------------------------------------------------------
tempabfrage34:
push r16
push r17
lds r16, 0x63 ;Twert3 aus sram laden
lds r17, 0x64 ;Twert4 aus sram laden
cp r16, midtemp ;vergleiche Twert3 mit midtemp
brsh firstpump3 ;spring zu firstpump3 wenn Twert3 >
sbr heizreg, 0b00001000 ;heizen möglich 3 setzen
rjmp locompare3
firstpump3: sbr pumpreg, 0b00010000 ;1.pumpen möglich 3 setzen
locompare3: cp r16, lotemp ;vergleiche Twert3 mit lotemp
brsh pump3set ;spring zu pump3set wenn Twert3 >=l
cbr pumpreg, 0b00100000 ;pumpen möglich 3 löschen
rjmp hicompare3
pump3set: sbr pumpreg, 0b00100000 ;pumpen möglich 3 setzen
hicompare3: cp r16, hitemp ;vergleiche Twert3 mit hitemp
brlo heizenon3 ;spring zu heizenon3 wenn Twert3 <
cbr heizreg, 0b00001000 ;heizen möglich 3 löschen
cbi PORTD, 6 ;heizen 3 off
heizenon3: sbrc heizreg, 3 ;skip wenn heizen möglich 3 nicht g
sbi PORTD, 6 ;heizen 3 on
cp r17, midtemp ;vergleiche Twert4 mit midtemp
brsh firstpump4 ;spring zu firstpump4 wenn Twert4 >
sbr heizreg, 0b00010000 ;heizen möglich 4 setzen
rjmp locompare4
firstpump4: sbr pumpreg, 0b01000000 ;1.pumpen möglich 4 setzen
locompare4: cp r17, lotemp ;vergleiche Twert4 mit lotemp
brsh pump4set ;spring zu pump4set wenn Twert4 >=l
cbr pumpreg, 0b10000000 ;pumpen möglich 4 löschen
rjmp hicompare4
pump4set: sbr pumpreg, 0b10000000 ;pumpen möglich 4 setzen
hicompare4: cp r17, hitemp ;vergleiche Twert4 mit hitemp
brlo heizenon4 ;spring zu heizenon4 wenn Twert4 <
cbr heizreg, 0b00010000 ;heizen möglich 4 löschen
cbi PORTD, 7 ;heizen 4 off
heizenon4: sbrc heizreg, 4 ;skip wenn heizen möglich 4 nicht g
sbi PORTD, 7 ;heizen 4 on
pop r16
pop r17
ret
;--------------------------------------------------------------------------
luefter: push r16
lds r16, 0x65 ;Twert5 aus sram laden
cpi r16, 120 ;einschaltpunkt lüfter
brsh luefteron ;springe zu lüfteron wenn Twert5 >=
cpi r16, 40
brlo luefteroff
pop r16
ret
luefteron: sbi PORTB, 0 ;lüfter on
pop r16
ret
luefteroff: cbi PORTB, 0 ;lüfter off
pop r16
ret
;--------------------------------------------------------------------------
pump12: push r16
lds r16, 0x60 ;läd pumpsignal-wert aus sram in r1
cpi r16, 130 ;vergleich
brlo pumpe12off
sbi PORTB, 1 ;pumpen 1-2 on
;heizen möglich 1 und 2 setzen (gab
sbrc blinkreg, 7
rjmp led12an
cbi PORTD, 2
rjmp return12
led12an: sbi PORTD, 2
rjmp return12
pumpe12off: cbi PORTB, 1 ;pumpen 1-2 off
sbi PORTD, 2 ;portD2 logisch 1 , "1-2 bereit le
return12: pop r16
ret
;--------------------------------------------------------------------------
pump34: push r16
lds r16, 0x60 ;läd pumpsignal-wert aus sram in r1
cpi r16, 130 ;vergleich
brlo pumpe34off
sbi PORTB, 2 ;pumpen 3-4 on
sbrc blinkreg, 7
rjmp led34an
sbi PORTD, 3
rjmp return34
led34an: cbi PORTD, 3
rjmp return34
pumpe34off: cbi PORTB, 2 ;pumpen 3-4 off
sbi PORTD, 3 ;portD2 logisch 1 , "3-4 bereit le
return34: pop r16
ret
;--------------------------------------------------------------------------
;
;versuchstext
ontimer: ;blinkbit an,aus
sbrc blinkreg, 7 ;skip wenn bit in blinkreg gelöscht
rjmp bitaus
sbr blinkreg, 0b10000000 ;setzt bit 7 im blinkreg
rjmp wertelesen
bitaus: cbr blinkreg, 0b10000000 ;löscht bit 7 in blinkreg
;Twert1 einlesen
wertelesen: push r16
push r20
ldi r20, 0
loop0: inc r20 ;zähler +1
ldi r16, 0b00000000 ;ADC channel 0
out ADMUX, r16 ;portC1 ADC channel 0
sbi ADCSRA, 6 ;starte nächste konvertierung
warten0: sbis ADCSRA, 4 ;skip wenn AD conversion abgeschlos
rjmp warten0
in r26, ADCL ;low-teil auslesen
in r27, ADCH ;high-teil auslesen
add r18, r26
adc r19, r27
cpi r20, 16 ;zähler =16?
brne loop0 ;wenn nicht dann geh zu loop0
;wert durch 16 teilen
clc ;carry flag löschen
ror r19 ;high byte durch zwei teilen, übert
ror r18 ;carry links einschieben und durch
clc ;carry für nächste teilung löschen
ror r19
ror r18
clc
ror r19
ror r18
clc
ror r19
ror r18
clc
;.................... ;10 bit zu 8 bit auflösung, alle bi
asr r19 ;schiebe bit 0 des high-teils ins C
ror r18 ;schiebe alle bits nach rechts, C-F
asr r19 ;schiebe nächstes bit des high teil
ror r18 ;schiebe alle bits nach rechts, C-F
sts 0x60, r18 ;r18 in sram speichern
;werte senden
putChar0: sbis UCSRA, 5 ;bit 5 = UDR empty
rjmp putChar0 ;warten bis UDR bereit
out UDR, r18 ;senden
;werte senden ende
ldi r18, 0 ;werteregister lo-teil zurücksetzen
ldi r19, 0 ;werteregister hi-teil zurücksetzen
ldi r20, 0 ;zähler zurücksetzen
loop1: inc r20 ;zähler +1
ldi r16, 0b00000001 ;ADC channel 1
out ADMUX, r16 ;portC1 ADC channel 1
sbi ADCSRA, 6 ;starte nächste konvertierung
warten1: sbis ADCSRA, 4 ;skip wenn AD conversion abgeschlos
rjmp warten1
in r26, ADCL ;low-teil auslesen
in r27, ADCH ;high-teil auslesen
add r18, r26
adc r19, r27
cpi r20, 16 ;zähler =16?
brne loop1 ;wenn nicht dann geh zu loop0
;wert durch 16 teilen
clc ;carry flag löschen
ror r19 ;high byte durch zwei teilen, übert
ror r18 ;carry links einschieben und durch
clc ;carry für nächste teilung löschen
ror r19
ror r18
clc
ror r19
ror r18
clc
ror r19
ror r18
clc
;.................... ;10 bit zu 8 bit auflösung, alle bi
asr r19 ;schiebe bit 0 des high-teils ins C
ror r18 ;schiebe alle bits nach rechts, C-F
asr r19 ;schiebe nächstes bit des high teil
ror r18 ;schiebe alle bits nach rechts, C-F
sts 0x61, r18 ;r18 in sram speichern
;werte senden
putChar1: sbis UCSRA, 5 ;bit 5 = UDR empty
rjmp putChar1 ;warten bis UDR bereit
out UDR, r18 ;senden
;werte senden ende
ldi r18, 0 ;werteregister lo-teil zurücksetzen
ldi r19, 0 ;werteregister hi-teil zurücksetzen
ldi r20, 0 ;zähler zurücksetzen
ldi r16, 0b00000010 ;ADC channel 2
out ADMUX, r16 ;portC2 ADC channel 2
sbi ADCSRA, 6 ;starte nächste konvertierung
warten2: sbis ADCSRA, 4 ;skip wenn AD conversion abgeschlos
rjmp warten2
;Twert2 einlesen
in r26, ADCL ;low-teil auslesen
in r27, ADCH ;high-teil auslesen
;.................... ;10 bit zu 8 bit auflösung, alle bi
asr r27 ;schiebe bit 0 des high-teils ins C
ror r26 ;schiebe alle bits nach rechts, C-F
asr r27 ;schiebe nächstes bit des high teil
ror r26 ;schiebe alle bits nach rechts, C-F
sts 0x62, r26 ;r26 in sram speichern
;werte senden
putChar2: sbis UCSRA, 5 ;bit 5 = UDR empty
rjmp putChar2 ;warten bis UDR bereit
out UDR, r26 ;senden
;werte senden ende
ldi r16, 0b00000011 ;ADC channel 3
out ADMUX, r16 ;portC3 ADC channel 3
sbi ADCSRA, 6 ;starte nächste konvertierung
warten3: sbis ADCSRA, 4 ;skip wenn AD conversion abgeschlos
rjmp warten3
;Twert3 einlesen
in r26, ADCL ;low-teil auslesen
in r27, ADCH ;high-teil auslesen
;.................... ;10 bit zu 8 bit auflösung, alle bi
asr r27 ;schiebe bit 0 des high-teils ins C
ror r26 ;schiebe alle bits nach rechts, C-F
asr r27 ;schiebe nächstes bit des high teil
ror r26 ;schiebe alle bits nach rechts, C-F
sts 0x63, r26 ;r26 in sram speichern
;werte senden
putChar3: sbis UCSRA, 5 ;bit 5 = UDR empty
rjmp putChar3 ;warten bis UDR bereit
out UDR, r26 ;senden
;werte senden ende
ldi r16, 0b00000100 ;ADC channel 4
out ADMUX, r16 ;portC4 ADC channel 4
sbi ADCSRA, 6 ;starte nächste konvertierung
warten4: sbis ADCSRA, 4 ;skip wenn AD conversion abgeschlos
rjmp warten4
;Twert4 einlesen
in r26, ADCL ;low-teil auslesen
in r27, ADCH ;high-teil auslesen
;.................... ;10 bit zu 8 bit auflösung, alle bi
asr r27 ;schiebe bit 0 des high-teils ins C
ror r26 ;schiebe alle bits nach rechts, C-F
asr r27 ;schiebe nächstes bit des high teil
ror r26 ;schiebe alle bits nach rechts, C-F
sts 0x64, r26 ;r26 in sram speichern
;werte senden
putChar4: sbis UCSRA, 5 ;bit 5 = UDR empty
rjmp putChar4 ;warten bis UDR bereit
out UDR, r26 ;senden
;werte senden ende
ldi r16, 0b00000101 ;ADC channel 5
out ADMUX, r16 ;portC5 ADC channel 5
sbi ADCSRA, 6 ;starte nächste konvertierung
warten5: sbis ADCSRA, 4 ;skip wenn AD conversion abgeschlos
rjmp warten5
;Twert5 einlesen
in r26, ADCL ;low-teil auslesen
in r27, ADCH ;high-teil auslesen
;.................... ;10 bit zu 8 bit auflösung, alle bi
asr r27 ;schiebe bit 0 des high-teils ins C
ror r26 ;schiebe alle bits nach rechts, C-F
asr r27 ;schiebe nächstes bit des high teil
ror r26 ;schiebe alle bits nach rechts, C-F
sts 0x65, r26 ;r26 in sram speichern
;werte senden
putChar5: sbis UCSRA, 5 ;bit 5 = UDR empty
rjmp putChar5 ;warten bis UDR bereit
out UDR, r26 ;senden
;werte senden ende
pop r16
pop r20
reti

agent07
04.07.2007, 14:57
CPI hat geholfen! blöder fehler #-o
Vielen Dank für die Hilfe!!!
Ich hab nur grad das nächste Problem. Die Werte sind jetzt einigermaßen in Ordnung aber die Hysterese macht immer noch nicht was sie soll. Auch wenn die Werte genau dazwischen liegen kommt es vor dass die Ausgänge mal aus- und mal eingeschaltet werden. Kann es sein das irgenwelche anderen Eingänge stören?
Terminalprogramm hab ich. Zeigt die Werte als Punkte in einem Diagramm von 0-255 an.

wkrug
04.07.2007, 18:43
Auch wenn die Werte genau dazwischen liegen kommt es vor dass die Ausgänge mal aus- und mal eingeschaltet werden. Kann es sein das irgenwelche anderen Eingänge stören?
Sind alle benötigten Kondensatoren an deinem Spannungsregler vorhanden ?
Hast Du den VCC Pin mit einem Kondensator entkoppelt ?
Hast Du die AVCC mit Drossel und Kondensator entkoppelt ?
Benutzt Du die interne 2,56V Referenz - hast Du den AREF Pin mit 100nF entkoppelt ?
Hast Du AGND und GND (DGND) auf der Platine eigens geroutet und die beiden Signale nur an einem Punkt (z.B. beim Spannungsregler) miteinander verbunden ?
Hast Du eine sternförmige Masseverbindung bei deinem Layout ?
Hast Du für deine Verbraucher die etwas mehr Strom ziehen eigene Leiterbahnen zum gemeinsamen Massepunkt vorgesehen ?
Hast Du andere Taktquellen NE555 oder MAX232 mit Drosseln entkoppelt ?

Das alles könnten Gründe für dein Problem sein.

agent07
05.07.2007, 17:46
Also bis auf die separate und sternförmige Masse kann ich eigentlich alles ausschließen. Ich benutze eine externe Referenzspannung 3,3V.
Um weitere Layoutfehler auszuschließen hab ich alles nochmal auf dem myAVR experimentierboard gesteckt. Hab jetzt nochmal alles unnötige aus dem Code genommen und die Hysterese etwas vereinfacht. Ändert aber nix.


;+----------------------------------------------------------------------
;| Title : myAVR Grundgerüst für ATmega8
;+----------------------------------------------------------------------
;| Funktion : ...
;| Schaltung:
;eingänge: gehäuse temp portC5
; verdampfer temp 1 portC1
; verdampfer temp 2 portC2
; verdampfer temp 3 portC3
; verdampfer temp 4 portC4
; pumpsignal portC0
; leistungswahl 1 portB4
; leistungswahl 2 portB5
; fluidmangel portB3
;Ausgänge: pumpen1-2 portB1
; pumpen3-4 portB2
; lüfter portB0
; pumpen bereit1-2 portD2
; pumpen bereit3-4 portD3
; heizung 1 portD4
; heizung 2 portD5
; heizung 3 portD6
; heizung 4 portD7
;
;blinkreg: bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0
; "blinkbit" - - - - - - -
;
;heizreg: bit7 bit6 bit5 bit4 bit3 bit2
; - - - heizen m.4 heizen m.3 heizen m.2
;
;pumpreg: bit7 bit6 bit5 bit4 bit3
; pumpen möglich 4 1.pumpen möglich 4 p.m.3 1.p.m.3 p.m.2
;+----------------------------------------------------------------------
;| Prozessor : ATmega8
;| Takt : 3,6864 MHz
;| Sprache : Assembler
;| Datum : 30.06.2007
;| Version : 1.5
;| Autor : Ulrich Betz
;+----------------------------------------------------------------------
.include "AVR.H"
.equ blinkreg, 0x14 ;r20 als variable (register für blink
.equ heizreg, 0x15 ;r21 als variable (register für heizf
.equ pumpreg, 0x16 ;r22 als variable (register für pumpf
.equ lotemp, 0x17 ;r23 als variable (untere temperatur)
.equ midtemp, 0x18 ;r24 als variable (mitlere temperatur
.equ hitemp, 0x19 ;r25 als variable (obere temperatur)
;------------------------------------------------------------------------
;Reset and Interrupt vector ;VNr. Beschreibung
rjmp main ;1 POWER ON RESET
reti ;2 Int0-Interrupt
reti ;3 Int1-Interrupt
reti ;4 TC2 Compare Match
reti ;5 TC2 Overflow
reti ;6 TC1 Capture
reti ;7 TC1 Compare Match A
reti ;8 TC1 Compare Match B
reti ;9 TC1 Overflow
rjmp ontimer ;10 TC0 Overflow
hystereseversuch.s, Seite 1 von 8
reti ;11 SPI, STC Serial Transfer Complet
reti ;12 UART Rx Complete
reti ;13 UART Data Register Empty
reti ;14 UART Tx Complete
reti ;15 ADC Conversion Complete
reti ;16 EEPROM Ready
reti ;17 Analog Comparator
reti ;18 TWI (I²C) Serial Interface
reti ;19 Store Program Memory Ready
;------------------------------------------------------------------------
;Start, Power ON, Reset
main: ;initialisiere stack
ldi r16,lo8(RAMEND)
out SPL,r16
ldi r16,hi8(RAMEND)
out SPH,r16
;initialsiere I/O Register
ldi r16, 0b00000111 ;portB5,B4,B3 als eingang portB2,B1,
out DDRB, r16
ldi r16, 0b00111000 ;pull up für portB5,B4,B3, ausgänge
out PORTB, r16
ldi r16, 0b11111100 ;portD7,D6,D5,D4,D3,D2 als ausgang
out DDRD, r16
;initialisierung timer0
ldi r16, 0b00000101 ;maskiere timer0
out TCCR0, r16
ldi r16, 0b00000001 ;konfiguriere
out TIMSK, r16 ;interrupt auslösen
;initialisierung ADC
ldi r16, 0b00000001 ;ADC channel 1
out ADMUX, r16 ;portC1 ADC channel 1
ldi r16, 0b10000101 ;ADC ein und 115KHz taktrate
out ADCSRA, r16 ;single step
;initialisierung UART
sbi UCSRB, 3 ;TX aktivieren
ldi r16, 23
out UBRRL, r16 ;baudrate 9600 einstellen
;Temperatur Vergleichswerte (Schaltpunkte)
ldi lotemp, 140 ;unterer schaltpunkt
ldi midtemp, 180 ;mitlerer schaltpunkt
ldi hitemp, 240 ;oberer schaltpunkt
ldi pumpreg, 0
ldi heizreg, 0
ldi r18, 0
ldi r19, 0
sei
;------------------------------------------------------------------------
mainloop:
sbis PINB, 4 ;skip wenn LWahl-1 nicht gewählt B4=l
rjmp tempabfr12
cbi PORTD, 4 ;heizen 1 off
cbi PORTD, 5 ;heizen 2 off
cbi PORTB, 1 ;pumpen 1-2 off
cbi PORTD, 2 ;pumpen 1-2 led off
rjmp LWahl2
tempabfr12: rcall tempabfrage12 ;unterprogrammaufruf
sbis PINB, 3 ;skip wenn kein fluidmangel B3=logisc
rjmp pump12off
sbrs pumpreg, 0 ;skip wenn 1pumpen 1 möglich
rjmp pump12off
sbrs pumpreg, 1 ;skip wenn pumpen 1 möglich
hystereseversuch.s, Seite 2 von 8
rjmp pump12off
sbrs pumpreg, 2 ;skip wenn 1pumpen 2 möglich
rjmp pump12off
sbrs pumpreg, 3 ;skip wenn pumpen 2 möglich
rjmp pump12off
;rcall pump12
rjmp LWahl2
pump12off: cbi PORTD, 2 ;portD2 logisch 0 , "1-2 bereit led"
cbi PORTB, 1 ;pumpen 1-2 off
LWahl2: sbis PINB, 5 ;skip wenn LWahl-2 nicht gewählt B5=l
rjmp tempabfr34
cbi PORTD, 6 ;heizen 3 off
cbi PORTD, 7 ;heizen 4 off
cbi PORTB, 2 ;pumpen 3-4 off
cbi PORTD, 3 ;pumpen 3-4 led off
rjmp mainloop
tempabfr34: rcall tempabfrage34 ;unterprogrammaufruf
sbis PINB, 3 ;skip wenn kein fluidmangel B3=logisc
rjmp pump34off
sbrs pumpreg, 4 ;skip wenn 1pumpen 3 möglich
rjmp pump34off
sbrs pumpreg, 5 ;skip wenn pumpen 3 möglich
rjmp pump34off
sbrs pumpreg, 6 ;skip wenn 1pumpen 4 möglich
rjmp pump34off
sbrs pumpreg, 7 ;skip wenn pumpen 4 möglich
rjmp pump34off
;rcall pump34
rjmp mainloop
pump34off: cbi PORTD, 3 ;portD3 logisch 0 , "3-4 lereit led"
cbi PORTB, 2 ;pumpen 3-4 off
rjmp mainloop
;------------------------------------------------------------------------
tempabfrage12:
push r16
push r17
lds r16, 0x61 ;Twert1 aus sram laden
lds r17, 0x62 ;Twert2 aus sram laden
cp r16, hitemp
brlo heizenon
cbi PORTD, 4
rjmp ende1
heizenon: cp r16, midtemp
brsh ende1
sbi PORTD, 4
ende1: cp r17, hitemp
brlo heizenon2
cbi PORTD, 5
rjmp ende2
heizenon2: cp r17, midtemp
brsh ende2
sbi PORTD, 5
ende2: pop r16
pop r17
ret
;-------------------------------------------------------------------------
tempabfrage34:
push r16
push r17
lds r16, 0x63 ;Twert3 aus sram laden
lds r17, 0x64 ;Twert4 aus sram laden
hystereseversuch.s, Seite 3 von 8
cp r16, hitemp
brlo heizenon3
cbi PORTD, 6
rjmp ende3
heizenon3: cp r16, midtemp
brsh ende3
sbi PORTD, 6
ende3: cp r16, hitemp
brlo heizenon4
cbi PORTD, 7
rjmp ende4
heizenon4: cp r16, midtemp
brsh ende4
sbi PORTD, 7
ende4: pop r16
pop r17
ret
;----------------------------------------------------------------------------
;
;versuchstext
ontimer:
;Twert1 einlesen
wertelesen: push r16
push r20
ldi r20, 0
loop0: inc r20 ;zähler +1
ldi r16, 0b00000000 ;ADC channel 0
out ADMUX, r16 ;portC1 ADC channel 0
sbi ADCSRA, 6 ;starte nächste konvertierung
warten0: sbis ADCSRA, 4 ;skip wenn AD conversion abgeschlosse
rjmp warten0
in r26, ADCL ;low-teil auslesen
in r27, ADCH ;high-teil auslesen
add r18, r26
adc r19, r27
cpi r20, 16 ;zähler =16?
brne loop0 ;wenn nicht dann geh zu loop0
;wert durch 16 teilen
clc ;carry flag löschen
ror r19 ;high byte durch zwei teilen, übertra
ror r18 ;carry links einschieben und durch zw
clc ;carry für nächste teilung löschen
ror r19
ror r18
clc
ror r19
ror r18
clc
ror r19
ror r18
clc
;.................... ;10 bit zu 8 bit auflösung, alle bits
asr r19 ;schiebe bit 0 des high-teils ins C-F
ror r18 ;schiebe alle bits nach rechts, C-Fla
hystereseversuch.s, Seite 4 von 8
asr r19 ;schiebe nächstes bit des high teils
ror r18 ;schiebe alle bits nach rechts, C-Fla
sts 0x60, r18 ;r18 in sram speichern
;werte senden
putChar0: sbis UCSRA, 5 ;bit 5 = UDR empty
rjmp putChar0 ;warten bis UDR bereit
out UDR, r18 ;senden
;werte senden ende
ldi r18, 0 ;werteregister lo-teil zurücksetzen
ldi r19, 0 ;werteregister hi-teil zurücksetzen
ldi r20, 0 ;zähler zurücksetzen
loop1: inc r20 ;zähler +1
ldi r16, 0b00000001 ;ADC channel 1
out ADMUX, r16 ;portC1 ADC channel 1
sbi ADCSRA, 6 ;starte nächste konvertierung
warten1: sbis ADCSRA, 4 ;skip wenn AD conversion abgeschlosse
rjmp warten1
in r26, ADCL ;low-teil auslesen
in r27, ADCH ;high-teil auslesen
add r18, r26
adc r19, r27
cpi r20, 16 ;zähler =16?
brne loop1 ;wenn nicht dann geh zu loop0
;wert durch 16 teilen
clc ;carry flag löschen
ror r19 ;high byte durch zwei teilen, übertra
ror r18 ;carry links einschieben und durch zw
clc ;carry für nächste teilung löschen
ror r19
ror r18
clc
ror r19
ror r18
clc
ror r19
ror r18
clc
;.................... ;10 bit zu 8 bit auflösung, alle bits
asr r19 ;schiebe bit 0 des high-teils ins C-F
ror r18 ;schiebe alle bits nach rechts, C-Fla
asr r19 ;schiebe nächstes bit des high teils
ror r18 ;schiebe alle bits nach rechts, C-Fla
sts 0x61, r18 ;r18 in sram speichern
;werte senden
putChar1: sbis UCSRA, 5 ;bit 5 = UDR empty
rjmp putChar1 ;warten bis UDR bereit
out UDR, r18 ;senden
;werte senden ende
ldi r18, 0 ;werteregister lo-teil zurücksetzen
ldi r19, 0 ;werteregister hi-teil zurücksetzen
ldi r20, 0 ;zähler zurücksetzen
loop2: inc r20 ;zähler +1
ldi r16, 0b00000010 ;ADC channel 2
out ADMUX, r16 ;portC2 ADC channel 2
hystereseversuch.s, Seite 5 von 8
sbi ADCSRA, 6 ;starte nächste konvertierung
warten2: sbis ADCSRA, 4 ;skip wenn AD conversion abgeschlosse
rjmp warten2
;Twert2 einlesen
in r26, ADCL ;low-teil auslesen
in r27, ADCH ;high-teil auslesen
add r18, r26
adc r19, r27
cpi r20, 16 ;zähler =16?
brne loop2 ;wenn nicht dann geh zu loop2
;wert durch 16 teilen
clc ;carry flag löschen
ror r19 ;high byte durch zwei teilen, übertra
ror r18 ;carry links einschieben und durch zw
clc ;carry für nächste teilung löschen
ror r19
ror r18
clc
ror r19
ror r18
clc
ror r19
ror r18
clc
;.................... ;10 bit zu 8 bit auflösung, alle bits
asr r19 ;schiebe bit 0 des high-teils ins C-F
ror r18 ;schiebe alle bits nach rechts, C-Fla
asr r19 ;schiebe nächstes bit des high teils
ror r18 ;schiebe alle bits nach rechts, C-Fla
sts 0x62, r18 ;r26 in sram speichern
;werte senden
putChar2: sbis UCSRA, 5 ;bit 5 = UDR empty
rjmp putChar2 ;warten bis UDR bereit
out UDR, r18 ;senden
;werte senden ende
ldi r18, 0 ;werteregister lo-teil zurücksetzen
ldi r19, 0 ;werteregister hi-teil zurücksetzen
ldi r20, 0 ;zähler zurücksetzen
loop3: inc r20 ;zähler +1
ldi r16, 0b00000011 ;ADC channel 3
out ADMUX, r16 ;portC3 ADC channel 3
sbi ADCSRA, 6 ;starte nächste konvertierung
warten3: sbis ADCSRA, 4 ;skip wenn AD conversion abgeschlosse
rjmp warten3
;Twert3 einlesen
in r26, ADCL ;low-teil auslesen
in r27, ADCH ;high-teil auslesen
add r18, r26
adc r19, r27
cpi r20, 16 ;zähler =16?
brne loop3 ;wenn nicht dann geh zu loop2
;wert durch 16 teilen
clc ;carry flag löschen
ror r19 ;high byte durch zwei teilen, übertra
ror r18 ;carry links einschieben und durch zw
clc ;carry für nächste teilung löschen
ror r19
ror r18
hystereseversuch.s, Seite 6 von 8
clc
ror r19
ror r18
clc
ror r19
ror r18
clc
;.................... ;10 bit zu 8 bit auflösung, alle bits
asr r19 ;schiebe bit 0 des high-teils ins C-F
ror r18 ;schiebe alle bits nach rechts, C-Fla
asr r19 ;schiebe nächstes bit des high teils
ror r18 ;schiebe alle bits nach rechts, C-Fla
sts 0x63, r18 ;r26 in sram speichern
;werte senden
putChar3: sbis UCSRA, 5 ;bit 5 = UDR empty
rjmp putChar3 ;warten bis UDR bereit
out UDR, r18 ;senden
;werte senden ende
ldi r18, 0 ;werteregister lo-teil zurücksetzen
ldi r19, 0 ;werteregister hi-teil zurücksetzen
ldi r20, 0 ;zähler zurücksetzen
loop4: inc r20 ;zähler +1
ldi r16, 0b00000100 ;ADC channel 4
out ADMUX, r16 ;portC4 ADC channel 4
sbi ADCSRA, 6 ;starte nächste konvertierung
warten4: sbis ADCSRA, 4 ;skip wenn AD conversion abgeschlosse
rjmp warten4
;Twert4 einlesen
in r26, ADCL ;low-teil auslesen
in r27, ADCH ;high-teil auslesen
add r18, r26
adc r19, r27
cpi r20, 16 ;zähler =16?
brne loop4 ;wenn nicht dann geh zu loop2
;wert durch 16 teilen
clc ;carry flag löschen
ror r19 ;high byte durch zwei teilen, übertra
ror r18 ;carry links einschieben und durch zw
clc ;carry für nächste teilung löschen
ror r19
ror r18
clc
ror r19
ror r18
clc
ror r19
ror r18
clc
;.................... ;10 bit zu 8 bit auflösung, alle bits
asr r19 ;schiebe bit 0 des high-teils ins C-F
ror r18 ;schiebe alle bits nach rechts, C-Fla
asr r19 ;schiebe nächstes bit des high teils
ror r18 ;schiebe alle bits nach rechts, C-Fla
sts 0x64, r18 ;r26 in sram speichern
;werte senden
putChar4: sbis UCSRA, 5 ;bit 5 = UDR empty
rjmp putChar4 ;warten bis UDR bereit
out UDR, r18 ;senden
hystereseversuch.s, Seite 7 von 8
;werte senden ende
ldi r18, 0 ;werteregister lo-teil zurücksetzen
ldi r19, 0 ;werteregister hi-teil zurücksetzen
ldi r20, 0 ;zähler zurücksetzen
ldi r16, 0b00000101 ;ADC channel 5
out ADMUX, r16 ;portC5 ADC channel 5
sbi ADCSRA, 6 ;starte nächste konvertierung
warten5: sbis ADCSRA, 4 ;skip wenn AD conversion abgeschlosse
rjmp warten5
;Twert5 einlesen
in r26, ADCL ;low-teil auslesen
in r27, ADCH ;high-teil auslesen
;.................... ;10 bit zu 8 bit auflösung, alle bits
asr r27 ;schiebe bit 0 des high-teils ins C-F
ror r26 ;schiebe alle bits nach rechts, C-Fla
asr r27 ;schiebe nächstes bit des high teils
ror r26 ;schiebe alle bits nach rechts, C-Fla
sts 0x65, r26 ;r26 in sram speichern
;werte senden
putChar5: sbis UCSRA, 5 ;bit 5 = UDR empty
rjmp putChar5 ;warten bis UDR bereit
out UDR, r26 ;senden
;werte senden ende
pop r16
pop r20
reti
hystereseversuch.s, Seite 8 von 8

wkrug
05.07.2007, 19:51
Du benutzt in deiner ontimer Routine eine menge Register, ohne die Werte zu sichern.
Ist das so OK ?
In deiner ontimer Interuptroutine wird das SREG zwar verändert aber nicht gesichert.

PUSH r16
IN r16,SREG
PUSH r16
.....


POP r16
OUT SREG,r16
POP r16

Hatte schon mal ein Problem mit sowas.

agent07
06.07.2007, 19:28
Guter Tip!
Bei der gekürzten Codeversion hilft das. Bei der richtigen Version hat sich das "Fehlverhalten" etwas geändert aber ist noch da. Dann hab ich den das Unterprogramm tempabfrage12 gegen das Kürzere aus der gekürzten Codeversion getauscht und dann ging es. Dann hab ich dieses mit ca 30 NOP versehen und dann war der Fehler wieder da. Es muss also an der Zeit liegen.
Müsste das Programm nach einem Interrupt nicht eigentlich an der Stelle weitermachen wo der Interrupt kam? Oder wird das Unterprogramm einfach abgebrochen?

wkrug
06.07.2007, 19:52
Müsste das Programm nach einem Interrupt nicht eigentlich an der Stelle weitermachen wo der Interrupt kam? Oder wird das Unterprogramm einfach abgebrochen?
Solange Du nicht am Stack rummanipulierst, sollte das Programm da weitermachen, wo es unterbrochen wurde.

Wenn Du verhindern willst, das bei einer Werteübergabe ein Interrupt auftritt, kannst Du vorher mit CLI die Interruptabarbeitung stoppen und danach gleich wieder mit SEI freigeben.

Beispiel:
In einem Interrupt wird ein 4Byte Zähler bearbeitet und im RAM zwischengespeichert.
Du verarbeitetst jetzt aber diese Werte im Hauptprogramm in Registern.
Also machst Du das so:
CLI
LDS r16,adr
LDS r17,adr + 1
LDS r18,adr + 2
LDS r19,adr + 3
SEI

Wenn jetzt also während der Werteübernahme dieser Interrupt auftreten würde, wird er aufgehalten, bist alle 4 Werte in den entsprechenden Registern sind.
Diese Wartezeiten sollten natürlich so kurz wie nur irgend möglich sein, sonst kommt dein Interrupttiming in Schwierigkeiten.

agent07
08.07.2007, 22:22
Jetzt funktioniert es einwandfrei!
Nochmal Vielen Dank für die Hilfe!

Gruß, agent