Forum: Mikrocontroller und Digitale Elektronik ATmega88 - ADC - free running mode


von Schmidt (Gast)


Lesenswert?

Hallo ihr Lieben

ich möchte den ADC im ATmega88 im Free running Modus betreiben, aber es 
geling mir nicht. Bei der Simulation mit AVR-Studio wird beim ADC-Enable 
einmal das ADC-Interrupt bei fertiger Messung aufgerufen und dann nicht 
mehr. Er scheint nicht im Freerunning mode zu sein. Ich habe das 
Datenblatt Stück für Stück abgearbeitet. Irgend etwas muss ich übersehen 
haben oder ich mache eine groben Fehler.

Vielleicht sieht einer von euch den Fehler und kann mir helfen. Vielen 
Dank.
1
///[...]
2
/* ADC */
3
#define ADC_PRESCALER 2
4
5
//[...]
6
/* DataPins */
7
#define PIN_DATAIN (1<<PC4)
8
#define PIN_DATAOUT (1<<PC5)
9
10
/* DisplayPins */
11
#define PIN_OUTERDSPL (1<<PD1)
12
#define PIN_INNERDSPL (1<<PD0)
13
14
/* TasterPins */
15
#define PIN_TASTER1 (0<<PD0)
16
17
#define DEBUG
18
#define ADCTEST
19
20
21
22
#include <avr/io.h>
23
#include <stdint.h>
24
#include <avr/interrupt.h>
25
#include "timer1/timer1.c"
26
#include "adc/adc.c"
27
#include "io/io.c"
28
//#include <util/delay.h>
29
30
31
int main (void) {
32
33
  /* Initialisation */
34
35
    /* DataOUT/IN */
36
      DDRC |= PIN_DATAOUT; //Define Pin as Output
37
      DDRC &= ~PIN_DATAIN; //Define Pin as Input
38
    
39
      //DDRB = 0b11111111; //Set all Pins as Output
40
      //PORTB = 0b00000000;
41
  
42
    /* DisplayOUT */
43
      DDRD |= PIN_OUTERDSPL; //Define Pin as Output
44
      DDRD |= PIN_INNERDSPL; //Define Pin as Output
45
46
      #ifdef DEBUG
47
        DDRD |= (1<<PD3)|(1<<PD4); //Define Pin as Output
48
      #endif
49
  
50
    /* Taster */
51
    
52
    /* Timer */
53
//      Timer1_init();
54
  
55
    /* ADC */
56
      ADC_init();
57
      ADC_SetChannel(7);
58
59
  /* END Initialisation */
60
  
61
  /* Referenzwerte Messen */
62
    sei(); //Global Enable Interrupts
63
    //messen
64
    //auswerten
65
    //messen
66
    //auswerten
67
    
68
69
  ADC_Enable();
70
  ADC_StartConversion();
71
72
73
    while(1) {
74
    if( (PINC & PIN_DATAIN) != PIN_DATAIN ){ //Wenn low
75
      PORTD |= PIN_OUTERDSPL;
76
    }else{
77
      PORTD &= ~PIN_OUTERDSPL;
78
    }
79
80
    //ADC-Werte Berechnen;
81
  }
82
83
  return 0;
84
}
85
86
87
88
//[...]
89
90
ISR(ADC_vect){
91
  #ifdef DEBUG
92
    PORTD |= (1<<PD3);
93
  #endif
94
  
95
  /* ADC Conversion Complete Interrupt */
96
  //Messdaten speichern
97
  ADC_GetHData();
98
99
  #ifdef DEBUG
100
    PORTD &= ~(1<<PD3);
101
  #endif
102
}

