Forum: Mikrocontroller und Digitale Elektronik Problem mit dem ADC


von Eric W. (ceikolon)


Lesenswert?

Hallo,
ich habe mich heute das erste mal an den ADC gewagt und versuche über 
ein Potentiometer die Geschwindigkeit des Fadings meiner RGB LEDs 
einzustellen.

Bisher leuchten einfach immer nur alle LEDs unabhängig vom verstellen 
des Potis. Vlt weis jmd von euch Rat.
Atmega8 @8Mhz
1
#include <avr/io.h>
2
#include <util/delay.h>
3
#include <stdint.h> 
4
5
int main()
6
{
7
  // OC1A auf Ausgang
8
  DDRB = (1 << PB1 )|(1 << PB2)|(1 << PB3);
9
  DDRC=0x00 ; //ADC Eingang
10
  //
11
  // Timer 1 einstellen
12
  //
13
14
  TCCR1A = (1<<COM1A1) | (1 << COM1B1)| (1<<WGM10);
15
  TCCR1B = (1 << CS10);
16
17
18
  //
19
  // Timer 2 einstellen
20
21
22
  TCCR2 |=  (1 << WGM20) | (1 << CS20) | (1 << COM21);
23
  TCCR2 |= (1 << CS20);
24
  
25
  //Analog Digitalwandler konfigurieren, Refpot=5V
26
  
27
  ADMUX |=  (1 << REFS0) | (1 << ADLAR) ;
28
  ADCSRA|=  (1 << ADSC)| (1 << ADPS1)| (1 << ADPS2)  ; //ADPS1 und ADPS2 so legen, dass ADC Frequenz zwischen 50kHz und 200kHz liegt
29
30
  unsigned char counter1 = 255;
31
  unsigned char counter2 = 0;
32
  unsigned char counter3 = 0;
33
  OCR1A = counter1;
34
  OCR1B = counter2;
35
  OCR2 = counter3;
36
  unsigned char a = 1;  //1-->Auschalten
37
  unsigned char b = 0;  //0-->Anschalten
38
  unsigned char c = 0;
39
  
40
  
41
  while( 1 )
42
  {
43
  unsigned char timer=ADCH; //Lese ADCH aus =timer
44
  
45
    if(a==1 & b==0 & c==0)
46
    {   counter1--;
47
      counter2++;
48
    }
49
    if(a==0 & b==1 & c==0)
50
    {   counter2--;
51
      counter3++;
52
    }
53
    if(a==0 & b==0 & c==1)
54
    {   counter1++;
55
      counter3--;
56
    }
57
    
58
    
59
    if (counter1==255 )
60
    {a=1;
61
    }
62
    if (counter2==255 )
63
    {b=1;
64
    }
65
    if (counter3==255 )
66
    {c=1;
67
    }
68
    if (counter1==0 )
69
    {a=0;
70
    }
71
    if (counter2==0 )
72
    {b=0;
73
    }
74
    if (counter3==0 )
75
    {c=0;
76
    }
77
    OCR1A = counter1;
78
    OCR1B = counter2;
79
    OCR2 = counter3;
80
    
81
    for (int i = 0; i < timer; i++) // warte solange wie Timer
82
    {_delay_ms(1);
83
    }      
84
    
85
  }
86
}

Bin für jede Hilfe dankbar ;-)

von Marcus P. (Gast)


Lesenswert?

Hi,
ich verstehe zwar nicht was du da mit deinen timern machst, aber
1. woher weißt du das die ADC-Wandlung fertig ist, wenn du den Wert 
ließt.
2. Du startest den ADC nur einmal, für genau 1x Messung (und die erste 
Messung sollte sowieso verworfen werden laut Datenblatt), ich denke mal 
der "Free Running Mode" ( ADCSRA|= (1<<ADFR) ) ist das was du suchst.

Gruß
marcus

von Eric W. (ceikolon)


Lesenswert?

mit den Timern steuer ich eine Hardware PWM

Marcus P. schrieb:
> 1. woher weißt du das die ADC-Wandlung fertig ist, wenn du den Wert
> ließt.

Das verstehe ich nicht ganz. Kannst mir das genauer erklären?

ADFR habe ich nun gesetzt, muss weiterhin ADSC stehen bleiben?

von Marcus P. (marc2100)


Lesenswert?

Also der ADC arbeitet folgender maßen:

