Hallo zusammen, ich versuche gerade ein LCD-Display 16x2 zu sinnvollen Leuchten zu bringen. Mit diesem Code: /* * LCD_1.c * * Created: 17.05.2013 20:08:01 * Author: Ich */ #include <avr/io.h> #include <avr/interrupt.h> #include "lcd.h" int main(void) { /* Inintialisierung Display, Cursor aus */ lcd_init(LCD_DISP_ON); /* Loesche das LCD-Display und Cursor auf Zeile 1 und Spalte 1 */ lcd_clrscr(); /* String anzeigen */ lcd_puts("Hallo, Du Nase."); while(1) { // kommt noch } } Aber es kommt immer diese Fehlermeldung und ich weiß nicht, warum *heul*: Error 1 undefined reference to `lcd_init' C:\Users\Ich\Documents\Atmel Studio\LCD_1\LCD_1\Debug/.././LCD_1.c 17 1 LCD_1 Das Gleiche für' 'clrscr' und 'lcd_puts'! Danke für eure Hilfe.
Hallo und einen Guten Morgen, ja, das habe ich, dann kommt der Fehler, dass 'defines.h: No such file or directory'. Binde ich diese ein, kommt die gleiche meldung für 'hd44780.h', etc. Es ist zum Haareraufen! Kann es vielleicht an dem AVR Studion 6 liegen?
Hugo Hugoson schrieb: > Hallo und einen Guten Morgen, > > ja, das habe ich, dann kommt der Fehler, dass 'defines.h: No such file > or directory'. Binde ich diese ein, kommt die gleiche meldung für > 'hd44780.h', etc. Die gleiche Meldung kommt ganz sicher nicht. Denn die eine Meldung ist vom Compiler und die andere ist vom Linker. > Es ist zum Haareraufen! Du brauchst mehr Geduld. > Kann es vielleicht an dem AVR Studion 6 liegen? Nein. Es liegt schon an dir. Die Files müssen am richtigen Verzeichnis liegen (das, welches durch den #include referenziert wird), C Files werden ins Projekt inkludiert, so dass sie compiliert und dann die Einzelteile zum kompletten Programm gelinkt werden. Mir deinen 3 Files ist das alles doch noch einfach. Also: keine Panik. Nichts desto trotz muss man das alles irgendwann mal lernen. Programmieren ist nun mal anspruchsvoller als Playstation-einschalten.
Hallo, nun findet er lcd.h (Habe Studio 4 benutzt), ABER -> C:\Users\Ich\Documents\AVR_Projekte\LCD_0\default/../LCD_0.c:18: undefined reference to `lcd_init' In der lcd.h ist die Funktion aber vorhanden: extern void lcd_clrscr(void); Nein, nein, ich raufe mir noch nicht die Haare, ich werde lernen. Ich verstehe das obige aber nicht :-(
> undefined reference to `lcd_init' Da meckert der ∗Linker∗ dass die Funktion nirgens ∗definiert∗ ist. > In der lcd.h ist die Funktion aber vorhanden: extern void > lcd_clrscr(void); Das ist die ∗Deklaration∗ für den ∗Compiler∗ (abgesehen vom copy-paste-Fehler). Füg die Definition der Funktion (vulgo: 'C-File') zum Projekt hinzu und compilier sie mit, dann wird auch der Linker glücklich.
Hugo Hugoson schrieb: > Hallo, nun findet er lcd.h (Habe Studio 4 benutzt), > ABER -> C:\Users\Ich\Documents\AVR_Projekte\LCD_0\default/../LCD_0.c:18: > undefined reference to `lcd_init' > In der lcd.h ist die Funktion aber vorhanden: extern void > lcd_clrscr(void); Nö. Diese Zeile sagt nur: "Es gibt eine derartige Funktion und so sieht sie aus (welche Argumente hat sie, was ist ihr Returnwert)". Nicht mehr und nicht weniger. (So wie das bei Header-Files im Regelfall eben so ist). Aber: Das ist ja nicht die Funktion selber. Die muss ja auch irgendwo implementiert sein! Irgendwo muss es ja Code dafür geben. Zu sagen "Es gibt ein rosa Einhorn" ist eine Sache. Aber irgendwann will man das dann auch tatsächlich mal sehen, wenn man einen Zoo zusammenstellt. Und in deinem Fall werden die Funktionen höchst wahrscheinlich in einer Datei namens lcd.c implementiert sein. Will man dann das komplette Programm zusammenbauen, dann benötigt man selbstverständlich dann auch die tatsächlichen, realen Implementierungen der Funktion. Daher muss lcd.c auch mit ins Projekt rein, damit es compiliert wird und zum fertigen Programm mit reinkommt. Der Linker sucht sich nicht auf einem Verzeichnis einfach alles zusammen, was er finden kann. Du musst ihm schon sagen, welche Dateien da alle zum kompletten Programm dazugehören. Und im Falle einer IDE (wie zb AVR-Studio) macht man das Eben, in dem man die entsprechenden C-Files alle mit ins Projekt aufnimmt. Daraus leitet sich dann ab, was alles zusammengelinkt werden muss.
Okay, ich werde mir einen Kaffee kochen, dein Geschriebenes verdauen, suchen, zusammenstellen und - sehen, was passiert. Danke!
So, nun habe ich den Kaffee ausgetrunken, alles eingebunden, es wird auch nicht gemeckert, aber es kommen viele viele Fehlermeldungen, mit denen ich nichts anzufangen weiß: Warning 1 declared here C:\Users\Ich\Documents\Atmel Studio\LCD_2\LCD_2\hd44780.h 30 6 LCD_2 . . Error 1 conflicting types for 'lcd_init' C:\Users\Ich\Documents\Atmel Studio\LCD_2\LCD_2\lcd.c 32 1 LCD_2 . . Error 4 too few arguments to function 'hd44780_wait_ready' C:\Users\Ich\Documents\Atmel Studio\LCD_2\LCD_2\lcd.c 41 3 LCD_2 . . Warning 2 previous declaration of 'lcd_init' was here C:\Users\Ich\Documents\Atmel Studio\LCD_2\LCD_2\lcd.h 187 13 LCD_2 Ob ich diese elende Anzeige noch zum Spielen binge? Na, eigentlich ist die Anzeige es ja nicht ;-)
Eine super einfache LCD-Lib findest Du hier: http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=102296
Hallo, ich bin's mal wieder :-) Nun dachte ich, dass ich das LCD verstanden habe und nun das: Auf dem LCD sind an einer Stelle nur vier waagerechte Balken zu sehen, keine Zahl, nichts. #include <avr/io.h> #include <avr/interrupt.h> #include "lcd-routines.h" #include "lcd-routines.c" int sekunde=0; // Variable definieren // ISR einbinden ISR(TIMER1_COMPA_vect) { PORTC ^= (1<<PC5); // Blinken der LED lcd_setcursor(2,1); lcd_data(sekunde); sekunde++; if (sekunde == 9) { sekunde=0; PORTC ^= (1<<PC4); } } int main(void) { lcd_init(); // LED DDRC |= (1<<PC5) | (1<<PC4); // Timer 1 konfigurieren TCCR1B |= (1<<WGM12) | (1<<CS11) | (1<<CS10); // CTC-Mode und Prescaler = 64 TIMSK1 |= (1<<OCIE1A); // Interrupt aufrufen, wenn Höchstwert erreicht OCR1A = 15625; // Vergleichswert für 1/2 sec an + 1/2 sec aus -> f= 1Hz sei(); // Globalen Interrupt erlauben while(1) { } } Die LEDs blinken, aber auf dem Display nur diese Balken. Was habe ich nicht beachtet?
Du musst Zahlen in ASCII-Zeichen zerlegen und einzelnd senden. Und bitte in der mainloop und nicht im Interrupt. Guck dir mal itoa() an.
Und weil es als nächste Frage kommt: Wenn du auf globale Variablen in der ISR und in der mainloop zugreifst muss das atomar geschehen und die Variablen müssen als volatile deklariert sein. Wenn du die Variable wie aktuell nur in der ISR brauchst kann man sie dort als static deklarieren, dann ist sie nur dort sichtbar und behält aber ihren Wert zwischen 2 Aufrufen.
Danke. Ich war fleißig und habe gelesen, aber sicher nicht genug :-(, denn es wird nur der ":" ausgegeben. volatile int sekunde=0, minute=0, stunde=0; // Variablen definieren volatile unsigned char zeichen[]; volatile unsigned char DP[] = ":"; volatile unsigned char aus_1[]; void show(void); // ISR einbinden ISR(TIMER1_COMPA_vect) { show(); } void show(void) { cli(); PORTC ^= (1<<PC5); // Blinken der LED itoa(sekunde, zeichen, 10); strcpy(aus_1, DP); strcat(aus_1, zeichen); lcd_setcursor(2,1); lcd_string(aus_1); sekunde++; if (sekunde == 59) { sekunde=0; PORTC ^= (1<<PC4); } sei(); } Was mache ich denn nun wieder falsch?
Hugo Hugoson schrieb: > Ich war fleißig und habe gelesen, aber sicher nicht genug :-( und so wie es aussieht auch die falsche Literatur > volatile unsigned char aus_1[]; Du musst schon auch mal sagen, wie groß denn dieses Array sein soll! Das kann sich der Compiler ja nicht aus den Fingern saugen. Hier > volatile unsigned char DP[] = ":"; kannst du die Längenangabe weglassen, weil der Compiler sich die Initialisierung ansieht, den ":", und für dich die Zeichen zählt. Um ":" in DP speichern zu können, muss DP mit einer Länge von 2 definiert werden. Und genau das macht der Compiler für dich. Da steht also eigentlich volatile unsigned char DP[2] = ":"; wobei der Compiler das Zählen für dich anhand der Initialisierung übernimmt. Aber den Fall hast du hier nicht volatile unsigned char aus_1[]; Hier bist du als Programmierer gefragt. Es ist dein Job dafür zu sorgen, dass dieses Array in der vom Programm benötigten Größe allokiert wird. Wieviel brauchst du denn mindestens? > strcpy(aus_1, DP); Also erst mal 1 > strcat(aus_1, zeichen); dann kommt noch 'zeichen' dazu. Wie groß kann 'zeichen' werden? itoa(sekunde, zeichen, 10); wenn wir mal davon ausgehen, dass sekunden (dem Namen nach) von 0 bis 59 laufen wird, sind das also 2 Zeichen. Macht in Summe erst mal 3 > lcd_setcursor(2,1); > lcd_string(aus_1); ok, das wars. 3 Zeichen. Dazu noch das obligatorische \0 Zeichen für das String Ende macht eine Mindestgröße von 4 für das Array. Wenn wir noch ein bischen Spielraum für Fehler einräumen (denn ob sekunden nicht auch mal 5478 sein wird, aus welchem Grund auch immer, kann ja mal passieren). Also wäre ein volatile unsigned char aus_1[4]; das Mindeste. Da Platz zur Zeit noch keine Rolle spielt, würde ich (um nicht gleich bei den ersten Fehlern auf die Schnauze zu fallen) einen volatile unsigned char aus_1[10]; machen.
1 | ISR(TIMER1_COMPA_vect) |
2 | {
|
3 | show(); |
4 | }
|
5 | |
6 | void show(void) |
7 | {
|
8 | cli(); |
9 | PORTC ^= (1<<PC5); // Blinken der LED |
10 | itoa(sekunde, zeichen, 10); |
11 | strcpy(aus_1, DP); |
12 | strcat(aus_1, zeichen); |
13 | lcd_setcursor(2,1); |
14 | lcd_string(aus_1); |
15 | sekunde++; |
16 | |
17 | if (sekunde == 59) |
18 | {
|
19 | sekunde=0; |
20 | PORTC ^= (1<<PC4); |
21 | }
|
22 | sei(); |
23 | }
|
Ausgaben aus einer ISR heraus sind keine gute Idee. Zum einen dauern sie viel zu lange. Zum anderen funkt dann eine Ausgabe aus der ISR heraus einer möglichen Ausgabe aus der Hauptschleife dazwischen. Und die wird eines Tages kommen! Zum andern: lass die sei() und cli() weg! Die willst du in einer ISR nicht haben. Interrupts sind während einer ISR sowieso automatisch gesperrt. Ganz im Gegenteil: der sei() kann dir eine Menge Ärger bereiten, solange du nicht weißt was du tust.
Karl Heinz Buchegger schrieb: >> volatile unsigned char aus_1[]; > > Du musst schon auch mal sagen, wie groß denn dieses Array sein soll! Das > kann sich der Compiler ja nicht aus den Fingern saugen. Dasselbe natürlich auch für volatile unsigned char zeichen[]; Hat sich denn dein Compiler da überhaupt nicht beschwert?`
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.