Forum: Mikrocontroller und Digitale Elektronik AVR ADC macht Probleme und liefert keine Messwerte


von Funky C. (funky4computer)


Lesenswert?

Hallo zusammen,

Ich komme bei meinem Projekt wirklich nicht mehr weiter. Ich habe 
wirklich alles schon mehrmals durchgecheckt, ohne einen konkreten Fehler 
zu finden.

Problem: Die Daten, die vom ADC kommen entsprechen gar keiner Messung 
-.-

Ich habe einen Beschleunigungssensor an Port F angeschlosse mit x an 
ADC0, y an ADC1 und z and ADC2
1
/************************************************************************/
2
/* imports & includes                                                   */
3
/************************************************************************/
4
#include <avr/io.h>
5
#include <avr/interrupt.h>
6
#include <stdlib.h>
7
#include <util/delay.h>
8
#include "lcd.h"
9
#include "uart.h"
10
#include "ZigBee.h"
11
#include "Utility.h"
12
#include "structs.h"
13
14
/************************************************************************/
15
/* parameters, constants & field variables                              */
16
/************************************************************************/
17
#define UART_BAUD_RATE 57600UL
18
#define F_CPU 8000000UL
19
20
#define STATE_READSENSORS 1
21
#define STATE_READSENSORS_ADXL330 2
22
#define STATE_READSENSORS_ADXL345 3
23
#define STATE_SENDOVERUART 4
24
unsigned char sensorMesh_state = STATE_READSENSORS;
25
26
#define NUMBER_OF_ADCVALUES 10
27
ADCVALUE adcValues[NUMBER_OF_ADCVALUES];
28
char adcValuesPointer = 0;
29
30
/************************************************************************/
31
/* functions, procedures & methods                                      */
32
/************************************************************************/
33
int main(void)
34
{
35
  init();
36
  //[debugging]
37
  //testSoftware();
38
  
39
  while(1)
40
  {
41
    //TODO:: Please write your application code
42
    
43
    //[debugging]
44
    //char rfDataFrame[5];
45
    //rfDataFrame[0] = 0x41;
46
    //rfDataFrame[1] = 0x41;
47
    //rfDataFrame[2] = 0x41;
48
    //rfDataFrame[3] = 0x41;
49
    //rfDataFrame[4] = 0x41;
50
    //ARRAY rfDataFrameArray;
51
    //rfDataFrameArray.elements = rfDataFrame;
52
    //rfDataFrameArray.size = 5;
53
    //sendDataOverZigbee(rfDataFrameArray);
54
    
55
    sensorMesh_stateMachine();
56
  }
57
}
58
59
/**************************************************************/
60
/* inits                                                      */
61
/**************************************************************/
62
void init()
63
{
64
  //initDisplay();
65
  initLeds();
66
  initUart();
67
  initAdc();
68
}
69
70
void initDisplay()
71
{
72
  lcd_init(LCD_DISP_ON);
73
  lcd_clrscr();
74
}
75
76
void initAdc()
77
{
78
  //Configure the ADC
79
  
80
  //Enable a prescaler - determinded by the internal/external clock
81
  //800/5 = 160, 80/2 = 40 prescaler khz must be between 50khz and 200khz
82
  ADCSRA |= (1<<ADPS2) | (1<<ADPS1);
83
  
84
  //Set reference voltage
85
  //ADMUX |= 1<<REFS0 | 1<<REFS1;
86
  ADMUX |= (1<<REFS0);
87
  
88
  //8-bit or 10-bit results (0 for 10 bit and 1 for 8 bit)
89
  ADMUX |= (1<<ADLAR);
90
  
91
  //Set default input channel to AD0 (by default). Nothing to do then.
92
  
93
  //Enable ADCConverter
94
  ADCSRA |= 1<<ADEN;
95
  
96
  //Enable interrupts function in ADC
97
  ADCSRA |= (1<<ADIE);
98
  
99
  //Enable global interrupts
100
  sei();
101
  
102
  //Start the first conversion
103
  ADCSRA |= 1<<ADSC;
104
}
105
106
void initUart()
107
{
108
  uart_init(UART_BAUD_SELECT(UART_BAUD_RATE, F_CPU));
109
  sei();
110
}
111
112
void initLeds()
113
{
114
  DDRD = 0xFF;
115
  
116
  // [debugging] check if LEDs work
117
  PORTD = 0x00;
118
}
119
120
/**************************************************************/
121
/* interrupt handlers                                         */
122
/**************************************************************/
123
ISR(ADC_vect){
124
  if(sensorMesh_state == STATE_READSENSORS_ADXL330)
125
  {
126
    //PORTD = 0xFF;
127
128
    //[debugging]
129
    ////LCD String variable declarration
130
    //char adcResultHigh[4];
131
    //itoa(ADCH, adcResultHigh, 10);
132
    //lcd_puts(adcResultHigh);
133
    //
134
    //char adcResultLow[4];
135
    //itoa(ADCL, adcResultLow, 10);
136
    //lcd_puts(adcResultLow);
137
    //
138
    //output to LEDs
139
    //char temp = ~ADCL;
140
    //PORTD = ADCH;
141
    //_delay_ms(100);
142
    //
143
    ////delay so that lcd is not flashing and clear lcd
144
    //_delay_ms(100);
145
    //lcd_clrscr();
146
    //[/debugging]
147
    
148
    //Write values to buffer until buffer limit is reached
149
    adcValues[adcValuesPointer].adcl = ADCL;
150
    adcValues[adcValuesPointer].adch = ADCH;
151
    adcValuesPointer++;
152
    
153
    //[debugging]
154
    PORTD = ~(adcValues[adcValuesPointer].adch);
155
    
156
    //Reset adcValuesPointer if end of buffer is reached and begin next state
157
    if(adcValuesPointer == NUMBER_OF_ADCVALUES)
158
    {
159
      adcValuesPointer = 0;
160
      sensorMesh_state = STATE_SENDOVERUART;
161
    }
162
  }
163
  //Start the next conversion
164
  ADCSRA |= 1<<ADSC;
165
}
166
167
/**************************************************************/
168
/* routines                                                   */
169
/**************************************************************/
170
void sendDataOverZigbee(ARRAY rfDataArray)
171
{
172
  //prepare result frame
173
  char resultFrame[18 + rfDataArray.size];
174
  ARRAY resultFrameArray;
175
  resultFrameArray.size = 23;
176
  resultFrameArray.elements = resultFrame;
177
  
178
  //set address
179
  char destinationAddress[8];
180
  destinationAddress[0] = 0x00;
181
  destinationAddress[1] = 0x13;
182
  destinationAddress[2] = 0xA2;
183
  destinationAddress[3] = 0x00;
184
  destinationAddress[4] = 0x40;
185
  destinationAddress[5] = 0xC2;
186
  destinationAddress[6] = 0x84;
187
  destinationAddress[7] = 0xEE;
188
  ARRAY destinationAddressArray;
189
  destinationAddressArray.size = 8;
190
  destinationAddressArray.elements = destinationAddress;
191
192
  //set 16 bit address
193
  char destination16BitAddress[2];
194
  destination16BitAddress[0] = 0xFF;
195
  destination16BitAddress[1] = 0xFF;
196
  ARRAY destination16BitAddressArray;
197
  destination16BitAddressArray.size = 2;
198
  destination16BitAddressArray.elements = destination16BitAddress;
199
200
  //set broadcast radius
201
  char broadcastRadius = 0x00;
202
203
  //set rf data from parameter
204
  
205
  //create zigbee transmit request message frame
206
  zigbee_createTransmitRequestMessageFrame(resultFrameArray, 0x01, destinationAddressArray, destination16BitAddressArray, broadcastRadius, 0x00, rfDataArray);
207
208
  //sending data over uart
209
  for(int i = 0; i < resultFrameArray.size; i++)
210
  {
211
    uart_putc(resultFrameArray.elements[i]);
212
  }
213
}
214
215
void sensorMesh_sendAllDataToZigbee()
216
{
217
  //Send all read values from ADXL330
218
  for(int i = 0; i < NUMBER_OF_ADCVALUES; i++)
219
  {
220
    char rfDataFrame[2];
221
    rfDataFrame[0] = adcValues[i].adcl;
222
    rfDataFrame[1] = adcValues[i].adch;
223
    ARRAY rfDataFrameArray;
224
    rfDataFrameArray.elements = rfDataFrame;
225
    rfDataFrameArray.size = 2;
226
    sendDataOverZigbee(rfDataFrameArray);
227
  }
228
  
229
  //Send all read values from ADXL345
230
231
}
232
233
void sensorMesh_stateMachine()
234
{
235
  switch(sensorMesh_state) {
236
    case STATE_READSENSORS:
237
    //Read values from sensors and write to buffer
238
    //---Read values from adxl 330 and write to buffer
239
    sensorMesh_state = STATE_READSENSORS_ADXL330;
240
    //---Read values from adxl 345 and write to buffer
241
    //sensorMesh_state = STATE_READSENSORS_ADXL345;
242
    //if all sensores are done, set machine state to send over uart
243
    break;
244
    
245
    case STATE_SENDOVERUART:
246
    //Send data from buffers over uart
247
    sensorMesh_sendAllDataToZigbee();
248
    //Set machine state to read sensor values
249
    sensorMesh_state = STATE_READSENSORS;
250
    break;
251
    
252
    default:
253
    //do nothing now
254
    break;
255
  }
256
}
257
258
void sensorMesh_nextState()
259
{
260
  sensorMesh_state++;
261
}
262
263
void sensorMesh_previousState()
264
{
265
  sensorMesh_state--;
266
}
267
268
/**************************************************************/
269
/* testing routines                                           */
270
/**************************************************************/
271
void testSoftware()
272
{
273
  testUartConnection();
274
}
275
276
void testUartConnection()
277
{
278
  while(1)
279
  {
280
    //prepare result frame
281
    char resultFrame[23];
282
    ARRAY resultFrameArray;
283
    resultFrameArray.size = 23;
284
    resultFrameArray.elements = resultFrame;
285
    
286
    //set address
287
    char destinationAddress[8];
288
    destinationAddress[0] = 0x00;
289
    destinationAddress[1] = 0x13;
290
    destinationAddress[2] = 0xA2;
291
    destinationAddress[3] = 0x00;
292
    destinationAddress[4] = 0x40;
293
    destinationAddress[5] = 0xC2;
294
    destinationAddress[6] = 0x84;
295
    destinationAddress[7] = 0xEE;
296
    ARRAY destinationAddressArray;
297
    destinationAddressArray.size = 8;
298
    destinationAddressArray.elements = destinationAddress;
299
300
    //set 16 bit address
301
    char destination16BitAddress[2];
302
    destination16BitAddress[0] = 0xFF;
303
    destination16BitAddress[1] = 0xFF;
304
    ARRAY destination16BitAddressArray;
305
    destination16BitAddressArray.size = 2;
306
    destination16BitAddressArray.elements = destination16BitAddress;
307
308
    //set broadcast radius
309
    char broadcastRadius = 0x00;
310
311
    //set data
312
    char rfData[5];
313
    rfData[0] = 0x41;
314
    rfData[1] = 0x42;
315
    rfData[2] = 0x43;
316
    rfData[3] = 0x44;
317
    rfData[4] = 0x45;
318
    ARRAY rfDataArray;
319
    rfDataArray.size = 5;
320
    rfDataArray.elements = rfData;
321
    
322
    //create zigbee transmit request message frame
323
    zigbee_createTransmitRequestMessageFrame(resultFrameArray, 0x01, destinationAddressArray, destination16BitAddressArray, broadcastRadius, 0x00, rfDataArray);
324
325
    //sending data over uart
326
    for(int i = 0; i < resultFrameArray.size; i++)
327
    {
328
      uart_putc(resultFrameArray.elements[i]);
329
    }
330
  }
331
}

