Forum: Mikrocontroller und Digitale Elektronik Zwei Analokanäle abfragen ?


von Michael H. (h_m)


Lesenswert?

Guten Morgen,

also ich habe einen Atmega88, dazu habe ich auch ein Buch in dem steht 
wie man den ADC-Konverter einstellt u.a wie man die Register für die 
Kanäle 0-5 einstellt.

allerdings ist hier nur ein Beispiel beschrieben wie man mit einem Kanal 
einen Wert einliest. Eigentlich genauso wie im AVR-Tutorial hier im 
Forum.

ich möchte aber gerne zwei Kanäle nutzen nämlich Kanal 4 und 5. Wie man 
das nutzt/konfiguriert finde ich im netz nichts, entweder suche ich 
falsch oder es geht nicht.

Um ADC 4 und 5 zu nutzen muss ich das im AMUX Register frei schalten
1
   ADMUX |= (1<<MUX2);                // ADC-Kanal 4 einstellen
2
    ADMUX |= (1<<MUX2)|(1<<MUX0);       // ADC-Kanal 5 einstellen

ich hatte jetzt keine andere Idee, so  wie unten im Code das mal zu 
versuchen, das geht natürlich nicht.

nach was muss ich da suchen um das zu realisieren, oder könnte es mir 
bitte jemand zeigen ?
1
#include <avr/io.h>
2
#include <util/delay.h>
3
4
#define FOSC 16000000                // Set clock Speed in Hz
5
#define BAUD 9600                   // Set baud rate
6
#define UBRR_Value FOSC/16/BAUD-1   // Set baud rate value in baud rate register
7
8
void USART_Init( uint16_t ubrr)
9
{
10
  UBRR0H = (uint8_t)(ubrr >> 8);        // Set baud rate in high- and low-register
11
  UBRR0L = (uint8_t)ubrr;             // Set low-register always after high-register
12
  UCSR0C = (1<<UCSZ01)|(1<<UCSZ00);   // Set frame format: 8data, 1stop bit
13
  UCSR0B = (1<<RXEN0)|(1<<TXEN0);     // Enable receiver and transmitter
14
}
15
16
void USART_Transmit(uint8_t data)
17
{
18
  while ( !( UCSR0A & (1<<UDRE0)) );    // Wait for empty transmit buffer
19
  UDR0 = data;                        // Put data into buffer, sends the data
20
}
21
22
uint8_t USART_Receive(void)
23
{
24
  while ( !(UCSR0A & (1<<RXC0)) );  // Wait for data to be received
25
  return UDR0;                        // Get and return received data from buffer
26
}
27
28
/**** Flush Receive-Buffer (entfernen evtl. vorhandener ungültiger Werte) ****/
29
void USART_Flush(void)
30
{
31
  uint8_t dummy;
32
  while (UCSR0A & (1<<RXC0))
33
  dummy = UDR0;
34
}
35
36
int main( void )
37
{
38
  uint16_t x, ergebnis,ergebnis1;
39
  uint8_t data;
40
  USART_Init(UBRR_Value);     // Init UART
41
  USART_Flush();              // Flush Receive-Buffer
42
  DDRB = 0xFF;                // alle PINs an PortB als Ausgänge
43
  
44
      //*** Init ADC ***
45
    ADCSRA |= (1<<ADEN);              // ADC aktivieren
46
    ADCSRA |= (1<<ADPS0)|(1<<ADPS1);    // Vorteiler auf 8
47
    ADMUX |= (1<<REFS0);              // Uref = 5V
48
  ADMUX |= (1<<MUX2);                // ADC-Kanal 4 einstellen
49
    ADMUX |= (1<<MUX2)|(1<<MUX0);       // ADC-Kanal 5 einstellen
50
    ADMUX |= (1<<ADLAR);              // Ausgabe linksbündig
51
    DIDR0 |= (1<<ADC5D);              // Dig. Input Kanal ADC5 deaktivieren (spart Strom)
52
     
53
    //*** Dummy Readout ***
54
    ADCSRA |= (1<<ADSC);              // Start ADC-Wandlung
55
    while (ADCSRA &(1<<ADSC));            // Auf Abschluss der Konvertierung warten
56
    x = ADC;                            // Das Ergebnis der 1.Wandlung in x speichern
57
     
58
59
  while(1)
60
  {           // Ausgabe ADC5
61
            ADCSRA |= (1<<ADSC);          // Start ADC-Wandlung
62
            while (ADCSRA &(1<<ADSC));        // Auf Abschluss der Konvertierung warten
63
            ergebnis = ADCH;                // Inhalt von ADCH in ergebnis speichern
64
           USART_Transmit(ergebnis);
65
         _delay_ms(1000);
66
         
67
         // Ausgabe ADC4
68
          ADCSRA |= (1<<ADSC);          // Start ADC-Wandlung
69
          while (ADCSRA &(1<<ADSC));        // Auf Abschluss der Konvertierung warten
70
          ergebnis1 = ADCH;                // Inhalt von ADCH in ergebnis speichern
71
          USART_Transmit(ergebnis1);
72
          _delay_ms(1000);
73
  }
74
}

