Forum: Mikrocontroller und Digitale Elektronik ADC to UART Problem C/C++


von Max K. (max_blanket)


Lesenswert?

Hey Leute,

ich habe ein Problem mit dem ADC meines AtMega2560.
Ich will ein analoges Signal am Kanal 0 des ADC einlesen und den Wert 
über UART an ein PC-Terminal zurückgeben.
UART läuft ohne Probleme mit einzelnen Zeichen, Zeichenketten oder 
variablen Inhalten. Also das Problem der Übertragung muss schon irgendwo 
im ADC liegen.
Die Konfiguration habe ich nach Tutorials die hier rumfliegen gemacht 
und da "sollten" keine Fehler drin sein. Da lass ich mich aber gerne 
belehren. Ich habe schon 3 Leute drüberschauen lassen, die aber alle 
nichts gefunden haben. (Naja, waren leider alle keine guten 
Programmierer, so wie ich^^)

Ich hoffe jemand hat mal Zeit drüberzuschauen und sieht vielleicht 
meinen Fehler.


Hier mein Code
1
////////////////////////////////////////////////////////////
2
///////////////////////Vordefinitionen//////////////////////
3
////////////////////////////////////////////////////////////
4
#define F_CPU 16000000    // Systemtakt in Hz
5
6
#define BAUD 9600      // Baudrate
7
8
#include <avr/io.h>
9
#include <inttypes.h>
10
#include <util/delay.h>
11
#include <stdio.h>
12
#include <stdlib.h>
13
#include <util/setbaud.h>
14
15
///////////////////////////////////////////////////////////
16
/////Deklarieren aller Funktionen//////////////////////////
17
void usart_init();
18
int usart_send(unsigned char zeichen);
19
void usart_sput(char *string);
20
void usart_var(int x);
21
///////////////////////////////////////////////////////////
22
void ADC_Init(void);
23
uint16_t ADC_Read(uint8_t channel);
24
uint16_t ADC_Read_Avg(uint8_t channel, uint8_t average);
25
///////////////////////////////////////////////////////////
26
27
int main() {
28
  
29
  _delay_ms(2000);
30
  _delay_ms(2000);
31
  
32
  usart_init();
33
  
34
  //uint16_t adcval;
35
  uint8_t channel = 0;
36
37
  ADC_Init();
38
    
39
  char text1[5] = "test";
40
  char text2[2] = "!";
41
  
42
  uint16_t x = ADC_Read(channel);
43
  
44
  char text3[8] = {};
45
  char text4[8] = {};
46
  
47
  usart_sput(text1);
48
  usart_sput(text2);  
49
  _delay_ms(1000);
50
  
51
        while(1)
52
        {
53
      *text3 = (uint8_t)x;
54
            *text4 = (uint8_t)(x>>8);
55
                        usart_sput(text3);
56
                        usart_sput("-");
57
      usart_sput(text4);
58
                        usart_sput("_");
59
      _delay_ms(1000);
60
        }
61
    
62
  return 0;
63
}
64
65
66
//USART-Schnittstelle konfigurieren
67
void usart_init()
68
{
69
  
70
  //Baudrate einstellen in Baudraten-Register
71
  UBRR0H = UBRRH_VALUE;
72
  UBRR0L = UBRRL_VALUE;
73
  
74
  #if USE_2X
75
  // U2X-Modus erforderlich
76
  UCSR0A |= (1 << U2X0);
77
  #else
78
  // U2X-Modus nicht erforderlich
79
  UCSR0A &= ~(1 << U2X0);
80
  #endif
81
  
82
  //Enable Recceiver and Transmitter
83
  UCSR0B = (1<<TXEN0);
84
  
85
  //Einstellen des Frame-Formates auf 8data-, 1stop-bits
86
  UCSR0C = (0<<USBS0) | (1<<UCSZ00) | (1<<UCSZ01);
87
}
88
89
90
//Übergeben einzelner Zeichen des Strings
91
void usart_sput(char *string)
92
{
93
  while(*string)
94
  {
95
    usart_send(*string);
96
    string++;
97
  }  
98
}
99
100
101
//Ausgeben einzelner Zeichen
102
int usart_send(unsigned char zeichen)
103
{
104
  while (!(UCSR0A & (1<<UDRE0)))    // warten bis Senden moeglich ist
105
{}
106
  UDR0 = zeichen;
107
  
108
  return 0;
109
}
110
111
112
//ADC initialisieren
113
void ADC_Init(void) {
114
 
115
  uint16_t result;
116
 
117
  ADMUX = (1<<REFS0);      // interne Referenzspannung nutzen
118
  ADCSRA = (1<<ADPS1) | (1<<ADPS0);     // Frequenzvorteiler
119
120
 
121
  /* nach Aktivieren des ADC wird ein "Dummy-Readout" empfohlen, man liest
122
     also einen Wert und verwirft diesen, um den ADC "warmlaufen zu lassen" */
123
 
124
 
125
  ADCSRA |= (1<<ADSC);                // eine ADC-Wandlung 
126
    ADCSRA |= (1<<ADEN);                  // ADC aktivieren
127
  
128
  while (ADCSRA & (1<<ADSC) ) {}      // auf Abschluss der Konvertierung warten
129
  /* ADCW muss einmal gelesen werden, sonst wird Ergebnis der nächsten
130
     Wandlung nicht übernommen. */
131
 
132
  result = ADCL;
133
  result = (8<<ADCH);
134
}
135
136
137
//ADC Einzelmessung
138
uint16_t ADC_Read(uint8_t channel)
139
{
140
  //ADCSRA |= (1<<ADEN);  
141
  // Kanal waehlen, ohne andere Bits zu beeinflußen
142
  ADMUX = (ADMUX & ~(0x1F)) | (channel & 0x1F);
143
  ADCSRA |= (1<<ADSC);            //eine Wandlung "single conversion"
144
  while (ADCSRA & (1<<ADSC)){}    //auf Abschluss der Konvertierung warten
145
  
146
  return ADCW;                    //ADC auslesen und zurückgeben
147
}
148
149
 