von jb (Gast)


Lesenswert?

Sind die Messwerte logisch, wenn du statt des Beschleunigungssensors 
einfach mal Potentiometer anschließt?

Ansonsten ist es normal das die Werte da ziemlich schwanken und digital 
aufbearbeitet (filtern) werden müssen.

Gruß Jonas

von Andreas K. (andreasmc)


Lesenswert?

Was für Werte kriegst du raus, was für Werte erwartest du?

Die restlichen Programmteile hast du mal mit festen Werten getestet und 
die kommen rüber wie erwartet?

Was für Werte kriegst du wenn du ein Trimmpoti statt dem 
Beschleunigungsmesser anschliesst?

von Funky C. (funky4computer)


Lesenswert?

jb schrieb:
> Sind die Messwerte logisch, wenn du statt des Beschleunigungssensors
> einfach mal Potentiometer anschließt?
>
> Ansonsten ist es normal das die Werte da ziemlich schwanken und digital
> aufbearbeitet (filtern) werden müssen.
>
> Gruß Jonas

Die Werte ändern sich nicht mal, wenn ich den Sensor bewege. Ich habe 
Spaßes halber mein STK600 auf 5Volt gestellt (ganz kurz), da schien sich 
dann was zu tun... Ansonsten müssen die Komponenten mit 3,3V laufen.