adc.c:
1
#include <stdint.h>
2
3
void ADC_init(void){
4
  /* Voltage Reference for the ADC: */
5
    ADMUX |= (0<<REFS1) | (0<<REFS0); //AREF, Internal Vref turned off
6
    //ADMUX |= (0<<REFS1) | (1<<REFS0); //AVcc with external capacitor at AREF pin
7
    //ADMUX |= (1<<REFS1) | (1<<REFS0); //Internal 1.1V Voltage Reference with external capacitor at AREF pin
8
  
9
  
10
  /* ADC Left Adjust Result: */
11
    ADMUX |= (1<<ADLAR); //Write one to left adjust the result. Otherwise, the result is right adjusted.
12
  
13
  
14
  /* ADC Control and Status Register A: */
15
    /* ADC Auto Trigger Enable: */
16
    ADCSRA |= (1<<ADATE); //When this bit is written to one, Auto Triggering of the ADC is enabled. The ADC will start a conversion on a positive edge of the selected trigger signal. The trigger source is selected by setting the ADC Trigger Select bits, ADTS in ADCSRB.
17
    
18
    /* ADC Interrupt Flag */
19
  
20
    /* ADC Interrupt Enable */
21
    ADCSRA |= (1<<ADIE);  //When this bit is written to one and the I-bit in SREG is set, the ADC Conversion Complete Interrupt is activated.
22
  
23
    /* ADC Prescaler Select Bits */
24
  #ifndef ADC_PRESCALER
25
    #define ADC_PRESCALER 128
26
  #endif
27
  #if ADC_PRESCALER == 2
28
    ADCSRA |= (0<<ADPS2) | (0<<ADPS1) | (0<<ADPS0); //Division Factor: 2
29
  #elif ADC_PRESCALER == 2
30
    ADCSRA |= (0<<ADPS2) | (0<<ADPS1) | (1<<ADPS0); //Division Factor: 2
31
  #elif ADC_PRESCALER == 4
32
    ADCSRA |= (0<<ADPS2) | (1<<ADPS1) | (0<<ADPS0); //Division Factor: 4
33
  #elif ADC_PRESCALER == 8
34
    ADCSRA |= (0<<ADPS2) | (1<<ADPS1) | (1<<ADPS0); //Division Factor: 8
35
  #elif ADC_PRESCALER == 16
36
    ADCSRA |= (1<<ADPS2) | (0<<ADPS1) | (0<<ADPS0); //Division Factor: 16
37
  #elif ADC_PRESCALER == 32
38
    ADCSRA |= (1<<ADPS2) | (0<<ADPS1) | (1<<ADPS0); //Division Factor: 32
39
  #elif ADC_PRESCALER == 64
40
    ADCSRA |= (1<<ADPS2) | (1<<ADPS1) | (0<<ADPS0); //Division Factor: 64
41
  #else
42
    ADCSRA |= (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0); //Division Factor: 128
43
  #endif
44
  
45
  /* ADC Control and Status Register B: */
46
    /* ADC Auto Trigger Source */
47
    ADCSRB |= (0<<ADTS2) | (0<<ADTS2) | (0<<ADTS2); //Trigger Source: Free Running mode
48
    //ADCSRB |= (0<<ADTS2) | (0<<ADTS2) | (1<<ADTS2); //Trigger Source: Analog Comparator
49
    //ADCSRB |= (0<<ADTS2) | (1<<ADTS2) | (0<<ADTS2); //Trigger Source: External Interrupt Request 0
50
    //ADCSRB |= (0<<ADTS2) | (1<<ADTS2) | (1<<ADTS2); //Trigger Source: Timer/Counter0 Compare Match A
51
    //ADCSRB |= (1<<ADTS2) | (0<<ADTS2) | (0<<ADTS2); //Trigger Source: Timer/Counter0 Overflow
52
    //ADCSRB |= (1<<ADTS2) | (0<<ADTS2) | (1<<ADTS2); //Trigger Source: Timer/Counter1 Compare Match B
53
    //ADCSRB |= (1<<ADTS2) | (1<<ADTS2) | (0<<ADTS2); //Trigger Source: Timer/Counter1 Overflow
54
    //ADCSRB |= (1<<ADTS2) | (1<<ADTS2) | (1<<ADTS2); //Trigger Source: Timer/Counter1 Capture Event
55
        
56
  /* Digital Input Disable Register 0: */
57
        
58
}
59
60
void ADC_SetChannel(uint8_t channel){
61
  if(0<= channel && channel <= 7){
62
    /* ADC Multiplexer Selection Register */
63
      //ADMUX |= (0<<MUX3) | (1<<MUX2) | (1<<MUX1) | (1<<MUX0);
64
      ADMUX |= channel;
65
  }
66
}
67
68
void ADC_Enable(void){
69
  /* ADC Control and Status Register A */
70
  ADCSRA |= (1<<ADEN); //Writing this bit to one enables the ADC. By writing it to zero, the ADC is turned off. Turning the ADC off while a conversion is in progress, will terminate this conversion.
71
}
72
73
void ADC_Disable(void){
74
  /* ADC Control and Status Register A */
75
  ADCSRA &= ~(1<<ADEN); //Writing this bit to one enables the ADC. By writing it to zero, the ADC is turned off. Turning the ADC off while a conversion is in progress, will terminate this conversion.
76
}
77
78
void ADC_StartConversion(void){
79
  /* ADC Control and Status Register A */
80
  ADCSRA |= (1<<ADSC); //In Single Conversion mode, write this bit to one to start each conversion. In Free Running mode, write this bit to one to start the first conversion.
81
}
82
83
uint8_t ADC_GetHData(void){
84
  /* ADC Data Register - Highbyte*/
85
  return ADCH;
86
}

