Forum: Mikrocontroller und Digitale Elektronik Denkfehler bei Displayansteuerung


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von gru (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Hallo,

bin grad ein bisschen durcheinandergekommen bei der LCD 
Ansteuerungsroutine, die es hier gibt.

Es wird ja erwartet, dass alle Pins an einem Port liegen und 
aufeinanderfolgend sind. Das trifft bei mir auch zu, jedoch erwartet das 
Programm für DB4-7 die Pins PB0-3. Bei mir liegt DB4-7 jedoch auf den 
Pins PB3-0. Also genau umgekehrt.

Hab nun angefangen mir Bitweise die lcd-routines.c anzusehen bzw. 
genauer was in der Funktion lcd_out() passiert.

z.B. wird mit
1
lcd_out( LCD_SOFT_RESET );
 auf DB4 und DB5 ein Bit gesetzt. Mit
1
LCD_PORT |= (data>>(2-LCD_DB));
 kriegt man das auch wieder hin. Werden nun jedoch andere Daten 
übergeben, stimmt das alles nicht mehr.
1
 lcd_out( LCD_SET_FUNCTION |
2
             LCD_FUNCTION_4BIT );
Hier z.B. wird mit der obigen Veränderung Bit 3, anstatt Bit 1 gesetzt 
(von 0 gezählt), also an DB4, anstatt an DB5.

Hat jemand eine ganz einfache Methode um das zu umgehen/anzupassen, oder 
sollte ich mich lieber nach einer anderen Routine umsehen?

von Karl H. (kbuchegg) (Moderator)


Bewertung
0 lesenswert
nicht lesenswert
gru schrieb:
> Hallo,
>
> bin grad ein bisschen durcheinandergekommen bei der LCD
> Ansteuerungsroutine, die es hier gibt.
>
> Es wird ja erwartet, dass alle Pins an einem Port liegen und
> aufeinanderfolgend sind. Das trifft bei mir auch zu, jedoch erwartet das
> Programm für DB4-7 die Pins PB0-3. Bei mir liegt DB4-7 jedoch auf den
> Pins PB3-0. Also genau umgekehrt.

Man kann es in Software ausgleichen, indem man die Bits entsprechend in 
sich spiegelt. Aber eigentlich ist das ein Fall, den man besser 'im 
Kabel' löst.

von Karl H. (kbuchegg) (Moderator)


Bewertung
0 lesenswert
nicht lesenswert
gru schrieb:

>
1
lcd_out( LCD_SOFT_RESET );
>  auf DB4 und DB5 ein Bit gesetzt. Mit
>
1
LCD_PORT |= (data>>(2-LCD_DB));
>  kriegt man das auch wieder hin.

Nein, kriegst du nicht.
Du brauchst eine Spiegelung und kein Verschieben.
Du argeumentierst gerade so: da 2+2 gleich 4 ist und das auch dasselbe 
ist wie 2*2, braucht eigentlich kein Mensch Multiplikation.

> Werden nun jedoch andere Daten
> übergeben, stimmt das alles nicht mehr.

Du zäumst das Pferd an der falschen Stelle auf.
Alles was dich interessiert, ist die eine Funktion, die 1 Byte in die 4 
Bits zerlegt und auf die Reise schickt. Diese 4 Bits musst du in sich 
spiegeln, um deine Torheit die Datenleitungen genau falsch herum 
anzuschliessen, wieder auszugleichen. So etwas macht man nicht ohne Not, 
die Bitnummern zu vertauschen. Und wenn dann nur mit vorgehaltener 
Waffe.

: Bearbeitet durch Moderator
von gru (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Die Platine ist leider fertig und das Display wird direkt aufgesteckt. 
Die Pins jetzt noch umzulenken wäre eine sehr unschöne Lösung.

Den Inhalt von data spiegeln wäre natürlich eine Lösung, aber ist das 
denn auch so ohne weiteres möglich? bzw. wie genau?

Hmm, sonst wäre mein weiterer Ansatz die Bitmasken in der LCD 
Headerdatei zu ändern, sodass es wieder passen dürfte.

von Karl H. (kbuchegg) (Moderator)


Bewertung
0 lesenswert
nicht lesenswert
gru schrieb:
> Die Platine ist leider fertig und das Display wird direkt aufgesteckt.
> Die Pins jetzt noch umzulenken wäre eine sehr unschöne Lösung.

Es gibt nichts was man nicht mit Teppichmesser und Fädeldraht lösen 
könnte.
In Zukunft wird es dich lehren erst mal einen Testaufbau zu machen, ehe 
du dann eine Platine ätzt (oder ätzen lässt). Das werd ich sowieso nie 
verstehen, wie man ohne Vortest, ob auch alles funktioniert, gleich mal 
eine Platine ätzt.

> Den Inhalt von data spiegeln wäre natürlich eine Lösung, aber ist das
> denn auch so ohne weiteres möglich? bzw. wie genau?

Du musst hier
1
static void lcd_out( uint8_t data )
2
{
3
    data &= 0xF0;                       // obere 4 Bit maskieren
4
5
// --------------------------------- <<<<<<<<<
6
 
7
    LCD_PORT &= ~(0xF0>>(4-LCD_DB));    // Maske löschen
8
    LCD_PORT |= (data>>(4-LCD_DB));     // Bits setzen
9
    lcd_enable();
10
}

eingreifen (das ist eine Möglichkeit).
Die Bits müssen die Plätze tauschen
1
    +---+---+---+---+---+---+---+---+
2
    |   |   |   |   |   |   |   |   |
3
    +---+---+---+---+---+---+---+---+
4
      |   |   |   |
5
      |   |   |   |
6
      |   |   |   /
7
      |   |   /  /
8
       \   \ /  /
9
        \   \  /
10
         \ / \
11
          \ / \
12
         | \  |
13
         |/ \ |
14
         /   \|
15
        /|    \
16
       / |    |\
17
      |  |    | \
18
      |  |    |  |
19
    +---+---+---+---+---+---+---+---+
20
    |   |   |   |   |   |   |   |   |
21
    +---+---+---+---+---+---+---+---+
22
23
Bit 7 kommt nach Bit 4
24
Bit 6 kommt nach Bit 5
25
Bit 5 kommt nach Bit 6
26
Bit 4 kommt nach Bit 7

Das 'spiegelt' die Bits genau so, dass durch die nochmalige Spiegelung 
in der Hardware wieder alles richtig rauskommt.

> Hmm, sonst wäre mein weiterer Ansatz die Bitmasken in der LCD
> Headerdatei zu ändern, sodass es wieder passen dürfte.

Das ist Quatsch. Und zwar richtig großer Quatsch.
Mach es richtig!

: Bearbeitet durch Moderator
von spess53 (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Hi

>Den Inhalt von data spiegeln wäre natürlich eine Lösung, aber ist das
>denn auch so ohne weiteres möglich? bzw. wie genau?

so:

Beitrag "Re: LCD Datenleitungen invertieren"

MfG spess

von Karl H. (kbuchegg) (Moderator)


Bewertung
0 lesenswert
nicht lesenswert
spess53 schrieb:
> Hi
>
>>Den Inhalt von data spiegeln wäre natürlich eine Lösung, aber ist das
>>denn auch so ohne weiteres möglich? bzw. wie genau?
>
> so:
>
> Beitrag "Re: LCD Datenleitungen invertieren"

Die spiegelt allerdings 8 Bit und ist somit hier nicht anwendbar.

von Karl H. (kbuchegg) (Moderator)


Bewertung
0 lesenswert
nicht lesenswert
eine Möglichkeit wäre zb
1
static void lcd_out( uint8_t data )
2
{
3
    uint8_t outData = 0;
4
5
    if( data & (1<<7) )   outData |= (1<<4);
6
    if( data & (1<<6) )   outData |= (1<<5);
7
    if( data & (1<<5) )   outData |= (1<<6);
8
    if( data & (1<<4) )   outData |= (1<<7);
9
10
    LCD_PORT &= ~(0xF0>>(4-LCD_DB));    // Maske löschen
11
    LCD_PORT |= (outData>>(4-LCD_DB));     // Bits setzen
12
    lcd_enable();
13
}

eine andere Möglichkeit wäre, die eigentliche Ausgabe
1
    LCD_PORT |= (data>>(4-LCD_DB));     // Bits setzen
in 4 Einzelbitoperationen aufzudröseln und sich inklusive der 
gewünschten Verschiebung durch LCD_DB zu überlegen, wo welches der 4 
interssierenden Bits wieder auftauchen muss.

Es gibt sicher auch eine clevere Methode wie man mit Bitoperationen die 
4 Bits spiegeln kann (wie es im 8 Bit Beispiel gemacht wurde), nur weiß 
ich die nicht auswendig und bin jetzt auch zu faul, das auszutüfteln.

: Bearbeitet durch Moderator
von Rufus Τ. F. (rufus) (Moderator) Benutzerseite


Bewertung
0 lesenswert
nicht lesenswert
Eine Konstantentabelle mit 16 Einträgen wäre auch eine Lösung.

uint8_t NibbleTabelle[] = { 0xF0, 0xE0, 0xD0, 0xC0, 0xB0 ... etc. bis 
0x10, 0x00}

Beim Zugriff wird das High-Nibble des auszugebenden Datenworts als Index 
verwendet, so daß aus

LCD_PORT = Wert;

ein

LCD_PORT = NibbleTabelle[(Wert >> 4) & 0xF];

werden kann.

Allerdings ist der Shift-Operator eine recht "teuere" Rechenoperation; 
der Compiler könnte allerdings erkennen, daß hier auf das High-Nibble 
zugegriffen wird und swap verwenden, dann ist das ganze sogar recht 
flott.

Auf diese Art und Weise ließen sich auch einzelne vertauschte 
Datenleitungen korrigieren.

von gru (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Danke Karl Heinz!
Das genügt mir fürs erste völlig.

von Peter D. (peda)


Bewertung
0 lesenswert
nicht lesenswert

von c-hater (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Karl Heinz schrieb:

> Die spiegelt allerdings 8 Bit und ist somit hier nicht anwendbar.

Natürlich ist die (mit einer klitzekleinen Anpassung) hier anwendbar. 
Die letzte der drei Zeilen einfach durch ein "n = n & 0xf;" ersetzen. 
Das spart sogar noch ein paar Takte. Jedem, der versteht, was da 
passiert, ist das sofort klar.

Es bleibt allerdings die unbestreitbare Tatsache, daß es trotzdem recht 
teuer ist und ohne wirkliche Not nicht getan werden sollte, da gebe ich 
dir absolut Recht. EIN falsch angelöteter Stecker ist sicher kein 
hinreichender Grund. 1000 oder vielleicht auch nur 100 allerdings 
schon...

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]
  • [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.