Gruß

von Rolf M. (rmagnus)


Lesenswert?

Funky Computer schrieb:
> Problem: Die Daten, die vom ADC kommen entsprechen gar keiner Messung

Was heißt das? Kommen zufällige Werte raus? Immer derselbe Wert? Ein 
Offset? Wo siehst du die falschen Werte? Kann vielleicht deine 
Senderoutine fehlerhaft sein?

> Ich habe einen Beschleunigungssensor an Port F angeschlosse mit x an
> ADC0, y an ADC1 und z and ADC2

Ich würde erstmal ein Poti anschließen, um zu schauen, ob's wirklich am 
ADC liegt. Erst wenn der richtig funktioniert, den Sensor anklemmen.

Ansonsten:
Welcher AVR?
Welcher Sensor?
Sind AVCC und AGND und alle GND-Pins korrekt beschaltet?
Schaltplan?

von Funky C. (funky4computer)


Lesenswert?

Andreas K. schrieb:
> Was für Werte kriegst du raus, was für Werte erwartest du?
>

Ich bekomme da für ADCL (lower byte) einen zufälligen Wert raus. Ich 
hätte erwartet, dass sich beim Bewegen des Sensors ÜBERHAUPT etwas an 
den Werten verändert.

> Die restlichen Programmteile hast du mal mit festen Werten getestet und
> die kommen rüber wie erwartet?
>

