Hallihallo liebe Bastlergemeinde!
Leider muss ich eure Aufmerksamkeit auf ein weiteres
Ich-sehe-den-Wald-vor-lauter-Bäumen-nicht-mehr-Problem lenken... Und es
geht, wie so oft, um den ADC.
Vorweg möchte ich gleich noch kurz anmerken, dass ich mich schon mehrere
Male durch das ADC-Kapitel im (richtigen) Datenblatt, sowie einige
Code-Beispiele und andere Threads gewälzt habe. Nun bin ich aber an dem
Punkt angekommen, wo mir nix mehr einfällt.
Ich habe also vor, den ADC des ATMega32 (CPU-Takt 16 MHz) im free
running mode laufen zu lassen. Am Kanal 7 (Pin PA7) hängt ein Poti und
dem AREF-Pin habe ich einen Kondensator spendiert. Die Schaltung scheint
OK zu sein, alles durchgemessen und wie erwartet.
Die LCD-Ansteuerung ist übrigens getestet und funktionsfähig.
Hier ist mein Code:
1 | Aus adc.c:
|
2 |
|
3 | bool ADC_initialized = false;
|
4 |
|
5 |
|
6 | void ADC_init(void) {
|
7 | ADC_initialized = true;
|
8 |
|
9 | // configure the pin
|
10 | setGpioPort(ADC_PORT, (1 < ADC_PIN), IN, false);
|
11 |
|
12 | // reference voltage: AVcc
|
13 | ADMUX = (0 < REFS1) | (1 < REFS0);
|
14 |
|
15 | // left-adjusted result -> ADCH yields the 8 bit value
|
16 | ADMUX |= (1 < ADLAR);
|
17 |
|
18 | // choose the ADC channel
|
19 | //ADMUX |= (ADC_CHANNEL < MUX0);
|
20 | ADMUX |= 0x07;
|
21 |
|
22 | // enable auto trigger (required for free running mode)
|
23 | ADCSRA = (1 < ADATE);
|
24 |
|
25 | // adjust the prescaler to get the right ADC clock
|
26 | //ADCSRA |= (ADPS_val < ADPS0);
|
27 | ADCSRA |= 0x07;
|
28 |
|
29 | // free running mode
|
30 | SFIOR &= ~((1 < ADTS2) | (1 < ADTS1) | (1 < ADTS0));
|
31 | }
|
32 |
|
33 | void ADC_start(void) {
|
34 | if (!ADC_initialized) return;
|
35 |
|
36 | // enable ADC and start sampling
|
37 | ADCSRA |= (1 < ADEN);
|
38 | ADCSRA |= (1 < ADSC);
|
39 | }
|
40 |
|
41 | void ADC_stop(void) {
|
42 | ADCSRA &= ~((1 < ADEN) | (1 < ADSC));
|
43 | ADCSRA |= (1 < ADIF);
|
44 | }
|
45 |
|
46 | void ADC_enableInterrupt(void) {
|
47 | if (!ADC_initialized) return;
|
48 |
|
49 | // clear interrupt flag and enable interrupt
|
50 | ADCSRA |= (1 < ADIF);
|
51 | ADCSRA |= (1 < ADIE);
|
52 | }
|
53 |
|
54 | void ADC_disableInterrupt(void) {
|
55 | ADCSRA &= ~(1 < ADIE);
|
56 | }
|
57 |
|
58 | uint8_t ADC_getValue(void) {
|
59 | if (!ADC_initialized) return 0;
|
60 |
|
61 | uint8_t temp = ADCH;
|
62 | return temp;
|
63 | }
|
64 | ------------------------------
|
65 |
|
66 | Aus adc_test.c:
|
67 |
|
68 | volatile uint8_t bla = 0;
|
69 |
|
70 |
|
71 | int main(void) {
|
72 | LCD_init();
|
73 | LCD_setContrast(0xC0);
|
74 |
|
75 | sei();
|
76 |
|
77 | ADC_init();
|
78 | ADC_enableInterrupt();
|
79 | ADC_start();
|
80 |
|
81 | uint8_t oldBla = bla;
|
82 | uint8_t adcVal;
|
83 | _delay_ms(10);
|
84 | adcVal = ADC_getValue();
|
85 | printf("%d", adcVal);
|
86 |
|
87 | while (1) {
|
88 | _delay_ms(1);
|
89 | uint8_t temp = ADC_getValue();
|
90 | if (temp != adcVal) {
|
91 | adcVal = temp;
|
92 | LCD_clear();
|
93 | printf("%u", adcVal);
|
94 | }
|
95 |
|
96 | if (bla != oldBla) {
|
97 | LCD_clear();
|
98 | printf("%X", bla);
|
99 | oldBla = bla;
|
100 | }
|
101 | }
|
102 | }
|
103 |
|
104 | ISR(ADC_vect) {
|
105 | bla++;
|
106 | }
|
Der Interrupt ist hier nur zu Test-Zwecken aktiv und sollte eine zahl
auf dem Display hochzählen, wenn eine Wandlung abgeschlossen ist. Dies
scheint niemals der Fall zu sein, also ist, denke ich, bei der
Konfiguration des ADC was faul.
Folgende Sachen hab ich ausprobiert:
- mit/ohne Interrupt
- mit/ohne explizitem clear des Interrupt-Flags (das Flag triggert ja im
free running)
- alle Einstellungen doppelt und dreifach überprüft... es bleibt dabei,
auf dem LCD bleibt die 0 stehen
Meine wichtigste Erkenntnis bisher ist wohl, dass der ADC gar nicht
anzulaufen scheint, aber ich komme trotzdem nicht weiter. Könnt ihr mir
weiter helfen?