Forum: Mikrocontroller und Digitale Elektronik set_cursor() - Funktion legt LCD lahm


von Rush (Gast)


Lesenswert?

Hallo an alle...

Zuerst:
Controller:  ATmega8
Compiler:    AVR-GCC
Taktrate:    8 Mhz

Ich verwende zur Ansteuerung eines Displays diese lib:
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Programmierung

Das hat immer wunderbar funktioniert. Doch jetzt macht auf einmal die
set_curosor() - Funktion Probleme. Sobald diese irgendwo im Code 
aufgerufen wird zeit das LCD in der ersten Zeile nur die schwarzen 
Blöcke an. Allerdings sind diese nicht wirklich schwarz, eher kaum zu 
erkennen. Für mich sieht es so aus als würde das LCD ständig gelöscht 
und dann die Balken geschrieben werden.

Hab ich im code nirgends die set_cursor() - Funktion drin funzt das 
Display einwandfrei...

Hat jemand eine Idee woran das liegen könnte?

Danke schonmal im Voraus

von holger (Gast)


Lesenswert?

>Hab ich im code nirgends die set_cursor() - Funktion drin funzt das
>Display einwandfrei...

Welcher Code? Vieleicht legt dein Code ne Bauchlandung
wegen Stacküberlauf hin. Aber das kann man nicht beurteilen
solange man ihn nicht kennt.

von Rush (Gast)


Lesenswert?

Hier ist die Timerroutine:
1
ISR(TIMER2_COMP_vect)
2
{
3
  _CLI();
4
  cnt++;
5
  if (cnt==50)
6
    {
7
      
8
      switch(MenuVal)
9
      {
10
        case 0:
11
          temperature = gettemp();
12
          if (temperature < 120)
13
            {
14
              temperature = temperature / 4;    // MAX6675-Wert durch vier teilen da Auflösung 0,25
15
              dtostrf(temperature, 2,2, temp);
16
              lcd_clear();
17
              set_cursor(0,2);
18
              lcd_string(temp);
19
              OUT_PORT |= (1<<HEAT_OUT);
20
            }else
21
            {
22
              temperature = temperature / 4;    // MAX6675-Wert durch vier teilen da Auflösung 0,25
23
              dtostrf(temperature, 2,2, temp);
24
              lcd_clear();
25
              lcd_string(temp);
26
              OUT_PORT &=~ (1<<HEAT_OUT);
27
            }break;
28
            }
29
    cnt = 0;
30
    }
31
32
33
  _SEI();
34
}

Und das ist der Code für die LCD-Funktionen:
1
// Ansteuerung eines HD44780 kompatiblen LCD im 4-Bit-Interfacemodus
2
// http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial
3
//
4
// Die Pinbelegung ist über defines in lcd-routines.h einstellbar
5
 
6
#include <avr/io.h>
7
#include "lcd-routines.h"
8
#include <util/delay.h>
9
 
10
// sendet ein Datenbyte an das LCD
11
 
12
void lcd_data(unsigned char temp1)
13
{
14
   unsigned char temp2 = temp1;
15
 
16
   LCD_PORT |= (1<<LCD_RS);        // RS auf 1 setzen
17
 
18
   temp1 = temp1 >> 4;
19
   temp1 = temp1 & 0x0F;
20
   LCD_PORT &= 0xF0;
21
   LCD_PORT |= temp1;               // setzen
22
   lcd_enable();
23
 
24
   temp2 = temp2 & 0x0F;
25
   LCD_PORT &= 0xF0;
26
   LCD_PORT |= temp2;               // setzen
27
   lcd_enable();
28
   
29
   _delay_us(42);
30
}
31
 
32
// sendet einen Befehl an das LCD
33
 
