Forum: Mikrocontroller und Digitale Elektronik Seltsames Problem - Programm läuft unter bestimmten Umständen nicht richtig [ASM]


von M. M. (mrmcchicken)


Lesenswert?

Gute Abend miteinander,
seit heute Mittag schreibe ich ein kleines Programm, was den ADC 
ausließt und bei einem Bestimmten Wert Lämpchen leuchten lassen soll.
Dies habe ich in ASM für einen Atmega8 geschrieben.
Das Programm selber läuft nun ohne Probleme, Allerdings habe ich unter 
bestimmten Umständen einen recht seltsamen Fehler.

Mir genügt eine Auflösung von 8 Bit. Deshalb lese ich zwar beide Bytes 
des ADC aus (High und Low), verwende aber nur das Low Byte.
Hierbei habe ich folgenden Fehler:
Die Anweisungen (wtr0 bis wtr7) werden viel zu früh ausgeführt.
Die Anweisungen werden bei etwa einem Drittel der Spannung ausgeführt 
bei der sie es eigentlich sollten. Erhöhe ich die Spannung weiter, geht 
es wider von vorne los. Sprich von wtr0 bis wtr7. Einen Dritten 
Durchlauf gibt es dann noch, dann ist PortD komplett auf 1.

Ich habe das Problem nun wie folgt (so wie es auch im Code unten steht) 
behoben: Mit setzen des ADLAR Bits vertausche ich das High und das Low 
Byte aus. Ich lese wie davor auch beide Bytes aus, verwende nun aber das 
High Byte. So leuchten die LEDs nun bei der Spannung bei der sie es auch 
sollen. Im Grunde genommen ist nichts anders, zumindest der Wert der 
ausgelesen wird nicht. Nur das Register unterscheidet sich.

Wenn ich allerdings anstatt den Anweisungen (wtr0 bis wtr7) den Wert des
ADC direkt binär auf meine LEDs ausgebe, macht es nun keinen Unterschied 
ob ich direkt das Low Byte verwende, oder das High mit dem Low tausche 
und dann das High Byte benutze.

Welchen Hintergrund hat der Fehler nun?

1
.def temp = r16
2
.def temp2 = r17
3
.def temp3 = r18
4
.def vgl = r19
5
ldi temp3, 0xFF
6
clr temp
7
clr temp2
8
9
ldi temp, 0xFF
10
out DDRD, temp
11
12
ldi temp, (1<<REFS0) | (1<<MUX2) | (1<<ADLAR)
13
out ADMUX, temp
14
15
ldi temp, (1<<ADEN) | (1<<ADPS1) | (1<<ADPS0)
16
out ADCSRA, temp
17
18
ldi temp, 0xFF
19
out PORTD, temp
20
21
22
23
loop:
24
CLC
25
26
27
sbi ADCSRA, ADSC
28
in temp2, ADCL
29
in temp, ADCH
30
31
cpi temp, 0x80
32
brlo wtr0
33
ldi temp, 0b11111111
34
out PORTD, temp
35
rjmp loop
36
37
wtr0:
38
cpi temp, 0x70
39
brlo wtr1
40
ldi temp, 0b01111111
41
out PORTD, temp
42
rjmp loop
43
44
wtr1:
45
cpi temp, 0x60
46
brlo wtr2
47
ldi temp, 0b00111111
48
out PORTD, temp
49
rjmp loop
50
51
wtr2:
52
cpi temp, 0x50
53
brlo wtr3
54
ldi temp, 0b00011111
55
out PORTD, temp
56
rjmp loop
57
58
wtr3:
59
cpi temp, 0x40
60
brlo wtr4
61
ldi temp, 0b00001111
62
out PORTD, temp
63
rjmp loop
64
65
wtr4:
66
cpi temp, 0x30
67
brlo wtr5
68
ldi temp, 0b00000111
69
out PORTD, temp
70
rjmp loop
71
72
wtr5:
73
cpi temp, 0x20
74
brlo wtr6
75
ldi temp, 0b00000011
76
out PORTD, temp
77
rjmp loop
78
79
wtr6:
80
ldi temp, 0x10
81
brge wtr7
82
ldi temp, 0b00000001
83
out PORTD, temp
84
rjmp loop
85
86
wtr7:
87
ldi temp, 0x00
88
out PORTD, temp
89
rjmp loop

von MarcO (Gast)


Lesenswert?

K. M. schrieb:
> sbi ADCSRA, ADSC
> in temp2, ADCL
> in temp, ADCH

Sollte man nicht warten bis die Messung beendet ist und dann erst die 
Messwerte verwenden? Du liest sie sofort nach Start der Messung aus.

von Chris L. (kingkernel)


Lesenswert?

Du musst vor dem abholen der Messwerte das Bit ADSC im Register ADCSRA 
abfragen. Erst wenn das 1 ist, ist die ADC-Wandlung auch abgeschlossen.

Des Weiteren sollte man nach dem Einschalten einmal eine Wandlung 
durchführen, da bei dieser ersten Messung nur Murx rauskommt.

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

K. M. schrieb:
> Ich habe das Problem nun wie folgt (so wie es auch im Code unten steht)
> behoben: Mit setzen des ADLAR Bits vertausche ich das High und das Low
> Byte aus.
 Nein, tust du nicht.
 Du schiebst nur den Wert ganz nach links,  somit hast du in High Byte
 8 bit Wert und nur die niederwertigen 2 bits bleiben im Low Byte.

> Welchen Hintergrund hat der Fehler nun?
 Welcher Fehler ?
 Kein Fehler vorhanden, ausser dass du die entsprechenden bits in
 ADCSRA nicht abfragst.

von oldmax (Gast)


