Forum: Mikrocontroller und Digitale Elektronik mehrere ADC und UART


von Kluski (Gast)


Lesenswert?

hy zusammen,

Ich wollte ein kleines Programm schreiben das herere adc-Kannele nutzt, 
aber nach abfrage per UART, der Code Läuft nur "halb".
Was es soll:
per Terminal wird 1, 2 oder 3 eingetippt und dann per ATMega8 der 
ADC-Kannal gemessen. (z.b: 1 => 1 = 123)
nach jeder neuen abfrage soll es messen und aus dem switch raus und 
warten bis etwas neues kommt

was es macht:
die abfrage der adc-Knäle funktioniert aber nur einmal.
wenn ich beim ersten mal 1 eingebe ist der Wert richtig und bei der 
zweiten Abfrage kommt sofort der maximale wert raus (1023).

Hier mal den Code
(habe die Funktionen für READ_ADC1 usw. sogewählt, weil ich den Die 
funktion aus dem Tutorial nicht gefunden habe)
1
#ifndef F_CPU
2
#warning "F_CPU war noch nicht definiert, wird nun nachgeholt mit 20000000"
3
#define F_CPU 20000000UL
4
#endif
5
#define BAUD 9600UL      // Baudrate
6
7
// Berechnungen
8
#define UBRR_VAL ((F_CPU+BAUD*8)/(BAUD*16)-1)   // clever runden
9
#define BAUD_REAL (F_CPU/(16*(UBRR_VAL+1)))     // Reale Baudrate
10
#define BAUD_ERROR ((BAUD_REAL*1000)/BAUD) // Fehler in Promille, 1000 = kein Fehler.
11
12
#if ((BAUD_ERROR<990) || (BAUD_ERROR>1010))
13
  #error Systematischer Fehler der Baudrate grösser 1% und damit zu hoch!
14
#endif
15
16
#include <avr/io.h>
17
#include <string.h>
18
#include <stdio.h>
19
20
#define Ausgang DDRC      //Datenrichtung bestimmen
21
#define Sensorspannung PORTC  //Datenregister für PORTC 
22
#define ON |= (1<<PC0)      //Pin C0 High setzten
23
#define OFF &= ~(1<<PC0)    //Pin C0 Low setzten
24
25
/*Analog-Digital-Wandler-Initalisierung*/
26
void ADC_Init(void)
27
{
28
29
Sensorspannung ON;
30
uint16_t result;//Hilfsvariable für Dummy wert
31
32
//Referenzspannung AVcc 
33
ADMUX  = (1<<REFS0);
34
35
//ADC enable| Frequenzvorteiler F_CPU/64
36
ADCSRA = (1<<ADEN)|(1<<ADSC)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0);
37
38
/*Dummy wert lesen*/
39
ADCSRA |= (1<<ADSC);             // eine ADC-Wandlung
40
while (ADCSRA & (1<<ADSC) ) {}
41
42
 result = ADCW;