34
void lcd_command(unsigned char temp1)
35
{
36
   unsigned char temp2 = temp1;
37
 
38
   LCD_PORT &= ~(1<<LCD_RS);        // RS auf 0 setzen
39
 
40
   temp1 = temp1 >> 4;              // oberes Nibble holen
41
   temp1 = temp1 & 0x0F;            // maskieren
42
   LCD_PORT &= 0xF0;
43
   LCD_PORT |= temp1;               // setzen
44
   lcd_enable();
45
 
46
   temp2 = temp2 & 0x0F;            // unteres Nibble holen und maskieren
47
   LCD_PORT &= 0xF0;
48
   LCD_PORT |= temp2;               // setzen
49
   lcd_enable();
50
   
51
   _delay_us(42);
52
}
53
 
54
// erzeugt den Enable-Puls
55
void lcd_enable(void)
56
{
57
   // Bei Problemen ggf. Pause gemäß Datenblatt des LCD Controllers einfügen
58
   // http://www.mikrocontroller.net/topic/81974#685882
59
   LCD_PORT |= (1<<LCD_EN);
60
    _delay_ms(1);                   // kurze Pause
61
   // Bei Problemen ggf. Pause gemäß Datenblatt des LCD Controllers verlängern
62
   // http://www.mikrocontroller.net/topic/80900
63
   LCD_PORT &= ~(1<<LCD_EN);
64
}
65
 
66
// Initialisierung: 
67
// Muss ganz am Anfang des Programms aufgerufen werden.
68
 
69
void lcd_init(void)
70
{
71
   LCD_DDR = LCD_DDR | 0x0F | (1<<LCD_RS) | (1<<LCD_EN);   // Port auf Ausgang schalten
72
 
73
   // muss 3mal hintereinander gesendet werden zur Initialisierung
74
 
75
   _delay_ms(15);
76
   LCD_PORT &= 0xF0;
77
   LCD_PORT |= 0x03;            
78
   LCD_PORT &= ~(1<<LCD_RS);      // RS auf 0
79
   lcd_enable();
80
 
81
   _delay_ms(5);
82
   lcd_enable();
83
 
84
   _delay_ms(1);
85
   lcd_enable();
86
   _delay_ms(1);
87
 
88
   // 4 Bit Modus aktivieren 
89
   LCD_PORT &= 0xF0;
90
   LCD_PORT |= 0x02;
91
   lcd_enable();
92
   _delay_ms(1);
93
 
94
   // 4Bit / 2 Zeilen / 5x7
95
   lcd_command(0x28);
96
    
97
   // Display ein / Cursor aus / kein Blinken
98
   lcd_command(0x0C); 
99
 
100
   // inkrement / kein Scrollen
101
   lcd_command(0x06);
102
 
103
   lcd_clear();
104
}
105
 
106
// Sendet den Befehl zur Löschung des Displays
107
 
108
void lcd_clear(void)
109
{
110
   lcd_command(CLEAR_DISPLAY);
111
   _delay_ms(5);
112
}
113
 
114
// Sendet den Befehl: Cursor Home
115
 
116
void lcd_home(void)
117
{
118
   lcd_command(CURSOR_HOME);
119
   _delay_ms(5);
120
}
121
 
122
// setzt den Cursor in Zeile y (1..4) Spalte x (0..15)
123
 
124
void set_cursor(uint8_t x, uint8_t y)
125
{
126
  uint8_t tmp;
127
 
128
  switch (y) {
129
    case 1: tmp=0x80+0x00+x; break;    // 1. Zeile
130
    case 2: tmp=0x80+0x40+x; break;    // 2. Zeile
131
    case 3: tmp=0x80+0x10+x; break;    // 3. Zeile
132
    case 4: tmp=0x80+0x50+x; break;    // 4. Zeile
133
    default: return;                   // für den Fall einer falschen Zeile
134
  }
135
  lcd_command(tmp);
136
}
137
 
138
// Schreibt einen String auf das LCD
139
 
140
void lcd_string(char *data)
141
{
142
    while(*data) {
143
        lcd_data(*data);
144
        data++;
145
    }
146
}

von holger (Gast)


Lesenswert?

Du solltest mal an den Routinen arbeiten die
du hier nicht gepostet hast. Du verschwendest
vermutlich zu viel RAM.

von Rush (Gast)


Lesenswert?

Naja, da ist nicht mehr drin außer die main ;)

von holger (Gast)


Lesenswert?

