www.mikrocontroller.net

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


Autor: Rush (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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-Tu...

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

Autor: holger (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Rush (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hier ist die Timerroutine:
ISR(TIMER2_COMP_vect)
{
  _CLI();
  cnt++;
  if (cnt==50)
    {
      
      switch(MenuVal)
      {
        case 0:
          temperature = gettemp();
          if (temperature < 120)
            {
              temperature = temperature / 4;    // MAX6675-Wert durch vier teilen da Auflösung 0,25
              dtostrf(temperature, 2,2, temp);
              lcd_clear();
              set_cursor(0,2);
              lcd_string(temp);
              OUT_PORT |= (1<<HEAT_OUT);
            }else
            {
              temperature = temperature / 4;    // MAX6675-Wert durch vier teilen da Auflösung 0,25
              dtostrf(temperature, 2,2, temp);
              lcd_clear();
              lcd_string(temp);
              OUT_PORT &=~ (1<<HEAT_OUT);
            }break;
            }
    cnt = 0;
    }


  _SEI();
}

Und das ist der Code für die LCD-Funktionen:
// Ansteuerung eines HD44780 kompatiblen LCD im 4-Bit-Interfacemodus
// http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial
//
// Die Pinbelegung ist über defines in lcd-routines.h einstellbar
 
#include <avr/io.h>
#include "lcd-routines.h"
#include <util/delay.h>
 
// sendet ein Datenbyte an das LCD
 
void lcd_data(unsigned char temp1)
{
   unsigned char temp2 = temp1;
 
   LCD_PORT |= (1<<LCD_RS);        // RS auf 1 setzen
 
   temp1 = temp1 >> 4;
   temp1 = temp1 & 0x0F;
   LCD_PORT &= 0xF0;
   LCD_PORT |= temp1;               // setzen
   lcd_enable();
 
   temp2 = temp2 & 0x0F;
   LCD_PORT &= 0xF0;
   LCD_PORT |= temp2;               // setzen
   lcd_enable();
   
   _delay_us(42);
}
 
// sendet einen Befehl an das LCD
 
void lcd_command(unsigned char temp1)
{
   unsigned char temp2 = temp1;
 
   LCD_PORT &= ~(1<<LCD_RS);        // RS auf 0 setzen
 
   temp1 = temp1 >> 4;              // oberes Nibble holen
   temp1 = temp1 & 0x0F;            // maskieren
   LCD_PORT &= 0xF0;
   LCD_PORT |= temp1;               // setzen
   lcd_enable();
 
   temp2 = temp2 & 0x0F;            // unteres Nibble holen und maskieren
   LCD_PORT &= 0xF0;
   LCD_PORT |= temp2;               // setzen
   lcd_enable();
   
   _delay_us(42);
}
 
// erzeugt den Enable-Puls
void lcd_enable(void)
{
   // Bei Problemen ggf. Pause gemäß Datenblatt des LCD Controllers einfügen
   // http://www.mikrocontroller.net/topic/81974#685882
   LCD_PORT |= (1<<LCD_EN);
    _delay_ms(1);                   // kurze Pause
   // Bei Problemen ggf. Pause gemäß Datenblatt des LCD Controllers verlängern
   // http://www.mikrocontroller.net/topic/80900
   LCD_PORT &= ~(1<<LCD_EN);
}
 
// Initialisierung: 
// Muss ganz am Anfang des Programms aufgerufen werden.
 
void lcd_init(void)
{
   LCD_DDR = LCD_DDR | 0x0F | (1<<LCD_RS) | (1<<LCD_EN);   // Port auf Ausgang schalten
 
   // muss 3mal hintereinander gesendet werden zur Initialisierung
 
   _delay_ms(15);
   LCD_PORT &= 0xF0;
   LCD_PORT |= 0x03;            
   LCD_PORT &= ~(1<<LCD_RS);      // RS auf 0
   lcd_enable();
 
   _delay_ms(5);
   lcd_enable();
 
   _delay_ms(1);
   lcd_enable();
   _delay_ms(1);
 
   // 4 Bit Modus aktivieren 
   LCD_PORT &= 0xF0;
   LCD_PORT |= 0x02;
   lcd_enable();
   _delay_ms(1);
 
   // 4Bit / 2 Zeilen / 5x7
   lcd_command(0x28);
    
   // Display ein / Cursor aus / kein Blinken
   lcd_command(0x0C); 
 
   // inkrement / kein Scrollen
   lcd_command(0x06);
 
   lcd_clear();
}
 
// Sendet den Befehl zur Löschung des Displays
 
void lcd_clear(void)
{
   lcd_command(CLEAR_DISPLAY);
   _delay_ms(5);
}
 
// Sendet den Befehl: Cursor Home
 
void lcd_home(void)
{
   lcd_command(CURSOR_HOME);
   _delay_ms(5);
}
 
// setzt den Cursor in Zeile y (1..4) Spalte x (0..15)
 
void set_cursor(uint8_t x, uint8_t y)
{
  uint8_t tmp;
 
  switch (y) {
    case 1: tmp=0x80+0x00+x; break;    // 1. Zeile
    case 2: tmp=0x80+0x40+x; break;    // 2. Zeile
    case 3: tmp=0x80+0x10+x; break;    // 3. Zeile
    case 4: tmp=0x80+0x50+x; break;    // 4. Zeile
    default: return;                   // für den Fall einer falschen Zeile
  }
  lcd_command(tmp);
}
 
// Schreibt einen String auf das LCD
 
void lcd_string(char *data)
{
    while(*data) {
        lcd_data(*data);
        data++;
    }
}

Autor: holger (Gast)
Datum:

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

Autor: Rush (Gast)
Datum:

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

Autor: holger (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Werner B. (werner-b)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Rush (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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
// 
// Anpassungen im makefile:
//    ATMega8 => MCU=atmega8 im makefile einstellen
//    lcd-routines.c in SRC = ... Zeile anhängen
// 
#include <avr/io.h>
#include "lcd-routines.h"
 
int main(void)
{
    lcd_init();
 
    lcd_data('T');
    lcd_data('e');
    lcd_data('s');
    lcd_data('t');
 
    set_cursor(0,2);
 
    lcd_string("Hello World!");
 
    while(1)
    {
    }
 
    return 0;
}


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

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Rush (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: holger (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Rush (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Rush (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Kann mir denn keiner mehr helfen ??

Autor: gast (Gast)
Datum:

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

Autor: Rush (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Läubi .. (laeubi) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Rush (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also bei dem Programm:
#include <avr/io.h>
#include "lcd-routines.h"
extern void lcd_data(unsigned char temp1);
extern void lcd_command(unsigned char temp1);
extern void lcd_enable(void);
extern void lcd_init(void);
extern void lcd_home(void);
extern void lcd_clear(void);
extern void set_cursor(uint8_t x, uint8_t y);

void main(void)
{
  DDRD |= (1<<PD4);
  PORTD |= (1<<PD4);
  lcd_init();
//  set_cursor(0,1);
  lcd_data('T');
  set_cursor(0,2);
  lcd_string("Hallo");
  PORTD &=~ (1<<PD4);
  
  while(1){}
}
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.

Autor: Läubi .. (laeubi) Benutzerseite
Datum:

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

Autor: Rush (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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 ?

Autor: Läubi .. (laeubi) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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 ;)
void set_cursor(uint8_t x, uint8_t y)
{
  uint8_t tmp;
 
  switch (y) {
    case 1: tmp=0x80+0x00+x+1; break;    // 1. Zeile
    case 2: tmp=0x80+0x40+x+1; break;    // 2. Zeile
    case 3: tmp=0x80+0x10+x+1; break;    // 3. Zeile
    case 4: tmp=0x80+0x50+x+1; break;    // 4. Zeile
    default: return;                   // für den Fall einer falschen Zeile
  }
  lcd_command(tmp);
}

Autor: Rush (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: holger (Gast)
Datum:

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

Autor: Rush (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: holger (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: holger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Noch vergessen: Probiers doch auch mal über ein richtiges Hexfile.

Autor: Rush (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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 ?

Autor: holger (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Rush (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Rush (Gast)
Datum:

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

Autor: holger (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Rush (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht 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!

Autor: Rush (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.