ATmega88PA mehrere ADC Kanäle auslesen

Gast #4701139
Lesenswert?
• ▲
▼
Guten Tag liebe Community,

Ich möchte 4 ADC Kanäle des ATmega88PA auslesen und die digitalisierten 
Werte via uart an meinen Rechner schicken.

Harware:

Ich habe 4 Potis, an einem Labornetzteil bei der Spannung 3,3V 
angeschlossen, den Abgriff je an einen ADC Pin des Mikrocontrollers.
Zur seriellen Übertragung verwende ich eine "Silicon Labs CP210x USB to 
UART Bridge".
Referenzspannung des ADC sind ebenfalls 3,3V.

Der Code:
1
#include <avr/io.h>
2
#define F_CPU 1000000UL
3
#include <util/delay.h>
4
#include <avr/interrupt.h>
5
#include <avr/pgmspace.h>
6
#include <stdlib.h>
7
#include "uart.h"
8

9

10
#define BOOT_UART_BAUD_RATE 9600
11

12

13
uint16_t readADC(uint8_t channel) {
14
  uint8_t i;
15
  uint16_t result = 0;
16
    
17
  ADCSRA = (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1);  
18
  ADMUX = channel | (1<<REFS1) | (1<<REFS0);  
19
  
20
  ADCSRA |= (1<<ADSC);
21
  while(ADCSRA & (1<<ADSC));  
22
  
23
  for(i=0; i<3; i++) {    
24
    ADCSRA |= (1<<ADSC);    
25
    while(ADCSRA & (1<<ADSC));    
26
    result += ADCW;
27
  }
28
  
29
  result /= 3;  
30
  return result;
31
}
32

33

34
int main(void)
35
{
36
  uart_init(UART_BAUD_SELECT(BOOT_UART_BAUD_RATE,F_CPU));
37
  sei();  
38
  
39
  uint16_t adc_ch1 = 0;
40
  uint16_t adc_ch2 = 0;
41
  uint16_t adc_ch3 = 0;
42
  uint16_t adc_ch4 = 0;
43

44
  char ch1_chr[] = "";
45
  char ch2_chr[] = "";
46
  char ch3_chr[] = "";
47
  char ch4_chr[] = "";
48

49
  while(1){
50
    
51
    adc_ch1 = readADC(0);
52
    adc_ch2 = readADC(1);
53
    adc_ch3 = readADC(2);
54
    adc_ch4 = readADC(3);  
55

56
    itoa(adc_ch1, ch1_chr, 10);
57
    itoa(adc_ch2, ch2_chr, 10);
58
    itoa(adc_ch3, ch3_chr, 10);
59
    itoa(adc_ch4, ch4_chr, 10);
60

61
    uart_puts(ch1_chr);
62
    uart_puts(",");
63
    uart_puts(ch2_chr);
64
    uart_puts(",");
65
    uart_puts(ch3_chr);
66
    uart_puts(",");
67
    uart_puts(ch4_chr);
68
    uart_puts(";");
69
  }
70
}

Problem:

Im Anhang ist ein Screenshot des Outputs der im Terminal Programm zu 
sehen ist.
Alle Potis befinden sich etwa in Mittelstellung und sollten daher einen 
Wert von ~500 ausgeben.
Ich habe die Software zur Fehleranalyse einmal soweit abgespeckt, dass 
ich nur einen Kanal auslese und das Ergebnis ausgebe, dies hat tadellos 
funktioniert.

Sobald ich allerdings auf zwei Kanäle erweitere tritt der im Screenshot 
zu sehende Fehlerfall ein.

Ich hoffe auf schnelle und konstruktive Antworten.

MfG

eTchz
Angehängte Dateien:
#4701300
Lesenswert?
• ▲
▼
eTchz schrieb:
1
...
2
>   uint16_t adc_ch1 = 0;
3
>   uint16_t adc_ch2 = 0;
4
>   uint16_t adc_ch3 = 0;
5
>   uint16_t adc_ch4 = 0;
6
> 
7
>   char ch1_chr[] = "";
8
>   char ch2_chr[] = "";
9
>   char ch3_chr[] = "";
10
>   char ch4_chr[] = "";
11
...
12
>     itoa(adc_ch1, ch1_chr, 10);
13
>     itoa(adc_ch2, ch2_chr, 10);
14
>     itoa(adc_ch3, ch3_chr, 10);
15
>     itoa(adc_ch4, ch4_chr, 10);

Aua. itoa() braucht einen Buffer, in den es den String schreibt. Mit
1
char ch1_chr[] = "";

legst du aber nur einen String der Länge 0 an. In den paßt dann auch 
nichts größeres als ein String der Länge 0. Was dein itoa() Aufruf dann 
macht, ist über das Ende des Buffers hinauszuschreiben und dabei andere 
Variablen zu überschreiben. Welche das sind, hängt davon ab wie der 
Compiler die Variablen im RAM plaziert hat.

Auf einem PC hättest du im Ergebnis wahrscheinlich einen schönen 
segmentation fault (vulgo: Crash) bekommen.

Einen Buffer legt man an, indem man ein char-Array mit einer bestimmten 
Länge definiert. Ein 16-Bit uint kann bis zu 5 Dezimalstellen ergeben. 
Dazu noch das \0 ans Endekennzeichen macht mindestens 6 Zeichen 
Buffer-Länge:
1
char ch1_chr[6];

Dito für die anderen Buffer.
(Firma: matzetronics) #4701305
Lesenswert?
• ▲
▼
eTchz schrieb:
> char ch1_chr[] = "";
>   char ch2_chr[] = "";
>   char ch3_chr[] = "";
>   char ch4_chr[] = "";

Hmm, was meinst du denn, wieviel Speicher du für die Buffer reservierst?
Icj zitiere mal kurz aus der avr-libc Hilfe zu itoa:
"Convert an integer to a string.

The function itoa() converts the integer value from val into an ASCII 
representation that will be stored under s. The caller is responsible 
for providing sufficient storage in s"

Edit: Zu spät, Axel war schneller.
Gast #4701317
Lesenswert?
• ▲
▼
Hallo Liebe Poster,

Vielen Dank für die Ratschläge!
Ich konnte das Problem lösen, vielleicht nicht mit dem Höchstmaß an 
Eleganz aber mit voller Funktionalität.

Ich habe für jeden Kanal eine eigene Funktion zum Auslesen geschrieben.
Der Code ist zwar jetzt um einiges größer, aber wie gesagt, es 
funktioniert.

Ich werde mir eure Tipps trotzdem zu Gemüte führen und sie in die 
Optimierung einfließen lassen.

Nochmals vielen Dank und einen schönen Tag wünsche ich!

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