Forum: Compiler & IDEs Anzeige verschiedener Inhalte auf LCD


von Jörg D. (misterbf)


Lesenswert?

Hallo zusammen,

Ich habe mal wieder ne kleine Hirnblockade, und brauchte von euch einen 
kleinen Wink mit dem Zaunpfahl.

Ich gebe den Inhalt des PIN C und B Register auf einem LCD aus, bzw 
möchte zwischen den den PINs hin und herschalten über eine binäre 
Auswertung.
Also drücke eine Taste und das LCD schaltet von PINC auf PINB und 
umgekehrt.

also die Anzeige eines PIN funktioniert, allerdings bereitet mit das 
löschen der Anzeige via lcd_clear() etwas Probleme weil die Anzeige 
anfängt zu flackern. das ist der Grundcode :
1
#include <avr/io.h>
2
#include "lcd-routines.h"
3
#include <util/delay.h> 
4
5
int main(void)
6
{
7
  
8
  lcd_init();            // Initialisierung des LCD
9
                  
10
                  //Beispiele für die LCD Ausgabe    
11
                  /*                    
12
                    Beispiel für die Ausgabe auf dem LCD Display 
13
 
14
                    lcd_setcursor(0, 1 );
15
                    lcd_string("Hello World");
16
                    lcd_setcursor(0, 2 );
17
                    lcd_string("Hello World");
18
                    lcd_setcursor(0, 3 );
19
                    lcd_string("Hello World");
20
                    lcd_setcursor(0, 4 );
21
                    lcd_string("Hello World");
22
                    
23
                    Text in einzelnen Zeichen ausgeben
24
                    
25
                    lcd_data( 'T' );
26
                    lcd_data( 'e' );
27
                    lcd_data( 's' );
28
                    lcd_data( 't' );
29
                  
30
                  */
31
DDRB=0x00;
32
PORTB=0xff;
33
DDRC=0x00;
34
PORTC=0xff;
35
 
36
  while(1)
37
  {
38
  if(!(PINC&0x01))
39
  {ausgabe_b();
40
  if(!(PINC&0x02))
41
  {ausgabe_c();}
42
    
43
  
44
  }
45
 
46
  return 0;
47
}
48
void ausgabe_b(void)
49
{
50
  int i = 0;
51
  char Buffer[20];
52
  
53
lcd_setcursor(0, 1 );      //PB0
54
55
lcd_string("PB0 = ");
56
if(!(PINB&(1<<PB0)))
57
{i=0;}
58
else
59
{i=1;}
60
itoa( i, Buffer, 10 );
61
lcd_string( Buffer );
62
63
lcd_setcursor(8, 1 );      //PB4
64
65
lcd_string("PB4 = ");
66
if(!(PINB&(1<<PB4)))
67
{i=0;}
68
else
69
{i=1;}
70
itoa( i, Buffer, 10 );
71
lcd_string( Buffer );
72
73
lcd_setcursor( 0, 2 );      //PB1
74
75
lcd_string("PB1 = ");
76
if(!(PINB&(1<<PB1)))
77
{i=0;}
78
else
79
{i=1;}
80
itoa( i, Buffer, 10 );
81
lcd_string( Buffer );
82
83
lcd_setcursor(8, 2 );      //PB5
84
85
lcd_string("PB5 = ");
86
if(!(PINB&(1<<PB5)))
87
{i=0;}
88
else
89
{i=1;}
90
itoa( i, Buffer, 10 );
91
lcd_string( Buffer );
92
93
lcd_setcursor( 0, 3 );      //PB2
94
95
lcd_string("PB2 = ");
96
if(!(PINB&(1<<PB2)))
97
{i=0;}
98
else
99
{i=1;}
100
itoa( i, Buffer, 10 );
101
lcd_string( Buffer );
102
103
lcd_setcursor(8, 3 );      //PB6
104
105
lcd_string("PB6 = ");
106
if(!(PINB&(1<<PB6)))
107
{i=0;}
108
else
109
{i=1;}
110
itoa( i, Buffer, 10 );
111
lcd_string( Buffer );
112
113
lcd_setcursor( 0, 4 );      //PB3
114
115
lcd_string("PB3 = ");
116
if(!(PINB&(1<<PB3)))
117
{i=0;}
118
else
119
{i=1;}
120
itoa( i, Buffer, 10 );
121
lcd_string( Buffer );
122
123
lcd_setcursor(8, 4 );      //PB7
124
125
lcd_string("PB7 = ");
126
if(!(PINB&(1<<PB7)))
127
{i=0;}
128
else
129
{i=1;}
130
itoa( i, Buffer, 10 );
131
lcd_string( Buffer );  
132
133
}
134
void ausgabe_c(void)
135
{
136
int j = 0;
137
char Buffer_1[20];
138
139
lcd_setcursor(0, 1 );      //PC0
140
141
lcd_string("PB0 = ");
142
if(!(PINC&(1<<PC0)))
143
{j=0;}
144
else
145
{j=1;}
146
itoa( j, Buffer_1, 10 );
147
lcd_string( Buffer_1 );
148
149
lcd_setcursor(8, 1 );      //PC4
150
151
lcd_string("PB4 = ");
152
if(!(PINC&(1<<PC4)))
153
{j=0;}
154
else
155
{j=1;}
156
itoa( j, Buffer_1, 10 );
157
lcd_string( Buffer_1 );
158
159
lcd_setcursor( 0, 2 );      //PC1
160
161
lcd_string("PB1 = ");
162
if(!(PINC&(1<<PC1)))
163
{j=0;}
164
else
165
{j=1;}
166
itoa( j, Buffer_1, 10 );
167
lcd_string( Buffer_1 );
168
169
lcd_setcursor(8, 2 );      //PC5
170
171
lcd_string("PB5 = ");
172
if(!(PINC&(1<<PC5)))
173
{j=0;}
174
else
175
{j=1;}
176
itoa( j, Buffer_1, 10 );
177
lcd_string( Buffer_1 );
178
179
lcd_setcursor( 0, 3 );      //PC2
180
181
lcd_string("PC2 = ");
182
if(!(PINC&(1<<PC2)))
183
{j=0;}
184
else
185
{j=1;}
186
itoa( j, Buffer_1, 10 );
187
lcd_string( Buffer_1 );
188
189
lcd_setcursor( 0, 4 );      //PC3
190
191
lcd_string("PC3 = ");
192
if(!(PINC&(1<<PC3)))
193
{j=0;}
194
else
195
{j=1;}
196
itoa( j, Buffer_1, 10 );
197
lcd_string( Buffer_1 );
198
199
}


So wenn ich jetzt am Ende der Unterprogramme ein lcd_clear setze dann 
fängt die Anzeige an zu flimmern.
Ich bin leider noch sehr unerfahren das das programmieren angeht, daher 
meine  kleine Blockade.
Wie kann ich sowas an sinnvollsten lösen ?

von Karl H. (kbuchegg)


Lesenswert?

Jörg Drösser schrieb:

> So wenn ich jetzt am Ende der Unterprogramme ein lcd_clear setze dann
> fängt die Anzeige an zu flimmern.
> Ich bin leider noch sehr unerfahren das das programmieren angeht, daher
> meine  kleine Blockade.
> Wie kann ich sowas an sinnvollsten lösen ?

indem du lcd_clear nur dann benutzt, wenn sich die komplette Anzeige 
deines LCD ändert. In allen anderen Fällen willst du möglichst mittels 
Überschreiben auskommen bzw. Teile die sich nicht geändert haben auch 
nicht neu schreiben.

Du machst dir also ein Flag, welche der beiden PINB oder PINC gerade 
angezeigt wird. Und nur dann, wenn das anzuzeigende von dem was 
angezeigt wird unterscheidet, nur dann löscht du das LCD (wenn 
überhaupt: PINB und PINC sind gleich lange Texte, wenn man den einen mit 
dem anderen überschreibt, dann wird vollständig berschrieben).

lcd_clear ist eine Funktion, die du nicht verwenden willst. Es sei denn, 
das generelle Layout deiner Anzeige ändert sich radikal. Aber ansonsten 
willst du immer nur nach möglichkeit einen bereits angezeigten Wert 
(oder Text) mit einem neuen überschreiben. Aber bitte so, dass auch 
vollständig überschrieben wird und danach keine Artefakte sichtbar 
bleiben.

Und formatier deinen Code besser. Da kriegt man ja Augenkrebs!

von foo (Gast)


Lesenswert?

Der Code ist so absolut nicht zu lesen, weil sämtliche Einrückung fehlt. 
Das hilft einem übrigens auch gerade als Anfänger selbst weiter. Wenn 
man sich mangels Einrückung in seinem eigenen Code nicht mehr 
zurechtfindet, fängt man irgendwann an, Code an zufällige Stellen 
einzufügen bis es irgendwann klappt.

Im Übrigen fehlt dir wahrscheinlich bei "{ausgabe_b();" die schließende 
geschweifte Klammer.

Jörg Drösser schrieb:
> So wenn ich jetzt am Ende der Unterprogramme ein lcd_clear setze dann
> fängt die Anzeige an zu flimmern.

Ich würde sagen, das liegt daran, dass das von der Hauptschleife aus 
ohne jegliche Verzögerung immer wieder aufgerufen wird ohne irgendeine 
Art von Delay dazwischen.

D.h. du siehst die Anzeige nur für die kurze Zeit, in der sie bereits 
geschrieben, aber noch nicht gecleart wurde, und das liegt bestenfalls 
im Millisekundenbereich.

Auf jeden Fall würde ich die Anzeige clearen, bevor du den Text 
ausgibst, und nicht direkt nach der Ausgabe den Text wieder löschen.

> Wie kann ich sowas an sinnvollsten lösen ?

Ich würde außerdem irgendwo ein Delay o.ä. einbauen, da du den Text 
ständig neu ausgibst solange du deinen Taster o.ä. gedrückt hältst 
(wodurch auch ständig das Display gecleart werden muss, was sich in 
Flackern äußern kann). Würde in der main nach den Aufrufen von 
ausgabe_b/c ein _delay_ms(1) o.ä. einbauen.

von Karl H. (kbuchegg)


Lesenswert?

Das hier
1
if(!(PINB&(1<<PB5)))
2
{i=0;}
3
else
4
{i=1;}
5
itoa( i, Buffer, 10 );
6
lcd_string( Buffer );

ist ja wohl an kompliziertheit kaum noch zu überbieten.

Was ist falsch an
1
  if(!(PINB&(1<<PB5)))
2
    lcd_string( "0" );
3
  else
4
    lcd_string( "1" );

oder aber, wenn man realisiert, dass das eigentlich für alle Pins 
ohnehin immer gleich ist: was ist falsch daran eine Funktion zu machen, 
der man übergibt: einen Text, einen Wert der entweder 0 oder nicht 0 
sein kann und eine Position an der das ganze anfangen soll.
1
void showValue( uint8_t zeile, uint8_t spalte, char* txt, uint8_t wert )
2
{
3
  lcd_setcursor( zeile, spalte );
4
  lcd_string( txt );
5
6
  if( wert )
7
    lcd_string( "1" );
8
  else
9
    lcd_string( "0" );
10
}

und das ganze wird dann benutzt
1
void ausgabe_b(void)
2
{
3
  showValue( 0, 1, "PB0 = ", PINB&(1<<PB0) );
4
  showValue( 8, 1, "PB4 = ", PINB&(1<<PB4) );
5
  showValue( 0, 2, "PB1 = ", PINB&(1<<PB1) );
6
  showValue( 0, 2, "PB5 = ", PINB&(1<<PB5) );
7
  showValue( 0, 3, "PB2 = ", PINB&(1<<PB2) );
8
  showValue( 8, 3, "PB6 = ", PINB&(1<<PB6) );
9
  showValue( 0, 4, "PB3 = ", PINB&(1<<PB3) );
10
  showValue( 8, 4, "PB7 = ", PINB&(1<<PB7) );
11
}

80% Code eingespart. Übersichtlichkeit trotzdem (oder gerade deswegen?) 
drastisch erhöht.


Wenn du Code schreibst, dann lehn dich immer wieder auch mal zurück und 
frag dich: kann ich das ganze nicht einfacher formulieren?
Speziell wenn du Code immer einfach nur weiter kopierst und Einzelteile 
durch andere ersetzt, dann solltest du dich fragen, ob es nicht 
angebracht wäre das ganze in eine Funktion zu verpacken. Wie man sieht 
kann das drastische Unterschiede ausmachen.

von Jörg D. (misterbf)


Lesenswert?

Danke schon mal für die Antworten.

Das mit der geschweiften Klammer habe ich auch gerade gemerkt. :-)

