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:> 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...
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.
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
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.