Lesenswert?

Hi
Schau mal ganz oben links unter Home steht AVR und in dieser Rubrik 
findest du AVR-Tutorials, die beschreiben, wie der AD-Wandler benutzt 
werden kann.
Gruß oldmax

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Hier noch ein kleiner Tipp, um die endlose Vergleichsorgie zu 
beschleunigen. Du hast 8 Zustände, kannst also aus dem ADC Ergebnis 
einfach durch ein wenig Swappen und Rollen einen Zeiger in eine Tabelle 
zusammenbasteln:
1
.def    temp = R16
2
; vorher ist der ADC initialisiert worden - auf linksbündiges Ergebnis
3
loop:
4
     sbi     ADCSRA,ADSC
5
 wait_adc:
6
    sbic    ADCSRA, ADSC        ; wenn der ADC fertig ist, wird dieses Bit gelöscht
7
    rjmp    wait_adc     
8
    in      temp,ADCH     ; ADCL muss man nicht lesen
9
; jetzt bastelt man sich daraus den Pointer in die Tabelle
10
    ldi     ZH,high(ledtab << 1)  ; Z wird auf den Anfang der Tabelle gesetzt
11
    ldi     ZL,low(ledtab << 1)
12
    andi    temp, 0xe0          ; maskieren der oberen 3 bit
13
    swap    temp                ; erstmal ins untere nibble
14
    clc                         ; carry low, weil wir rollen wollen
15
    ror                         ; noch einmal nach rechts
16
    adc     ZL, temp            ; pointer errechnen, carry is sowieso clear
17
    brcc    nopageborder
18
    inc     ZH
19
nopageborder:
20
    LPM     temp,Z              ; hole aus der tabelle
21
    out     PORTD, temp         ; auf die LED
22
    rjmp    loop                ; ende banane
23
ledtab:
24
    .db     0x01,0x03,0x07,0x0f,0x1f,0x3f,0x7f,0xff

Genuaso könntest du auch schon mal den ADC starten und währendessen die 
o.a. Routine durchackern lassen, während der ADC noch wandelt. Puristen 
könnten dann allerdings einwenden, das das schalten der LED mögl. den 
ADC beeinflusst.

von Maude (Gast)


Lesenswert?

Ich vermute, dass das dein Problem ist:

>Mir genügt eine Auflösung von 8 Bit. Deshalb lese ich zwar beide Bytes
>des ADC aus (High und Low), verwende aber nur das Low Byte.

Was du eigentlich brauchst sind die zwei Bit aus dem highByte und die 
höchsten 6 Bit aus dem lowByte.

Man kann einen right und einen left adjusted mode für den ADC 
einstellen. Ich weiß nicht mehr, welchen man benutzt, wenn man nur die 8 
Bit braucht.
Das steht explizit im Datenblatt beschrieben.
Ich tippe mal, dass dein lowByte logierweise ein paar Mal überläuft, 
wenn du die Eingangsspannung am ADC hochdrehst.

von oldmax (Gast)


Lesenswert?

Hi
Maude schrieb:
> Man kann einen right und einen left adjusted mode für den ADC
> einstellen. Ich weiß nicht mehr, welchen man benutzt, wenn man nur die 8
> Bit braucht.
Man nimmt bei Leftadjust das Highbyte, da die niederwertigen Bits im 
Lowbyte 6 und 7 sind,
right adjust:   00000011 11111111
left adjust:    11111111 11000000

Läßt man das Low-Byte weg, bleiben nur die höherwertigen Bits und ein 
digitalisierter Wert zwischen 0 und 255 übrig.
Zum Programmierstil hab ich absichtlich noch nichts gesagt. Klar, es 
gibt immer Ansichten, wie es besser gemacht werden kann und klar, man 
wächst mit der Zeit. Auch wird man erkennen, das es vielleicht sinn 
macht, das Einlesen und das Auswerten der Analogwerte n eigenen Routinen 
durchzuführen. Auch Einrücken von Zeilen macht gelegentlich Sinn. Und 
Kommentare. Auch wenn man glaubt, es tut nicht not, nach einem Monat ist 
oft der Faden gerissen und ohne Kommentare aufarbeiten wird dann 
zeitraubend. Wie sowas aussehen kann ist ja bereits mehrfach 
beschrieben. Dann ist Assembler auch lesbar.
Gruß oldmax

von M. M. (mrmcchicken)


Lesenswert?

Maude schrieb:
>
> Ich weiß nicht mehr, welchen man benutzt, wenn man nur die 8
> Bit braucht.
> Das steht explizit im Datenblatt beschrieben.
> Ich tippe mal, dass dein lowByte logierweise ein paar Mal überläuft,
> wenn du die Eingangsspannung am ADC hochdrehst.

Also ich habe mir das Datenblatt mal angeschaut und auf Seite 195 wird 
man darauf hingewiesen, dass es ausreicht bei 8bit Genauigkeit das High 
Byte zu lesen. Es heißt dort "ausreichend". Sollte wohl in "muss" 
geändert werden.
Danke für die Info :).

von oldmax (Gast)


Lesenswert?

Hi
Ja, es reicht, das Highbyte zu lesen, wenn du die Bits entsprechend 
gesetzt hast. Highbyte hat sonst eben nur die zwei höchstwertigen Bits, 
von daher ist deine Aussage ohne den Bezug auf die Ausrichtung falsch. 
Das Bit ADLAR muss gesetzt sein.

>The ADLAR bit in ADMUX, and the MUXn bits in ADMUX affect the way the >result is 
read from
>the registers. If ADLAR is set, the result is left adjusted. If ADLAR is >cleared 
(default), the result
>is right adjusted.
Gruß oldmax

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.