Forum: Compiler & IDEs Init ADC beim ATT85


von Pierre G. (bqube)


Lesenswert?

Guten Abend,

ich schreibe momentan für ein anderes Projekt ein Program, wo ich die 
Spannung über den ADC (PB4) Eingang am ATT85 einlese, verwerte und 
ausgebe.

Ich hatte schon mal erfolgreich mit einem Atmega8 eine ADC Wandlung plus 
Auswertung zum laufen gebracht und dachte mir ich benutzte die gleiche 
Init. die im GCC Tut angegeben ist für den ATT85.
1
void ADC_Init(void)
2
{
3
 
4
  ADMUX = (1<<REFS2);    
5
  ADCSRA = (1<<ADPS1) | (1<<ADPS0);
6
  ADCSRA |= (1<<ADEN);
7
  ADCSRA |= (1<<ADSC);
8
  while (ADCSRA & (1<<ADSC) ) 
9
  {         
10
  }
11
  (void) ADCW;
12
}

Nach der Init. soll eine LED ein paar mal Blinken aber soweit kommt es 
garnicht, klammer ich die Init. aus (rufe sie vom Program her nicht auf)
dann fängt die LED an zu Blinken.

Stimmt was mit meiner Initialisierung nicht ?

Mfg Bqube

von Thomas E. (thomase)


Lesenswert?

Pierre Gnauck schrieb:
> Stimmt was mit meiner Initialisierung nicht ?

Eigentlich nicht. Zumindest sollte der Controller nach der Init mit 
seinem Normalprogramm weiterlaufen.

Das ist allerdings Quatsch:
> ADMUX = (1<<REFS2);

Wenn du Vcc als Referenz nutzen willst, musst du an der Stelle gar 
nichts einstellen. Der Wert von REFS2 ist hier zwar egal, aber dann 
lässt man ihn auf 0. Alles andere verwirrt nur.

Was allerdings nicht eingetellt ist, ist der Eingang. PB4 ist ADC2. Im 
Moment misst du an ADC0, also an PB5(Reset). Das schadet aber auch 
nicht.

Zeig mal das ganze Programm.

mfg.

von Pierre G. (bqube)


Lesenswert?

Das hier wäre das gesamte Programm:
1
#include <avr/io.h>
2
#ifndef F_CPU
3
#define F_CPU 1000000
4
#endif
5
#include <util/delay.h>
6
7
void ADC_Init(void)
8
{
9
 
10
  ADMUX = (1<<REFS2);    
11
  ADCSRA = (1<<ADPS1) | (1<<ADPS0);
12
  ADCSRA |= (1<<ADEN);
13
  ADCSRA |= (1<<ADSC);
14
  while (ADCSRA & (1<<ADSC) ) 
15
  {         
16
  }
17
  (void) ADCW;
18
}
19
20
21
22
uint16_t ADC_Read( uint8_t channel )
23
{
24
  ADMUX = (ADMUX & ~(0x1F)) | (channel & 0x1F);
25
  ADCSRA |= (1<<ADSC);
26
  while (ADCSRA & (1<<ADSC) ) {
27
  }
28
  return ADCW;
29
}
30
31
int main( void )
32
{
33
  DDRB = 0x03;
34
  uint16_t adcval;
35
  ADC_Init();
36
  
37
  PORTB |= (1<<0);
38
  _delay_ms(500);
39
  PORTB &=~ (1<<0);
40
  _delay_ms(500);
41
  PORTB |= (1<<0);
42
  _delay_ms(500);
43
  PORTB &=~ (1<<0);
44
  
45
  while( 1 ) {
46
    adcval = ADC_Read(2);
47
    ADC_Read();
48
    
49
    if(adcval >= 860)
50
    {
51
      PORTB |= (1<<0);
52
    }
53
    
54
    if(adcval <=840)
55
    {
56
      PORTB &=~ (1<<0);
57
    }
58
  }
59
}

Mfg Bqube

von Thomas E. (thomase)


Lesenswert?

Das Programm läuft fast.

Das geht natürlich nicht:

Pierre Gnauck schrieb:
> ADC_Read();

Das kompiliert gar nicht. Aber sonst tut es eigentlich, was es soll.