Im Bezug aufs Formatieren habe ich keinerlei Vorgaben wie man das 
sinnvoll oder optisch besser gestaltet. bitte mal beispiele geben damit 
ich weiss wie Ihr das meint dann ändere Ich gerne den Code ab.

@ Karl Heinz: Was meinst du mit Flag ( sorry für die Frage, aber das 
sagt mir so jetzt nicht direkt was) Bin wie gesagt in der Thematik nicht 
zuhause und stehe noch am Anfang.

@ Foo : Die Anzeige soll ja ständig aktuell sein. heisst ändert sich was 
am PIN soll das direkt angezeigt werden, daher lasse ich das LCD 
zyklisch schreiben. Das mit dem Delay habe ich schon versucht und das 
flackert ebenfalls. Auch mit einem Delay von 100 ms

von Karl H. (kbuchegg)


Lesenswert?

Jörg Drösser schrieb:
> Danke schon mal für die Antworten.
>
> Das mit der geschweiften Klammer habe ich auch gerade gemerkt. :-)
>
> Im Bezug aufs Formatieren habe ich keinerlei Vorgaben wie man das
> sinnvoll oder optisch besser gestaltet. bitte mal beispiele geben damit
> ich weiss wie Ihr das meint dann ändere Ich gerne den Code ab.