>>Naja, da ist nicht mehr drin außer die main ;)

Och das würde ich so nicht sagen ;)

          temperature = gettemp();

gettemp() fehlt.

>          dtostrf(temperature, 2,2, temp);

Muss temperature float sein?
Wie groß ist das temp Array?
Fragen über Fragen.

von Werner B. (werner-b)


Lesenswert?

@Rush,

Ein Tipp.
Gewöhne dir das _CLI() / _SEI() in der ISR ab, denn  ...
A) das macht schon der Compiler.
B) es kann Probleme machen wenn du es zusätzlich selbst
   machst (rätselhaft Abstürze etc.).
C) Sind in <avr/interrupt.h> definiert als sei() / cli().


P.S. Schrecklich - Hinweis mit zwei P schreiben zu müssen (grusel).
     Zumal für uns Franken, da gibt es diesen Buchstaben nicht ;-)
     Übersetzung P -> B; T -> D

P.P.S. Und "delay" in einer ISR ... noch mehr Gruseln + Schaudern.

von Rush (Gast)


Lesenswert?

Die Funktion fehlt, stimmt ;-)
Die gettemp() gibt einen uint_16 zurück.
Da ich diesen Wert aber noch durch 4 teilen muss brauche ich doch einen 
float, sonst komme ich nicht an die Kommastellen rein.

Was den Code angeht: Ich habe testweise einfach den aus dem Tutorial 
verwendet
1
// 
2
// Anpassungen im makefile:
3
//    ATMega8 => MCU=atmega8 im makefile einstellen
4
//    lcd-routines.c in SRC = ... Zeile anhängen
5
// 
6
#include <avr/io.h>
7
#include "lcd-routines.h"
8
 
9
int main(void)
10
{
11
    lcd_init();
12
 
13
    lcd_data('T');
14
    lcd_data('e');
15
    lcd_data('s');
16
    lcd_data('t');
17
 
18
    set_cursor(0,2);
19
 
20
    lcd_string("Hello World!");
21
 
22
    while(1)
23
    {
24
    }
25
 
26
    return 0;
27
}

Der funktioniert auch nicht. Aber auf einem Mega16 per JTAG geflasht 
läuft er komischerweise.

Den neusten Compiler habe ich auch schon installiert, ohne Erfolg :-(

von Peter D. (peda)


Lesenswert?

Werner B. wrote:
> Gewöhne dir das _CLI() / _SEI() in der ISR ab, denn  ...
> A) das macht schon der Compiler.

Nein, das macht die Hardware.


Peter

von Rush (Gast)


Lesenswert?

@Werner B.

Ich habe doch garkein delay in der ISR drin.

und was _CLI und _SEI angeht, meinste ich soll das einfach weglassen, 
oder sei() und cli() benutzen?

von Stefan E. (sternst)


Lesenswert?

Rush wrote:

> Ich habe doch garkein delay in der ISR drin.

Doch, in den LCD-Funktionen.

> und was _CLI und _SEI angeht, meinste ich soll das einfach weglassen,
> oder sei() und cli() benutzen?

Komplett weglassen.

von holger (Gast)


Lesenswert?

>Der funktioniert auch nicht. Aber auf einem Mega16 per JTAG geflasht
>läuft er komischerweise.

Also wenn dein Minicode (ohne Interrupt) schon nicht
funktioniert wird es wohl an etwas anderem liegen.
Hast du den Code auch für einen ATMega8 neu compiliert?
Oder vieleicht die falsche HEX-Datei erwischt?

von Rush (Gast)


Lesenswert?

alles neu kompiliert, im AVR-Studio auch ein anderes Device angelegt, 
die Taktraten angepasst und direkt ausm AVR-Studio draufgeflasht. Tut 
sich nichts.
Eben habe ich es mit einem zweiten Mega8 probiert, ebenfalls nichts.

von Rush (Gast)


Lesenswert?

Kann mir denn keiner mehr helfen ??

von gast (Gast)


Lesenswert?

"direkt ausm AVR-Studio draufgeflasht"
deswegen musst du trotzdem die richtige *.hex vorher einstellen

