Forum: Compiler & IDEs LCD - Ausgabefehler


von Christian (Gast)


Angehängte Dateien:

Lesenswert?

Hallo Forum

Habe ein Problem mit der LCD - Ausgabe.
Kurze Fehlerbeschreibung:
Gebe an das Display in Zeile1 'Satellite Tracking' und in Zeile2 
'System' aus. Beide Strings habe ich in die Mitte des LCD positioniert.
Nach 5 sec soll ein anderer Text ausgegeben werden und nach weiteren 5 
sec ein weiterer Text. Danach soll wieder Text Nr.1 ausgegeben werden.
Da das LCD nach dem Umschalten auf den nächsten Text einzelne Buchstaben 
des vorigen Textes ausgab, begann ich mit der Fehlersuche.
Ich veränderte den Code so, dass immer nur Text 1 ausgegeben werden 
soll. Nachdem ich den Code an den µC übertragen hatte, bestand immer 
noch das Problem. In Zeile2 stand kurz nach der Übertragung nicht mehr 
'System', sondern 'SystemSysem'. Nach weiteren 5 sec werden wieder 
andere Zeichen übertragen.

Verwende als Routinen den LCD Code vom Tutorial.
Programmiere mit AVR Studio und WinAVR 20090313

Hier ein Kleiner Ausschnitt des Codes:
1
ISR(TIMER0_COMP_vect){
2
3
  
4
  Zaehler++;
5
  if(Zaehler == 625){
6
    
7
    if(dddd == 1){
8
      .
9
      .
10
      .
11
    }
12
13
    if(dddd == 2){
14
          
15
      lcd_clear();
16
      //LCD_Ausgabe++;       // zur Fehlerbegrenzung
17
                             // auskommentiert
18
      Zaehler = 0;
19
      if(LCD_Ausgabe == 4){
20
21
        LCD_Ausgabe = 1;
22
        
23
      }
24
      asdf = 1;
25
    }
26
  }
27
}
28
29
30
31
32
int main(void){
33
34
        .
35
        .
36
        .
37
38
  TIMSK |= (1<<OCIE0);
39
40
  DDRC = 0xff;
41
  PORTC = 0xFF;
42
  sei();
43
44
  lcd_init();
45
46
  TCCR0 |= (1<<WGM01);
47
  OCR0 = 249;
48
  Uebertragung1 = 1;
49
  LCD_Ausgabe = 1;
50
        gh = 1;
51
  
52
  while(1){
53
54
    if(Uebertragung1 == 1){
55
      
56
      dddd = 2;
57
      
58
      if(LCD_Ausgabe == 1){
59
60
        set_cursor(1,1);
61
        lcd_string("Satellite Tracking");  
62
        set_cursor(7,2);
63
        lcd_string("System");
64
        //set_cursor(5,1);
65
        if(gh == 1){
66
67
          TCCR0 |= (1<<CS02);
68
          gh = 0;
69
        }
70
      }
71
72
      if(LCD_Ausgabe == 2){
73
74
        set_cursor(1,1);
75
        lcd_string("aaaaaaaaaaaaaaaaaaa");  
76
        set_cursor(7,2);
77
        lcd_string("bbbbbbbbbbbbb");
78
      }
79
80
      if(LCD_Ausgabe == 3){
81
82
        set_cursor(1,1);
83
        lcd_string("ccccccccccccccccccc");  
84
        set_cursor(7,2);
85
        lcd_string("dddddddddddddddd");
86
      }
87
    }
88
89
      .
90
      .
91
      .


Weiß leider nicht wo der Fehler liegt.
Es kann sich nur um einen kleinen Fehler handeln, da das Programm (außer 
das LCD) an sich funktioniert.


Weiters bekomme ich immer ein Warning.
> passing argument 1 of 'strtok' discards qualifiers from pointer target type


Wo liegt hier das Problem?

Danke für eure Hilfe.

von Εrnst B. (ernst)


Lesenswert?

Welcher AVR?
Evtl zu wenig Ram => Stacküberlauf?
oder F_CPU falsch gesetzt => LCD-Wartezeiten zu kurz => set_cursor 
funktioniert nicht?

> passing argument 1 of 'strtok' discards qualifiers from pointer target type

strtok mag einen char * als source-string, keinen volatile unsigned char 
*...
Richtige typen verwenden oder mit cast compiler zum schweigen bringen.

von Christian (Gast)


Lesenswert?

Verwende einen ATmegs32, hab also noch ausreichend Ressourcen.
F_CPU kann nicht falsch gesetzt sein, da alle anderen Programme damit 
einwandfrei funktionierten.

von Peter D. (peda)


Lesenswert?

Du mußt Dich schon entscheiden, wo Du das LCD benutzt, im Main oder im 
Interrupt.
Beides zusammen geht nicht!

Und Interrupt ist definitiv der falsche Platz, wenn Du auch mal größere 
Programme schreiben willst.
Das LCD ist nämlich ein sehr langsames Gerät, versaut Dir also die 
Interrupt-Response.


Peter

von Christian (Gast)


Lesenswert?

Hallo Peter

Danke für den Tipp.
Hab statt lcd_clear(); eine Variabe gesetzt und das LCD im main 
gelöscht.
Jetzt funktioniert es ohne Probleme. Sind solche Hilfsvariablen die 
beste Lösung für LCD-Befehle, die in der ISR gebraucht werden?

In der Interrupt - Routine habe ich unter if(dddd == 1) noch ein 
lcd_clear();. Dieser Befehl scheint dem Programm nichts auszumachen, 
erst bei zwei LCD-Befehlen arbeitet der µC nicht korrekt. Sollte ich das 
noch vorhandene lcd_clear(); aus der Routine auch entvernen?
Warum funktioniert die Verwendung im main und im Interrupt zusammen 
nicht?
Danke für Deine Bemühungen.

von Karl H. (kbuchegg)


Lesenswert?

Christian schrieb:

> Jetzt funktioniert es ohne Probleme. Sind solche Hilfsvariablen die
> beste Lösung für LCD-Befehle, die in der ISR gebraucht werden?

Im Grunde ja.
Man nennt die Dinger 'Jobflags'.
Sie zeigen der Hauptschleife an, dass ein Job zu erledigen ist, bei dir 
das löschen eines LCD.

Aber im Grunde hast du trotzdem immer noch einen falschen Ansatz.
Die ISR soll sich nämlich im Grunde überhaupt nicht um das LCD kümmern.
Die ISR macht eine Modusumschaltung. Dein LCD geht vom Modus "Ausgabe 1 
anzeigen" über in den Modus "Ausgabe 2 anzeigen". Und die Hauptschleife 
entscheidet, was dazu alles notwendig ist.

> In der Interrupt - Routine habe ich unter if(dddd == 1) noch ein
> lcd_clear();. Dieser Befehl scheint dem Programm nichts auszumachen,
> erst bei zwei LCD-Befehlen arbeitet der µC nicht korrekt. Sollte ich das
> noch vorhandene lcd_clear(); aus der Routine auch entvernen?

Ja. Schmeiss es raus. Und wechsle deine Sichtweise der Dinge. Die ISR 
geht es überhaupt nichts an, dass da ein LCD existiert (siehe oben mit 
den Modi)

> Warum funktioniert die Verwendung im main und im Interrupt zusammen
> nicht?

Weil du nicht darauf achtest, welche Anweisungen in der Hauptschleife 
unterbrichen werden, wenn der Interrupt kommt.

Du hast momentan eine gemeinsam genutzte Resource, die aus mehreren 
Threads angesprochen wird.
Stell dir einen Drucker vor und 2 Threads. Der 2.te Thread kann den 
ersten jederzeit unterbrechen.
So, jetzt versucht der 1.te Thread eine Ausgabe am Drucker zu machen. Er 
will "Willkommen" dort hinschreiben. Also fängt er an:
W hinmalen
i hinmalen
l hinmalen
l hinmalen

und jetzt schlägt der 2.te Thread zu und gibt seinerseits etwas auf dem 
Drucker aus: "Hallo"
H hinmalen
a hinmalen
l hinmalen
l hinmalen
o hinmalen

der 2. Thread hat seinen Job erledigt und die Kontrolle geht zum 1.ten 
Thread zurück. Der wurde bei der Ausgabe unterbrochen und macht dort 
weiter wo er unterbrichen wurde. Also malt er weiter
k hinmalen
o hinmalen
...

Auf dem Druckerpapier steht dann: WillHallokommen

So. jetzt kanns natürlich noch dicker kommen. Was ich so lapidar als 
'hinmalen' bezeichnet habe, sind in Wirklichkeit ja auch Aktionen, die 
eine gewisse Zeit dauern und in sich wieder aus vielen Aktionen 
bestehen. Je nachdem, wo genau der 2-te Thread den ersten unterbricht, 
kann da alles mögliche entstehen. Von "der eine Thread hat den Cursor an 
die Position 10 geschickt, der andere ändert ihm das 'unter dem Arsch'" 
bis hin zu "der eine Thread schaltet die Portpins so wie er sie braucht, 
die ihm der andere gleich wieder anders umschaltet".

von Christian (Gast)


Lesenswert?

Karl heinz Buchegger schrieb:
> Aber im Grunde hast du trotzdem immer noch einen falschen Ansatz.
> Die ISR soll sich nämlich im Grunde überhaupt nicht um das LCD kümmern.
> Die ISR macht eine Modusumschaltung. Dein LCD geht vom Modus "Ausgabe 1
> anzeigen" über in den Modus "Ausgabe 2 anzeigen". Und die Hauptschleife
> entscheidet, was dazu alles notwendig ist.

Ok! Habe verstanden, dass sich die ISR nicht um das LCD kümmern soll. 
Trotzdem entscheidet die ISR durch diese Jobflags was zu tun ist. In 
meinem Programm kümmert sie sich um das LCD.
Wo ist der falsche Ansatz, wenn meine ISR durch setzen von Variablen dem 
main mitteilt, dass es im darauffolgenden Durchlauf das LCD löschen 
soll?

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.