Forum: Mikrocontroller und Digitale Elektronik ADC Atmega16 single mode


von Martin Sörensen (Gast)


Lesenswert?

Hallo,

ich hatte bisher immer einen single mode beim ADC Atmega8 verwendet. Nun 
wollte ich auf differential mit Atmega16 umstellen. Dabei habe ich auch 
den Programmcode geändert. Da ich es nicht ganz hinbekommen habe wollte 
ich nun zurück zu single mode wechseln. Nun klappt gar nichts mehr -.- 
und ich sehe den Fehler nicht. Kann eventuell einer von euch über den 
Code schauen?

Ich habe momentan GND an ADC0 anliegen. Dennoch wird mir immer der Wert 
276 angezeigt.
1
#include <avr/io.h>
2
#include <util/delay.h>
3
4
void adc_init( void )
5
{ 
6
  ADMUX = (1<<REFS1) | (1<<REFS0);
7
  _delay_us( 10 );
8
 // ADCSRA = (1<<ADPS1) | (1<<ADPS0);     // Frequenzvorteiler, Dummyreadout
9
  ADCSRA = (1<<ADPS2);     // Frequenzvorteiler, Dummyreadout
10
  ADCSRA |= (1<<ADEN);                  // ADC aktivieren
11
  ADCSRA |= (1<<ADSC);                  // eine ADC-Wandlung
12
  while (ADCSRA & (1<<ADSC)) {         // auf Abschluss der Konvertierung warten
13
  }
14
  (void) ADCW;
15
}
16
17
18
uint16_t ADC_Read_single()
19
{
20
21
  //ADMUX = (0<<MUX4) | (0<<MUX3) | (0<<MUX2) | (0<<MUX1) | (0<<MUX0);
22
  ADCSRA |= (1<<ADSC);            // eine Wandlung "single conversion"
23
  while (ADCSRA & (1<<ADSC) ) {   // auf Abschluss der Konvertierung warten
24
  }
25
  return ADCW;                    // ADC auslesen und zurückgeben
26
  
27
}

=======================
1
#include <avr/io.h>
2
#include <util/delay.h>
3
#include <stdlib.h>
4
#include "lcd-routines.h"
5
#include "myADC.h"
6
7
uint16_t adcval;
8
9
int main(void)
10
{
11
   adc_init();
12
   lcd_init();
13
      
14
  while(1)
15
  {
16
    adcval = ADC_Read_single;  
17
18
    lcd_setcursor(0,1);
19
    
20
    char Buffer[20];
21
    itoa( adcval, Buffer, 10 );
22
    lcd_string( Buffer );
23
    
24
    _delay_us( 100 );
25
  }
26
}

von Thomas H. (Firma: CIA) (apostel13)


Lesenswert?

Was genau macht das:
1
(void) ADCW;

in deinem Code?

von Martin Sörensen (Gast)


Lesenswert?

Das soll ein dummy auslesen sein. Hab ich im Netz gesehen. Kann man 
sicher auch anders machen bspw. return ADCW. Führt aber leider auch 
nicht zum Erfolg :(

von Martin Sörensen (Gast)


Lesenswert?

Kann man den Atmega wieder initial setzen? Vielleicht habe ich ja ein 
Register falsch gesetzt durch das herumprobieren, welches nun "falsch" 
steht.

von Thomas H. (Firma: CIA) (apostel13)


Lesenswert?

Und was bedeutet das:
1
//ADMUX = (0<<MUX4) | (0<<MUX3) | (0<<MUX2) | (0<<MUX1) | (0<<MUX0);

von Thomas H. (Firma: CIA) (apostel13)


Lesenswert?

Wo ist diese Variable definiert, die Du zurück gibst

1
ADCW

von Martin Sörensen (Gast)


Lesenswert?

damit hatte ich zwischen den ADC-Eingängen umgeschaltet aber sollte 
jetzt grundsätzlich auf "0" stehen, sodass nur ADC0 für die single conv. 
verwendet wird.

Hatte ich ursprünglich verwendet, um auf diff-mode umzustellen (dann 
natürlich nicht mit 00000 sondern 01011).

von Martin Sörensen (Gast)


Lesenswert?

Thomas H. schrieb:
> Wo ist diese Variable definiert, die Du zurück gibst
>
> ADCW

Ich habe angenommen, dass ich keine Variable benötige. Das ist doch ein 
Register im Atmega

von Thomas H. (Firma: CIA) (apostel13)


Lesenswert?

Worauf ich hinaus will, Du hast "C" noch nicht so ganz verstanden, kann 
das sein?

von Martin Sörensen (Gast)


Lesenswert?

Bin nicht Profi das ist richtig. Bin froh, dass ich mein LCD zum 
Anzeigen bekomme und Relais schalten kann. Nun möchte ich mich auch mal 
am ADC versuchen.

von Peter II (Gast)


Lesenswert?

Thomas H. schrieb:
> Worauf ich hinaus will, Du hast "C" noch nicht so ganz verstanden, kann
> das sein?

oder du?
1
(void) ADCW;

ist ok, und macht auch sinn.

von Thomas H. (Firma: CIA) (apostel13)


Lesenswert?

Wie kommst Du denn auf den Code...? Zusammengewürfelt aus Beispielen, 
oder selber ausgedacht mit Datenblatt zur Hand?

Warum hast Du den Vorteiler so genommen wie Du es getan hast? Warum die 
interne Ref Spannung auf 2,56V Hast Du einen Kondensator am AREF pin?

Mit wieviel MhZ läuft dein Atmega8

von Martin Sörensen (Gast)


Lesenswert?

Ich habe mit einem Tutorial hier angefangen und das dann über das manual 
auf meine benötigten Funktionalitäten angepasst (bspw. nur single 
conversion und fest definierten channel).

Die interne Ref Spannung habe ich verwendet um "klein" anzufangen. 
Wollte einfach mal schauen wie das so funktioniert und dafür war Vref 
ausreichend. Einen Kondensator habe ich nicht angeschlossen.

Atmega läuft mit 1 Mhz. Das sollte sich auch mit F_CPU decken, sonst 
würde das LCD nichts anzeigen.

von Thomas H. (Firma: CIA) (apostel13)


Lesenswert?

Hier ein minimalistisches funktionierendes Beispiel, entsprechend an LCD 
anpassen:
1
//*******************************************************************************
2
//*
3
//* ADC single conv demonstration
4
//* Datum: 19/01/2014 Version:
5
//* Autor: Dr. ThXXXXXXXXX
6
//*
7
//* Informationen zur Beschaltung:
8
//* SDK600 SOIC
9
//* Prozessor: ATmega8 Quarzfrequenz: INT  1Mhz
10
//* Eingaenge: PORTC PC0 <- Potentiometer (VCC  PC0   GND)
11
//* Ausgaenge: PORTB 8 LED'S
12
//*
13
//* Informationen zur Funktionsweise: Binäre Ausgabe des HI anteils des ADC auf PORTB
14
//*
15
//*******************************************************************************
16
#define F_CPU 1000000UL
17
#include <avr/io.h>
18
19
20
21
22
int main(void)
23
{
24
  uint8_t adclow;
25
  uint8_t adchigh;
26
  
27
  
28
  //setup PortB output
29
  DDRB  = 0b11111111;
30
  PORTB  = 0b11111111;
31
  //initialisaton of ADC0 Vref = VCC, fCPU/8, left adjusted
32
  ADMUX  |= (1<<REFS0) | (1<<ADLAR);
33
  ADCSRA  |= (1<<ADEN) | (1<<ADPS1) | (1<<ADPS0);
34
  
35
  
36
  while(1)
37
    {  
38
        
39
    ADCSRA |= (1<<ADSC);
40
    while(ADCSRA & (1<<ADSC));
41
    
42
    adclow = ADCL;
43
    adchigh= ADCH;
44
    
45
    
46
    
47
    //ausgabe nur wenn unterschied zu vorheriger messung  > 10
48
    
49
    if(abs(PORTB-adchigh)>10)
50
    PORTB = adchigh;
51
    
52
        
53
    }
54
}
55
}