43
44
Sensorspannung OFF;
45
}
46
47
void UART_Init(void)
48
{
49
//Schreibt die Baudrate in das Register
50
  UBRRH = UBRR_VAL >> 8;
51
  UBRRL = UBRR_VAL & 0xFF;
52
  
53
// UART TX einschalten
54
UCSRB |= (1<<TXEN)|(1<<RXEN); 
55
//Asynchrone Übertragung | 8 bit Modus | 1 Stopbit  
56
UCSRC = (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0);  
57
}
58
59
uint8_t uart_getc(void)
60
{
61
    while (!(UCSRA & (1<<RXC)))   // warten bis Zeichen verfuegbar
62
        ;
63
    return UDR;                   // Zeichen aus UDR an Aufrufer zurueckgeben
64
}
65
66
void send_string (char *s)
67
{  
68
  // Schleife solange bis s versendet ist
69
  while(*s)
70
    {   
71
    //Warte bis senden möglich
72
        while (!(UCSRA & (1<<UDRE))) 
73
      {
74
      }
75
    //Sende einzelne Zeichen
76
      UDR = *s;   
77
        //Nächtes Zeichen
78
    s++;
79
    }
80
}
81
82
int Read_ADC1()
83
{
84
Sensorspannung ON;
85
 ADMUX = (1<<MUX0);
86
//Start der Wandlung
87
  ADCSRA |= (1<<ADSC);
88
              
89
// Warte bis Wandlung Ageschlossen
90
  while (ADCSRA & (1<<ADSC) ) {}  
91
92
Sensorspannung OFF;
93
94
//Ausgabe der Wandlung
95
  return ADCW;                    
96
}
97
98
int Read_ADC2()
99
{
100
Sensorspannung ON;
101
102
  ADMUX = (1<<MUX1);
103
//Start der Wandlung
104
  ADCSRA |= (1<<ADSC);
105
              
106
// Warte bis Wandlung Ageschlossen
107
  while (ADCSRA & (1<<ADSC) ) {}  
108
109
Sensorspannung OFF;
110
111
//Ausgabe der Wandlung
112
  return ADCW;                    
113
}
114
115
int Read_ADC3()
116
{
117
Sensorspannung ON;
118
  ADMUX = (1<<MUX1)|(1<<MUX0);
119
//Start der Wandlung
120
  ADCSRA |= (1<<ADSC);
121
              
122
// Warte bis Wandlung Ageschlossen
123
  while (ADCSRA & (1<<ADSC) ) {}  
124
125
Sensorspannung OFF;
126
127
//Ausgabe der Wandlung
128
  return ADCW;                    
129
}
130
131
132
int main()
133
{
134
135
Ausgang ON;
136
Sensorspannung OFF;
137
138
//Einbinden der Initialisierungen 
139
ADC_Init();
140
UART_Init();
141
uint8_t c;
142
uint16_t adc_Value;
143
char     Buffer[6];
144
145
    //Endlosschleife
146
    while( 1 ) 
147
    {
148
149
  
150
151
  if((UCSRA & (1<<RXC)))
152
  {  PORTB &= ~(1<<PB0);
153
    c = uart_getc();
154
    
155
    switch(c)
156
    {  
157
      /*ASCII = 1*/
158
      case 49:  c= 1;
159
      adc_Value = Read_ADC1();//Channel 0;
160
      break;
161
      
162
      /*ASCII = 2*/
163
      case 50:   c= 2;
164
      adc_Value = Read_ADC2();//Channel 2;
165
      break;
166
      
167
      /*ASCII = 3*/
168
      case 51:   c= 3;
169
      adc_Value = Read_ADC3();//Channel 3;
170
      break;
171
      
172
      default: adc_Value = 0;
173
                   
174
       
175
    }//Ende switch
176
    
177
  
178
179
      
180
      sprintf( Buffer, "%d=%4d\r\n",c,adc_Value );
181
      ADCW = 0;
182
      send_string( Buffer );
183
      
184
      //adc_Value = 0;
185
  
186
      
187
  
188
  }//ende if
189
190
  else 
191
  {
192
      
193
  }
194
  
195
  
196
197
198
    }//Ende while
199
200
return 0;
201
202
}//Ende main

Hoffe Ihr Könnt mir bei dem Problem weiter Helfen.
MFG
Kluski

von Stefan E. (sternst)


Lesenswert?