: Bearbeitet durch User
von HildeK (Gast)


Lesenswert?

Michael H. schrieb:
> Um ADC 4 und 5 zu nutzen muss ich das im AMUX Register frei schalten
>     ADMUX |= (1<<MUX2);                // ADC-Kanal 4 einstellen
>     ADMUX |= (1<<MUX2)|(1<<MUX0);       // ADC-Kanal 5 einstellen
>
> ich hatte jetzt keine andere Idee, so  wie unten im Code das mal zu
> versuchen, das geht natürlich nicht.

Das geht schon, aber nicht auf ein Mal.
Du musst zunächst Kanal 4 einstellen und dann den ADC starten und das 
Ergebnis holen.
Dann musst du mit der zweiten Zeile Kanal 5 einstellen und wieder den 
ADC starten und das zweite Ergebnis ermitteln.
Also nacheinander, nicht gleichzeitig!

von HildeK (Gast)


Lesenswert?

... also so:
1
 while(1)
2
 {           // Ausgabe ADC5
3
    ADMUX |= (1<<MUX2)|(1<<MUX0); // Kanal 5
4
    ADCSRA |= (1<<ADSC);          // Start ADC-Wandlung
5
    while (ADCSRA &(1<<ADSC));        // Auf Abschluss der Konvertierung warten
6
    ergebnis = ADCH;                // Inhalt von ADCH in ergebnis speichern
7
    USART_Transmit(ergebnis);
8
    _delay_ms(1000);
9
 
10
    // Ausgabe ADC4                 
11
    ADMUX &= ~(1<<MUX0);   // Kanal 4 (nur MUX2=1)
12
    ADCSRA |= (1<<ADSC);          // Start ADC-Wandlung
13
    while (ADCSRA &(1<<ADSC));        // Auf Abschluss der Konvertierung warten
14
    ergebnis1 = ADCH;                // Inhalt von ADCH in ergebnis speichern
15
    USART_Transmit(ergebnis1);
16
   _delay_ms(1000);

Beitrag #5328761 wurde von einem Moderator gelöscht.
von Michael H. (h_m)


Lesenswert?

@Hildek

also Danke schon einmal für die Antwort, da es nicht so ganz bei 
funkioniert. Ich bekomme im H-term nur einen wert angezeit der von dem 
anderen etwas beeinflusst wird, wenn ich am Poti des anderen Kanal 
drehe. Muss ich hier noch bei den Registern vor der while schleife dann 
was ausklammern ?

aktuell sieht es jetzt so  aus .:
1
#include <avr/io.h>
2
#include <util/delay.h>
3
4
#define FOSC 16000000                // Set clock Speed in Hz
5
#define BAUD 9600                   // Set baud rate
6
#define UBRR_Value FOSC/16/BAUD-1   // Set baud rate value in baud rate register
7
8
void USART_Init( uint16_t ubrr)
9
{
10
  UBRR0H = (uint8_t)(ubrr >> 8);        // Set baud rate in high- and low-register
11
  UBRR0L = (uint8_t)ubrr;             // Set low-register always after high-register
12
  UCSR0C = (1<<UCSZ01)|(1<<UCSZ00);   // Set frame format: 8data, 1stop bit
13
  UCSR0B = (1<<RXEN0)|(1<<TXEN0);     // Enable receiver and transmitter
14
}
15
16
void USART_Transmit(uint8_t data)
17
{
18
  while ( !( UCSR0A & (1<<UDRE0)) );    // Wait for empty transmit buffer
19
  UDR0 = data;                        // Put data into buffer, sends the data
20
}
21
22
uint8_t USART_Receive(void)
23
{
24
  while ( !(UCSR0A & (1<<RXC0)) );  // Wait for data to be received
25
  return UDR0;                        // Get and return received data from buffer
26
}
27
28
/**** Flush Receive-Buffer (entfernen evtl. vorhandener ungültiger Werte) ****/
29
void USART_Flush(void)
30
{
31
  uint8_t dummy;
32
  while (UCSR0A & (1<<RXC0))
33
  dummy = UDR0;
34
}
35
36
int main( void )
37
{
38
  uint16_t x, ergebnis,ergebnis1;
39
  uint8_t data;
40
  USART_Init(UBRR_Value);     // Init UART
41
  USART_Flush();              // Flush Receive-Buffer
42
  DDRB = 0xFF;                // alle PINs an PortB als Ausgänge
43
  
44
      //*** Init ADC ***
45
    ADCSRA |= (1<<ADEN);              // ADC aktivieren
46
    ADCSRA |= (1<<ADPS0)|(1<<ADPS1);    // Vorteiler auf 8
47
    ADMUX |= (1<<REFS0);              // Uref = 5V
48
  ADMUX |= (1<<MUX2);                // ADC-Kanal 4 einstellen
49
    ADMUX |= (1<<MUX2)|(1<<MUX0);       // ADC-Kanal 5 einstellen
50
    ADMUX |= (1<<ADLAR);              // Ausgabe linksbündig
51
    DIDR0 |= (1<<ADC5D);              // Dig. Input Kanal ADC5 deaktivieren (spart Strom)
52
     
53
    //*** Dummy Readout ***
54
    ADCSRA |= (1<<ADSC);              // Start ADC-Wandlung
55
    while (ADCSRA &(1<<ADSC));            // Auf Abschluss der Konvertierung warten
56
    x = ADC;                            // Das Ergebnis der 1.Wandlung in x speichern
57
     
58
59
  while(1)
60
  {           // Ausgabe ADC5
61
            ADCSRA |= (1<<ADSC);          // Start ADC-Wandlung
62
            while (ADCSRA &(1<<ADSC));        // Auf Abschluss der Konvertierung warten
63
            ergebnis = ADCH;                // Inhalt von ADCH in ergebnis speichern
64
           USART_Transmit(ergebnis);
65
         _delay_ms(1000);
66
         
67
         // Ausgabe ADC4
68
         ADMUX &= ~(1<<MUX0);   // Kanal 4 (nur MUX2=1)
69
         ADCSRA |= (1<<ADSC);          // Start ADC-Wandlung
70
         while (ADCSRA &(1<<ADSC));        // Auf Abschluss der Konvertierung warten
71
         ergebnis1 = ADCH;                // Inhalt von ADCH in ergebnis speichern
72
         USART_Transmit(ergebnis1);
73
         _delay_ms(1000);
74
75
  }
76
}






Simplex schrieb im Beitrag #5328761:
> Analo?
> Haha, is fürn Arsch?

 Was soll jetzt das heissen, ich bin gerade am testen, und so richtig 
funktioniert es auch nicht, ich bekomme im H-term nur einen wert 
angezeit der von dem anderen etwas beeinflusst wird, wenn ich am Poti 
des anderen Kanal drehe

von MWS (Gast)


Lesenswert?

Beim erstmaligen Beschreiben von Konfigurationsregistern nicht verodern.
In der while() fehlt die Rückkonfiguration des ADMUX für den zweiten 
Kanal.

von HildeK (Gast)


Lesenswert?

Michael H. schrieb:
> da es nicht so ganz bei funkioniert.

Du hast noch immer vergessen, am Anfang der while-Schleife für Kanal 5 
den Mux wieder auf 5 zu stellen. da, wo du "// Ausgabe ADC5" kommentiert 
hast.
Die hier:
    ADMUX |= (1<<MUX2)|(1<<MUX0); // Kanal 5

Ich muss aber zugeben, dass ich nicht alle Settings verifiziert habe, 
weil die fehlende Anpassung der Multiplexers an den gewünschten Kanal 
für mich Grund genug war für das Fehlverhalten.

von Stefan F. (Gast)


Lesenswert?

>> Ich bekomme im H-term nur einen wert angezeit der von dem
> anderen etwas beeinflusst wird

> Du hast noch immer vergessen, am Anfang der while-Schleife
> für Kanal 5 den Mux wieder auf 5 zu stellen.

Falls dein problem nach der Korrektur immer noch besteht, kann es daran 
liegen, dass deine Signalquelle zu hochohmig ist (>10kΩ). Durch einen 
zusätzlichen Dummy Read kann man das häufig umgehen - falls du die Zeit 
dazu übrig hast.
1
int8_t read_adc(uint8_t channel)
2
{
3
    ADMUX = (ADMUX & 0xF0)+channel;   // Kanal wählen
4
    ADCSRA |= (1<<ADSC);              // Start ADC-Wandlung
5
    while (ADCSRA &(1<<ADSC));        // Auf Abschluss der Konvertierung warten
6
    ADCSRA |= (1<<ADSC);              // Start nochmal ADC-Wandlung
7
    while (ADCSRA &(1<<ADSC));        // Auf Abschluss der Konvertierung warten
8
    return ADCH;                      // Inhalt von ADCH lesen
9
}
10
11
while(1)
12
{
13
    USART_Transmit(read_adc(5));
14
    _delay_ms(1000);
15
16
    USART_Transmit(read_adc(4));
17
    _delay_ms(1000);
18
  }

von Michael H. (h_m)


Lesenswert?

@Hildek und Stefan US schon einmal herzlichen Dank


Jetzt kann ich es mir zumindest vorstellen wie es geht. Ich habe jetzt 
zwei Potis mit jeweil 10K dran.


Es scheint zu funtionieren :-)