150
//ADC Mehrfachmessung mit Mittelwertbbildung
151
uint16_t ADC_Read_Avg( uint8_t channel, uint8_t average )
152
{
153
  uint32_t result = 0;
154
 
155
  for (uint8_t i = 0; i < average; ++i )
156
    result += ADC_Read( channel );
157
 
158
  return (uint16_t)( result / average );
159
}


Danke für eure Zeit.

MfG
Max

von Karl H. (kbuchegg)


Lesenswert?

Max K. schrieb:

Und was 'genau' ist jetzt eigentlich dein Problem?

> belehren. Ich habe schon 3 Leute drüberschauen lassen, die aber alle
> nichts gefunden haben. (Naja, waren leider alle keine guten
> Programmierer, so wie ich^^)

das müssen aber miserable Programmierer sein, wenn sie die Funktion utoa 
nicht kennen und keiner gesehen hat, dass das hier ...

>       *text3 = (uint8_t)x;
>             *text4 = (uint8_t)(x>>8);
>                         usart_sput(text3);
>                         usart_sput("-");
>       usart_sput(text4);
>                         usart_sput("_");

... ausser Unsinn nur noch Unsinn ist.
Entweder du gibst die Bytes direkt aus, dann ist aber usart_sput die 
offenbar falsche Funktion dafür. Oder aber du willst auf dem Terminal 
den Zahlenwert in Textform sehen, dann musst du dir erst mal einen 
String generieren lassen, der den Zahlenwert in x in Textform beschreibt

         utoa( x, text3, 10 );
         usart_sput( text3 );
         usart_sput( " " );

>       _delay_ms(1000);
>         }


Ausserdem wird es eher hilfreich sein, wenn du dann innerhalb der 
Schleife den ADC immer wieder abfrägst. Sonst ändert sich der WErt von x 
so schlecht, wenn sich die externe Spannung ändert.

von Max K. (max_blanket)


Lesenswert?

Erstmal dakne für deine schnelle Antwort.

Ja, es sind alles blutige Anfänger wie ich, aber ich habe den 
Mikrocontroller vor ner Woche erhalten und hab die Aufgabe gleich 
aufgehalst bekommen.

Ich bin nach deiner Beschreibung vorgegangen und hat alles geklappt.

Die Abfrage des ADC-Wertes außerhalb der Schleife ist natürlich sehr 
doof. Ist mir das peinlich. -.-

Vielen Dank für deine Hilfe.

PS:Wo darf ich Blumen+Pralinen oder den Kasten Bier hinschicken?^^

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.