www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik 4Bit LCD, restliche Portpins Problem


Autor: Sebastian F. (snake080)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo liebe Gemeinde,
ich habe folgendes Problem:

Ein Display im 4-Bit Modus wie im Tutorial angeschlossen (PD0-PD5). PD6 
& PD7
benutze ich als Eingänge.
Allerdings werden mir jedes mal, wenn ich etwas mit dem Display mache, 
meine Eingangspins auf 0 gesetzt... (ist nicht gerade Sinnvoll, da ich 
dort abfragen mache). In den LCD-Routinen wird immer der ganze Port 
beschrieben. Daran wirds liegen.
Hat jemand einen Tipp, wie man das hinbekommt ohne die ganze Datei 
umzuschreiben?

Autor: XY (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
(Port & Pinmaskierung) |= Daten

Autor: Michael B. (planlessmichi)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Schau mal, ob Du mit den Funktionen in den angehängten LCD-Sourcen 
auskommst; ich habe die mal vor längerer Zeit so umgeschrieben, dass ich 
jeden beliebigen PIN nehmen kann und auch nur die benötigt werden...
Vielleicht musst Du es noch etwas umbauen, aber sollte eiegentlich 
passen...

Viele Grüße,
Michael

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sebastian Fässer schrieb:
> Hat jemand einen Tipp, wie man das hinbekommt ohne die ganze Datei
> umzuschreiben?

Nö, man muß viele Stellen anpassen.

Oder gleich nen universellen Code nehmen:

Beitrag "Re: LCD nicht nur für einen Port in C"


Peter

Autor: Sebastian F. (snake080)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke für die Antworten,
ich versuche mich mal da durchzuarbeiten. Ich habe keine Ahnung von C. 
Hätte ich vielleicht dazuschreiben sollen :)

Autor: Michael B. (planlessmichi)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sebastian Fässer schrieb:
> Ich habe keine Ahnung von C.

Kein Problem; ändere einfach nur die Zeilen 37-45 in der .h Datei, dass 
es mit Deinem Aufbau übereinstimmt. "Sollte" reichen.

Autor: Sebastian F. (snake080)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Joa, das mit dem ändern habe ich gemacht. Dann mit .include die Datei 
eingefügt und die ganzen Verknüpfungen rausgeworfen, die ich nicht habe. 
Und jetzt kommen lauter Fehler: Syntax error Unexpected "("  Ab den 
Zeilen:
void lcd_data(unsigned char temp1);

Autor: Michael B. (planlessmichi)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
.include?? Arbeitest Du mit WinAVR (über AVRStudio?) oder CodeVision?
Oder meintest Du #include?

Welche includes hast Du denn in der C-Datei entfernt? Oder besser: 
Welche stehen noch drin?

Autor: Sebastian F. (snake080)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nur die Verknüpfungen zu deinen Dateien, die ich nicht habe:
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <avr/interrupt.h>
#include <ctype.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>

#include <util/delay.h>

Die #include "lcd-routines.h" steht natürlich noch drin :-)
Ich arbeite mit dem AVR Studio. Schön im alten Assembler...

Autor: Hc Zimmerer (mizch)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Includes in spitzen Klammern sind systemweit; sie gehören zum Compiler, 
nicht zum Projekt.  Die hast Du also mit dem Compiler installiert.

Autor: Michael B. (planlessmichi)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
O.k.; das ist jetzt dann aber schon ein Problem :-)
"Keine Ahnung von C" haben und gar nicht in C programmieren ist ein 
kleiner Unterschied :-)
In C wird das üblicherweise so gehandhabt, das includes mit spitzen 
Klammern also <xyz.h> includes von einer Entwicklungsumgebung sind; 
globale Header hört sich doof an; also welche, die in irgendeinem Paket 
(IDE) waren. "Persönliche" includes werden dann mit "" eingebunden. (hat 
alles was mit der Suchreihenfolge zu tun).
Kurz: (Fast) Alle includes sind nötig und können nicht einfach 
weggelassen werden. Wie man das jetzt NUR auf Assembler umbiegen kann... 
Keine Ahnung.

Vielleicht installierst Du Dir doch noch das WinAVR-Paket dazu?

EDIT: Mein Vorredner hat die bessere Bezeichnung für "globale" Header 
gehabt: systemweit :-)

Die stehen halt dann an Orten, die irgendwie in den "PATH"-Variablen des 
Systems bekannt gemacht wurden (während der Installation der 
entsprechenden Bibliotheken / IDEs)

