Forum: Mikrocontroller und Digitale Elektronik ADC-Problem beim XPLAIN-Board


von Gerebuar (Gast)


Lesenswert?

Hallo zusammen,

ich habe folgendes Problem:
Ich möchte am XPLAIN-Board über das Poti am ADC-Eingang eine Spannung 
messen und diese per UART ausgeben. Poti ist am Port B1.

Hier die Fehlerbeschreibung:

Wenn ich die Zeile
1
while(!ADCB.CH0.INTFLAGS)
 auskommentiere erhalte im Terminal nur Nullen("Analog: 00000") für den 
ADC Eingang (immer abwechselnd zu "Analog: 01357", was ich als Test 
eingefügt habe).

Wenn ich die Zeile
1
while(!ADCB.CH0.INTFLAGS)
 allerdings drin lasse hängt er in einer Endlosschleife und gibt gar 
nichts aus.

Dabei habe ich als Vorlage das UART-Beispiel aus dem AVRStudio 5 genutzt 
und es entprechend erweitert.



Hier mal der Code:

1
#include <asf.h>
2
#include "conf_usart_example.h"
3
#include "status_codes.h"
4
5
6
/*FUNKTIONSPROTOTYPEN*/
7
void senden(uint16_t wert);
8
void pause(uint16_t ms);
9
void analog(uint16_t zahl);
10
void ADC_init();
11
12
13
14
int main(void)
15
{
16
  
17
  // USART init
18
  static usart_rs232_options_t USART_SERIAL_OPTIONS = {
19
    .baudrate = USART_SERIAL_EXAMPLE_BAUDRATE,
20
    .charlength = USART_SERIAL_CHAR_LENGTH,
21
    .paritytype = USART_SERIAL_PARITY,
22
    .stopbits = USART_SERIAL_STOP_BIT
23
  };
24
  
25
  ADC_init();      //ADC init
26
  sysclk_init();      
27
  board_init();
28
29
#ifdef USARTC0
30
  if ((uint16_t) USART_SERIAL_EXAMPLE == (uint16_t) & USARTC0) {
31
    sysclk_enable_module(SYSCLK_PORT_C, PR_USART0_bm);
32
  } 
33
#endif
34
35
  // Initialize usart driver in RS232 mode
36
  usart_init_rs232(USART_SERIAL_EXAMPLE, &USART_SERIAL_OPTIONS);
37
38
  uint16_t temp=0;
39
  
40
  while (true) {
41
    
42
      
43
    ADCB.CH0.MUXCTRL = ADC_CH_MUXPOS_PIN1_gc;
44
    ADCB.CTRLA |= 0x4;
45
    //while(!ADCB.CH0.INTFLAGS);
46
    temp=ADCB.CH0RES;
47
    
48
    pause(500);      
49
    analog(temp);
50
    pause(500);
51
    analog(1357);
52
    }
53
    
54
    
55
}
56
57
/*FUNKTIONEN*/
58
void senden(uint16_t zahl)  //Hier wird nur die Zahl ins ASCII-Format gebracht
59
{
60
  uint8_t temp = 0;
61
  
62
  temp = zahl/10000;
63
  usart_putchar(USART_SERIAL_EXAMPLE,temp+48);
64
  zahl -= temp*10000;
65
66
  temp = zahl/1000;
67
  usart_putchar(USART_SERIAL_EXAMPLE,temp+48);
68
  zahl -= temp*1000;
69
70
  temp = zahl/100;
71
  usart_putchar(USART_SERIAL_EXAMPLE,temp+48);
72
  zahl -= temp*100;
73
74
  temp = zahl/10;
75
  usart_putchar(USART_SERIAL_EXAMPLE,temp+48);
76
  zahl -= temp*10;
77
78
  usart_putchar(USART_SERIAL_EXAMPLE,zahl+48);
79
    
80
}
81
void pause(uint16_t ms)
82
{
83
  uint32_t count;
84
85
  // Berechnet den counter von der Runtergezählt wird
86
  count = sysclk_get_cpu_hz() / 6;
87
  count *= ms;
88
  count /= 1000;
89
90
  do {
91
    asm("");
92
  } while (--count);
93
}
94
void analog(uint16_t zahl)
95
{
96
  usart_putchar(USART_SERIAL_EXAMPLE, 0x0D);
97
  usart_putchar(USART_SERIAL_EXAMPLE,'A');
98
  usart_putchar(USART_SERIAL_EXAMPLE,'n');  
99
  usart_putchar(USART_SERIAL_EXAMPLE,'a');  
100
  usart_putchar(USART_SERIAL_EXAMPLE,'l');  
101
  usart_putchar(USART_SERIAL_EXAMPLE,'o');  
102
  usart_putchar(USART_SERIAL_EXAMPLE,'g');
103
  usart_putchar(USART_SERIAL_EXAMPLE,':');
104
  usart_putchar(USART_SERIAL_EXAMPLE,' ');
105
  senden(zahl);    
106
  
107
}
108
void ADC_init(){
109
  
110
  
111
  
112
  
113
  ADCB.CTRLA |= 0x01;                                     // enable adc
114
  ADCB.CTRLB = ADC_RESOLUTION_12BIT_gc;                  // 12-bit
115
  ADCB.REFCTRL = ADC_REFSEL_VCC_gc | 0x02;       // internal VCC-0.6V
116
  ADCB.PRESCALER = ADC_PRESCALER_DIV128_gc;               
117
  ADCB.CH0.CTRL = ADC_CH_INPUTMODE_SINGLEENDED_gc;      // single ended
118
  ADCB.CH0.MUXCTRL = ADC_CH_MUXPOS_PIN1_gc;             // input pin B1 - Poti
119
   
120
121
  
122
}