von Walter (Gast)


Lesenswert?

vielleicht den ADMUX mal auf 0 setzen und nicht immer bloss die Bits 
rein odern?

von Schmidt (Gast)


Lesenswert?

Hallo

ich verstehe nicht ganz was du meinst. Standart-Anfanagswert von ADMUX 
ist 0. Ich oder dann Einsen hinein, wenn nötig. (Übersichtshalber oder 
ich manchmal auch Nullen hinein, aber das ist ja gleichgültig)

Ist irgendwo ein Fehler, oder ein potenzieller Fehler?

Welchen Teil genau meinst du? Die MUX-Kanalwahl?

Danke dir.

von Günter J. (gjung)


Lesenswert?

Hallo,

wenn Du Bits auf 0 setzen willst, dann must Du ein
AND mit dem Komplement machen, ein OR mit 0 ist ein NOP.

siehe
1
ADMUX |= (0<<REFS1) | (0<<REFS0);
und ähnliche Zeilen.

Also richtig wäre:
1
ADMUX &= ~((1<<REFS1) | (1<<REFS9));

Gruß,
Günter

von Schmidt (Gast)


Lesenswert?

Vielen Dank.

Ja, ich weiß, dass so keine Bits gelöscht werden.
1
ADMUX |= (0<<REFS1) | (0<<REFS0);

Da das Register as Defaultwert mit Nullen initialisiert ist, wäre das 
Löschen überflüssig.Somit die Zeilen auch überflössig. Ich habe die 
Zeilen des Verständnisses und der Übersicht wegen trotzdem 
hingeschrienen. Aber ihr habt recht, sicher ist sicher, ich werde es 
ändern.

Die Register bits haben also trotzdem die gewünschten Werte gehabt und 
der Free running mode lässt auf sich warten.

Habt ihr eine Idee, weshalb der ADC nicht losrennen will?

Ich vermute stark, dass es an einem Fehler im Code liegt und kein bug 
des AVR-Studio-Simulators ist. Aber mit gewissheit kann ich es natürlich 
nicht sagen.

Ich wäre euch sehr dankbar.

Schmidt

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

Schmidt schrieb:
> Ich vermute stark, dass es an einem Fehler im Code liegt und kein bug
> des AVR-Studio-Simulators ist. Aber mit gewissheit kann ich es natürlich
> nicht sagen.
Du könntest im AVR Studio mal unter den Bekannten Einschränkungen 
nachsehen...

Ansosnten hatte ich auch mal das Problem das im Freerunning Mode das 
interuptbit nicht automatisch von der HW zurückgesezt wurde.

von Schmidt (Gast)


Lesenswert?

Vielen Dank für den Hinweis mit dem ADC Interupt Flag.

Folgendes habe ich festgestellt:

Nach einem ADC Start Conversation (ADSC = 1) startet eine Messung.
Nach der Messung wird und bleibt das ADSC Flag aber gelöscht.
Wenn ich es im Simulator wieder auf ADSC=1 setzte, dann tritt wieder 
eine Messung ein. ADSC wird aber immer wieder nach der Messung gelöscht. 
Laut Datenblatt sollte es (ich hoffe ich irre mich nicht) im Free 
Running Mode jedoch auf 1 bleiben.

Das ADC Interrupt Flag (ADIF wird laut Anzeige im Simulator garnicht 
gesetzt. Vielleicht wird es nur nicht angezeigt, wer weiß. Scheint 
jedoch kein Problem darzustellen.)

So, nun haben wir erkannt, woran es scheinbar liegt. Das ADSC wird nach 
der Messung gelöscht.

Nun bleibt die Frage WARUM?

Ist das Problem jemandem bekannt? Lösungsidee? Habe ich etwas falsch 
eingestellt?

Danke.

von Jean (Gast)


Lesenswert?

Hi,
ich würde das mal auf deinem µC testen und nicht nur im Avr-Studio.
Da gibt es genug Bugs im Studio.

Gruß

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.