Autor: Micha (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sebastian Fässer schrieb:
> Allerdings werden mir jedes mal, wenn ich etwas mit dem Display mache,
> meine Eingangspins auf 0 gesetzt
Sicher? Egtl. sollte da nichts passieren, wenn du die entsprechenden 
DDR-Bits nicht veränderst, außer dass du die Pullups ein-/ausschaltest.

Ändere doch deine ASM-Routinen entsprechend: lies zuerst die Zustände 
der Bits, maskiere alles entsprechend und schreibe die neuen Werte dann 
wieder nach draussen.

Autor: Sebastian F. (snake080)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke für die gute Erklärung.
Man sollte aber trotzdem nicht versuchen Assembler und C zu mischen, 
oder?
Ich habe mal versucht die Dateien zu finden. Im System sind sie schon 
mal nirgends... und irgenwas installieren wovon ich nix kenne macht auch 
nicht viel Sinn, oder? Dann lieber umständlich und hoffen dass man 
versteht was man macht :)
Also werde ich mal die Variante mit dem Maskieren versuchen...

Autor: Hc Zimmerer (mizch)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bis auf die Bemerkung, dass Du Dich nicht mit C auskennst, hast Du noch 
nichts über die verwendete Sprache gesagt.  Es wäre recht günstig, Deine 
Mitleser darüber nicht im Dunkeln tappen zu lassen und dabei vielleicht 
auch mal den Code, über den Du redest, zu posten.

Das Mischen von Assembler und C ergibt sogar sehr viel Sinn.  Man kann 
dann jeweils die Sprache wählen, die für die momentane Teilaufgabe am 
besten geeignet ist.  Die Übergabe-Modalitäten zwischen beiden Sprachen 
sind einfach und gut dokumentiert (ich rede hier über gcc und avr-as) 
und leicht zu kapieren.

Aber äußere Dich doch zuerst mal zu Deiner Programmier-Umgebung.  Die 
ist (jedenfalls mir) noch nicht klar.  Es scheint, Du verwendest 
avrasm2.  In Sachen Hochsprachenkopplung ist der nicht einfach zu 
handhaben und eine ziemliche Sackgasse.

