Hallo,
ich möchte gerne eine Variable an ein Display (EA W204-BNLED via Channaa
I2C- LCD Adapter) ausgeben. Dazu muss ich aber erst einen String an das
LCD senden können.
Ich habe nun einfach den Code des String-Unterprogrammes aus dem
Tutorial übernommen und angepasst.
Hier der betroffene Ausschnitt aus dem ganzen Programm (siehe Anhang):
1
voidi2c_writes(char*data)
2
{
3
i2c_start_wait(LCD+I2C_WRITE);// I2C Adresse und "Schreib Modus" setzen
4
i2c_write(0x76);// Schreib Adresse 0x76 (String)
5
while(*data)
6
{
7
i2c_write('*data');
8
data++;
9
}
10
i2c_stop();// I2C Stop
11
}
Nun erhalte ich beim Kompilieren die Warnung "warning character constant
too long for its type"
Das Display zeigt dann bloss Spannung A an wobei das A blinkt. TEST
erscheint nicht.
Was läuft hier schief?
Marcel wrote:
> i2c_write('*data');
Ohne '
Du willst ja das Zeichen senden, welches an der Position data
gespeichert ist
i2c_wwrite( *data );
> Nun erhalte ich beim Kompilieren die Warnung "warning character constant> too long for its type"
Logisch. ' steht in C für dies_ist_ein_Character, so wie
beispielsweise 'A', 'B' oder auch '9'
'*data' ist aber kein einzelnes Zeichen.
Aber das willst du ja auch gar nicht, du willst das Zeichen
senden, welches an der Speicheradresse die in data steht.
Marcel wrote:
> while(*data)> {> i2c_write('*data');
^ ^
Lass das weg. Das käme nur hin, wenn ein Buchstabenkonstante oder eine
Zifferkonstante direkt als Funktionsargument übergeben würde.
Also hier die neueste Version, habe noch einen Uart Test eingebaut
welcher auch funktioniert. Die Ausgabe des Strings funktioniert nun
jedoch erhalte ich wieder 2 Warnungen:
../ipa_2902_v01.c:37: warning: passing argument 1 of 'i2c_write' makes
integer from pointer without a cast
../ipa_2902_v01.c: In function 'i2c_writes':
../ipa_2902_v01.c:45: warning: passing argument 1 of 'i2c_writec' makes
pointer from integer without a cast
Betroffen sind die Unterprogramme:
1
voidi2c_writec(char*data)
2
{
3
i2c_start_wait(LCD+I2C_WRITE);// I2C Adresse und "Schreib Modus" setzen
4
i2c_write(0x76);// Schreib Adresse 0x76 (String)
5
i2c_write(data);
6
i2c_stop();
7
}
8
9
voidi2c_writes(char*data)
10
{
11
while(*data)
12
{
13
i2c_writec(*data);
14
data++;
15
}
16
}
Die ausgabe des Strings funktioniert zwar, jedoch erscheint jeweils das
2te Zeichen des Strings nicht, in diesem Fall ACDEFE....
Marcel wrote:
>> void i2c_writec(char *data)
Hier willst du keinen Pointer haben.
In data steht bereits der auszugebende Character.
void i2c_writec(char data)
Wenn ich "void i2c_writec(char data)" schreibe kriege ich einen Fehler,
wenn ich einfach nur den Pointer weglass kriege ich nur noch eine
Warnung aber `bcde... anstelle ABCDE.
Marcel wrote:
> ../ipa_2902_v01.c:50: error: expected expression before 'char'>> in der Zeile die ich geändert habe also "void i2c_writec(char data)"
Das ergibt so noch keinen Sinn.
Zeig mal mehr von der Umgebung an dieser Stelle.
Oder einfach den kompletten Code.
Wenn ichs so schreibe wie Stefan erhalte ich keine Fehler und auch keine
Warnung. Der Text ist auch grossgeschrieben wie gewünscht jedoch fehlt
wie immer das zweite Zeichen des Strings also ACDEF statt ABCDEF. Sehr
merkwürdig.
Marcel wrote:
> Wenn ichs so schreibe wie Stefan erhalte ich keine Fehler und auch keine> Warnung.
Liegt, daran, dass zumindest die String-Behandlung damit korrekt
ist.
> Der Text ist auch grossgeschrieben wie gewünscht jedoch fehlt> wie immer das zweite Zeichen des Strings also ACDEF statt ABCDEF. Sehr> merkwürdig.
Könnte das irgend ein I2C-Problem sein?
Was ist mit dem Code 0x76, der in deinem Code immer wieder
auftaucht. Könnte der damit etwas zu tun haben?
Erst kurz zu Stefans Beitrag:
Habe ich derzeit auskommentiert, schreibt aber auch erst an 10ter Stelle
das blinkende A wie ich es auch möchte.
Jetzt zu Karl Heinz:
Das LCD Display ist über den Adapter des Ingenieurbüros Channaa
angeschlossen. Ich muss möglichst viele Port Pins freihalten daher habe
ich mich überhaupt für I2C entschieden.
Mit dem Code 0x76 gebe ich nun den Befehl WriteString siehe Datenblatt
Seite 17: http://www.channaa.com/files/I2C_LCD_Adapter_V10_Rev5.PDF
In der Ursprungsversion sah das ganze so aus:
1
i2c_start_wait(LCD+I2C_WRITE);// I2C Adresse und "Schreib Modus" setzen
@Marcel
Was passiert, wenn du nicht die WriteString sondern die
CharToLCD Funktion benutzt
1
voidi2c_writec(chardata)
2
{
3
i2c_start_wait(LCD+I2C_WRITE);
4
i2c_write(0x64);
5
i2c_write(data);
6
i2c_stop();
7
}
8
9
voidi2c_writes(char*data)
10
{
11
while(*data)
12
{
13
i2c_writec(*data);
14
data++;
15
}
16
}
Im übrigen würde ich da sowieso 2 getrennte Funktionen dafür
einsetzen, wenn dir der I2C Adapter das schon so anbietet
1
voidi2c_writec(chardata)
2
{
3
i2c_start_wait(LCD+I2C_WRITE);
4
i2c_write(0x64);
5
i2c_write(data);
6
i2c_stop();
7
}
8
9
voidi2c_writes(char*data)
10
{
11
i2c_start_wait(LCD+I2C_WRITE);
12
i2c_write(0x76);
13
14
while(*data)
15
{
16
i2c_write(*data);
17
data++;
18
}
19
20
i2c_stop();
21
}
Probier mal beide Varianten aus.
(Ich finde es nicht sehr schlau, wenn du in ein Testprogramm
für die LCD gleich UART und ADC mit einbaust. Je mehr Subsysteme
aktiv sind, desto mehr Fehler kann man sich einhandeln. Test-
programme sollten eigentlich immer so einfach wie nur irgendwie
möglich sein)
Hallo,
so habe heute morgen mal beide Varianten ausprobiert, die erste
Funktionierte nicht, "frass" erneut das 2te Zeichen.
Die zweite musste ich noch etwas anpassen und nun läuft es:
1
voidi2c_writec(char*data)
2
{
3
i2c_start_wait(LCD+I2C_WRITE);// I2C Adresse und "Schreib Modus" setzen
Marcel wrote:
> Hallo,>> so habe heute morgen mal beide Varianten ausprobiert, die erste> Funktionierte nicht, "frass" erneut das 2te Zeichen.>> Die zweite musste ich noch etwas anpassen und nun läuft es:>
Hallo,
hattest recht habe ich noch angepasst.
Nun versuche ich den ADC Wert auf dem Display anzuzeigen. Die Ausgabe
einer Variable hat auf Anhieb geklappt, doch der AD Wandler mach noch
macken.
Die ADC Subroutine habe ich aus dem Tutorial übernommen und für meine
Zwecke angepasst (8MHz, AVREF als Referenz). Nun gibt er mir auf dem
Display aber immer 1023 also quasi 5V aus. Egal ob ich auf den Kanal0
via Poti zwischen 0-5V habe.
Sieht jemand den Fehler? Dürfe in der Sensor Subroutine liegen:
1
// Analog-Digital Wandler einlesen
2
uint16_tSensor(uint8_tmux)
3
{
4
uint8_ti;// Varaible i
5
uint16_tresult;// Variable result
6
7
ADCSRA=(1<<ADEN)|(1<<ADPS2)|(1<<ADPS1);// ADC aktivieren und Frequenzvorteiler auf 64
8
9
ADMUX=mux;// Kanal waehlen
10
ADCSRA|=(1<<ADSC);// "Aufwärm" Wandlung
11
while(ADCSRA&(1<<ADSC)){}// auf Abschluss der Wandlung warten
12
result=ADCW;// ADCW muss einmal gelesen werden,
13
// sonst wird Ergebnis der nächsten Wandlung
14
// nicht übernommen.
15
16
/* Eigentliche Messung - Mittelwert aus 4 aufeinanderfolgenden Wandlungen */
17
result=0;
18
for(i=0;i<4;i++)
19
{
20
ADCSRA|=(1<<ADSC);// eine Wandlung "single conversion"
21
while(ADCSRA&(1<<ADSC)){}// auf Abschluss der Konvertierung warten
22
result+=ADCW;// Wandlungsergebnisse aufaddieren
23
}
24
25
ADCSRA&=~(1<<ADEN);// ADC deaktivieren
26
27
result/=4;// Summe durch vier teilen = arithm. Mittelwert
Ich bins nochmal. Nun möchte ich ja die Spannung die ich einlese auch
noch auf dem Display ausgeben. Mit dem jetztigen Code geht das schonmal
jedoch nur ganzzahlig. Das heisst mit dem Code so wie er angehängt ist
wird mir 0-5 angezeigt, kommentiere ich die Umrechnung aus wird mir
0-1023 angezeigt.
Gehe ich richtig in der Annahme das ich für Nachkommastellen mit
Festkommaarithmetik arbeiten muss wie es im Tutorial steht? Leider wird
im Tutorial nur Assembler Code verwendet und ich kann die als Bild
eingefügten Formeln im Tutorial nicht lesen da sie flasch dargestellt
werden.
Marcel wrote:
> Gehe ich richtig in der Annahme das ich für Nachkommastellen mit> Festkommaarithmetik arbeiten muss wie es im Tutorial steht? Leider wird> im Tutorial nur Assembler Code verwendet und ich kann die als Bild> eingefügten Formeln im Tutorial nicht lesen da sie flasch dargestellt> werden.
Das Prinzip ist sehr einfach:
Wenn du anstelle von 5 mit 50 multiplizierst, dann erhältst du
nicht Zahlen von 0 bis 5 sondern von 0 bis 50. Im Prinzip
hast du dann schon eine Kommastelle, du musst nur bei der
Ausgabe dafür sorgen, daß zwischen erster und zweiter
Ausgabestelle ein Komma eingefügt wird. So wird dann aus 49
auf der Anzeige ein 4,9 und aus 12 wird 1,2. Vorsicht bei
Werten kleiner 10, musst du noch eine künstliche 0 davorstellen.
Denn aus 8 muss ja 0,8 werden.
Eine sehr simple, wenn auch rechenintensive Methode ist
zb. folgendes
1
....
2
adcval*=50;// eine Nachkommastelle, daher 50
3
adcval/=1023;
4
5
sprintf(buffer,"%d,%01d",adcval/10,adcval%10);
PS: an deinen Kommentaren musst du noch arbeiten. Ein Kommentar ala
adcval *= 5; // mit 5 multiplizieren
ist ein sinnloser Kommentar. Da ist es besser du lässt ihn weg.
Das verwirrt dann wenigstens keinen, wenn du im Code die 5 mal
gegen etwas anderes austauschst und im Kommentar den Update vergisst.
Kommentare sollen nicht das erzählen, was ohnehin im Code bereits
steht. Jeder halbwegs C-mächtige Anfänger kann aus
adcval *= 5;
in weniger als 2 Zehntelsekunden ablesen, dass hier adcval mit
5 multiplizert wird. Das brauchst du nicht kommentieren. Viel
interesanter ist warum adcval ausgerechnet mit 5 multipliziert
wird! Aber das steht, leider, leider, nicht im Kommentar.
Hallo,
habe es mit deinem Vorschlag versucht klappt ganz gut ich erhalte aber 2
Warnungen:
../ipa_2902_v01.c:118: warning: implicit declaration of function
'sprintf'
../ipa_2902_v01.c:118: warning: incompatible implicit declaration of
built-in function 'sprintf'
Wie kriege ich die noch weg?
Ausserdem möchte ich gerne noch eine zweite Nachkommastelle, dies habe
ich versucht es klappt aber nicht:
So nun läuft es, jedoch sind noch zwei Fehler zu beheben:
1. Bei 9mV ist die Anzeige noch 0.9V, erst wenn 10 mV erreicht sind wird
die Stelle geschoben und die Anzeige wechselt auf 0.10V.
Wie kann ich nun noch die zusätzliche 0 erzeugen um 0.09V bei 9mV
anzuzeigen.
2. Die Angezeigte Spannung stimmt nicht mit der realen Spannung überein
bei 4.3V werden bereits 5V angezeigt also 0.7V Offset je niedriger die
Spannung desto kleiner der Offset. Die Rechnung (ADC*500)/1023 stimmt
doch?
ändere so stimmen die Messwerte zwar duchs Band weg jedoch ist dann der
Maximale Messwert natürlich bei 4.32V.
Gibt es noch einen Anderen Weg das anzugleichen?
Marcel wrote:
> So nun läuft es, jedoch sind noch zwei Fehler zu beheben:>> 1. Bei 9mV ist die Anzeige noch 0.9V, erst wenn 10 mV erreicht sind wird> die Stelle geschoben und die Anzeige wechselt auf 0.10V.> Wie kann ich nun noch die zusätzliche 0 erzeugen um 0.09V bei 9mV> anzuzeigen.
Du hast die Doku zu sprintf (und Konsorten) immer noch nicht
gelesen. Sonst wüsstest du, dass du das mit dem Format String
hinbügeln kannst.
sprintf( adc, "%ld,%02ld", ....
^^
||
|+-- Diese 2 bedeutet, dass die Ausgabe in
| einem Feld der Breite 2 Zeichen gemacht
| werden soll. 10 würde als als "10"
| ausgegeben, wohingegen 9 als " 9" ausgegeben
| wird
|
+--- Diese 0 bedeutet, dass führende Leerzeichen
in der Ausgabe, wie sie zb. bei " 9"
auftreten würden, durch 0 ersetzt werden.
eine Ausgabe von 9 würde also als "09"
ausgegeben.
Summa, summarum wird also dein 'Nachkommaanteil' in einem Feld
der Breite 2 ausgegeben, wobei führende Leerzeichen als '0'
ausgegeben werden.
wenn dein Wert also 209 ist, dann liefert 209/100 -> 2
und 209%100 -> 9
Zuerst werden die 2 ausgegeben, dann das ',' und dann die 9, wobei
die 9 als "09" ausgegeben werden. In Summe steht also dort "2,09"
Marcel wrote:
> 2. Die Angezeigte Spannung stimmt nicht mit der realen Spannung überein> bei 4.3V werden bereits 5V angezeigt also 0.7V Offset je niedriger die> Spannung desto kleiner der Offset. Die Rechnung (ADC*500)/1023 stimmt> doch?
Miss mal deine Referenzspannung am Pin ARef nach.
Jetzt erhalte ich als Anzeige z.B 1. 2V oder 1. 23V. Das ist schonmal
besser da alle Stellen fixiert sind jedoch wäre es schön wenn man nun
noch die Leerschläge duch Nullen ersetzen kann.
Das zweite Problem mit den 4.32V konnte ich bisher auch noch nicht
lösen.
Ah, die eine Null hat noch gefehlt, danke.
An ARef habe ich derzeit 0V da ich noch mit AVCC als Referenz arbeite.
Diese Spannung hat etwas Brumm aber nicht so stark das es einen solchen
Offset gibt. Am Montag erhalte ich noch eine Referenzspannung welche ich
dann an ARev anschliesse.
Mein Kollege das Problem liege ev. beim Datenbereich, also das die Zahl
zu gross wird. Was meinst du?
Marcel wrote:
> Ah, die eine Null hat noch gefehlt, danke.>> An ARef habe ich derzeit 0V da ich noch mit AVCC als Referenz arbeite.
Das macht nichts.
Wenn du AVcc als Referenz gewählt hast, wird diese Spannung an ARef
ausgegeben. Als Minimalbeschaltung sollte dann ein Kondensator
von ARef nach Masse geschaltet werden. So um die 100nF
> Mein Kollege das Problem liege ev. beim Datenbereich, also das die Zahl> zu gross wird. Was meinst du?
Hab ich nicht kontrolliert. Aber rechne doch einfach mal nach.
Nimm einen Taschenrechner und vollzieh die Berechnung nach. Wenn
irgendwann auf deinem Taschenrechner eine Zahl größer als 32767
auftaucht, dann hast du ein Problem.
Sehe gerade beim Zurückscrollen:
Dein adcval ist ein uint32_t. Daher: Vergiss das mit den 32767.
Die Grenze liegt wesentlich höher und ist so sicher nicht zu
erreichen.
Ich bleibe dabei: Halte mal ein Voltmeter an den Pin ARef.
(Oszi wäre besser)
Hallo, ja Kondensator ist drin. Nachgerechnet haben wir vorhin auch,
kein Problem.
Hast Recht, sowohl an ARev wie auch an AVCC messe ich mit Scope bloss
4.4-4.5V, merkwürdig. Als Speisung habe ich einen AC/DC Wandler von
Traco mit 5V/3A also daran dürfte es nicht liegen.