Ich weiß leider nicht wo ich den Fehler suchen muss und wäre für 
Hinweise sehr dankbar!!

Vielen Dank
Gerebuar

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Mach auf jeden Fall noch :
1
sysclk_enable_module(SYSCLK_PORT_B, PR_ADC_bm);

irgendwo in der init routine, denn ASF schaltet in der sysclk routine 
öfter einfach mal Module ab.
Ich vermisse das starten des ADC. Da ich den ADC immer im Freerun Mode 
benutze und ich im Moment nicht im Datenblatt rumstochern kann, poste 
ich einfach mal meine Init/Run Routine:
1
#define ADC ADCA
2
static void ADCInit(void)
3
{
4
  ADC.CTRLA = 0x01;
5
  ADC.CTRLB = ADC_RESOLUTION_12BIT_gc | (ADC_MODE << 4) ;  // 12 bit right adjusted
6
  ADC.PRESCALER = ADC_PRESCALER_DIV256_gc;
7
  ADC.REFCTRL = ADC_REFSEL_AREFA_gc;
8
  ADC.EVCTRL = ADC_SWEEP_0123_gc ;
9
//  ADC.CALL = adc_get_calibration_data() && 0xff;
10
//  ADC.CALH = (uint16_t)adc_get_calibration_data() >> 8;
11
// AREF input
12
  ADC.CH0.CTRL = ADC_CH_INPUTMODE_SINGLEENDED_gc;
13
  ADC.CH0.MUXCTRL = ADC_CH_MUXPOS_PIN0_gc;
14
// the Acceleration Sensor inputs
15
  ADC.CH1.CTRL = ADC_CH_INPUTMODE_SINGLEENDED_gc;
16
  ADC.CH1.MUXCTRL = ADC_CH_MUXPOS_PIN1_gc;
17
  ADC.CH2.CTRL = ADC_CH_INPUTMODE_SINGLEENDED_gc;
18
  ADC.CH2.MUXCTRL = ADC_CH_MUXPOS_PIN2_gc;
19
  ADC.CH3.CTRL = ADC_CH_INPUTMODE_SINGLEENDED_gc;
20
  ADC.CH3.MUXCTRL = ADC_CH_MUXPOS_PIN3_gc;
21
  ADC.CTRLB = ADC_RESOLUTION_12BIT_gc | (ADC_MODE << 4) | (1 << 3);  // enable freerun
22
}
Ich benutze alle 4 Kanäle hier, streich raus, was du nicht brauchst. 
Freerun mit Sweep bedeutet , das der ADC einfach immer im Hintergrund 
läuft und du die Werte aus den RES registern liest, wenn du grade Zeit 
hast.

von Günter (Gast)


Lesenswert?

Wichtiger Hinweis: Wenn du die ADCs auf an den JTAG Pins benutzen 
möchtest muss du das JTAGEN Fuse deaktivieren, sonst liest der ADC keine 
Werte aus!

Zu deinem Problem: Nehm doch einfach die ADC Drivers aus dem Software 
Framework! Die dort definierten Befehle funktionieren und sind außerdem 
viel komfortabler!

von Gerebuar (Gast)


Lesenswert?

Hallo Matthias,
vielen Dank für deinen Tipp!

Nach einfügen von
1
 sysclk_enable_module(SYSCLK_PORT_B, PR_ADC_bm);
Klappt alles wunderbar!!


Vielen Dank!!!

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Günter schrieb:
> Zu deinem Problem: Nehm doch einfach die ADC Drivers aus dem Software
> Framework! Die dort definierten Befehle funktionieren und sind außerdem
> viel komfortabler!

Das wäre schön, aber leider ist dem (noch) nicht so. Wie oben schon 
erwähnt, ist ASF noch an vielen Stellen nachbesserungsfähig. sysclk.h 
ist nur ein Beispiel. Wenn du versuchst, über diese include z.B. den 
Oszillator umzuschalten, stehst du danach im 
'alle-peripheren-clocks-aus' Regen und musst zu Fuss wieder anschalten. 
Die Behandlung des ADC ist auch spassig - er wird zwar initialisiert, 
aber danach abgeschaltet :O , bzw. es wird vergessen, ihn anzuschalten.
Ausserdem ist der Lerneffekt mit der XMega Peripherie deutlich besser, 
wenn man es selber macht, und dazu ist das XPlain(ed) board ja da. Lass 
uns abwarten, wann die ersten ASF Updates kommen. Auf AVRFreaks ist da 
einiges an bugs zusammengekommen und die Atmel Jungs schauen da 
regelmässig rein.

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.