das heisst ich müsste Beim initialisieren des ADC"s vor der 
While-schleife
die Registerbits für die Kanalwahl gar nicht setzen?

und jetzt genau so Habe ich ihn auf den Controller.:
1
#include <avr/io.h>
2
#include <util/delay.h>
3
4
#define FOSC 16000000                // Set clock Speed in Hz
5
#define BAUD 9600                   // Set baud rate
6
#define UBRR_Value FOSC/16/BAUD-1   // Set baud rate value in baud rate register
7
8
void USART_Init( uint16_t ubrr)
9
{
10
  UBRR0H = (uint8_t)(ubrr >> 8);        // Set baud rate in high- and low-register
11
  UBRR0L = (uint8_t)ubrr;             // Set low-register always after high-register
12
  UCSR0C = (1<<UCSZ01)|(1<<UCSZ00);   // Set frame format: 8data, 1stop bit
13
  UCSR0B = (1<<RXEN0)|(1<<TXEN0);     // Enable receiver and transmitter
14
}
15
16
void USART_Transmit(uint8_t data)
17
{
18
  while ( !( UCSR0A & (1<<UDRE0)) );    // Wait for empty transmit buffer
19
  UDR0 = data;                        // Put data into buffer, sends the data
20
}
21
22
uint8_t USART_Receive(void)
23
{
24
  while ( !(UCSR0A & (1<<RXC0)) );  // Wait for data to be received
25
  return UDR0;                        // Get and return received data from buffer
26
}
27
28
/**** Flush Receive-Buffer (entfernen evtl. vorhandener ungültiger Werte) ****/
29
void USART_Flush(void)
30
{
31
  uint8_t dummy;
32
  while (UCSR0A & (1<<RXC0))
33
  dummy = UDR0;
34
}
35
36
int8_t read_adc(uint8_t channel)
37
{
38
  ADMUX = (ADMUX & 0xF0)+channel;   // Kanal wählen
39
  ADCSRA |= (1<<ADSC);              // Start ADC-Wandlung
40
  while (ADCSRA &(1<<ADSC));        // Auf Abschluss der Konvertierung warten
41
  ADCSRA |= (1<<ADSC);              // Start nochmal ADC-Wandlung
42
  while (ADCSRA &(1<<ADSC));        // Auf Abschluss der Konvertierung warten
43
  return ADCH;                      // Inhalt von ADCH lesen
44
}
45
46
47
int main( void )
48
{
49
  uint16_t x, ergebnis,ergebnis1;
50
  uint8_t data;
51
  USART_Init(UBRR_Value);     // Init UART
52
  USART_Flush();              // Flush Receive-Buffer
53
  DDRB = 0xFF;                // alle PINs an PortB als Ausgänge
54
  
55
      //*** Init ADC ***
56
    ADCSRA |= (1<<ADEN);              // ADC aktivieren
57
    ADCSRA |= (1<<ADPS0)|(1<<ADPS1);    // Vorteiler auf 8
58
    ADMUX |= (1<<REFS0);              // Uref = 5V
59
    //ADMUX |= (1<<MUX2);                // ADC-Kanal 4 einstellen
60
    //ADMUX |= (1<<MUX2)|(1<<MUX0);       // ADC-Kanal 5 einstellen
61
    ADMUX |= (1<<ADLAR);              // Ausgabe linksbündig
62
    DIDR0 |= (1<<ADC5D);              // Dig. Input Kanal ADC5 deaktivieren (spart Strom)
63
     
64
    //*** Dummy Readout ***
65
    ADCSRA |= (1<<ADSC);              // Start ADC-Wandlung
66
    while (ADCSRA &(1<<ADSC));            // Auf Abschluss der Konvertierung warten
67
    x = ADC;                            // Das Ergebnis der 1.Wandlung in x speichern
68
     
69
70
  while(1)
71
  {          
72
   
73
   USART_Transmit(read_adc(5));
74
   _delay_ms(1000);
75
76
   USART_Transmit(read_adc(4));
77
   _delay_ms(1000);
78
79
  }
80
}

