Forum: Mikrocontroller und Digitale Elektronik Atmega32, Poti, ADC, Poti-am LCD ausgeben


von Stefan S. (derprogrammierer2)


Lesenswert?

Hallo an alle!
Mein zweiter Post!

Und zwar will ich diesmal 2 Potis auf meinem Atmega32 Bord bedienen und 
den Zahlenwert am LCD-Display ausgeben. Am Ausgeben scheitert es bei 
mir:
1
// system-includes
2
#include <avr/io.h>
3
// lokale includes
4
#include "..\LCD\lcd.h"
5
// Prototyps
6
void AD_Init();
7
unsigned char ucGetADValue_8Bit(char cAD_Channel);
8
char* Convert_ADU_to_Text(unsigned char ADC_Value);
9
10
11
int main(void)
12
{
13
  unsigned char ADC_Value_CH1,ADC_Value_CH2;    // unsigned nur im positiven bereich
14
  char Text[21];        // 21 Zeichen weil LCD hat 20 + ENTER
15
  
16
  lcd_init();
17
  lcd_blank();
18
  
19
    while(1)
20
    {
21
    // Beide Potis einlesen
22
        ADC_Value_CH1 = ucGetADValue_8Bit (1);
23
    ADC_Value_CH2 = ucGetADValue_8Bit (2);  // nicht sicher ob der 2er richtig ist
24
    
25
    // Anzeigen der ADU Werte
26
    lcd_print(1,0,Convert_ADU_to_Text(ADC_Value_CH1));
27
    lcd_print(2,0,Convert_ADU_to_Text(ADC_Value_CH2));
28
    
29
    }
30
}
31
32
char* Convert_ADU_to_Text(unsigned char ADC_Value)
33
{
34
  // Funktion 
35
}
36
37
// Initialisierung des ADU
38
void AD_Init()
39
{
40
  // interne Referenzspannung von 5V .. VCC
41
  //    REFS0 .. 1
42
  //    REFS1 .. 0
43
  // Ausrichtung des Ergebnisses im ADCL und ADCH -- Rechts
44
  //    ADLAR = 0
45
  // Auswahl des Kanals
46
  //    MUX0...MUX4 alle 0 --> ADC0 --> Kanal 0 ausgewählt
47
  
48
  // ADMUX = 0x40;
49
  // oder
50
  ADMUX = (1 << REFS0);
51
  
52
  // ADEN=1 ... Einschalten des ADC
53
  // Prescaler setzen ... auf 128 --> 125kHz automatik Umsetzung
54
  // ADPS0..2 alle auf 1
55
  // eine Möglichkeit:  ADCSRA = 0x87;    // 1000 0111
56
  // oder
57
  ADCSRA = (1<<ADEN) | (1<<ADPS0) | (1<<ADPS1) | (1<<ADPS2);
58
}
59
60
61
// Unterste 8 Bit - ADCLOW nehmen wir
62
unsigned char ucGetADValue_8Bit(char cAD_Channel)
63
{
64
  AD_Init();  // Initialisierung
65
  // Kanal einstellen ... vorher alle Kanäle löschen - tut das ADInit schon
66
  ADMUX |= cAD_Channel;
67
  
68
  // Starten der Umsetzung
69
  ADCSRA |= (1<<ADSC);
70
  
71
  // warten bis die Umsetzung fertig ist
72
  while (ADCSRA & (1<<ADSC))
73
  {
74
    ;
75
  }
76
  
77
  // Ergebnis auslesen
78
  return(ADCL);  
79
  
80
}

So schaut mein Programm aus. Wie realisiere ich das jetzt mit sprintf, 
itoa usw?  Also im Unterprogramm wo // Funktion steht

p.s: Danke euch schon im Vorraus! Entschuldige mich für meine Kommentare 
im Programm falls etw falsch ist haha , sind nur meine Gedanken

: Verschoben durch User
von Stefan S. (derprogrammierer2)


Lesenswert?

