Forum: Mikrocontroller und Digitale Elektronik AVR ATMega32 ADC Konfiguration


von Chris L. (hazdur)


Angehängte Dateien:

Lesenswert?

Hallo Leute,

obwohl ich schon das eine oder andere Mal mit AVRs gearbeitet und mich 
ebenfalls mit den Tutorial zum ADC beschäftigt habe, komme ich leider 
gerade nicht weiter. Im Anhang von diesem Beitrag habe ich meine 
Schlatung als Schematic angefügt, so wie ich sie auf einer 
Lochrasterplatine gelötet habe.

Es sollen LEDs (PortD am uC) per Software-PWM gedimmt werden. Die 
Helligkeit für jede Farbe soll dabei über einen Poti eingestellt werden 
können (P1 - P3 im Schematic). Nichts außergewöhnliches, wie ich denke.

Zur Hardware:
------------
Die Ansteuerung der LEDs selber funktioniert einwandfrei. Wenn ich die 
Ausgänge an PortD "fest" auf 1 setze, verhält sich die Schaltung wie 
gewollt. Mein Problem bezieht sich lediglich auf das Einlesen der 
Spannungswerte der Potis P1 - P3 an PortA. Was ich schon mal mit 
Sicherheit sagen kann, ist, dass sich der Spannungswert von jedem Pin 
des uC ändert, wenn am Poti gedreht wird. Der Spannungsbereich liegt wie 
erwartet zwischen 5V und 0V. Da nur ein ADC im ATMega32 vorhanden ist, 
müssen die drei Potis also nacheinander ausgelesen werden.

Die Spule zwischen VCC und AVCC des uCs aus dem ADC-ASM-Tutorial habe 
ich durch einen 47 Ohm Widerstand ersetzt (Hinweis dazu steht ebenfalls 
im Tutorial). Als Referenzspannung für den ADC soll die interne 
Referenz, also die Spannung an AVCC genutzt werden. Vref ist deswegen 
mit einer 100nF Kapazität gegen GND gezogen. Im Betrieb kann ich an AVCC 
ein Spannung von 4,11V und an Vref ein Spannung von 3,7V messen.

Als Taktgeber ist der interne RC-Oszillator des AVR auf 8MHz eingestellt 
worden. Für die n-MOS-Transistoren (Q1 - Q6) habe ich den IRLD024 
gewählt.

Fragen dazu:
 - Ist der Aufbau soweit in Ordnung?
 - Gibt es Stellen die verbessert werden sollten?
 - Ist es ein Wunder, dass diese Schaltung überhaupt funktioniert?


Zur Software:
------------
Im ersten Schritt wollte ich probieren nur einmal die Spannung vom Poti 
P1 an Port A, Pin 0 des uCs einzulesen. Abhängig davon soll eine LED an- 
oder ausgeschaltet werden. Anschalten wenn, der Wert des ADC > 0x7F ist, 
andernfalls LED aus.

Hier mein bisheriges Assembler-Programm (Beschreibung folgt danach):
1
  .include "m32def.inc"      ; Definitionsdatei
2
3
;Definitions
4
  .def A           = r0
5
  .def prg       = r1
6
  .def temp        = r16
7
  .def D        = r17
8
  .def counter1    = r18
9
  .def counter2    = r19
10
  .def red_light    = r20
11
  .def green_light  = r21
12
  .def blue_light    = r22
13
14
; Stackpointer initialisieren
15
  LDI temp, LOW(RAMEND)        ; LOW-Byte  der obersten RAM-Adresse
16
    OUT SPL, temp
17
  LDI temp, HIGH(RAMEND)       ; HIGH-Byte der obersten RAM-Adresse
18
  OUT SPH, temp
19
20
;Ein- & Ausgänge definieren
21
    LDI  temp,0b11110000
22
  OUT  DDRA,temp        ; Eingänge für Potis und den Schalter setzen
23
     
24
  LDI  temp,0b11111111
25
    OUT  DDRD,temp          ; Ausgänge für LEDs setzen
26
27
; Testcode:
28
29
  ; Init ADC
30
  LDI   temp, (1<<REFS0) | (1<<ADLAR) | (0<<MUX1)  | (0<<MUX0)  ; Kanal 0, interne Referenzspannung 5V, linksbündig
31
  OUT   ADMUX, temp
32
  RCALL WAIT_30ms
33
34
  LDI   temp, (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0)   ; Enable ADC, Prescaler -> 64
35
  OUT   ADCSRA, temp
36
  RCALL WAIT_30ms
37
  
38
  SBI   ADCSRA, ADSC                        ; Start conversion
39
40
WAIT_ADC:    
41
    SBIC  ADCSRA, ADSC                          ; Warten bis ADC fertig ist
42
    RJMP  WAIT_ADC
43
44
  IN    red_light  , ADCL                      ; ADC Wert auslesen (low)
