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
voidAD_Init();
7
unsignedcharucGetADValue_8Bit(charcAD_Channel);
8
char*Convert_ADU_to_Text(unsignedcharADC_Value);
9
10
11
intmain(void)
12
{
13
unsignedcharADC_Value_CH1,ADC_Value_CH2;// unsigned nur im positiven bereich
14
charText[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
// 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
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
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)
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)?
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.
> 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).
(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.
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
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?
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.
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
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?
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_tt=ADC;
2
return(unsignedchar)(t>>2);
Alternative: ADLAR = 1 setzen und dann stattdessen nur:
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.
:(
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
intmain(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?
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:
"
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.
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 !
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
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
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_tReadADC(uint8_tADCport){
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:
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."
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 :-)
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)"
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 ... .
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.
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.
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
//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_tADC_read(uint8_tkanal){
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
returnADCW;
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
voidlcd_wInt(intconvNum)
77
{
78
charstringNum[10],charNum[10]="0123456789";
79
intrunVar=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(inti=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..
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.
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.