von Stefan F. (Gast)


Lesenswert?

> das heisst ich müsste Beim initialisieren des ADC"s vor der
> While-schleife
> die Registerbits für die Kanalwahl gar nicht setzen?

Richtig, doppelt gemoppelt ist nicht besser als einfach.

von HildeK (Gast)


Lesenswert?

>> das heisst ich müsste Beim initialisieren des ADC"s vor der
>> While-schleife
>> die Registerbits für die Kanalwahl gar nicht setzen?

Häufig hat so ein μC n Eingänge für Analogsignale, einen 
Kanalwahlschalter n:1 (den MUX) aber nur einen ADC.
Nutzt man nur einen Kanal, reicht die Initialisierung wie deinem ersten 
Beispiel, also einmal den Kanal anwählen und dann immer wieder die 
Wandlung anstoßen.
Willst du aber mehrere Kanäle abfragen, dann musst du zuerst auf den 
gewünschten Kanal umschalten und dann wandeln.

von Stefan F. (Gast)


Lesenswert?

Eine Korrektur:
> int8_t read_adc(uint8_t channel)

Ich glaube, der Rückgabewert sollte uint8_t sein, auch wenn man den 
Unterschied auf der seriellen Schnittstelle nicht bemerkt.

von Michael H. (h_m)