45
    IN    green_light, ADCH                          ; ADC Wert auslesen (high)
46
47
48
  CPI    red_light, 0x7F
49
  BRLO  endless
50
  SBI   PORTD, 1
51
52
endless:
53
  RJMP endless
54
55
56
WAIT_30ms:
57
  PUSH temp
58
  PUSH counter1
59
  PUSH counter2
60
  CLR   temp
61
  CLR  counter1
62
  CLR  counter2
63
WAIT_30ms_loop:
64
  INC  temp
65
  CPI  temp, 0xFF
66
  BRNE WAIT_30ms_loop
67
  INC  counter1
68
  CLR  temp
69
  CPI  counter1, 0xFF
70
  BRNE WAIT_30ms_loop
71
  INC  counter2
72
  CLR  counter1
73
  CPI  counter2, 0x01
74
  BRNE WAIT_30ms_loop
75
  POP  counter2
76
  POP  counter1
77
  POP  temp
78
  RET

Beschreibung vom Testcode:
-------------------------
Zuerst wird der Stackpointer initialisiert und die Ein- und Ausgänge 
definiert.

Bei der Initialisierung vom ADC wird eingestellt, dass die interne 
Spannung als Refernz genommen und das Ergebnis einer Wandlung 
linksbündig in den ADC-Registern ADCH, ADCL abgelegt werden soll.

Dann wird ca. 30ms gewartet.

Den ADC einschalten und den Prescaller auf 64 setzen. Bei 8MHz ergibt 
das dann eine ADC-Frequenz von 125kHz.

Dann wird erneut ca. 30ms gewartet.

Durch "SBI   ADCSRA, ADSC" wird eine Konvertierung gestartet.

Warten, bis der ADC fertig ist.

Das Ergebnis vom ADC auslesen, den Vergleich durchführen und eine LED 
entsprechend anschalten, falls Bedingung nicht gültig.

Danach -> Endlossschleife.



Fragen dazu:
-----------
Ich vermute, dass in der SW irgendwo was nicht stimmt. Soweit ich weiss, 
gibt es bei ATMega32 auch keine Fuse-Bits, die den ADC ein- oder 
ausschalten.

 - Wo ist der Fehler?
 - Wie ist das mit den Wartezeiten, müssen die dahin oder nicht? (Glaube 
da mal was in der Doku zu uC gelesen zu haben.
 - Bin ich halbwegs auf den richtigen Weg?



Vielen Dank schon mal im voraus und ich freue mich über jede Hilfe! :)

von Chris L. (hazdur)


Lesenswert?

Da dieses Thema ja nicht gerade der Renner zu sein scheint, hier mal ein 
"push". Ist der Eintrag zu lang, zu unverständlich oder uninteressant?

Bin ich mit meinem Vorhaben grundsätzlich auf dem richtigen Weg?

von spess53 (Gast)


Lesenswert?

Hi

Ein paar Bemerkungen:

>  OUT   ADMUX, temp
>  RCALL WAIT_30ms

Das Warten kannst du stecken lassen. Ist unnötig.

>  IN    red_light  , ADCL
>  IN    green_light, ADCH
>  CPI    red_light, 0x7F

In ADCL sind die niederwertigsten 2 Bit deines ADC-Wertes. ADCL kann bei 
ADLAR=1 nur die Werte $00, $40, $80 und $C0 annehmen. Welchen Wert genau 
ist aber eher Zufall. Die eigentliche Information über die Stellung des 
Potis befindet sich in ADCH.

>  BRLO  endless
>  SBI   PORTD, 1
>endless:
>  RJMP endless

Damit macht dein Programm genau einen Durchlauf. Danach keine Reaktion 
mehr. Besser duspringst nach

> SBI   ADCSRA, ADSC

zurück. Dann musst du aber, bei nicht erfüllter Bedingung, die Led auch 
wieder ausschalten.

MfG Spess

von spess53 (Gast)


Lesenswert?

Hi

Der Code sollte funktionieren:
1
aaa:
2
    SBI   ADCSRA, ADSC         ; Start conversion
3
4
WAIT_ADC:    
5
    SBIC  ADCSRA, ADSC         ; Warten bis ADC fertig ist
6
    RJMP  WAIT_ADC
7
8
    IN    red_light  , ADCL    ; ADC Wert auslesen (low)
9
    IN    green_light, ADCH    ; ADC Wert auslesen (high)
10
11
12
    CPI    green_light, 0x7F
13
    BRLO  led_aus
14
    SBI   PORTD, 1
15
    rjmp aaa
16
17
led_aus:
18
    cbi PORTD, 1
19
    RJMP aaa

MfG Spess

von Chris L. (hazdur)


Lesenswert?

Hallo,
vielen Dank für die Antworten erstmal. Ich werde eure Vorschläge nachher 
mal ausprobieren. An meiner HW-Schaltung ist sonst soweit nichts 
auszusetzen?