Sieh dir einfach mal an, wie andere das machen.

Eine simple Regel
nach einer { wird grundsätzlich nicht in derselben Zeile 
aweitergeschrieben. Jede Anweisung (auch wenn { jetzt in dem Sinn keine 
'Anweisung' ist) kommt auf eine neue Zeile

nach einer { wird das im {} Block eingeschlossene eingerückt. Ob das 
jetzt 2 oder 4 Zeichen sind, ist erst mal nicht so wichtig. Wichtig ist, 
das eingerückt wird!

Die Einrückung wird bei der schliessenden } wieder aufgehoben. Die } 
selber kommt wieder um die Einrückungstiefe weiter nach links.

Enthält ein {}-Block selbst wieder weitere {, dann wird 
selbstverständlich auch weiter eingerückt.

Ob man bei if und lediglich einer einzigen abhängigen Anweisung 
{}-Klammern macht oder nicht, ist in weiten Grenzen Geschmackssache. Ich 
mach sie nicht oder selten, andere machen das generell.
Wichtig ist aber: die abhängige Anweisung kommt auf ihre eigene Zeile 
und wird eingerückt.

Die Einrückung zeigt dir optisch an, welche Programmteile von anderen 
Programmteilen abhängig sind. In
1
  if( wert )
2
    lcd_string( "1" );
3
  else
4
    lcd_string( "0" );

kann man aus 3 Meter Entfernung sehen (selbst wenn man es nicht lesen 
kann), dass da 2 Anweisungen offenbar von irgendetwas abhängen.

> @ Karl Heinz: Was meinst du mit Flag ( sorry für die Frage, aber das
> sagt mir so jetzt nicht direkt was) Bin wie gesagt in der Thematik nicht
> zuhause und stehe noch am Anfang.
1
uint8_t momentaneAnzeige;   // 0 = jetzt wird gerade PINB angezeigt
2
                            // 1 = jetzt wird gerade PINC angezeigt
3
4
int main()
5
{
6
  uint8_t anzuzeigenIst = 0;   // selbe Bedeutung wie momentane Anzeige
7
8
  ....
9
10
  while( 1 )
11
  {
12
13
    if( !(PINC&0x01) )
14
      anzuzeigenIst = 0;   // PINB soll angezeigt werden
15
16
    if( !(PINC&0x02) )
17
      anzuzeigenIst = 1;  // PINC soll angezeigt werden
18
19
    if( momentanteAnzeige != anzuzeigenIst )
20
      lcd_clear();
21
     
22
    if( anzuzeigenIst == 0 )
23
      ausgabe_b();
24
    else
25
      ausgabe_c();
26
27
    momentaneAnzeige = anzuzeigenIst;
28
  }
29
}

Der lcd_clear wird nur dann ausgeführt, wenn die Anzeige (auf 
Benutzerwunsch) von B auf C wechselt oder umgekehrt.

Ein FLag ist einfach nur eine Variable, die mit ihrem Wert etwas über 
eienn Zustand ausdrückt. So wie hier: die Bits welches PINx werden 
gerade angezeigt.

von Karl H. (kbuchegg)


Lesenswert?

Karl Heinz schrieb:

>> Das mit der geschweiften Klammer habe ich auch gerade gemerkt. :-)

Sowas
1
  while(1)
2
  {
3
  if(!(PINC&0x01))
4
  {ausgabe_b();
5
  if(!(PINC&0x02))
6
  {ausgabe_c();}
7
    
8
  
9
  }

geht gar nicht.
Wenn man das mal nach simplen FOrmatierregeln formatiert, dann erhält 
man
1
...
2
  while(1)
3
  {
4
    if(!(PINC&0x01))
5
    {
6
      ausgabe_b();
7
8
      if(!(PINC&0x02))
9
      {
10
        ausgabe_c();
11
      }
12
    }
13
14
    return 0;
15
  }

da die Funktion main() nach dem return zu Ende sein soll, die letzte 
schliesende } aber nicht am linken Rand landet, muss daher irgendwo ein 
Klammerfehler vorliegen.

Formatiert man das nach der (erkennbaren) Absicht
1
...
2
  while(1)
3
  {
4
    if(!(PINC&0x01))
5
    {
6
      ausgabe_b();
7
8
    if(!(PINC&0x02))
9
    {
10
      ausgabe_c();
11
    }
12
  }
13
14
  return 0;
15
}

dann landet die letzte } der Funktion zwar dort wo sie hingehört, aber 
man sieht sofort, dass hier
1
    if(!(PINC&0x01))