UART funktioniert einwandfrei

> Was für Werte kriegst du wenn du ein Trimmpoti statt dem
> Beschleunigungsmesser anschliesst?

Müsste ich machen. Ich habe zusätzlich einen anderen ADXL330 
angeschlossen, um sicher zu gehen, dass der 1. Sensor nicht kaputt ist. 
Da gibt es dasselbe Problem...

von jb (Gast)


Lesenswert?

>Die Werte ändern sich nicht mal, wenn ich den Sensor bewege.

Um einen defekten Sensor auszuschließen folge doch dem vielgesagten Tip 
und schließe einmal ein Potentiometer an und prüfe dann die Messwerte!

>Ich habe Spaßes halber mein STK600 auf 5Volt gestellt (ganz kurz), da >schien 
sich dann was zu tun... Ansonsten müssen die Komponenten mit 3,3V >laufen.

Hm, das hätte ich gelassen.

Gruß Jonas

von Funky C. (funky4computer)


Lesenswert?

Rolf Magnus schrieb:
> Funky Computer schrieb:
>> Problem: Die Daten, die vom ADC kommen entsprechen gar keiner Messung
>
> Was heißt das? Kommen zufällige Werte raus? Immer derselbe Wert? Ein
> Offset? Wo siehst du die falschen Werte? Kann vielleicht deine
> Senderoutine fehlerhaft sein?
>

Wie gesagt scheinen die Werte sich NICHT mit der Bewegung des Sensors zu 
verändern. Es ist eher ein Randomwert (aber die meisten Werte sind 
"0x00"). Ich habe die Werte sowohl über UART gesendet und sehe es Per 
Terminal auf dem Laptop als auch auf den LEDs ausgegeben (Auch die LEDs 
reagieren nicht auf den Sensor!).