1
void ADC_Init(void)
2
{
3
...
4
ADMUX  = (1<<REFS0);
1
int Read_ADC1()
2
{
3
...
4
 ADMUX = (1<<MUX0);

x = 1;
x = 2;
Welchen Wert hat x nach diesen beiden Zeilen?

von Kluski (Gast)


Lesenswert?

eigendlich x=3
hatte aber auch schon dran gedacht und READ_ADCX() jedes mal
ADCW = 0;
und nach dem senden
adc_value = 0;
zusetzten aber hatt auch kein erfolg.

von Cyblord -. (cyblord)


Lesenswert?

Kluski schrieb:
> eigendlich x=3

Dicht drann. x=2 ist aber richtig. ;-)
Ein ADMUX=xxx überschreibt dir ADMUX jedesmal komplett neu.
Der vorherige Zustand wird so niemals irgendwie übernommen. Egal was da 
vorher drinstand, es ist nun weg.

Um das zu verhindern musst du so vorgehen:
Mit
ADMUX |= Bits setzen und
ADMUX &= ~ bits löschen. Dann klappts.

Nachzulesen hier: 
http://www.mikrocontroller.net/articles/Bitmanipulation

Und wenn du meherere ADCs auslesen willst, dann mach um Himmels Willen 
nur EINE Auslesefunktion und parametriere die mit dem gewünschten ADC 
Kanal. Für jeden Kanal eine eigene Funktion ist doch humbug hoch 10.

gruß cyblord

von Kluski (Gast)


Lesenswert?

ja ok da gebe ich mal geschlagen mit der x=2 :D
klar klinkt einleuchtend, aber wenn ich jedes mal nur channel 1 nutzt, 
überschreibe ich es doch jedes mal mit der 1 oder nicht?

Danke das Problem mit den ADC hat sich erledigt.
MFG Kluski

von Karl H. (kbuchegg)


Lesenswert?

Kluski schrieb:
> eigendlich x=3

????
echt.
Das wär aber fatal. Da würden 100% aller C-Programme nicht mehr 
funktionieren, wenn das so wäre.

  x = 1;
  x = 2;
  // an dieser Stelle hat x den Wert 2
  // Eine Zuweisung ist immer noch eine Zuweisung und gibt einer
  // Variablen einen neuen Wert unabhängig davon, was vorher
  // drinn gestanden hat

von Karl H. (kbuchegg)


Lesenswert?

Kluski schrieb:
> ja ok da gebe ich mal geschlagen mit der x=2 :D
> klar klinkt einleuchtend, aber wenn ich jedes mal nur channel 1 nutzt,
> überschreibe ich es doch jedes mal mit der 1 oder nicht?

Darum gehts aber nicht.
Was passiert mit dem Bit, welches die Referenzspannung einstellt und im 
selben Register beheimatet ist?

von Karl H. (kbuchegg)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Kluski schrieb:
>> ja ok da gebe ich mal geschlagen mit der x=2 :D
>> klar klinkt einleuchtend, aber wenn ich jedes mal nur channel 1 nutzt,
>> überschreibe ich es doch jedes mal mit der 1 oder nicht?
>
> Darum gehts aber nicht.
> Was passiert mit dem Bit, welches die Referenzspannung einstellt und im
> selben Register beheimatet ist?


Oder anders gefragt:
Warum denkst du fängt die ADC Routine aus dem Tutorial
AVR-GCC-Tutorial/Analoge Ein- und Ausgabe
genau so an:
1
/* ADC Einzelmessung */
2
uint16_t ADC_Read( uint8_t channel )
3
{
4
  // Kanal waehlen, ohne andere Bits zu beeinflußen
5
  ADMUX = (ADMUX & ~(0x1F)) | (channel & 0x1F);
6
  ...

und weist nicht einfach nur den Channel an ADMUX zu?




PS:
Das hier
1
    switch(c)
2
    {  
3
      /*ASCII = 1*/
4
      case 49:  c= 1;
5
      adc_Value = Read_ADC1();//Channel 0;
6
      break;
7
      
8
      /*ASCII = 2*/
9
      case 50:   c= 2;
10
      adc_Value = Read_ADC2();//Channel 2;
11
      break;
12
      
13
      /*ASCII = 3*/
14
      case 51:   c= 3;
15
      adc_Value = Read_ADC3();//Channel 3;
16
      break;
17
      
18
      default: adc_Value = 0;
19
                   
20
       
21
    }//Ende switch

schreibst du besser so (die Zeichen selber anstatt ihrem Code
1
    switch(c)
2
    {  
3
      case '1':  c= 1;
4
      adc_Value = Read_ADC1();//Channel 0;
5
      break;
6
      
7
      case '2':   c= 2;
8
      adc_Value = Read_ADC2();//Channel 2;
9
      break;
10
      
11
      case '3':   c= 3;
12
      adc_Value = Read_ADC3();//Channel 3;
13
      break;
14
      
15
      default: adc_Value = 0;
16
    }//Ende switch

erstens brauchst du dir dann die ASCII Codes nicht merken (die kennt der 
Compiler auswendig) und zweitens brauchst du dann auch die Kommentare 
nicht (die im Extremfall sowieso einfach nur falsch sind)

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.