Lesenswert?

Guten Morgen,

jetzt möchte ich bei einem Attiny85 den Analogwert von ADC1-Kanal1 in 
eine Variable übergeben. Jetzt kann ich mir das aber nicht auf dem 
Terminal seriell anzeigen lassen, weil der ja keine Usart Schnittstelle 
hat.Jetzt bekomme ich das einfach nicht hin.

könnte mir hier Bitte noch einmal jemand sagen was ich hier falsch 
mache. Oder wie ich mir den Variablen Inhalt ansehen kann.
1
/*
2
 * ATTINY_85.c
3
 *
4
 * Created: 03.03.2018 15:59:47
5
 * Author : USER
6
 */ 
7
#define F_CPU 1000000UL
8
#include <avr/io.h>
9
#include <util/delay.h>
10
11
12
uint16_t t = 0; // Variable für Delay ()
13
14
15
void MyDelay(uint16_t t)
16
 {
17
  while(t > 0) 
18
  {
19
    _delay_ms(1);
20
    t--;
21
  }
22
  return;
23
}
24
25
int8_t read_adc(uint8_t channel)
26
{
27
  ADMUX = (ADMUX & 0xF0)+channel;   // Kanal wählen
28
  ADCSRA |= (1<<ADSC);              // Start ADC-Wandlung
29
  while (ADCSRA &(1<<ADSC));        // Auf Abschluss der Konvertierung warten
30
  ADCSRA |= (1<<ADSC);              // Start nochmal ADC-Wandlung
31
  while (ADCSRA &(1<<ADSC));        // Auf Abschluss der Konvertierung warten
32
  return ADCH;                      // Inhalt von ADCH lesen
33
}
34
35
int main(void)
36
{
37
    DDRB &= ~ (1<<PB2); // auf Eingang Bewegungsmelder
38
    DDRB =    (1<<PB3); // auf Ausgang Magnetventil
39
  
40
    uint16_t x;
41
  
42
   //*** Init ADC ***
43
    ADCSRA |= (1<<ADEN);                 // ADC aktivieren
44
    ADCSRA |= (1<<ADPS0)|(1<<ADPS1);     // Vorteiler auf 8
45
    ADMUX |= (1<<REFS0);                 // Uref = 5V
46
    ADMUX |= (1<<ADLAR);                 // Ausgabe linksbündig
47
   
48
     
49
    //*** Dummy Readout ***
50
    ADCSRA |= (1<<ADSC);                  // Start ADC-Wandlung
51
    while (ADCSRA &(1<<ADSC));            // Auf Abschluss der Konvertierung warten
52
    x = ADC;                              // Das Ergebnis der 1.Wandlung in x speichern
53
     
54
55
  
56
    while (1) 
57
    {
58
                  
59
     t = read_adc(1);
60
    
61
    
62
    if (PINB & (1<<PB2))
63
    {
64
      PORTB |= (1<<PB3);
65
      MyDelay(t);
66
    } 
67
    else
68
    {
69
      PORTB &= ~(1<<PB3);
70
    }
71
    }
72
}

von Stefan F. (Gast)


Lesenswert?

Schau Dir meine HelloTiny Vorlage an, da wird serielle Ausgabe selbst 
auf den Kleinsten Tinies gemacht (durch Bit-Banging). Ist ganz einfach.
http://stefanfrings.de/avr_hello_world/index.html

von Michael H. (h_m)


Lesenswert?

Danke, das ist sehr interessant, da muss ich mich mal in Ruhe umsehen.

und noch einmal zu obigen Code,da müsste doch jetzt in t 255 oder 1023 
drin stehen oder ? wenn nicht wie kann ich das ändern ?

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.