>> Ich habe einen Beschleunigungssensor an Port F angeschlosse mit x an
>> ADC0, y an ADC1 und z and ADC2
>
> Ich würde erstmal ein Poti anschließen, um zu schauen, ob's wirklich am
> ADC liegt. Erst wenn der richtig funktioniert, den Sensor anklemmen.
>
Ich habe einen 2. Sensor des gleichen Modells angeschlossen und hatte 
auch damit keinen Erfolg gehabt.

> Ansonsten:
> Welcher AVR?
Atmega2560 auf STK600 (Aref0 und Aref1 Jumper habe ich entfernt)

> Welcher Sensor?
ADXL330 (MEMS1)

> Sind AVCC und AGND und alle GND-Pins korrekt beschaltet?
Ja

> Schaltplan?
ADXL330       STK600
GND           GND(PortF)
Vcc           Vcc(PortF)
X             PinF0
Y             PinF1
Z             PinF2

von Karl H. (kbuchegg)


Lesenswert?

> Ich würde erstmal ein Poti anschließen, um zu schauen, ob's wirklich am
> ADC liegt. Erst wenn der richtig funktioniert, den Sensor anklemmen.

Ich würde auch erst mal mit einem wesentlich simpleren Testprogramm 
anfangen als dieser dann doch schon relativ komplexen Statemachine mit 
Interruptbeteiligung.
1
int main()
2
{
3
  uint16_t value;
4
5
  DDRD = 0xFF;
6
7
  ADC_Init();
8
9
  while( 1 ) {
10
    value = ADC_Read( 0 );
11
    PORTD = value;
12
  }
13
}

das ist einfach genug, dass man davon ausgehen kann, dass eventuelle 
Fehler sich nur noch im Hardwareaufbau bzw. in einer falschen 
Referenzspannung manifestieren können. Die ADC Routinen finden sich hier

http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/Analoge_Ein-_und_Ausgabe#Der_interne_ADC_im_AVR


Es ist KEINE gute Idee, bei einer neuen Systemkomponente gleich mal mit 
einem komplexen Programm loszulegen. Die Devise heisst abspecken und 
erst mal so einfach wie nur möglich testen, ob die Hardware überhaupt 
funktioniert. Ein komplexes Programm ist dabei kontraproduktiv, weil du 
nie weisst, ob dieses neue Teilsystem das Problem verursacht, oder ob du 
im Rest noch irgendwo einen Bock hast. Die Zeit, die du in ein einfaches 
Testprogramm investierst, kriegst du in Folge 100-fach wieder rein.

von Funky C. (funky4computer)


Lesenswert?

Mensch, ihr seid echt fix im Antworten.

Vielen Dank für die Tips! Ich werde erst nächste Woche das Material 
haben, um das Ganze umzusetzen.

von Stefan F. (Gast)


Lesenswert?

Ich vermisse einen Zugriff auf den ADC Multiplexer. Wenn du drei ADC 
Eingänge beschaltest hast, dann musst du doch irgendwo zwischen diesen 
Eingängen umschalten.

Wie hast du dir das mit der Interrupt Routine und dem Array gedacht? 
Sollte der aktuelle Kanal fortlaufend gemessen werden, bis das Array 
voll ist, oder wolltest du, dass das Array einen Wert pro Eingang 
enthält?

von Funky C. (funky4computer)


Lesenswert?

Stefan Us schrieb:
> Ich vermisse einen Zugriff auf den ADC Multiplexer. Wenn du drei ADC
> Eingänge beschaltest hast, dann musst du doch irgendwo zwischen diesen
> Eingängen umschalten.
>
> Wie hast du dir das mit der Interrupt Routine und dem Array gedacht?
> Sollte der aktuelle Kanal fortlaufend gemessen werden, bis das Array
> voll ist, oder wolltest du, dass das Array einen Wert pro Eingang
> enthält?

1. Ja, ich greife auf den Multiplexer, wenn ich erstmal Werte von 
zumindest einem Kanal bekomme.