von Martin Sörensen (Gast)


Lesenswert?

Danke jetzt funktioniert es wieder mit single conv. Den Fehler verstehe 
ich zwar dennoch nicht aber das hilft mir weiter. Danke!

von Thomas H. (Firma: CIA) (apostel13)


Lesenswert?

Funktioniert es jetzt wieder mit deinem Code, oder mit dem Beispiel?

von Martin Sörensen (Gast)


Lesenswert?

Mit deinem Beispiel angepasst auf LCD.

von Martin Sörensen (Gast)


Lesenswert?

Ich habe jetzt auf diff mode geswitcht. Funktioniert super.

Nur noch eine Frage zur Versätkrung mit 200x.  Was genau verstärkt er 
hier? Beide Eingänge falls die Differenz im mV Bereich liege um diese 
dennoch zu identifizieren? Sprich sollte ich einen sehr großen 
Unterschied feststellen wird mir ab einer bestimmten Schranke immer 255 
angezeigt, also irgendwann könnte der ADC den Unterschied nicht mehr 
messen da er aufgrund der 200x außerhalb der Range liegt. Ist das so?

von Martin Sörensen (Gast)


Lesenswert?

Okay habs schnell mal ausprobiert. Die Verstärkung ändert tatsächlich 
die Auflösung. Ist ja geil :)

von Karl H. (kbuchegg)


Lesenswert?

Martin Sörensen schrieb:

>   while(1)
>   {
>     adcval = ADC_Read_single;

Das hier ist KEIN Funktionsaufruf.

Wie hast du das durch den Compiler gebracht?

von Thomas E. (thomase)


Lesenswert?

Karl H. schrieb:
> Wie hast du das durch den Compiler gebracht?

Das gibt doch nur eine Warnung:
1
warning: assignment makes integer from a pointer without a cast.

Und Warnungen ignoriert man. Wusstest du das nicht?

Wenn man nochmal kompiliert ist sie weg.

"Na, da hat der Compiler sich wohl beim ersten Mal geirrt."

mfg.

von Karl H. (kbuchegg)


Lesenswert?

Thomas E. schrieb:
> Karl H. schrieb:
>> Wie hast du das durch den Compiler gebracht?
>
> Das gibt doch nur eine Warnung:

Hoffen wir mal, dass der TO (sollte er noch einmal reinschauen) seine 
Lektion gelernt hat.

von Thomas H. (Firma: CIA) (apostel13)


Lesenswert?

Peter II schrieb:
> oder du?
> (void) ADCW;
>
> ist ok, und macht auch sinn.

Abgesehen von der Tatsache das die Frage darauf abzielte zu evaluieren 
ob der TO weiss was er da macht und in keiner Weise von mir offen, oder 
implizit darauf hingewiesen wurde das diese Instruktion an dieser Stelle 
falsch sei, oder generell keinen Sinn macht, würde mich an dieser Stelle 
aber natürlich interessieren warum das genau "hier" Ok ist und auch noch 
einen Sinn hat. Ich lerne nämlich immer gerne etwas dazu. Vielen Dank im 
Voraus!

von Thomas H. (Firma: CIA) (apostel13)


Lesenswert?

@Peter II

..wie ich mir dachte, da kommt nichts mehr. Früher in der Schule nannten 
wir so Leute "Klugscheisser". Nach der Schule waren die einsam, heute 
machen Sie auch nach Schulfrei im Internet weiter..

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.