2
    {
3
      ausgabe_b();
4
5
    if(!(PINC&0x02))
offenbar eine schliessende } Klammer fehlt. Denn das zweite if kann 
nicht um 2 Zeichen ausgerückt sein, ohne das vorher eine schliessende } 
kommt, wenn die Einrückung wegen einer { erfolgt ist. Auch sieht man, 
indem man in derselben Spalte wie die öffnende { die Zeilen darunter 
absucht, dass es die zugehörige } nicht gibt. Öffnende { und 
schliessende } stehen immer in derselben Spalte und dazwischen kann es 
keine Zeile geben, die in derselben Spalte anfängt.
D.h. man hat 2 optische Indizien für denselben Sachverhalt: du hast eine 
} vergessen.


DAS ist der Wert einer ordentlichen Formatierung. Sie hilft dir Fehler 
zu finden. Und zwar rein nur dadurch, dass die Optik 'nicht stimmt'.
Daher ist auch die oft gehörte Aussage "Formatierung mach ich nachher, 
jetzt such ich erst mal den Fehler" Unsinn. Denn viele Fehler kann man 
ganz einfach vermeiden, INDEM man ordentlich formatiert.

von foo (Gast)


Lesenswert?

Jörg Drösser schrieb:
> @ Foo : Die Anzeige soll ja ständig aktuell sein.