spess53 schrieb:
> Das Warten kannst du stecken lassen. Ist unnötig.

Alles klar. :)


spess53 schrieb:
> In ADCL sind die niederwertigsten 2 Bit deines ADC-Wertes. ADCL kann bei
> ADLAR=1 nur die Werte $00, $40, $80 und $C0 annehmen. Welchen Wert genau
> ist aber eher Zufall. Die eigentliche Information über die Stellung des
> Potis befindet sich in ADCH.

Vollkommen richtig, vielen Dank für den Hinweis.


spess53 schrieb:
> ...
> Damit macht dein Programm genau einen Durchlauf. Danach keine Reaktion
> mehr.

Stimmt! In diesem Fall war dies so gewollt, auch wenn es ungünstig ist. 
Mein Verfahren war 1. Poti gegen 0V drehen -> 2. reset -> 3. schauen was 
passiert -> 4. Poti gegen 5V drehen -> 5. reset -> 6. siehe Schritt 3

Die Schleife ist dennoch praktischer. :)


Schönen Gruß

von Blackbird (Gast)


Lesenswert?

Der 100nF-C am Reset sollte max. 4,7nF sein, sonst könnte ein 
angeschlossener Programmer Schwierigkeiten beim Programmieren haben.
An VCC fehlt dagegen der 100nF-C.

Blackbird

von spess53 (Gast)


Lesenswert?

Hi

> An meiner HW-Schaltung ist sonst soweit nichts auszusetzen?

Da hatte ich nicht so drauf geachtet. Was mir auffällt:

>Im Betrieb kann ich an AVCC
>ein Spannung von 4,11V und an Vref ein Spannung von 3,7V messen.

Ist das mit dem aufgespieltem Programm gemessen? Bei initialisiertem ADC 
sollt VREF identisch mit AVCC sein. Und AVCC sollte auch nicht 
wesentlich kleiner als VCC sein.

MfG Spess

von Chris L. (hazdur)


Lesenswert?

Hallo


Blackbird schrieb:
> Der 100nF-C am Reset sollte max. 4,7nF sein, sonst könnte ein
> angeschlossener Programmer Schwierigkeiten beim Programmieren haben.
> An VCC fehlt dagegen der 100nF-C.

Alles klar, programmieren geht zwar, werde die Kapazitäten trotzdem mal 
ersetzen bzw. hinzufügen.


spess53 schrieb:
> Ist das mit dem aufgespieltem Programm gemessen?

Ja.


spess53 schrieb:
> Bei initialisiertem ADC sollt VREF identisch mit AVCC sein. Und AVCC
> sollte auch nicht wesentlich kleiner als VCC sein.

Da dem nicht so ist, muss ja über R2 im Schematic eine Spannung 
abfallen, was wiederum einem Stromfluss erfordert. Ich weiss nicht 
genau, wie hoch der Einfangswiderstand von AVCC ist, aber ich vermute 
mal sehr hoch (~1MOhm). Falls ich damit richtig liege, sollte doch da 
ansich eher kein "großer" Strom fliessen.
Warum sich jetzt genau VREF und AVCC unterscheiden kann ich mir nicht 
erklären. Die Schuld dem uC zuzuschieben, scheint mir da etwas einfach.


Schönen Gruß :)

von spess53 (Gast)


Lesenswert?

Hi

>Ich weiss nicht genau, wie hoch der Einfangswiderstand von AVCC ist, aber
>ich vermute mal sehr hoch (~1MOhm).

Da vermutest du falsch. AVCC ist ein Stromversorgungsanschluß. Damit 
wird der ADC und PortA versorgt.

MfG Spess

von Chris L. (hazdur)


Lesenswert?

Moin

spess53 schrieb:
> Da vermutest du falsch. AVCC ist ein Stromversorgungsanschluß. Damit
> wird der ADC und PortA versorgt.

Gut, dann klärt sich das schon mal damit, warum AVCC kleiner als VCC 
ist. Den genauen Wert vom Strom kann ich nachher mal messen, aber 
grundsätzlich würde ich diesen im folgenden Bereich einordnen: (5V - 
4,11V) / 47 Ohm = ~19mA.

Richtig soweit?


Gruß! :)

von Chris L. (hazdur)


Lesenswert?

Hallo Leute,

vielen Dank für eure Tipps und Hinweise, das Problem ist gelöst. Das 
ironische ist, dass es dann wirklich am uC lag. Selbst nach Änderung der 
HW und SW entsprechend den Hinweisen hierm funktionierte die Schaltung 
erst nicht. Nachdem ich den uC ausgetauscht hatte, lief alles wunderbar.

Als Fazit, das in diesem Beitrag beschriebene Problem lag am uC selber. 
Meinetwegen kann der Thread daher gelöscht werden.


Vielen Dank!

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.