1
#ifndef F_CPU
2
   #define F_CPU 1000000      //Unschoen
3
//   #error F_CPU not defined.  //Besser. Hat man sich aucht anders verdient.
4
#endif
5
6
#include <avr/io.h>
7
#include <util/delay.h>
8
9
void ADC_Init(void)
10
{ 
11
  ADCSRA = (1<<ADPS1) | (1<<ADPS0) | (1<<ADEN) | (1<<ADSC);
12
  while (ADCSRA & (1<<ADSC));
13
  (void)ADC;
14
}
15
16
uint16_t ADC_Read(uint8_t channel)
17
{
18
  ADMUX &= ~(0x0F);
19
  ADMUX |= (channel & 0x0F);
20
  ADCSRA |= (1<<ADSC);
21
  while (ADCSRA & (1<<ADSC));
22
  return ADC;
23
}
24
25
int main( void )
26
{
27
  DDRB |= (1 << 1) | (1 << 0);
28
  uint16_t adcval;
29
  ADC_Init();
30
  
31
  PORTB |= (1<<0);
32
  _delay_ms(500);
33
  PORTB &= ~(1<<0);
34
  _delay_ms(500);
35
  PORTB |= (1<<0);
36
  _delay_ms(500);
37
  PORTB &= ~(1<<0);
38
  
39
  while(1) 
40
  {
41
    adcval = ADC_Read(2);
42
    
43
    if(adcval >= 860)
44
    {
45
      PORTB |= (1<<0);
46
    }
47
    
48
    if(adcval <=840)
49
    {
50
      PORTB &= ~(1<<0);
51
    }
52
  }
53
}

Ich habe ein paar Kleinigkeiten verändert. Sonst schiesst du dir ins 
Knie, wenn du das mal anders verwendest(ADMUX/Ref). Es lief vorher aber 
auch. Aber jetzt ist alles richtig. Richtiger sozusagen.

mfg.

von Pierre G. (bqube)


Lesenswert?

Vielen Dank für deine Hilfe, ich hab das ganze Compilert und direkt mal 
ausprobiert :-).

Jetzt schau ich mir noch deine Veränderung an und warum mein 
Uhrsprungscode nicht funktioniert hat.

Falls es jemanden Interessiert hier ist das Projekt dazu.

Beitrag "Spg_Auswertung_KFZ"

Mfg Bqube

von Pierre G. (bqube)


Lesenswert?

Moin moin,
Mir ist bis auf den Funktions Aufruf ADC_READ(); warum auch immer ich 
den drin hatte, nur aufgefallen das es nicht wie bei mir (void)ADCW; 
sonder nur (void)ADC; heißt ? War das etwar der Fehler.

MFG Bqube

von Thomas E. (thomase)


Lesenswert?

Läuft es denn jetzt?

Pierre Gnauck schrieb:
> ADMUX = (ADMUX & ~(0x1F)) | (channel & 0x1F);

Da steckt der Fehler drin. Das hat in diesem Fall aber zufällig keine 
Auswirkungen. Das Programm läuft ja auch in deiner Version. Bei auf 
diesen Lapsus hier:
> ADC_Read();
Aber damit kompiliert es auch nicht.

Warum es bei dir nicht lief oder immer noch nicht läuft, kann ich dir 
nicht sagen.

Aber das ADMUX wird hier platt gemacht, obwohl dort die Konfiguration 
der Referenzspannung drinsteckt. Und dann steht sie eben nicht mehr 
drin. Das hat hier keine Auswirkung, da die Referenzbits bei Vcc ohnehin 
alle 0 sind. Stellst du allerdings eine andere Referenz ein, schiesst du 
dir damit ins Knie und suchst dich tot. Weil sonst funktionierte es ja 
immer. Die zweite Sache dabei ist, dass auch bei Veroderung 5 Bits 
gelöscht werden, der Muxer aber nur mit 4 Bits eingestellt wird.

Ob ADC oder ADCW gelesen wird ist egal, da beides definiert ist:
1
#ifndef __ASSEMBLER__
2
#define ADC     _SFR_IO16(0x04)
3
#endif
4
#define ADCW    _SFR_IO16(0x04)


mfg.

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.