von Rush (Gast)


Lesenswert?

Da der mega8 kein JTAG hat starte ich das Programm mit "Built and Run" 
im Simulator. Um das Proggi zu flashen wähle ich dann kein HEX-File 
sondern nehme die Option "Use current Simulator/Emulator Flash memory". 
Und ich flashe auch das Flash und schreibe nicht ins EEPROM.

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

Hast du vieleicht ne Wackelkontakt/Lötbrücke am Mega8 Baord die nur 
schaden bei diesem Speziellem Befehl erzeugt? Vieleicht geht der Mega8 
auch in Reset. Ich würd das mal prüfen das du ne LED am Anfang des 
Programms einschaltest und nach dem Setcursor aus.
Wenn die LED ausbleibt dan hängt das LCD sonst resetet vermutlich der 
AVR.

von Rush (Gast)


Lesenswert?

Also bei dem Programm:
1
#include <avr/io.h>
2
#include "lcd-routines.h"
3
extern void lcd_data(unsigned char temp1);
4
extern void lcd_command(unsigned char temp1);
5
extern void lcd_enable(void);
6
extern void lcd_init(void);
7
extern void lcd_home(void);
8
extern void lcd_clear(void);
9
extern void set_cursor(uint8_t x, uint8_t y);
10
11
void main(void)
12
{
13
  DDRD |= (1<<PD4);
14
  PORTD |= (1<<PD4);
15
  lcd_init();
16
//  set_cursor(0,1);
17
  lcd_data('T');
18
  set_cursor(0,2);
19
  lcd_string("Hallo");
20
  PORTD &=~ (1<<PD4);
21
  
22
  while(1){}
23
}
geht die LED an und auch wieder aus. Display bleibt leer.
Kommentiere ich das set_cursor(0,2) aus, schreibt er mir in die erste 
Zeile "THallo" rein.

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

Set cursor sollte eigentlich nur werte > 0 aktzeptieren oder seh ic das 
jezt gerade falsch?

von Rush (Gast)


Lesenswert?

der erste wert steht für die stelle in der zeile und der zweite eben für 
die zeile.
Also (0,2) wäre in dem Fall die erste Stelle in der zweiten zeile.
(1,2) wäre die zweite Stelle in der zweiten Zeile. Wobei ich das mal 
testweise versucht habe und es klappt.... Schreibt dann in die zweite 
Zeile aber auch in die zweite Stelle. Also akzeptiert die funktion die 0 
nicht, nur warum ?

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

Vieleicht hat dein Display ein etwas anderes Speicherlayout als das 
welches Im Tutorial verwendet wird. Einige Controller haben da ihre 
eigene Ansichten (Datenblatt zu dem auf dem Display verwendeten 
Controller kann darüber aufschluß geben).

Kannst natürlich die Funktion auch das +1 überlassen ;)
1
void set_cursor(uint8_t x, uint8_t y)
2
{
3
  uint8_t tmp;
4
 
5
  switch (y) {
6
    case 1: tmp=0x80+0x00+x+1; break;    // 1. Zeile
7
    case 2: tmp=0x80+0x40+x+1; break;    // 2. Zeile
8
    case 3: tmp=0x80+0x10+x+1; break;    // 3. Zeile
9
    case 4: tmp=0x80+0x50+x+1; break;    // 4. Zeile
10
    default: return;                   // für den Fall einer falschen Zeile
11
  }
12
  lcd_command(tmp);
13
}

von Rush (Gast)


Lesenswert?

Das seltsame ist ja dass die Funktion schon mit dem Display was ich in 
diesem Fall verwende immer einwandfrei funktioniert hat. Nur eben jetzt 
komischerweise nicht.

das mit dem +1 wäre ja machbar, dann verliere ich aber immer die 1. 
Stelle der Zeile, bei set_cursor(1,2) wird der Text erst ab der zweiten 
Stelle des LCD dargestellt.

von holger (Gast)


Lesenswert?

Kannst du probehalber einfach statt setcursor(0,2); mal
lcd_command(0xC0); ausführen?

von Rush (Gast)


Lesenswert?