Autor: Sebastian F. (snake080)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Entschuldigung, wenn das noch undeutlich ist.
Ich programmiere im AVR-Studio4 mit dem Assembler.
Code von der LCD Ansteuerung ist so ziemlich der des Tutorials. 
(http://www.mikrocontroller.net/articles/AVR-Tutori...)

Mein Code ist ja egal, da ja feststeht, dass in der Routine an den 
Datenrichtungsregistern etwas geändert wird... aber ich kanns ja mal 
posten:


.include "m8def.inc"

.def temp1  = r16  ; Temporärregister
.def temp2  = r17  ; Temp2
.def temp3  = r18

ldi temp1, LOW(RAMEND)
out SPL,temp1
ldi temp1, HIGH(RAMEND)
out SPH,temp1

; ADC initialisieren

ldi temp1, 0b11000000  ; Int.2,56V ref
out ADMUX, temp1

ldi temp1, 0b10000011  ; ADC enable / f/8
out ADCSRA, temp1

;**************************************
; Portpins zuweisen

ldi temp1, 0xfe
out DDRB, temp1

sbi DDRC,4
sbi DDRC,5

ldi temp1, 0x3f
out DDRD, temp1

; Pull-ups an
sbi PORTB,0
sbi PORTD,6
sbi PORTD,7

rcall lcd_init
rcall lcd_clear

main:
nop
rjmp main

Sobald ich das lcd initialisiere bleiben PD6 & PD7 auf GND. Wenn ich die 
beiden rausnehme funktioniert es mit den Pull-ups...

Autor: Hc Zimmerer (mizch)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Die LCD-Routinen im Tutorial machen nichts mit DDRD, nur in der danach 
folgenden Anwendung wird DDRD geändert.

Mit Deiner Aussage „Code von der LCD Ansteuerung ist so ziemlich der des 
Tutorials" kann ich in diesem Zusammenhang nichts anfangen, denn mit 
Deiner Fehlerbeschreibung am Beginn dieses Threads passt das nicht 
zusammen - nach der muss irgendwas in DDRD rumschreiben.  Eine 
Überprüfung lässt Du aber nicht zu, denn den Display-Code verschweigst 
Du nach wie vor.  Somit kann man nur raten (und das ist nicht mein 
Ding).

EDIT: siehe nächsten Post (kommt gleich).

Autor: Hc Zimmerer (mizch)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Eine Möglichkeit wäre allerdingst, wenn Du keine "harte" Null an den 
Ausgängen 6 und 7 bekommst, sondern nur die Pullups weggeschaltet 
werden.  Das ist beim Code im Tutorial natürlich (deutlich sichtbar) der 
Fall.  Falls das zutrifft, musst Du an allen Stellen, an denen nach 
PORTS geschrieben wird, die beiden oberen Bits setzen, z.B aus
           ldi temp1, 0b00000011        ; muss 3mal hintereinander gesendet
           out PORTD, temp1             ; werden zur Initialisierung
wird
           ldi temp1, 0b11000011        ; muss 3mal hintereinander gesendet
           out PORTD, temp1             ; werden zur Initialisierung
und so weiter.  Einfach im Quelltext nach „PORTD“ suchen und dafür 
sorgen, dass Bit 6 und 7 gesetzt sind.

Autor: Sebastian F. (snake080)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
So, hier haben wir den Code den ich benutze:
bei dem lcd_init wird der Port geändert... Aber auch wenn ich die bits 
einzelnd auf 1 setze klappts nicht...



;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;                 LCD-Routinen                ;;
;;                 ============                ;;
;;              (c)andreas-s@web.de            ;;
;;                                             ;;
;; 4bit-Interface                              ;;
;; DB4-DB7:       PD0-PD3                      ;;
;; RS:            PD4                          ;;
;; E:             PD5                          ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


.equ LCD_PORT = PORTD
.equ LCD_DDR  = DDRD
.equ PIN_E    = 5
.equ PIN_RS   = 4

 ;sendet ein Datenbyte an das LCD
lcd_data:
  push temp1
  push temp2
           mov temp2, temp1             ; "Sicherungskopie" für
                                        ; die Übertragung des 2.Nibbles
           swap temp1                   ; Vertauschen
           andi temp1, 0b00001111       ; oberes Nibble auf Null setzen
           sbr temp1, 1<<PIN_RS         ; entspricht 0b00010000
           out LCD_PORT, temp1          ; ausgeben
           rcall lcd_enable             ; Enable-Routine aufrufen
                                        ; 2. Nibble, kein swap da es 
schon
                                        ; an der richtigen stelle ist
           andi temp2, 0b00001111       ; obere Hälfte auf Null setzen
           sbr temp2, 1<<PIN_RS         ; entspricht 0b00010000
           out LCD_PORT, temp2          ; ausgeben
           rcall lcd_enable             ; Enable-Routine aufrufen
           rcall delay50us              ; Delay-Routine aufrufen
  pop temp2
  pop temp1
          ret                          ; zurück zum Hauptprogramm


 ; sendet einen Befehl an das LCD

lcd_command:                            ; wie lcd_data, nur RS=0
  push temp1
  push temp2
     mov temp2, temp1
           swap temp1
           andi temp1, 0b00001111
           out LCD_PORT, temp1
           rcall lcd_enable
           andi temp2, 0b00001111
           out LCD_PORT, temp2
           rcall lcd_enable
           rcall delay50us
  pop temp2
  pop temp1
          ret

 ; erzeugt den Enable-Puls
lcd_enable:
           sbi LCD_PORT, PIN_E          ; Enable high
           nop                          ; 3 Taktzyklen warten
           nop
           nop
           cbi LCD_PORT, PIN_E          ; Enable wieder low
           ret                          ; Und wieder zurück

 ; Pause nach jeder Übertragung
delay50us:                              ; 50us Pause
           ldi  temp1, $42
delay50us_:dec  temp1
           brne delay50us_
           ret                          ; wieder zurück

 ; Längere Pause für manche Befehle
delay5ms:                               ; 5ms Pause
       push temp1
       push temp2
           ldi  temp1, $21
WGLOOP0:   ldi  temp2, $C9
WGLOOP1:   dec  temp2
           brne WGLOOP1
           dec  temp1
           brne WGLOOP0
           pop temp2
       pop temp1
       ret                          ; wieder zurück

 ; Initialisierung: muss ganz am Anfang des Programms aufgerufen werden
lcd_init:
   push temp1
        ldi   temp1, 0xFF            ; alle Pins am Ausgabeport auf 
Ausgang
        out   LCD_DDR, temp1

           ldi   temp3,6
powerupwait:
           rcall delay5ms
           dec   temp3
           brne  powerupwait
           ldi   temp1,    0b00000011   ; muss 3mal hintereinander 
gesendet
           out   LCD_PORT, temp1        ; werden zur Initialisierung
           rcall lcd_enable             ; 1
           rcall delay5ms
           rcall lcd_enable             ; 2
           rcall delay5ms
           rcall lcd_enable             ; und 3!
           rcall delay5ms
           ldi   temp1, 0b00000010      ; 4bit-Modus einstellen
           out   LCD_PORT, temp1
           rcall lcd_enable
           rcall delay5ms
           ldi   temp1, 0b00101000      ; 4 Bit, 2 Zeilen
           rcall lcd_command
           ldi   temp1, 0b00001100      ; Display on, Cursor off
           rcall lcd_command
           ldi   temp1, 0b00000100      ; endlich fertig
           rcall lcd_command
       pop temp1
          ret

 ; Sendet den Befehl zur Löschung des Displays
lcd_clear:
     push temp1
           ldi   temp1, 0b00000001      ; Display löschen
           rcall lcd_command
           rcall delay5ms
  pop temp1
  ret

 ; Sendet den Befehl: Cursor Home
lcd_home:
  push temp1
           ldi   temp1, 0b00000010      ; Cursor Home
           rcall lcd_command
           rcall delay5ms
    pop temp1
          ret

 ; Einen konstanten Text aus dem Flash Speicher
 ; ausgeben. Der Text wird mit einer 0 beendet
lcd_flash_string:
           push  temp1
           push  ZH
           push  ZL

lcd_flash_string_1:
           lpm   temp1, Z+
           cpi   temp1, 0
           breq  lcd_flash_string_2
           rcall  lcd_data
           rjmp  lcd_flash_string_1

lcd_flash_string_2:
           pop   ZL
           pop   ZH
           pop   temp1
           ret

Autor: Sebastian F. (snake080)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke für den Tipp, aber klappt leider auch nicht :(

Autor: Hc Zimmerer (mizch)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Erfreulich ist, dass Du in Deinem Code Labels verwendet hast anstelle 
der festen Zahlen.

Ansonsten hat sich Deine Antwort mit meinem Post wohl überschnitten (in 
dem es PORTD statt PORTS an einer Stelle heißen muss).  Trifft es denn 
zu, dass die Pins 6 und 7 gar nicht Ausgang sind, sondern nur der Pullup 
weggeschaltet wird?  Das macht nämlich Dein Code auch.

Autor: Hc Zimmerer (mizch)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nun ja ...
lcd_init:
   push temp1
        ldi   temp1, 0xFF            ; alle Pins am Ausgabeport auf
Ausgang
        out   LCD_DDR, temp1

Das wurde von Dir den Routinen aus dem Tutorial zugefügt.  Was glaubst 
Du denn, was das aus Deinen Inputs an Bit 6 und 7 von LCD_PORT macht?

Autor: Sebastian F. (snake080)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ja wir haben uns ein wenig überschnitten.
I ch muss zugeben, das ich noch gar nicht probiert habe, ob es noch 
Ausgänge sind oder nicht. Das werde ich mal schnell machen...

Das hier habe ich gerade schon geändert:

lcd_init:
   push temp1
   ldi   temp1, 0xFF            ; alle Pins am Ausgabeport auf
Ausgang
   out   LCD_DDR, temp1

Autor: Hc Zimmerer (mizch)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Schon wieder überschnitten.  <Westernmelodie>Er war einsam, aber 
schneller ...</Westernmelodie>

Autor: Sebastian F. (snake080)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hehe, ja das können wir gut :)
So, ich habe das mal ein wenig umgeschrieben:
- Definition DDRD
- Initialisierung lcd_init
- Erneute definition DDRD
- Pull-ups einschalten

Ergebis: Alles funktioniert, wie es soll.

Dann habe ich ein lcd_clear hinter die Pull-ups gesetzt (mit umschreiben 
der lcd_command).

Ergebnis: Eingänge auf 0. Funktionieren aber noch.

Nachträgliches einschalten mit "sbi PORTD,6" bzw 7 funktioniert auch...

Autor: Hc Zimmerer (mizch)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Dann habe ich ein lcd_clear hinter die Pull-ups gesetzt (mit umschreiben
> der lcd_command).
> Ergebnis: Eingänge auf 0. Funktionieren aber noch.

Hast Du aus
           andi temp1, 0b00001111
           out LCD_PORT, temp1
in lcd_command ein
           andi temp1, 0b00001111
           ori temp1, 0xC0
           out LCD_PORT, temp1
gemacht und danach analog für temp2 auch?  Dann sollte das nicht 
passieren.

Autor: Sebastian F. (snake080)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jupp, das ist auch wesentlich eleganter als am ende von lcd_command die 
Pull-ups wieder einzuschalten.
Jetzt funktioniert alles.
Vielen Dank!!!

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.