"Ständig aktuell" gibt es nicht, es wird mit Sicherheit immer einige 
CPU-Takte hinterher hängen ;)

Immer aktuell (im Rahmen des technisch möglichen) und ohne überflüssige 
Neuanzeigen würdest du mit der Lösung von Karl-Heinz (erste Antwort) 
erreichen.

Der Vorschlag mit dem Delay war als Idee gedacht, falls eine leichte 
Verzögerung ggf auch ausreicht, dann wäre das nämlich noch einfacher zu 
implementieren gewesen.

> Das mit dem Delay habe ich schon versucht und das
> flackert ebenfalls. Auch mit einem Delay von 100 ms

Entweder du hast das Delay nach dem Clear (dann hast du 100ms lang 
nichts auf dem Display stehen -> flackert) oder du meinst das 
Restflackern, welches bei einem Clear immer auftritt und sich nicht 
vermeiden lässt, egal wie schnell das Display wieder neu beschrieben 
wird. In letzterem Fall hilft dir auch wieder die erste Antwort von 
Karl-Heinz: überschreibe den existierenden Inhalt nur.

von Jörg D. (misterbf)


Lesenswert?

ok ,

Ich danke schon mal für die Vielen hilfreichen Tipps.
Ich werde in den nächsten Zwei wochen im Urlaub nicht sonderlich oft 
dazu kommen was auszuprobieren aber wenn doch bekommt Ihr natürlich 
bescheid.

Danke schon mal


LG

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.