Forum: Mikrocontroller und Digitale Elektronik Probleme ADC AVR AT90CAN128


von Marcus B. (baembezz)


Lesenswert?

Hallo,

Ich bin noch Anfänger in Sachen Microcontroller. Habe auch schon im 
Forum diverse Threads durchgelesen finde aber leider keinen der mein 
Problem behandelt! Es geht um eine Spannungsüberwachung die 4 Spannungen 
überwachen soll. Den ADC hab ich zum laufen gebracht liefert auch Werte. 
Diese Werte kann ich mir auch auf dem Display anzeigen lassen das ist 
alles kein Problem. Jetzt zu meinem Problem. Ich will diese Werte jetzt 
aktualisieren das habe ich über einen Taster realisiert. Beim ersten 
Drücken zeigt er mir 4 verschiedene Werte an und beim zweiten Drücken 
löscht er auch das Display. Drücke ich jetzt ein weiteres Mal zeigt er 
mir 4 gleiche Werte an und das ist das Problem! Diese 4 Werte 
entsprechen dem letzten der 4 Werte nach dem ersten drücken! Also muss 
hier irgendwo das Problem liegen.

Ich habe schon versucht die Funktion ADC_Init nach dem Tastendruck 
aufzurufen aber das hat leider auch nichts gebracht so bin ich jetzt 
ratlos und wende mich an euch ;-D
Ich benutze den AVR AT90CAN128 + AVRISP mkII + AVR Studio 4.19 und 
aktuellem WINAVR.
1
//---------------------------ADC---------------------------
2
void ADC_Init(void)
3
{
4
 
5
  uint16_t result;
6
 
7
  ADMUX |= (1<<REFS0);      // interne Referenzspannung nutzen
8
  ADCSRA |= (1<<ADPS1) | (1<<ADPS0) | (1<<ADPS2);     // Frequenzvorteiler
9
  ADCSRA = (1<<ADEN);                  // ADC aktivieren
10
 
11
  /* nach Aktivieren des ADC wird ein "Dummy-Readout" empfohlen, man liest
12
     also einen Wert und verwirft diesen, um den ADC "warmlaufen zu lassen" */
13
 
14
  ADCSRA |= (1<<ADSC);                  // eine ADC-Wandlung 
15
  while (ADCSRA & (1<<ADSC) );          // auf Abschluss der Konvertierung warten
16
17
  result = ADCW;
18
19
}
20
 
21
/* ADC Einzelmessung */
22
uint16_t ADC_Read( uint8_t channel )
23
{
24
  // Kanal waehlen, ohne andere Bits zu beeinflußen
25
  ADMUX |= (ADMUX & ~(0x1F)) | (channel & 0x1F);
26
  ADCSRA |= (1<<ADSC);            // eine Wandlung "single conversion"
27
  while (ADCSRA & (1<<ADSC) )     // auf Abschluss der Konvertierung warten
28
    ;
29
  return ADCW;                    // ADC auslesen und zurückgeben
30
}
31
 
32
/* ADC Mehrfachmessung mit Mittelwertbbildung */
33
uint16_t ADC_Read_Avg( uint8_t channel, uint16_t average )
34
{
35
  uint32_t result = 0;
36
 
37
  for (uint8_t i = 0; i < average; ++i )
38
    result += ADC_Read( channel );
39
 
40
  return (uint16_t)( result / average );
41
}
42
43
//---------------------------------------------------------------

Hier wird der Code zur Ausgabe auf dem Display beim Betätigen des 
Schalters aufgerufen.

1
    Taster4_ON_OFF ^= 1;
2
    
3
    if (Taster4_ON_OFF == 1)
4
    {
5
    
6
        //UNetz
7
    u_net =   ADC_Read_Avg(0, 100);
8
9
      if(u_net<70) 
10
      {
11
        u_net = 0;
12
      }
13
    //UBat
14
    u_bat =   ADC_Read_Avg(1, 100);
15
      if(u_bat<70)
16
       {
17
         u_bat = 0;
18
       }
19
    //UVers12
20
    u_vers12 =   ADC_Read_Avg(2, 100);
21
      if(u_vers12<70) 
22
      {
23
        u_vers12 = 0;
24
      }    
25
    //UVers5
26
    u_vers5 =   ADC_Read_Avg(3, 100);    
27
      if(u_vers5<70) 
28
      {
29
      u_vers5 = 0;
30
      }
31
  
32
  lcd_clear();
33
  _delay_ms (1000);
34
  lcd_home ();
35
  lcd_ausgabe_volt (u_net);
36
  lcd_setcursor (0,2);
37
  lcd_ausgabe_volt (u_bat);
38
  lcd_setcursor (0,3);
39
  lcd_ausgabe_volt (u_vers12);
40
  lcd_setcursor (0,4);
41
  lcd_ausgabe_volt (u_vers5);
42
    }
43
    else
44
    {
45
    lcd_clear ();
46
    }    
47
            
48
    }
49
50
void lcd_ausgabe_volt (unsigned int z)
51
{
52
  char anzahl_zeichen = 3;
53
  char max_groesse_v = 100;
54
  char y=0;
55
  char x=anzahl_zeichen;
56
57
  while(anzahl_zeichen)
58
  {
59
  y = z/max_groesse_v;
60
61
  
62
  if(y || anzahl_zeichen!=x) 
63
    lcd_data(y+0x30);
64
  else 
65
    lcd_string(" ");
66
67
  if(anzahl_zeichen==2) lcd_string(",");
68
69
  z = z-y*max_groesse_v;
70
  max_groesse_v=(max_groesse_v/10);
71
  anzahl_zeichen--;
72
73
  }
74
75
}

Ich hoffe jemand sieht wo es hackt ;-)

Danke schon mal im voraus

MfG

Marcus

von Karl H. (kbuchegg)


Lesenswert?

Entgegen den Tutorial Routinen hast du hier
1
 ADMUX |= (ADMUX & ~(0x1F)) | (channel & 0x1F);

ein |= reingemacht wo ein = hingehört.

von Karl H. (kbuchegg)


Lesenswert?

Und nochmal Gratulation
1
  ADCSRA |= (1<<ADPS1) | (1<<ADPS0) | (1<<ADPS2);     // Frequenzvorteiler
2
  ADCSRA = (1<<ADEN);                  // ADC aktivieren

mit der 2.ten Zuweisung ist damit die erste Einstellung des 
Frequenzvorteilers Geschichte geworden.

von Marcus B. (baembezz)


Lesenswert?

Hallo Karl Heinz

Dankeschön das hat den Fehler behoben. Aber warum hat es dann beim 
ersten Mal funktioniert und es hat die richtigen Werte angezeigt?


Und dann hätte ich noch eine Frage.
1
TCCR1B |=  (1<<CS10) | (1<<CS12)| (1<<WGM12);

Hier stell ich den Prescaler für einen Timer ein ist dann |= auch falsch 
und müsste nur ein = sein? Nur rein fürs Verständnis weil der Timer 
funktioniert wie gewünscht.

vielen Dank

MfG

Marcus

von Karl H. (kbuchegg)


Lesenswert?

Marcus B. schrieb:
> Hallo Karl Heinz
>
> Dankeschön das hat den Fehler behoben. Aber warum hat es dann beim
> ersten Mal funktioniert und es hat die richtigen Werte angezeigt?

Weil du beim ersten mal die Kanäle in der Reihenfolge
 0, 1, 2, 3

durchgegangen bist. Wenn du dir diese Zahlen binär ansiehst, dann kommt 
mit Ausnahme der 2 immer nur 1 Bit dazu.

   0000
   0001
   0010
   0011

d.h. anstelle der Kanals 2 hast du im ersten Durchgang den Kanal 3 
gemessen. Ich gehe mal davon aus, dass dir das nicht weiter aufgefallen 
ist.

Mit einem |= kannst du immer nur Bits setzen, aber du kriegst sie nicht 
wieder auf 0 zurück. Und da das so ist, kannst du im nächsten Durchgang 
eine Kanalnummer im Bereich 0 bis 3 angeben, das Ergebnis der Veroderung 
wird immer 3 sein.

Die Korrekte Anweisung lautet

  ADMUX |= (ADMUX & ~(0x1F)) | (channel & 0x1F);

siehst du dir den Teil rechts vom = an, dann steht da

   ADMUX & ~(0x1F)

der Teil setzt die Kanalbits gezielt auf 0. Und der Teil

                   | (channel & 0x1F)

bringt dann die neuen Kanalbits ein.

In Summe ergibt dieser Ausdruck also
 * alle Nicht-Kanal Bits bleiben unverändert
 * zuerst werden die Kanal-Bits gezielt auf 0 gesetzt
 * diese 0 wird dann mit dem Bitmuster des gewünschten Kanals
   überschrieben
 * und dieses Endergebnis ist damit das vollständige Byte, welches
   an ADMUX wieder zugewiesen wird, bei dem die Kanalbits gegen das
   Bitmuster des neu gewünschten Kanals ausgetauscht wurde.



>
1
> TCCR1B |=  (1<<CS10) | (1<<CS12)| (1<<WGM12);
2
>
>
> Hier stell ich den Prescaler für einen Timer ein ist dann |= auch falsch

Du sollst nicht raten sondern dir überlegen, warum da ein |= gemacht 
wird, was der bewirkt und was da mit den Bits passiert.

Bitmanipulation

von Marcus B. (baembezz)


Lesenswert?

Okay jetzt hab ich es verstanden.
Hab nicht dran gedacht das PORTB |= variable die Kurzschreibweise für 
PORTB = PORTB | variable ist.
Hätte mir das Kapitel mit Bitmanipulation nochmal genau anschauen 
sollen. ;-)

Vielen vielen Dank

von Volkmar D. (volkmar)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Die Korrekte Anweisung lautet
>
>   ADMUX |= (ADMUX & ~(0x1F)) | (channel & 0x1F);

Ich denke Dir ist hier ein kleiner Tippfehler untergekommen.

  ADMUX = (ADMUX & ~(0x1F)) | (channel & 0x1F);

Die Erklärung dazu war korrekt.

Volkmar

von Karl H. (kbuchegg)


Lesenswert?

Volkmar Dierkes schrieb:
> Karl Heinz Buchegger schrieb:
>> Die Korrekte Anweisung lautet
>>
>>   ADMUX |= (ADMUX & ~(0x1F)) | (channel & 0x1F);
>
> Ich denke Dir ist hier ein kleiner Tippfehler untergekommen.
>
>   ADMUX = (ADMUX & ~(0x1F)) | (channel & 0x1F);
>
> Die Erklärung dazu war korrekt.

War ein Copy&Paste Fehler. Bin in die falsche Zeile gerutscht.
Danke für die Anmerkung.

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.