mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Bits schieben und auf Port ausgeben (c)


Autor: Sonke A. (soeni)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich habe folgendes Problem:

für ein LCD muss ich Daten senden. Hierzu teile ich diese zuerst in die 
Nibbels auf (hab ich soweit übernommen aus dem Tutorial.) Mein Problem 
ist nun, dass ich die Ausgabe nicht ganz verstehe. Ich muss nämlich 
nicht wie im Tutorial die ersten 4 Bit des Ports für die Datenleitung 
nutzen, sondern die lezten 4 (also Bit 4-7).

Hier mal der Codeausschnitt mit Kommentaren:
  void lcd_data(unsigned char temp1){

    
     unsigned char temp2 = temp1;
 
     LCD_PORT |= (1<<LCD_RS);        // RS auf 1 setzen funktioniert soweit
    temp1 = temp1 >> 4;        // erstes (oberes) Nibbel holen
     temp1 = temp1 + 0x0F;      // hiermit verschiebt man doch nach oben
     LCD_PORT &= 0x0F;        // obere 4 Bit löschhen
     LCD_PORT |= temp1;              // setzen
     lcd_enable();
 
    temp2 = temp2 + 0x0F;      // zweites (unteres) Nibbel holen und nach oben schieben
     LCD_PORT &= 0x0F;        // obere 4 Bit löschhen
     LCD_PORT |= temp2;              // setzen
     lcd_enable();
   
     _delay_us(42);
  
  }

Kann mir villeicht jemand sagen, wie ich das Problem löse, das die 
jeweiligen Nibbels an die oberen Bits gelangen???

Gerne auch mit Erklährung, ich bin da noch nicht so fit.

Autor: Matthias Lipinsky (lippy)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wenn du meinst, dass du von temp1 erst die oberen vier bits und dann die 
unteren vier bits auf LCD_PORT[7:4] ausgeben willst, dann versuch mal 
das:
void lcd_data(unsigned char temp1)
{
  unsigned char temp2 = (temp1<<4);
 
  LCD_PORT |= (1<<LCD_RS);                     // RS setzen

  LCD_PORT |= (  (LCD_PORT & 0x0F) | (temp1 & 0xF0) );  // ausgeben

  lcd_enable();                                // ???????????????????
  _delay_us(42);

  LCD_PORT |= (  (LCD_PORT & 0x0F) | (temp2 & 0xF0) );  // ausgeben

  lcd_enable();                                // ???????????????????
  _delay_us(42);
  
  }

Die Fragezeichen zeigen an, dass ich nicht weiß, wie du die Daten im 
Display übernimmst. Also welche Bits da wie gesetzt/gelöscht werden 
müssen...

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Matthias Lipinsky wrote:
  LCD_PORT |= (  (LCD_PORT & 0x0F) | (temp1 & 0xF0) );  // ausgeben
...
  LCD_PORT |= (  (LCD_PORT & 0x0F) | (temp2 & 0xF0) );  // ausgeben

Das "|=" ist hier falsch und muss durch "=" ersetzt werden.

Autor: Matthias Lipinsky (lippy)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Das "|=" ist hier falsch und muss durch "=" ersetzt werden.

Das ist korrekt.

Ich wollte nur sehen, ob du aufpasst ;-))

Autor: Sonke A. (soeni)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
also ich habe Port D meines Atmega128 mit einem Display verbunden. 
hierbei nutze ich Pin4-7 als 4 Bit Datenbus zum Display. Pin PD0 ist der 
Enablepin und Pin PD1 ist der RS Pin. Pin 2 und 3 sind für den UART 
reserviert, deshalb diese Belegung. Nun hoffte ich das Beispiel aus dem 
Tutorial abändern zu können, und anstatt der ersten 4Pins des Ports die 
Letzten zu nehmen. Leider funktioniert euer Code auch nicht.

PS. Es geht um ein alphanumerisches LCD