lcd_command(0xC0) geht auch nicht,
lcd_command(192) geht auch nicht,
set_cursor(1,2); set_cursor(2,2); set_cursor(3,2) bis set_cursor(15,2) 
funktioniert, ich kann nur nicht die erste Stelle in der Zeile 
ansprechen.

Die Funktion an sich wird auch durchlaufen, denn danach lasse ich eine 
LED aufleuchten und die leuchtet auch.

von holger (Gast)


Lesenswert?

>lcd_command(0xC0) geht auch nicht,

Jetzt wirds aber ziemlich unheimlich.
Also dein Display funktioniert auf ATMega16.
Hast du nach dem umstellen des Prozessors mal
ein "Rebuild all" oder "make clean" gemacht?
Nicht das die LCD Routinen noch als Objektfile
vom ATMega16 gelinkt werden.

von holger (Gast)


Lesenswert?

Noch vergessen: Probiers doch auch mal über ein richtiges Hexfile.

von Rush (Gast)


Lesenswert?

Ich habe diesen minicode in einem eigenständigen Projekt geschrieben, 
also nicht einfach das Projekt vom mega16 genommen und den Controllertyp 
gewechselt. Make clean, Rebuild all... hab ich alles schon probiert.

Ich habe geschrieben das selbe Display mit einem mega16 funzt. 
Vielleicht habe ich mich etwas falsch ausgerückt...
Mit "das selbe Display" meine ich ein vom Typ identisches, hatte damals 
6 Stück bei ebay gekauft. Also eins habe ich am mega16 hängen, das 
andere in meiner Schaltung an der ich rumdoktor....

PS: habe die Schaltung zum x-ten mal durchgemessen... alles OK.

Kann es sein das das Display aus welchem Grund auch immer einen Schaden 
hat, dass es mit den ersten stellen der Zeilen nicht klar kommt ?

von holger (Gast)


Lesenswert?

>Kann es sein das das Display aus welchem Grund auch immer einen Schaden
>hat, dass es mit den ersten stellen der Zeilen nicht klar kommt ?

Das sieht zumindest so aus. Kannst du die Displays nicht
mal durchtauschen? Das wär das erste was ich machen würde.

von Rush (Gast)


Lesenswert?

Das ist das letzte was ich machen würde bzw. wohl muss :(
Die Sch****e ist nur das die Lötstellen jetzt nur schwer zugänglich sind 
da die Schaltung schon komplett aufgebaut ist :-(

Das ist seltsam, das Teil lief ja schonmal ohne Probleme, dann lag es ne 
zeit lang rum ohne dass ich was dran gemacht hatte. Bis ich dann auf die 
Idee kam die Software umzugestalten, dann gings auf einmal nicht.

von Rush (Gast)


Lesenswert?

Aber ist doch komisch, wenn ich doch auf die 2. Stelle einer Zeile 
springen kann, kann es doch auch nicht kaputt sein ?!

von holger (Gast)


Lesenswert?

>Aber ist doch komisch, wenn ich doch auf die 2. Stelle einer Zeile
>springen kann, kann es doch auch nicht kaputt sein ?!

Zumindest nicht ganz kaputt. Vieleicht doch noch
irgendwo am Code gefummelt? Poste das fehlerhafte
Projekt doch mal komplett als ZIP.

von Rush (Gast)


Angehängte Dateien:

Lesenswert?

So, hier das komplette Projekt als Zip.
In der lcd-routines.c habe ich die Zeit in der lcd_enable() Funktion auf 
90ms gesetzt.
So sehe ich bei Ausführung des angehängten codes wie die erste Zeile 
dargestellt wird und anschließend das LCD wieder gelöscht wird. Die LED 
zum Schluss des Programms geht an!

von Rush (Gast)


Lesenswert?

Info an alle hier Beteiligten...

Das LCD hat einen Schlag.... hab es eben mal ausgetauscht und siehe da 
es funzt auf Anhieb..

Einene derartigen Defekt habe ich jetzt garnicht erwartet.

Vielen Dank für eure Bemühungen

Gruß, Konrad

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.