wäre echt super, wenn mir irgendwer helfen könnt :( verzweifle grad

von Ralph W. (ralph_w713)


Lesenswert?

Stefan S. schrieb:
> #include "..\LCD\lcd.h"

mir kommt der include ein wenig falsch vor!

von Stefan S. (derprogrammierer2)


Lesenswert?

Ralph W. schrieb:
> Stefan S. schrieb:
>> #include "..\LCD\lcd.h"
>
> mir kommt der include ein wenig falsch vor!

ich könnt auch nur lcd.h reinschreiben

von Wolfgang A. (Gast)


Lesenswert?

Stefan S. schrieb:
> ich könnt auch nur lcd.h reinschreiben

Reinschreiben kannst du da vieles. Nützen tut es nur etwas, wenn die 
Datei dort auch liegt.

von Stefan S. (derprogrammierer2)


Lesenswert?

Wolfgang A. schrieb:
> Stefan S. schrieb:
>> ich könnt auch nur lcd.h reinschreiben
>
> Reinschreiben kannst du da vieles. Nützen tut es nur etwas, wenn die
> Datei dort auch liegt.

es liegt nicht an den Includes, sondern am Programm. da bin ich mir 
sicher

: Bearbeitet durch User
von Rene H. (Gast)


Lesenswert?

Was für ein Display? Wie angeschlossen etc. etc.

Im Zweifelsfall nimm die Fleury Lib.

Grüsse,
R.

von Stefan S. (derprogrammierer2)


Lesenswert?

Rene H. schrieb:
> Was für ein Display? Wie angeschlossen etc. etc.
>
> Im Zweifelsfall nimm die Fleury Lib.
>
> Grüsse,
> R.

ich hab 0 ahnung... das lcd funktioniert .. jedoch kann ich nicht diese 
ADU Werte ausgeben... ich muss sie vorher hier:

char* Convert_ADU_to_Text(unsigned char ADC_Value)
{
}

umwandeln in character, und das schaffe ich nicht

oder vielleicht liege ich auch in dem punkt falsch,

Ich würde euch dann fragen, was muss ich eurer Meinung nach tun damit 
ich den Wert vom Poti ausgeben kann? (ADC_Value_CH1, ADC_Value_CH2)

: Bearbeitet durch User
von fb (Gast)


Lesenswert?


von Stefan S. (derprogrammierer2)


Lesenswert?

fb schrieb:
> http://www.mikrocontroller.net/articles/FAQ
> Gleich das erste Kapitel!

wie genau wende ich das an? itoa geht nicht, da ich keine integer zahl 
habe.

was ist utoa? ultoa?

von Dieter F. (Gast)


Lesenswert?

Stefan S. schrieb:
> fb schrieb:
>> http://www.mikrocontroller.net/articles/FAQ
>> Gleich das erste Kapitel!
>
> wie genau wende ich das an? itoa geht nicht, da ich keine integer zahl
> habe.
>
> was ist utoa? ultoa?

Kennst Du google (und kannst ggf. auch Englisch)?

von fb (Gast)


Lesenswert?

Stefan S. schrieb:
> itoa geht nicht, da ich keine integer zahl habe.
Dann mach halt eine draus. Oder besser überlaß das dem Compiler, der 
weis wie es geht.
1
char* Convert_ADU_to_Text( unsigned char ADC_Value, char* buffer )
2
{
3
  return itoa( ADC_Value, buffer, 10 );
4
}

> was ist utoa? ultoa?
utoa ist die Variante für 'unsigned', ultoa für 'unsigned long'. utoa 
kannst Du auch nehmen (ultoa ginge ebenfalls, wäre hier aber etwas 
zuviel des Guten).
1
char* Convert_ADU_to_Text( unsigned char ADC_Value, char* buffer )
2
{
3
  return utoa( ADC_Value, buffer, 10 );
4
}

von Stefan S. (derprogrammierer2)


Lesenswert?

(Kann ich davon ausgehen das mir keiner mit dem Problem da oben (mein 
Programm) helfen kann? )Habe in ein paar Tagen einen Test und das wäre 
so ein Programm, bei dem ich mir gut vorstellen könnte,dass das zum Test 
kommt.
Ich bin echt nicht gut im Programmieren, ich kenne nur die 
Grundfunktionen. Wenn ich irgendwie euch auf die Nerven gehe, tut es mir 
Leid (:

ah, danke für den obigen Post.

: Bearbeitet durch User
von Rene H. (Gast)


Lesenswert?

Nimm sprintf.

Grüsse,
R.

von Stefan S. (derprogrammierer2)


Lesenswert?

so schauts jz bei mir aus:
1
// Prototyps
2
void AD_Init();
3
unsigned char ucGetADValue_8Bit(char cAD_Channel);
4
char* Convert_ADU_to_Text(unsigned char ADC_Value, char* Text);
5
6
7
int main(void)
8
{
9
  unsigned char ADC_Value_CH1,ADC_Value_CH2;    // unsigned nur im positiven bereich
10
  char Text[21];        // 21 Zeichen weil LCD hat 20 + ENTER
11
  
12
  lcd_init();
13
  lcd_blank();
14
  
15
    while(1)
16
    {
17
    // Beide Potis einlesen
18
        ADC_Value_CH1 = ucGetADValue_8Bit (1);
19
    ADC_Value_CH2 = ucGetADValue_8Bit (2);  // nicht sicher ob der 2er richtig ist
20
    
21
    // Anzeigen der ADU Werte
22
    lcd_print(1,0,Convert_ADU_to_Text(ADC_Value_CH1,Text));
23
    lcd_print(2,0,Convert_ADU_to_Text(ADC_Value_CH2,Text));
24
    
25
    }
26
}
27
28
char* Convert_ADU_to_Text(unsigned char ADC_Value, char* Text)        // char* kein direkter Speicher zugewiesen
29
{
30
  // Funktion
31
  return sprintf(Text,"%s",ADC_Value);
32
}

zeigt immernoch nichts an

: Bearbeitet durch User
von fb (Gast)


Lesenswert?

Rene H. schrieb:
> Nimm sprintf.

Für das, was der TE haben wollte völliger overkill. Und da er schon mit 
einem simplen itoa/utoa Aufruf überfordert ist, ist er das mit dem 
Aufruf von 'variadic Functions' erst recht

von Stefan S. (derprogrammierer2)


Lesenswert?

1
unsigned char ucGetADValue_8Bit(char cAD_Channel);
2
char* Convert_ADU_to_Text(unsigned char ADC_Value, char* buffer);
3
4
5
int main(void)
6
{
7
  unsigned char ADC_Value_CH1,ADC_Value_CH2,buffer;    // unsigned nur im positiven bereich
8
  char Text[21];        // 21 Zeichen weil LCD hat 20 + ENTER
9
  
10
  lcd_init();
11
  lcd_blank();
12
  
13
    while(1)
14
    {
15
    // Beide Potis einlesen
16
        ADC_Value_CH1 = ucGetADValue_8Bit (1);
17
    ADC_Value_CH2 = ucGetADValue_8Bit (2);  // nicht sicher ob der 2er richtig ist
18
    
19
    // Anzeigen der ADU Werte
20
    lcd_print(1,0,Convert_ADU_to_Text(ADC_Value_CH1,buffer));
21
    lcd_print(2,0,Convert_ADU_to_Text(ADC_Value_CH2,buffer));
22
    
23
    }
24
}
25
26
char* Convert_ADU_to_Text( unsigned char ADC_Value, char* buffer )
27
{
28
  return utoa( ADC_Value, buffer, 10 );
29
}

klappt auch nicht.

von fb (Gast)


Lesenswert?

fb schrieb:
> ist er das mit dem
> Aufruf von 'variadic Functions' erst recht
Sag ich doch:
1
return sprintf(Text,"%s",ADC_Value);
das funktioniert nicht, lies dir die Doku zu sprintf durch! Insbesondere 
die zum Formatstring.

von Rene H. (Gast)


Lesenswert?

Ich tippe auf dem Handy, deshalb halte ich mich knapp.
1
char* Convert_ADU_to_Text( unsigned char ADC_Value, char* val)
2
{
3
  sprintf(val, "%u", ADC_Value);
4
  
5
  return(val);
6
}

von fb (Gast)


Lesenswert?

Stefan S. schrieb:
> klappt auch nicht.

Da sollte schon der Compiler rummeckern.
In der Version davor war der Aufruf von 'Convert_ADU_to_Text' noch 
richtig.

Kannst Du mit lcd_print überhaupt irgenwas auf dem Display ausgeben?

von Stefan S. (derprogrammierer2)


Lesenswert?

fb schrieb:
> Stefan S. schrieb:
>> klappt auch nicht.
>
> Da sollte schon der Compiler rummeckern.
> In der Version davor war der Aufruf von 'Convert_ADU_to_Text' noch
> richtig.
>
> Kannst Du mit lcd_print überhaupt irgenwas auf dem Display ausgeben?

wenn ich sowas wie
lcd_print(0,1,"Hallo!"); eingebe , ja.
auch ein character (oder besser gesagt nur ein char.

char Text[20];
..
lcd_print(0,1,Text);

das geht alles.

von fb (Gast)


Lesenswert?

Rene H. schrieb:
> Ich tippe auf dem Handy, ...
Wenn er die FAQ (http://www.mikrocontroller.net/articles/FAQ) ein paar 
Zeilen weiter gelesen hätte, wäre er vielleicht auch selbst drauf 
gekommen.

von fb (Gast)


Lesenswert?

Was klappt denn dann nicht? Wird gar nichts ausgegeben? Was falsches?
Stimmen die ersten beiden Parameter von lcd_print? Also geht z.B.
lcd_print(1,0,"Hallo");
lcd_print(2,0,"Huhu");
?

Ansonsten, wie sieht denn Deine Beschaltung aus?
Was hängt bei Dir am AREF-Pin (ich hoffe nur ein Kondensator)?
An welchen Pins hängen Deine Potis? PA1 & PA2?

Mit welcher Frequenz läuft dein ATmega? Der ADC braucht min 50kHz und Du 
teilst durch 128.

Deine ucGetADValue_8Bit hat auch noch Probleme. Du liest z.B. nie ADCH

von Stefan S. (derprogrammierer2)


Lesenswert?

fb schrieb:
> Was klappt denn dann nicht? Wird gar nichts ausgegeben? Was falsches?
> Stimmen die ersten beiden Parameter von lcd_print? Also geht z.B.
> lcd_print(1,0,"Hallo");
> lcd_print(2,0,"Huhu");
> ?
>
> Ansonsten, wie sieht denn Deine Beschaltung aus?
> Was hängt bei Dir am AREF-Pin (ich hoffe nur ein Kondensator)?
> An welchen Pins hängen Deine Potis? PA1 & PA2?
>
> Mit welcher Frequenz läuft dein ATmega? Der ADC braucht min 50kHz und Du
> teilst durch 128.
>
> Deine ucGetADValue_8Bit hat auch noch Probleme. Du liest z.B. nie ADCH


PA1 und PA0  - potis  (ADC1 und ADC0)

der quartz  hat 16 MHz

und wie lese ich ADCH mit? Man hat ja bei (wenn ADLAR = 0) ADCLOW, und 
da ist Bit: 0,1,2,3,4,5,6,7,8,9 ansprechbar, nur weis ich nicht wie 
genau ich Bit 8 und 9 anspreche. das wäre ja ADCL und ADCH zusammen??? 
Wie schreibe ich das in meine Funktion?

von fb (Gast)


Lesenswert?

Stefan S. schrieb:
> PA1 und PA0  - potis  (ADC1 und ADC0)

Dann stimmt das hier nicht:
1
ADMUX |= cAD_Channel;
bzw. das:
1
ADC_Value_CH1 = ucGetADValue_8Bit (1);
2
ADC_Value_CH2 = ucGetADValue_8Bit (2);  // nicht sicher ob der 2er richtig ist
Du fragst ADC1 und ADC2 ab, Datenblatt lesen (z.B. Table 84)!

> der quartz  hat 16 MHz
Ok, das passt dann mit dem 128er Prescaler (vorausgesetzt die Fuses sind 
auch passend eingestellt).

> nur weis ich nicht wie
> genau ich Bit 8 und 9 anspreche.
Indem Du ADCH liest. Das mußt Du bei ADLAR = 0 sowieso tun, siehe 
Datenblatt S.203.
Oder Du überläßt das dem GCC, der weis wie es geht:
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#16-Bit_Register_.28ADC.2C_ICR1.2C_OCR1x.2C_TCNT1.2C_UBRR.29
1
uint16_t t = ADC;
2
return (unsigned char)(t >> 2);
Alternative: ADLAR = 1 setzen und dann stattdessen nur:
1
return(ADCH);

von fb (Gast)


Lesenswert?

Achso, die wichtigsten Fragen sind immer noch offen:
Was klappt denn nicht? Wie sind Deine Erwartungen, was passiert 
stattdessen?
...

von Stefan S. (derprogrammierer2)


Lesenswert?

fb schrieb:
> Achso, die wichtigsten Fragen sind immer noch offen:
> Was klappt denn nicht? Wie sind Deine Erwartungen, was passiert
> stattdessen?
> ...

Sorry.

Und zwar:

Ich will jetzt auf meinem AVR-Board, auf dem 2 Potentiometer drauf sind 
diese 2 Potis verstellen(also drehen) und zugleich das dieser Wert am 
LCDangezeigt wird. D.h. ich drehe mein Poti (nur im positiven Bereich 
0+) und der Wert bei dem ich gerade bin wird am LCD angezeigt.

Was nicht klappt: Da bin ich mir auch nicht sicher. Ich kriege halt 
keinen Wert auf meinem LCD wenn ich am Poti drehe, und ich weiss nicht 
ob das an meinem sprintf liegt oder an sonst was.

Was stattdessen passiert: Nichts. Das LCD ist an(geschlossen), getestet 
habe ich es mit anderen Programmen, es funktioniert. Ich bin relativ neu 
in diesem Mikrocontroller-Bereich und auch im Programmieren allgemein. 
:(

von Stefan S. (derprogrammierer2)


Lesenswert?

Ich möchte den "Wert" eines Potis (den aktuellen)
mittels ADC einlesen und danach auf einem LCD ausgeben

von fb (Gast)


Lesenswert?

Du hast geschrieben, das ein
1
lcd_print(0,1,"Hallo!");
 funktioniert. Was bedeuten denn die ersten beiden Parameter? Welche 
Werte sind möglich?
Wie groß ist Dein Display? Wo auf dem Display steht das "Hallo"?
Geht z.B.:
1
int main(void)
2
{
3
  lcd_init();
4
  lcd_blank();
5
6
  while(1)
7
  {
8
    lcd_print(1,0,"Hallo");
9
    lcd_print(2,0,"Huhu");
10
  }
11
}
Das Dein Program falsche Werte anzeigt ist klar. Aber irgendwas sollte 
schon angezeigt werden.

BTW. Welche LCD Lib verwendest Du? Link?

von Stefan S. (derprogrammierer2)


Lesenswert?

fb schrieb:
> Du hast geschrieben, das einlcd_print(0,1,"Hallo!"); funktioniert. Was
> bedeuten denn die ersten beiden Parameter? Welche
> Werte sind möglich?
> Wie groß ist Dein Display? Wo auf dem Display steht das "Hallo"?

lcd_print(0,1,"Hallo!");

ist falsch. da habe ich etwas falsches hingeschrieben.

es müsste: lcd_print(1,0,"Hallo!"); -- x,y, ist halt meine position am 
lcd

stehen. das funktioniert, bzw mein Text fängt in der ersten Zeile links 
an.

ein ausschnitt aus dem handbuch:

"Zur Konfiguration des LCD gibt es im Controller-IC Control-Register. 
Die darzustellenden Zeichen werden
zunächst in die 80 Speicherzellen aufgenommen und danach am LCD 
angezeigt. Dabei sind die Speicherzellen
0 bis 15 der ersten Zeile am Display und die Speicherzellen 40 bis 55 
der 2. Zeile zugeordnet.
"

Noch ein Auszug:

"
1
void toggle_enable_pin(void);
2
  void lcd_send(unsigned char type, unsigned char c);
3
  void lcd_set_cursor(uint8_t x, uint8_t y);
4
  void lcd_write(char *t);
5
  void lcd_print(int x,int y,char *t);
6
  void lcd_init();
7
  void lcd_blank();
"

: Bearbeitet durch User
von fb (Gast)


Lesenswert?

Ok x und y, dann müßte bei:
1
  while(1)
2
  {
3
    lcd_print(1,0,"Hallo");
4
    lcd_print(2,0,"Huhu");
5
  }
eigentlich sowas wie "HHuhu" links oben im Display stehen.
Bei
1
  while(1)
2
  {
3
    lcd_print(1,0,"Hallo");
4
    lcd_print(1,1,"Huhu");
5
  }
sollten dann zwei Zeilen zu sehen sein?

von Stefan S. (derprogrammierer2)


Lesenswert?

fb schrieb:
> Ok x und y, dann müßte bei:
>
1
>   while(1)
2
>   {
3
>     lcd_print(1,0,"Hallo");
4
>     lcd_print(2,0,"Huhu");
5
>   }
6
>
> eigentlich sowas wie "HHuhu" links oben im Display stehen.
> Bei
>
1
>   while(1)
2
>   {
3
>     lcd_print(1,0,"Hallo");
4
>     lcd_print(1,1,"Huhu");
5
>   }
6
>
> sollten dann zwei Zeilen zu sehen sein?

jap, Hallo links oben in der ersten
und Huhu in der zweiten links

von fb (Gast)


Lesenswert?

Dann so?
1
#include <avr/io.h>
2
#include "..\LCD\lcd.h"
3
4
void AD_Init();
5
unsigned char ucGetADValue_8Bit(unsigned char cAD_Channel);
6
char* Convert_ADU_to_Text(unsigned char ADC_Value, char* buffer);
7
8
int main(void)
9
{
10
  unsigned char ADC_Value_CH1,ADC_Value_CH2;    // unsigned nur im positiven bereich
11
  char Text[21];        // 21 Zeichen weil LCD hat 20 + ENTER
12
  
13
  lcd_init();
14
  lcd_blank();
15
  
16
  while(1)
17
  {
18
    // Beide Potis einlesen
19
    ADC_Value_CH1 = ucGetADValue_8Bit(0);
20
    ADC_Value_CH2 = ucGetADValue_8Bit(1);  // nicht sicher ob der 2er richtig ist
21
    
22
    // Anzeigen der ADU Werte
23
    lcd_print(1,0,Convert_ADU_to_Text(ADC_Value_CH1,Text));
24
    lcd_print(1,1,Convert_ADU_to_Text(ADC_Value_CH2,Text));
25
    
26
  }
27
}
28
29
char* Convert_ADU_to_Text( unsigned char ADC_Value, char* buffer )
30
{
31
  sprintf( buffer , "%u    ", ADC_Value );
32
  return buffer;
33
}
34
35
void AD_Init()
36
{
37
  ADMUX = (1<<REFS0) | (1<<ADLAR);
38
  ADCSRA = (1<<ADEN) | (1<<ADPS0) | (1<<ADPS1) | (1<<ADPS2);
39
}
40
41
unsigned char ucGetADValue_8Bit(unsigned char cAD_Channel)
42
{
43
  AD_Init();  // Initialisierung
44
  ADMUX = (ADMUX & 0xe0) | ( cAD_Channel & 0x07 );
45
  ADCSRA |= (1<<ADSC);
46
  while (ADCSRA & (1<<ADSC));
47
  return(ADCH);  
48
}
Da die ADC-Werte durchaus von Messung zu Messung schwanken und sehr 
schnell aufs LCD geschrieben werden, könnte es allerdings schwer werden 
die dann auch zu lesen.

von Stefan S. (derprogrammierer2)


Lesenswert?

fb schrieb:

> Da die ADC-Werte durchaus von Messung zu Messung schwanken und sehr
> schnell aufs LCD geschrieben werden, könnte es allerdings schwer werden
> die dann auch zu lesen.

würde dagegen helfen wenn man das ganze mit delay verlangsamt? oder mit 
einer if (PIND & (1<<TASTE) erst das lesen starte. ich probier mal rum. 
Danke !

von Stefan S. (derprogrammierer2)


Lesenswert?

im lcd wird wieder nichts angezeigt.
ich bin offiziell jetzt verzweifelt. ich glaub ich gebs auf heute und 
versuchs in paar tagen wieder. ich weiss einfach nicht worans liegt

: Bearbeitet durch User
von Marco G. (grmg2010)


Lesenswert?

Das klingt ein wenig so, als ob du keinen Wert vom ADC bekommst und der 
Buffer daher leer ist und somit nichts angezeigt wird.
Versuch doch mal der Funktion einen festen Wert zu geben/also dem 
ADC_VALUE_CH1 oder ADC_VALUE_CH2). Wenn dann kein Wert angezeigt wird, 
muss etwas an der Ausgaberoutine nicht ganz korrekt sein. Wenn mit einem 
festen Wert eine Anzeige bekommst gibt es Probleme mit dem ADC

: Bearbeitet durch User
von DH1AKF W. (wolfgang_kiefer) Benutzerseite


Lesenswert?

Schau mal hier, wie es geht:
Beitrag "80 MHz- Zähler mit Atmega32A"

von Dieter F. (Gast)


Lesenswert?

fb schrieb:
> return(ADCH);

Warum liest Du kein Datenblatt und schaust auch nicht mal im WWW, wie 
andere es machen.

Aus der Messung resultiert ein 16-Bit-Wert im "Doppel-Register" ADC 
(ADCH und ADCL). Datenblatt S. 213:

After the conversion is complete (ADIF is high), the conversion result 
can be found in the ADC Result Registers (ADCL, ADCH).

In Assembler musst Du die in einer definierten Reihenfolge auslesen und 
verarbeiten. Der GCC-Compiler kennt die Reihenfolge und übernimmt das 
für Dich. Du kannst das Ergebnis (sofern Du keine linksbündige Ausgabe 
gewählt hast - was Du leider mit Setzen des ADLAR-Bits gemacht hast 
...!!) als "normale" 16-Bit-Zahl ohne Vorzeichen verwenden und mit 
SPRINTF für die Ausgabe umformen.

DH1AKF liest den jeweiligen ADC-Kanal so:
1
uint16_t ReadADC(uint8_t ADCport){
2
  
3
  ADMUX  |=(ADCport & 7);           // Kanal anwählen
4
  ADCSRA |= (1<<ADSC);              // Start A/D- Wandlung
5
  while(ADCSRA&(1<<ADSC));          // Warten auf Ende der Konversion
6
7
  return(ADC);
8
}

Das Ergebnis / den Aufruf könntest Du (z.B. für ADC-Kanal 1)so 
gestalten:
1
char outString[10];
2
3
...
4
5
sprintf(outString, "%u", ReadADC(1));
6
lcd_print(1,0,outString)

von DH1AKF W. (wolfgang_kiefer) Benutzerseite


Lesenswert?

Dieter F. schrieb:
> DH1AKF liest den jeweiligen ADC-Kanal so:


Das wurde korrigiert:
1
uint16_t ReadADC(uint8_t ADCport){
2
const uint8_t admux_mask = (1<<MUX4)|(1<<MUX3)|(1<<MUX2)|(1<<MUX1)|(1<<MUX0);
3
4
  ADMUX = (ADMUX & ~(admux_mask)) | (ADCport & 7);//    Kanal anwählen, vorher löschen  
5
  ADCSRA |= (1<<ADSC);//              Start A/D- Wandlung
6
  while(ADCSRA&(1<<ADSC));//            Warten auf Ende der Konversion
7
  return(ADC);
8
}

Warum? Weil bei Wechsel des Kanals erst einmal die alten Kanalbits 
gelöscht werden müssen.

Man könnte auch schreiben:
1
ADMUX = (ADMUX & 224) | (ADCport & 7);// Kanal löschen und neu setzen

von fb (Gast)


Lesenswert?

Dieter F. schrieb:
> fb schrieb:
>> return(ADCH);
>
> Warum liest Du kein Datenblatt und schaust auch nicht mal im WWW, wie
> andere es machen.
>
> Aus der Messung resultiert ein 16-Bit-Wert im "Doppel-Register" ADC
> (ADCH und ADCL). Datenblatt S. 213:

Dann solltest Du das Datenblatt ebenfalls nochmal lesen!
Wenn ADLAR auf 1 gesetzt ist steht der Wert linksbündig in ADC. Wenn man 
nur 8 Bit (die obersten halt) haben will reicht es nur ADCH zu lesen. 
Datenblat S.217:
"Consequently, if the result is left adjusted and no more than 8-bit 
precision is required, it is sufficient to read ADCH."

von Dieter F. (Gast)


Lesenswert?

fb schrieb:
> Dieter F. schrieb:
>> fb schrieb:
>>> return(ADCH);
>>
>> Warum liest Du kein Datenblatt und schaust auch nicht mal im WWW, wie
>> andere es machen.
>>
>> Aus der Messung resultiert ein 16-Bit-Wert im "Doppel-Register" ADC
>> (ADCH und ADCL). Datenblatt S. 213:
>
> Dann solltest Du das Datenblatt ebenfalls nochmal lesen!
> Wenn ADLAR auf 1 gesetzt ist steht der Wert linksbündig in ADC. Wenn man
> nur 8 Bit (die obersten halt) haben will reicht es nur ADCH zu lesen.
> Datenblat S.217:
> "Consequently, if the result is left adjusted and no more than 8-bit
> precision is required, it is sufficient to read ADCH."

Ja, wenn Du die volle Auflösung nicht brauchst und sowieso runden 
willst.
Der TO hat aber nichts davon geschrieben.

Sorry - ich meinte mit meiner Antwort den TO und habe Deinen Beitrag 
erwischt :-\

Dieter F. schrieb:
> Du kannst das Ergebnis (sofern Du keine linksbündige Ausgabe
> gewählt hast - was Du leider mit Setzen des ADLAR-Bits gemacht hast
> ...!!)

Und ADLAR kenne ich sehr wohl :-)

von fb (Gast)


Lesenswert?

Dieter F. schrieb:
> Der TO hat aber nichts davon geschrieben.

Geht doch eindeutig aus dem Funktionsnamen und dem Returntyp hervor:
"unsigned char ucGetADValue_8Bit(char cAD_Channel)"

von Dieter F. (Gast)


Lesenswert?

fb schrieb:
> Geht doch eindeutig aus dem Funktionsnamen und dem Returntyp hervor:
> "unsigned char ucGetADValue_8Bit(char cAD_Channel)"

Ja, deswegen liest er im Einstiegs-Post auch das low-Register aus. Er 
weiß/wusste es wahrscheinlich nicht besser ... .

von fb (Gast)


Lesenswert?

Dieter F. schrieb:
> Ja, deswegen liest er im Einstiegs-Post auch das low-Register aus.
Aber nur das ADCL ohne ADCH, was auch verkehrt ist weil:
"When ADCL is read, the ADC Data Register is not updated until ADCH is 
read."
Daß der Wert ohne die 2 obersten Bit dann ziemlich

Hatte ich den TE aber auch schon alles geschrieben, einschließlich dem 
Hinweis auf die 16Bit Variante, siehe: 
Beitrag "Re: Atmega32, Poti, ADC, Poti-am LCD ausgeben" und die 
2 folgenden Posts.

> Er weiß/wusste es wahrscheinlich nicht besser ... .
Sicher.

von fb (Gast)


Lesenswert?

fb schrieb:
> Daß der Wert ohne die 2 obersten Bit dann ziemlich
Ooops, da fehlt noch was:

Daß der Wert ohne die 2 obersten Bit dann ziemlich sinnlos ist, ist 
sowieso klar.

von Dieter F. (Gast)


Lesenswert?

fb schrieb:
> Daß der Wert ohne die 2 obersten Bit dann ziemlich sinnlos ist, ist
> sowieso klar.

Schön, dass Du das auch merkst :-)

von Stefan S. (derprogrammierer2)


Lesenswert?

jap, habe es jz geschafft. danke euch!!

von Dietrich L. (dietrichl)


Lesenswert?

Stefan S. schrieb:
> jap, habe es jz geschafft. danke euch!!

Üblicherweise sagt man dann auch, was bei Dir das Problem war und wie 
Deine Lösung aussieht - als Hilfe für andere Leser!

Gruß Dietrich

von Stefan S. (derprogrammierer2)


Lesenswert?

so schaut meine Lösung aus:
1
#include <avr/io.h>
2
#include "..\LCD\lcd.h"
3
4
5
void ADC_init(void);
6
uint16_t ADC_read(uint8_t kanal);
7
void lcd_wInt(int convNum);
8
9
10
11
12
int main(void)
13
{
14
  int ADC_Wert=0;
15
  ADC_init();
16
  lcd_init();
17
  DDRD = 0xF0;
18
  int buttonstate = 0;
19
  
20
  while(1)
21
  {
22
    
23
    if (!(PIND & (1<<PD3))&&(buttonstate == 0))
24
    {
25
      
26
      buttonstate = 1;
27
      
28
      ADC_Wert = ADC_read(1);
29
      lcd_wInt(ADC_Wert);  
30
      
31
      PORTD= 0xF0;
32
      
33
    }
34
    else if ((PIND & (1<<PD3))&&(buttonstate == 1))
35
    {
36
      
37
      buttonstate = 0;
38
      
39
      lcd_blank();
40
      
41
      PORTD= 0x00;
42
        
43
    }
44
  
45
  }
46
}
47
void ADC_init(void){
48
  //Diese Funktion aktiviert den ADC -- falsch muss 3 prescaler setzen
49
  ADCSRA |= (1<<ADEN);  //ADC aktivieren und
50
  ADCSRA |= (1<<ADPS2);  //Teilungsfaktor auf 64 stellen:
51
  ADCSRA |= (1<<ADPS1);  //siehe Datenblatt Maskierung
52
  
53
}
54
uint16_t ADC_read(uint8_t kanal){
55
56
  ADMUX=kanal; //Kanal des Multiplexers wählen:
57
  sbi(ADCSRA,ADSC);//Messung starten
58
  while(bit_is_set(ADCSRA,ADSC));// Auf Ergebnis warten:
59
  return ADCW;
60
}
61
/*
62
  Funktion:      LCD_wInt(write Integer)
63
  
64
  Eingabeparameter:  int convNum:
65
              Integerzahl die in einen String umgewandelt werden soll
66
              und übers LCD ausgegeben werden soll
67
  
68
  Augabeparameter:  keine
69
  
70
  Rückgabe      keine(Ich wollte dass die Funk. eine string Var. zurückgibt dass hat aber nicht funktioniert)
71
  
72
  Die Funktion ermittelt zuerst wieviele Stellen Die Integer Zahl hat. Als nächstes ermittelt sie die Ziffern der 
73
  einzelnen Stellen und schreibt diese schließlich als Character in den String. Zum Schluss wird der String am LCD
74
  ausgegeben.
75
*/
76
void lcd_wInt(int convNum)
77
{
78
  char stringNum[10], charNum[10]="0123456789";
79
  int runVar = 1,saveVar=0,numLen = 0;
80
  
81
  while((convNum%runVar)!=convNum)  //Ermittlung der Ziffernanzahl 
82
  {                  //Schleife wird durchlaufen solange Rest der Modfunk. Die Zahl selbst ist.
83
    numLen++;            //Erhöhung der Ziffernanzahl
84
    runVar=runVar*10;        //Anpassung der Laufvariable
85
  }
86
  
87
  stringNum[numLen]='\0';        //Ende des Strings festlegen
88
  runVar = 10;            //Anpassung der Laufvariable
89
  for(int i=numLen;i>0;i--)      //Schleife wird durchlaufen bis alle Stellen der Zahl abgearbeitet wurden
90
  {
91
    saveVar = convNum%runVar;    //Ziffernwert auf die Zwischenvariable speichern
92
    stringNum[i-1]=charNum[saveVar];//Ziffernwert auf den string speichern
93
    convNum = convNum-(saveVar);  //Anpassen der Int Zahl
94
    convNum = convNum/10;      //-"-
95
  }
96
  lcd_write(stringNum);        //String ausgeben
97
}

Ich weiss zwar nicht wieso, aber sprintf oder itoa funktionieren hier 
nicht. das mit uint (also der hinweis und die hilfe von euch hat echt 
geholfen. danke).

Wäre echt interessant zu wissen wieso sprintf oder itoa nicht klappen..

von Stefan S. (derprogrammierer2)


Lesenswert?

geht doch mit itoa und sprintf, nur bissl pfuschen und tricksen.

#case closed

von Dieter F. (Gast)


Lesenswert?

Stefan S. schrieb:
> nur bissl pfuschen und tricksen

K.A., was Du mit "pfuschen und tricksen" meinst - aber das geht ganz 
normal:
1
#include <stdlib.h>
2
#include <avr/io.h>
3
#include <string.h>
4
#include <stdio.h>
5
#include <util/delay.h>
6
#include "lcd.h"
7
8
char    outString[10];
9
uint8_t    printposy;
10
uint16_t    adc0_wert = 1024;
11
uint16_t    adc1_wert = 1024;
12
uint16_t    adc0_wert_old = 0;
13
uint16_t    adc1_wert_old = 0;
14
15
void    ADC_init(void);
16
uint16_t  ADC_read(uint8_t kanal);
17
18
19
int main(void)
20
{
21
  ADC_init();
22
  lcd_init(LCD_DISP_ON);
23
  lcd_clrscr();
24
  
25
  while(1)
26
  {
27
    adc0_wert = 0;
28
    for (uint8_t i=0;i<32;i++)
29
    {
30
      adc0_wert += ADC_read(0);
31
    }
32
    adc0_wert = adc0_wert>>5;
33
    if (adc0_wert != adc0_wert_old)
34
    {
35
      lcd_gotoxy(0,0);
36
      lcd_puts("ADC0:           ");
37
      sprintf(outString, "%u", adc0_wert);
38
      printposy = 16 - strlen( outString );
39
      lcd_gotoxy(printposy,0);
40
      lcd_puts(outString);
41
      adc0_wert_old = adc0_wert;
42
    }
43
    
44
    adc1_wert = 0;
45
    for (uint8_t i=0;i<32;i++)
46
    {
47
      adc1_wert += ADC_read(1);
48
    }
49
    adc1_wert = adc1_wert>>5;
50
    if (adc1_wert != adc1_wert_old)
51
    {
52
      lcd_gotoxy(0,1);
53
      lcd_puts("ADC1:           ");
54
      sprintf(outString, "%u", adc1_wert);
55
      printposy = 16 - strlen( outString );
56
      lcd_gotoxy(printposy,1);
57
      lcd_puts(outString);
58
      adc1_wert_old = adc1_wert;
59
    }
60
  }
61
}
62
63
64
void ADC_init(void)
65
{
66
  ADCSRA |= (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0);
67
  ADCSRA |= (1<<ADEN);
68
}
69
70
uint16_t ADC_read(uint8_t kanal)
71
{
72
  static uint8_t kanal_old = 0x08;
73
  
74
  const uint8_t admux_mask = (1<<MUX4)|(1<<MUX3)|(1<<MUX2)|(1<<MUX1)|(1<<MUX0);
75
76
  if (kanal_old != kanal)
77
  {
78
    ADMUX = (ADMUX & ~(admux_mask)) | (kanal & 0x07);
79
  }
80
  ADCSRA |= (1<<ADSC);
81
  while(ADCSRA&(1<<ADSC));
82
  return(ADC);
83
}

Ich hab die Display-Ausgabe noch etwas beruhigt (durch 
Mittelwert-Bildung aus 32 Lese-Zyklen und Abfrage auf Wert-Änderung). 
Ich nutze den ADC-Prescaler 128, da ich einen 16 MHz Quarz dran habe.
Basis ist die Fleury-Lib mit einen 4 * 16 Zeichen Display.

von Wolfgang (Gast)


Lesenswert?

Dieter F. schrieb:
> Ich hab die Display-Ausgabe noch etwas beruhigt (durch
> Mittelwert-Bildung aus 32 Lese-Zyklen und Abfrage auf Wert-Änderung).

Richtig beruhigen würde man sie, indem man die Anzeige mit einer 
Hysterese versieht, die größer als das Rauschen der (ggf. vorher 
gemittelten) Daten ist. Sonst gibt es immer Werte, bei denen die Anzeige 
unruhig wird.

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.