Hier nochmal der jetzige Code:
void lcd_data(unsigned char temp1){

    
   unsigned char temp2 = (temp1<<4);
 
  LCD_PORT |= (1<<LCD_RS);                     // RS setzen

  LCD_PORT = (  (LCD_PORT & 0x0F) | (temp1 & 0xF0) );  // ausgeben

  lcd_enable();                                // ???????????????????
  _delay_us(42);

  LCD_PORT = (  (LCD_PORT & 0x0F) | (temp2 & 0xF0) );  // ausgeben

  lcd_enable();                                // ???????????????????
  _delay_us(42);

  
  }

Autor: soeni (nicht angemeldet) (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
kann mir hierbei nochmal jemand helfen??

Autor: Matthias Lipinsky (lippy)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Leider funktioniert euer Code auch nicht.

Da meine ??????????????? in dem Code noch drin sind, vermute ich, dass 
du nur COdeschnipsel zusammenkopierst und nict selbst schreibst, sonst 
hättest du das wohl beachtet:

>>Die Fragezeichen zeigen an, dass ich nicht weiß, wie du die Daten im
>>Display übernimmst. Also welche Bits da wie gesetzt/gelöscht werden
>>müssen...

Wir kennen ja weder die Funktion lcd_enable, noch das Display noch den 
Anschluss desselben an den µC

Autor: Sonke A. (soeni)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
hab ich doch oben geschrieben, wie der Anschluss ist und was ich für ein 
Display habe.

Hier nochmal die Enablefunktion. Diese muss funktionieren, da ich sie 
beim Initialisieren nutze und das funktioniert.
  // erzeugt den Enable-Puls
  void lcd_enable(void){
 
     LCD_PORT |= (1<<LCD_EN);
      _delay_us(1);                   // kurze Pause
 
     LCD_PORT &= ~(1<<LCD_EN);
  }
 

Autor: Karl B. (gustav)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
In Assembler ist's einfacher zu erklären.
Zunächst die Portdefinition. Welche D's am ATMega nimmst Du. Da hast Du 
Wahlfreiheit. Entweder Bits D0 bis D3 oder Bist D4 bis D7 für die vier 
aktivenb Datenleitungen. Dass ist pure Definitionssache und kann hernach 
leicht geändert werden.
Darauf bin ich am Anfang nämlich auch drauf reingefallen.

Das Display verlangt demhingegen strengste Konventionen.
Also zunächst Hig-Nibble dann Low nibble.
Den Grund werde ich später noch angeben.
Ist höchst interessant.

Da machst Du erst eine Portdefinition als Ausgang über das 
Datenrichtungsregister, dann lädst Du das Temorärregister.
Dann kopierst Du das Temnporärregister zu Sicherheit und
Verundest mit andi so, daß nur die oberen vier Bit einsen bekommen.
Oder in Hex F0
jetzt veroderst Du mit dem RS-Impuls der sitzt wo? Port sowieso Bit 
sowieso
Bei mir Port D und Bit D1 also ori Hex 0x02.

Dann kannst Du den RS Impuls einmal durch Registerladen erzeugen oder 
durch Direrktsetzung von Bits. Mit dem Sbi bzw Sbr Befehl
Und Rücksetzen mit cbi und cbr.

Achtung. Bei sbi/ cbi ist die Syntax etwas anders als beim sbr /cbr.

Und jetzt kommt ein Enableimpuls.

Dann der Befehl swap
Swap nibbles.
Nur Du nimmst jetzt das ins zweite Temprärregister kopierte 
TEMP-Argument.
hier vertauschst Du jetzt die Nibbles.
dann kommt wieder der andi temp1, 0xF0
und so weiter
Wichtig zwei Enable-Impulse, obwohl das Busy-Flag nur einmal abgefragt 
werden darf. Das Busy spinnt dann nämlich sonst.

Autor: Karl B. (gustav)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hier der Code mit Comments.
Das funktioniert sogar (RS-Toggeln ist nicht nötig, dient nur zur 
Kontrolle, ob die Don't cares auch wirklich ignoriert werden)

Datenuebernahme:

mov  temp1,  temp    ;Kopie des Wertes fuer weitere;
;        ;Operation unten
andi   temp,  0b11110000  ;unteres Nibble ausblenden
ori  temp,  0b00000010  ;RS auf "high" maskieren(Pinout PORTB)
out   daten,  temp    ;Ausgabe oberes Nibble auf D4-D7
ldi  temp,  0x02    ;RS auf "high" Pinout PORTD
out  impuls,  temp    ;Funktion wie "sbi impuls, 1"
rcall  enable
nop
nop
swap   temp1      ;Nibble-Vertauschen, Wert aus temp;
;        ;kopiert, s.o.
andi  temp1,  0b11110000  ;unteres Nibble ausblenden
ori  temp1,  0b00000010  ;RS auf "high" maskieren(Pinout PORTB)
out  daten,  temp1    ;Ausgabe unteres Nibble auf D4-D7
rcall  enable
nop
rcall  Verzoegerung
ldi  temp,  0x02  ;RS kurz auf "high" Pinout PORTD
out  impuls,  temp
ldi  temp,  0x00  ;RS auf "low" Pinout PORTD
out  impuls,  temp
ret

Kommando:

mov  temp1,  temp    ;Kopie des Wertes fuer weitere;
;        ;Operation unten
andi   temp,  0b11110000  ;unteres Nibble ausblenden
out   daten,  temp    ;Ausgabe oberes Nibble auf D4-D7
ldi  temp,  0x00    ;RS auf "low" Pinout PORTD
out  impuls,  temp    ;Funktion wie "cbi impuls, 1"
rcall  enable
nop
nop
swap   temp1      ;Nibble-Vertauschen, Wert aus temp;
;        ;kopiert, siehe oben
andi   temp1,  0b11110000  ;unteres Nibble ausblenden
out  daten,  temp1    ;Ausgabe unteres Nibble auf D4-D7
rcall  enable
rcall  Verzoegerung
ldi  temp,  0x02  ;RS kurz auf "high" Pinout PORTD
out  impuls,  temp
ldi  temp,  0x00  ;RS auf "low" Pinout PORTD
out  impuls,  temp
ret

Enable:

nop
sbi  impuls, 0  ;Enable auf "high" setzen
nop      ;Impulsdauer mindestens
nop      ;0,5 Mikrosekunden laut Datenblatt
nop      ;lieber ein paar "nops" mehr
nop      ;spendieren
nop
nop
nop
cbi  impuls, 0  ;Enable auf "low" zurücksetzen
nop
ret

Verzoegerung:  ;2+[4x(255-1)+3]x[5x(2-1)]+7=1,276 ms bei 4 MHz

ldi  zeit,  0xFF
ldi  zeit1,  0x05

Verzoegerungs_Schleife:

dec  zeit
cpi  zeit,  1
brlt  Verzoegerungs_Schleife
ldi  zeit,  0xFF
dec  zeit1
cpi  zeit1,  1
brlt  Verzoegerungs_Schleife
ret

Verzoegerung2:  ;2+[4x(255-1)+3]x[5x(32-1)]+7= 39,49 ms bei 4 MHz

ldi   zeit,  0xFF
ldi   zeit1,  0x20

Verzoegerungs_Schleife2:

dec  zeit
cpi  zeit,  1
brlt  Verzoegerungs_Schleife2
ldi  zeit,  0xFF
dec  zeit1
cpi  zeit1,  1
brlt  Verzoegerungs_Schleife2
ret

Autor: Karl B. (gustav)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
die Berechnung der Verz-Schleife statt 2 in der zweiten Klammer ne 5 ich 
hatte zwischenzeitlich noch was am Ladewert geändert und den Kommentar 
nicht upgedatet.

Autor: Sonke A. (soeni)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
soweit ich das überblicken kann funktioniert das doch auch bei meinem c 
code so oder?? kann mir da jemand helfen?? ich finde da keinen Fehler, 
nur funktionieren tuts auch nicht

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.