Seltsames Problem - Programm läuft unter bestimmten Umständen nicht richtig [ASM]

#3867387
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
(Firma: Vescomp) #3867410
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.
(Firma: matzetronics) #3867581
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.
Gast #3867637
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.
Gast #3867656
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
#3868640
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 :).
Gast #3869107
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

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren