Problem mit Pointern

Gast #1939354
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:
1
char* display;


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

19
    }
20
    
21
    
22
  }
23
}

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


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

6
  if (power_status & (get_taster_zustand(PWR)))
7
  {
8
    int i = 3;
9
    char switch_off[4][20] = {"Anlage wird in","3 Sekunden","abgeschaltet....",""};
10
    lcd_display(*switch_off, 1);  //hier soll der neue Text dargestellt werden
11
    while((i>0) & get_taster_delay(PWR, 1000,0))
12
    {
13
      i--;
14
      lcd_setcursor(2, 6);
15
      lcd_data(i+48);
16
    }    
17
    if (!i) shutdown();
18
  } else {
19
    if(get_taster_delay(PWR, 1000,0))
20
    {
21
      sleep_disable();
22
      wakeup();
23
    }
24
  }
25
  lcd_display(*display, 1);   //Hier soll der alte Text wieder angezeigt werden
26
    
27
}
Im Vorraus schonmal vielen Dank für Eure Hilfe!!!
Gast #1939367
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.
Gast #1939382
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 :-(
Gast #1939386
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
#1939387
Lesenswert?

Das hier

    lcd_display(*switch_off, 1);

kann auch nicht stimmen.

Holla!

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

3
....
4

5
    char switch_off[4][20] = {"Anlage wird in","3 Sekunden","abgeschaltet....",""};
6
    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.
#1939394
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:
1
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
1
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.
#1939400
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
1
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.
#1939404
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 :-)
#1939418
Lesenswert?

zb so
1
#define DISPLAY_WIDTH 20
2

3
void lcd_display(const char *data ,uint8_t center)
4
{
5
  uint8_t start = 1;
6
  uint8_t i = 1;
7
  
8
  lcd_clear();
9
  _delay_ms(5);
10
//  display = data;   //Hier soll in display der anzuzeigende Inhalt gespecihert werden
11

12
  while (*data != '\0') {
13
  
14
    if (center) {
15
      // Länge der nächsten Zeile feststellen
16
      uint8_t laenge = 0;
17
      const char* tmp = data;
18
      while( *tmp && *tmp != '\n' ) {
19
        laenge++;
20
        tmp++;
21
      }
22
        
23
      if (laenge < DISPLAY_WIDTH)
24
        start = (DISPLAY_WIDTH-laenge)/2 + 1;
25
    }
26
    lcd_setcursor(i, start);
27
    
28
    while (*data && *data != '\n') {
29
      lcd_data(*data);
30
      data++;
31
    }
32

33
    if (*data == '\n')
34
      data++; 
35
  }
36
}
Gast #1939471
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.
Gast #1939736
Lesenswert?

Danke für Eure schnelle Hilfe
Ich habe mir jetzt die Display-Funktione so ungeschrieben, dass ich sie 
z.B. mit
1
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!

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren