mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Problem mit Pointern


Autor: astroscout (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,
ich habe die Poiter zwar weitgehend verstanden, aber irgendwie stehe ich 
gerade auf dem Schlau :-)

Ich will den Inhalt (oder genauer den Pointer auf den Inhalt), der auf 
meinem LCD dargestellt werden soll, in einer Globalen Variable 
speichern. Die ist notwendig, da ich per ISR (durch einen Taster 
ausgelöst) kutzzeitig einen anderen Text auf dem LCD darstellen will, 
beim verlassen der ISR soll jedoch der ursprünglich Text wieder 
angezeigt werden.
Leider zeigt das Display beim Rücksprung zum ursprünglichen Text nur 
"Müll" an.

Könnt Ihr mir helfen??





Hier mal eine Code-Schnipsel:

In display soll der der dargestellte text (bzw. der Pointer dahin) 
gespeichert werden:
char* display;


Diese Prozedur stellt den Inhalt, der übergeben wurde, auf dem LCD dar
/*Sendet den komletten Display-Inhalt zum LCD (Array-Pointer)*/
void lcd_display(const char *data ,uint8_t center)
{
  lcd_clear();
  _delay_ms(5);
  int start = 1;
  display = data;   //Hier soll in display der anzuzeigende Inhalt gespecihert werden
  for (int i=0;i<4;i++){
    int laenge = strlen(data);
    if (center && laenge < 20) start = (20-laenge)/2 + 1;
    
    lcd_setcursor(i+1,start);
    
    for (int j=0; j<20;j++)
    {
      if (*data != '\0') lcd_data(*data);
      data++;

    }
    
    
  }
}

aufgerufen wird die Funktion z.B. folgendermaßen
char switch_off[4][20] = {"Anlage wird ","heruntergefahren","","Bitte warten..."};
lcd_display(*switch_off, 1);


Hier noch die ISR
/*Interupt-Service-Routine für Power-Taster*/
SIGNAL(SIG_INTERRUPT2)
{
  cli();

  if (power_status & (get_taster_zustand(PWR)))
  {
    int i = 3;
    char switch_off[4][20] = {"Anlage wird in","3 Sekunden","abgeschaltet....",""};
    lcd_display(*switch_off, 1);  //hier soll der neue Text dargestellt werden
    while((i>0) & get_taster_delay(PWR, 1000,0))
    {
      i--;
      lcd_setcursor(2, 6);
      lcd_data(i+48);
    }    
    if (!i) shutdown();
  } else {
    if(get_taster_delay(PWR, 1000,0))
    {
      sleep_disable();
      wakeup();
    }
  }
  lcd_display(*display, 1);   //Hier soll der alte Text wieder angezeigt werden
    
}
Im Vorraus schonmal vielen Dank für Eure Hilfe!!!

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das "LCD-Ausgabe innerhalb der ISR" hört sich nicht gut an.

Diese Aufgabe wird üblicherweise aus gutem Grund anders programmiert. 
Z.B. Die ISR übergibt dem Anwendungsprogrammteil ein Flag und der 
Anwendungsprogrammteil kümmert sich darum.

Autor: Andreas B. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
astroscout schrieb:
> char* display;
...
> /*Sendet den komletten Display-Inhalt zum LCD (Array-Pointer)*/
> void lcd_display(const char *data ,uint8_t center)
> {
...
>   lcd_display(*display, 1);   //Hier soll der alte Text wieder angezeigt werden

Warum nicht einfach mal lesen, was der Compiler zu sagen hat? Diesen 
Fehler hat er ganz bestimmt angemotzt.

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Abgesehen davon machst du in lcd_display() selbst eine Zuweisung nach 
display. Der vorherige Inhalt von display wird also durch 
lcd_display(*switch_off, 1); zerstört und kann an der Stelle 
lcd_display(*display, 1); nicht mehr verwendet werden.

Autor: astroscout (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke für eure schnellen Antworten:
@Stefan B.:
Ich gebe dir da völlig recht, ist nicht sehr schön, aber hier ist der 
Interrupt zeitunkritisch, sodass ich das so gelöst habe ;-)




@Andreas B.:
Der kompiler gibt mir folgendes aus:

In file included from lcd.h:88,
                 from main.c:44:
lcd.c: In function 'lcd_display':
lcd.c:238: warning: assignment discards qualifiers from pointer target 
type
In file included from taster.h:61,
                 from main.c:45:
taster.c: In function '__vector_3':
taster.c:189: warning: passing argument 1 of 'lcd_display' makes pointer 
from integer without a cast

leider hilft mir die aber nicht wirklich weiter :-(

Autor: Oliver (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Du solltest das Programmkonzept nochmals überdenken.

Nach der Rückkehr aus der ISR musst du die Ausgabe des 
Hauptprogramm-Textes komplett neu starten, weil sich ja in der ISR 
zwischenzeitlich der Zustand des LCDs geändert hat. Das aber geht mit 
deinem Ansatz nicht.

Oliver

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das hier

    lcd_display(*switch_off, 1);

kann auch nicht stimmen.

Holla!

Du hast versucht, dich hier
void lcd_display(const char *data ,uint8_t center);

....

    char switch_off[4][20] = {"Anlage wird in","3 Sekunden","abgeschaltet....",""};
    lcd_display(*switch_off, 1);  //hier soll der neue Text dargestellt werden

um einen Typfehler drumherum zu schwindeln, und jetzt kriegst du die 
Rechnung dafür präsentiert.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Deine

 void lcd_display(const char *data ,uint8_t center)

ist überhaupt höchst ungeschickt programmiert.

Du solltest dir zum Ziel setzen, dass du sowas:
char switch_off[4][20] = {"Anlage wird in","3 Sekunden","abgeschaltet....",""};

in der Komplexität, gar nicht brauchst.
Das Argument zu lcd_display muss aus 4 Teiltexten bestehen, die 
hintereinander im Speicher abgelegt sind, wobei jeder Teiltext aus 20 
Buchstaben (+abschliessendem 0 Byte) bestehen muss.

Tut es das nicht, dann machts bei dir kaboom. Da sind Fehler 
vorprogrammiert.

Es wäre doch viel schöner, wenn du sowas machen könntest
char switch_off[] = {"Anlage wird in\n3 Sekunden\nabgeschaltet...." };

und lcd_display kümmert sich selber darum wieviele Zeilenumbrüche da im 
String enthalten sind und wie sie auszuwerten und anzuzeigen sind. 
Denkst du nicht?
Kein Aufrufer muss mehr darauf aufpassen, dass er dem lcd_display das 
richtige vorwirft. Keine Längenangaben, die stimmen müssen. Und das 
beste am Ganzen: ein String - ein Pointer.

Autor: astroscout (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Karl heinz Buchegger schrieb:
> Das hier
>
>     lcd_display(*switch_off, 1);
>
> kann auch nicht stimmen.


okay, wie müsste es denn "sauber" lauten?

Autor: astroscout (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Karl heinz Buchegger schrieb:
> und lcd_display kümmert sich selber darum wieviele Zeilenumbrüche da im
> String enthalten sind und wie sie auszuwerten und anzuzeigen sind.
> Denkst du nicht?

ja, das geben ich dir recht, aber wie kann ich das sinnvoll 
realisieren??

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
astroscout schrieb:
> Karl heinz Buchegger schrieb:
>> Das hier
>>
>>     lcd_display(*switch_off, 1);
>>
>> kann auch nicht stimmen.
>
>
> okay, wie müsste es denn "sauber" lauten?


Sauber?
Sauber übernimmt lcd_display nicht einfach nur einen String sondern ein
void lcd_display(const char data[4][20] ,uint8_t center);

Dein Problem ist hier, dass du einen wilden Mischmasch aus 2D Arrays mit 
1D Arrays veranstaltet hast, der nur deswegen 'funktioniert' weil der 
Pointer auf den Anfang eines 2D Arrays auch gleichzeitig der Pointer auf 
den Anfang der ersten Zeile dieses 2D Arrays ist.


Oder aber natürlich, die wirst diese ganzen 2D Array los, indem du noch 
ein wenig Intelligenz in lcd_display steckst. Dann kannst du dem einen 
beliebigen String vorwerfen, mit Formatierzeichen (dem \n) und 
lcd_display macht das Richtige damit.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
astroscout schrieb:
> Karl heinz Buchegger schrieb:
>> und lcd_display kümmert sich selber darum wieviele Zeilenumbrüche da im
>> String enthalten sind und wie sie auszuwerten und anzuzeigen sind.
>> Denkst du nicht?
>
> ja, das geben ich dir recht, aber wie kann ich das sinnvoll
> realisieren??

Im Prinzip ist gar nicht mal soviel Unterschied zu dem was du hast.
Nur kannst du nicht mehr strlen zur Bestimmung der Länge einer Zeile 
benutzen. :-)
Und natürlich überall, wo in deinem jetzigen Code 4 oder 20 steht musst 
du auf die tatsächlichen Gegebenheiten Rücksicht nehmen und nicht 
einfach nur Zahlenwerte voraussetzen. Aber ist ja kein Problem: while 
Schleifen sind ja schon erfunden :-)

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
zb so
#define DISPLAY_WIDTH 20

void lcd_display(const char *data ,uint8_t center)
{
  uint8_t start = 1;
  uint8_t i = 1;
  
  lcd_clear();
  _delay_ms(5);
//  display = data;   //Hier soll in display der anzuzeigende Inhalt gespecihert werden

  while (*data != '\0') {
  
    if (center) {
      // Länge der nächsten Zeile feststellen
      uint8_t laenge = 0;
      const char* tmp = data;
      while( *tmp && *tmp != '\n' ) {
        laenge++;
        tmp++;
      }
        
      if (laenge < DISPLAY_WIDTH)
        start = (DISPLAY_WIDTH-laenge)/2 + 1;
    }
    lcd_setcursor(i, start);
    
    while (*data && *data != '\n') {
      lcd_data(*data);
      data++;
    }

    if (*data == '\n')
      data++; 
  }
}

Autor: Andreas B. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
astroscout schrieb:
> taster.c:189: warning: passing argument 1 of 'lcd_display' makes pointer
> from integer without a cast
>
> leider hilft mir die aber nicht wirklich weiter :-(

Um das spezielle Problem noch mal aufzulösen (warum man das alles 
sowieso anders macht haben schon andere erläutert):

astroscout schrieb:
> char* display;

Display ist ein Zeiger auf char…

> lcd_display(*display, 1);   //Hier soll der alte Text wieder angezeigt werden

…also ist *display ein char (das * folgt dem Zeiger), in diesem Fall das 
erste Zeichen im String, auf den display zeigt. Das erste Argument von 
lcd_display ist aber ein Zeiger auf einen String, also wird das Zeichen 
als Zeiger interpretiert — und davor hat der Compiler gewarnt.

Dass dann Müll angezeigt wird ist nicht verwunderlich, es werden ja 
Daten ab einer Startadresse zwischen 0 und 255 (der Wertebereich eines 8 
bit char in Zeiger umgewandelt) als String interpretiert.

Autor: astroscout (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke für Eure schnelle Hilfe
Ich habe mir jetzt die Display-Funktione so ungeschrieben, dass ich sie 
z.B. mit
lcd_display("Anlage wird in\n3 Sekunden\nabgeschaltet....", 1); 

aufrufen kann.
Auch das speihern des Displayinhaltes funktioniert nun einwandfrei.

Eine Frage habe ich aber noch.
Wie kann ich zwei Teilstring miteinander verbinden?
In php gibt es ja dafür den Punktoperator, ich kann aber in C nichts 
dazu finden!

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
astroscout schrieb:

> Eine Frage habe ich aber noch.
> Wie kann ich zwei Teilstring miteinander verbinden?
> In php gibt es ja dafür den Punktoperator, ich kann aber in C nichts
> dazu finden!

Du brauchst euin C Buch.
Ernsthaft

http://www.mikrocontroller.net/articles/FAQ#Wie_fu...

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.