0. ADC einstellen (8bit / Frequenz...)
1. ADC wird gestartet (ADCSRA|=(1<<ADSC) )
2. ADC Messung läuft  (ADSC=1 & ADIF=0)
3. ADC Messung fertig
Wenn die Wandlung fertig ist, setzt der ADC Bit4 (ADIF) in ADCSRA, egal 
ob du Interrupts aktiviert hast oder nicht.
Falls der ADC nicht im "Free Running Mode" läuft kann man auch das 
ADSC-Bit abfragen, das ist solange 1, bis die Wandlung beendet ist, da 
der ADC im "Free Running Mode" direkt danach automatisch eine Wandlung 
startet ist das Bit in dem Fall nutzlos, da es immer 1 wäre.

Da du aber eine kontinuierlich Messung benötigst, bleibt dir nur das 
ADIF-Bit, das ist immer 1, wenn ein neues Ergebnis vorhanden ist.
Du könntest also eine Abfrage einbauen die so aussieht

unsigned char adc_wert (void)
{
  if ( ADCSRA & (1<<ADIF) ) //Wenn Bit=1 Wandlung fertig
  {
    ADCSRA|= (1<<ADIF);     //Bit löschen, mit 1 überschreiben
    return ADCH;            //ADC_wert ausgeben
  }
   return 0;                //Musst du dir selbst überlegen, was du 
zurückgeben willst, falls noch kein ergebniss vorliegt
}

Alternativ kannst du natürlich auch solange warten bis es fertig ist, 
aber dann hängt deine Timer-Geschichte auch, wäre also nicht so gut.

while ( !(ADCSRA & (1<<ADIF)) ) //vor dem auslesen einfügen

Aber achtung, auch hier musst du ADIF selbst wieder löschen (mit 1 
überschreiben! )


Gruß
Marcus

von Stefan E. (sternst)


Lesenswert?

Wenn du den ADC garnicht einschaltest, kannst du damit natürlich auch 
nichts messen (egal ob Single-Shot oder Free-Running).

von Eric W. (ceikolon)


Lesenswert?

Erstmal vielen Dank für die beiden einleuchtenden Beiträge. Jetzt habe 
ich glaub den ADC besser verstanden.
Letzendlich habe ich es so gemacht:

1
 if ( ADCSRA & (1<<ADIF) ) //Wenn Bit=1 Wandlung fertig
2
    {
3
      timer=ADCH;        //Setzer timer
4
      ADCSRA|=  (1<<ADSC);  //Starte neue Messung
5
    }

Also kein Free Running, funktioniert auch soweit ganz gut.
Aber ich habe doch noch die ein oder andre Frage offen:
Der ADC wirft nen 10 Bit Wert aus aber bisher lese ich nur einen 8 Bit 
Wert ein (ADCH). Was muss ich tun damit mein Ergebniss feiner wird?

Zweite Frage wäre der ADC seine arbeit neben dem durchgehen des 
Quelltextes tut und somit vlt ein free running besser angebracht wäre, 
indem immer nur der letzte Wert (aktuellste des Potis) in das delay 
eingetragen wird.

Dritte Frage: der ATmega8 besitzt ja 6 ADCs. Kann ich alle gleichzeitig 
laufen lassen? Weil das Problem ist das alle das gleiche Register 
haben...

Sry wenn ich noch etwas unbeholfen bin, aber ich bin nochn Anfänger ( 
wie ihr schon bemerkt habt ;-))

von Karl H. (kbuchegg)


Lesenswert?


von Stefan E. (sternst)


Lesenswert?

Eric Weiß schrieb:
> funktioniert auch soweit ganz gut.

Na ja, eher zufällig. Du musst das Interrupt-Flag auch wieder löschen.

Eric Weiß schrieb:
> Dritte Frage: der ATmega8 besitzt ja 6 ADCs.

Nein, nur einen. Dieser eine ADC kann mittels eines Multiplexers mit 
einem von 6 Eingängen verbunden werden.

von Spess53 (Gast)


Lesenswert?

Hi

>Dritte Frage: der ATmega8 besitzt ja 6 ADCs. Kann ich alle gleichzeitig
>laufen lassen? Weil das Problem ist das alle das gleiche Register
>haben...

Es gibt nur einen ADC mit gemultiplexten Eingängen.

MfG Spess

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.