2. Überlegung war: Ich habe irgendwo gelesen, dass unterschiedliche 
Interruptroutinen unterschiedliche Prioritäten hätten. D.h. wenn eine 
Routine zu lange dauert, kann es durchaus dazu kommen, dass andere 
Routinen erst gar nicht drankommen bzw. sehr unregelmäßig drankommen und 
das wollte ich nicht, da ich eine relativ gleichmäßige Übertragung 
möchte (z.B. "Hole 10 Werte und sende 10 Werte"). Ich speichere erst 
einen Array voll, bevor ich die Werte dieses Arrays per UART übertrage. 
Das ist zunächst mal die grobe Idee, später könnte ich die Daten aller 3 
Kanäle schön verpackt in einem struct abspeichern und einen Array aus 
diesem struct machen.

von Rolf M. (rmagnus)


Lesenswert?

Funky Computer schrieb:
> 2. Überlegung war: Ich habe irgendwo gelesen, dass unterschiedliche
> Interruptroutinen unterschiedliche Prioritäten hätten.

Echte Prioritäten gibt es beim AVR nicht.

> D.h. wenn eine Routine zu lange dauert, kann es durchaus dazu kommen, dass
> andere Routinen erst gar nicht drankommen bzw. sehr unregelmäßig drankommen

Dazu muß die ISR aber sehr lang sein oder sehr häufig aufgerufen werden. 
Außerdem kommen dann nicht nur andere ISRs nicht mehr dran, sondern auch 
das Hauptprogramm.

> und das wollte ich nicht, da ich eine relativ gleichmäßige Übertragung
> möchte (z.B. "Hole 10 Werte und sende 10 Werte"). Ich speichere erst
> einen Array voll, bevor ich die Werte dieses Arrays per UART übertrage.

Die ISR ist dabei so ziemlich das, was am wenigsten Zeit braucht. Im 
Vergleich dazu braucht die UART-Übertragung ewig.

von Stefan F. (Gast)


Lesenswert?

Hast du einen Kondensator an Aref angeschlossen? Hast du auch einen 
Abblockkondensator an VCC?

Du kannst zum Spass man den ADC0 Pin als Ausgang konfigurieren (Sensor 
abklemmenm!) und auf Low schalten. Dann müsste der ADC ungefähr den Wert 
0 liefern. Und bei High müsste er ungefähr den Wert 0x3FFF liefern.

von Funky C. (funky4computer)


Lesenswert?

Stefan Us schrieb:
> Hast du einen Kondensator an Aref angeschlossen? Hast du auch einen
> Abblockkondensator an VCC?
>
> Du kannst zum Spass man den ADC0 Pin als Ausgang konfigurieren (Sensor
> abklemmenm!) und auf Low schalten. Dann müsste der ADC ungefähr den Wert
> 0 liefern. Und bei High müsste er ungefähr den Wert 0x3FFF liefern.

Korrigiere mich bitte, wenn ich falsch liege...
1. Soweit ich verstanden habe, waren die Kondensatoren eher optional, um 
das Rauschen des Signals einzudämmen?

2. Werde ich ausprobieren.

von Funky C. (funky4computer)


Lesenswert?

Rolf Magnus schrieb:
>> D.h. wenn eine Routine zu lange dauert, kann es durchaus dazu kommen, dass
>> andere Routinen erst gar nicht drankommen bzw. sehr unregelmäßig drankommen
>
> Dazu muß die ISR aber sehr lang sein oder sehr häufig aufgerufen werden.
> Außerdem kommen dann nicht nur andere ISRs nicht mehr dran, sondern auch
> das Hauptprogramm.
>

Ich hatte vorher in der ISR die Routine für die UART-Übertragung 
aufgerufen und irgendwas schien da etwas blockiert zu sein...

von OldMan (Gast)


Lesenswert?

Funky Computer schrieb:
> waren die Kondensatoren eher optional,

Sind ein MUSS!

von (prx) A. K. (prx)


Lesenswert?

OldMan schrieb:
>> waren die Kondensatoren eher optional,
>
> Sind ein MUSS!

An (A)VCC ja, an AREF nicht.

von Stefan F. (Gast)


Lesenswert?

An AREF ist der Kondensator optional. Da du aber kritisierst, dass die 
Messwerte micht plausibel sind, ist es einen Versuch wert.

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.