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?
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
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
Danke für die Antworten, ich versuche mich mal da durchzuarbeiten. Ich habe keine Ahnung von C. Hätte ich vielleicht dazuschreiben sollen :)
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.
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);
.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?
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...
Includes in spitzen Klammern sind systemweit; sie gehören zum Compiler, nicht zum Projekt. Die hast Du also mit dem Compiler installiert.
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)
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.
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...
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.
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-Tutorial:_LCD#Initialisierung_f.C3.BCr_4_Bit_Modus) 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...
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).
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
1 | ldi temp1, 0b00000011 ; muss 3mal hintereinander gesendet |
2 | out PORTD, temp1 ; werden zur Initialisierung |
wird
1 | ldi temp1, 0b11000011 ; muss 3mal hintereinander gesendet |
2 | 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.
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
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.
Nun ja ...
1 | lcd_init: |
2 | push temp1 |
3 | ldi temp1, 0xFF ; alle Pins am Ausgabeport auf |
4 | Ausgang |
5 | 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?
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
Schon wieder überschnitten. <Westernmelodie>Er war einsam, aber schneller ...</Westernmelodie>
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...
> 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
1 | andi temp1, 0b00001111 |
2 | out LCD_PORT, temp1 |
in lcd_command ein
1 | andi temp1, 0b00001111 |
2 | ori temp1, 0xC0 |
3 | out LCD_PORT, temp1 |
gemacht und danach analog für temp2 auch? Dann sollte das nicht passieren.
Jupp, das ist auch wesentlich eleganter als am ende von lcd_command die Pull-ups wieder einzuschalten. Jetzt funktioniert alles. Vielen Dank!!!
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.