Forum: Compiler & IDEs LCD und kein Ende


von Hugo H. (planetenbepinkler)


Lesenswert?

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.

von troll (Gast)


Lesenswert?

Du musst lcd.c zum Projekt hinzufügen.

von Hugo H. (planetenbepinkler)


Lesenswert?

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?

von Karl H. (kbuchegg)


Lesenswert?

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.

von Hugo H. (planetenbepinkler)


Lesenswert?

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 :-(

von Hugo H. (planetenbepinkler)


Lesenswert?

Sorry, solte natürlich undefined reference to `lcd_clrscr' heißen.

von g457 (Gast)


Lesenswert?

> 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.

von Karl H. (kbuchegg)


Lesenswert?

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.

von Hugo H. (planetenbepinkler)


Lesenswert?

Okay, ich werde mir einen Kaffee kochen, dein Geschriebenes verdauen, 
suchen, zusammenstellen und - sehen, was passiert.
Danke!

von Hugo H. (planetenbepinkler)


Lesenswert?

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 ;-)

von Peter D. (peda)


Lesenswert?


von Hugo H. (planetenbepinkler)


Lesenswert?

Alles gut jetzt!
Vielen Dank an alle! :-)

von Hugo H. (planetenbepinkler)


Lesenswert?

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?

von troll (Gast)


Lesenswert?

Du musst Zahlen in ASCII-Zeichen zerlegen und einzelnd senden. Und bitte 
in der mainloop und nicht im Interrupt. Guck dir mal itoa() an.

von troll (Gast)


Lesenswert?

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.

von Hugo H. (planetenbepinkler)


Lesenswert?

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?

von Karl H. (kbuchegg)


Lesenswert?

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.

von Karl H. (kbuchegg)


Lesenswert?

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.

von Karl H. (kbuchegg)


Lesenswert?

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
Noch kein Account? Hier anmelden.