Jetzt wo Tasterabfrage mit Blinklich, Lauflicht usw. funktionieren, hab
ich mir gedacht ich versuche mich an einer LCD Ansteuerung.
Ich habe mir das "AVR-Tutorial: LCD" und die Dokumentation von Stefan
Buchgeher (http://www.stefan-buchgeher.info/elektronik/lcd/lcd.html)
durchgelesen und versucht es für den 16f887 umzusetzen.
Aber leider sehe ich nur eine schwarze Zeile.
Nach etlichen erfolglosen Versuchen das Problem zu beheben, wende ich
mich nun an Pro's in diesem Forum.
Es wäre lieb wenn ihr mir ein paar Tipps bzw. Anregungen gebt, was das
Problem sein könnte.
Verwendetes Display: Batron BTHQ 21605VSS-15
Im Anhang habe ich das Programm und die verwendete Schaltung eingefügt.
***lg Pielo***
Im Programm sind deine Steuerleitungen auf PORTB festgelegt:
LCD_CTRL equ PORTB
LCD_CTRL_TRIS equ TRISB
und die einzelnen Pins sind so belegt:
LCD_RS equ 1
LCD_RW equ 2
LCD_E equ 3
Laut Schaltplan hängen die Steuerleitungen alle an PORTA und die
einzelnen Pins haben folgende Funktionen:
3 = RS
1 = RW
0 = E
Pass irgendwie überhaupt nicht zum Programm....
Beim F887 hat PORTB auch Analogfunktionen. Diese müssen abgeschaltet
werden (wenn ich mich recht erinnere geht das mit ANSEL oder ANSELH).
Warum?
Weil BUSYLCD auf PORTB Lesend zugreift und bei Analogkonfiguration dort
immer nur 0x00 eingelesen wird - für die Busyflagabfrage tödlich ;-)
Damit bist du in Bank3 - völlig richtig
BANKSEL ANSEL ;springe direkt zu Bank3 zum Register Ansel
CLRF ANSEL ;setze PortA auf digital I/O
jetzt ist RP0 = 1, RP1 = 1
nur mit dem hier:
BSF STATUS,RP0 ;springe zu Bank1
kommst du sicher nicht in Bank1 zu TRISA und TRISB
Verwende einfach BANKSEL KONSEQUENT !!! dann passieren solche Sachen
nicht.
hmmm Stimmt...
das ist halt die Sch... wenn man es in der Schule viel umständlicher
erklärt bekommt.
Habe es jetzt geändert, aber leider noch immer ohne Erfolg :-(
1
INIT
2
BSF STATUS,RP1 ;Bank 2
3
BCF CM1CON0,C1ON ;Comparator 1 ist aus
4
BCF CM2CON0,C2ON ;Comparator 2 ist aus
5
6
BANKSEL PORTA ;springe direkt zum Register PortA
7
CLRF PORTA ;Init PORTA
8
BANKSEL ANSEL ;springe direkt zum Register Ansel
9
CLRF ANSEL ;setze PortA auf digital I/O
10
BANKSEL TRISA ;springe zu Bank1
11
MOVLW b'00001011' ;schreibe Wert Inputs ins W-Reg
12
MOVWF TRISA ;schreibe Wert aus W-Reg in TristateA
13
BANKSEL TRISB ;springe direkt zum Register Tristate
14
MOVLW b'00000000' ;schreibe Wert Outputs ins W-Reg
15
MOVWF TRISB ;schreibe Wert aus W-Reg in TristateB
16
BANKSEL ANSELH ;springe direkt zum Register AnselH
Leider habe ich noch nie mit Libaries gearbeitet, daher weis ich
garnicht so genau was das ist, bzw was ich damit machen kann. Dazu kommt
noch das ich es ja auch irgendwie lernen möchte. Oder meine gemachten
Fehler kennen lernen möchte um ihnen nicht noch einmal zu begegnen ;-)
Robert Manzke schrieb:> Leider habe ich noch nie mit Libaries gearbeitet,
In diesem Zusammenhang ist mit 'LIbrary' einfach nur der Source-Code
gemeint und seltener eine tatsächlich richtige Library.
> daher weis ich> garnicht so genau was das ist, bzw was ich damit machen kann.
Auf Deutsch: er gibt dir seinen Source Code, der nachweislich bei ihm
funktioniert.
> Dazu kommt> noch das ich es ja auch irgendwie lernen möchte. Oder meine gemachten> Fehler kennen lernen möchte um ihnen nicht noch einmal zu begegnen ;-)
Fremden Code zu analysieren ist dabei gar nicht mal die schlechteste
Methode. Man kann sehr viel lernen, wenn man sich ansieht, wie andere
ein bestimmtes Problem lösen. Kein Mensch sagt, dass du den Code ohne
genauer anzusehen übernehmen sollst, bzw. ob du ihn überhaupt 1:1 ohne
Änderungen übernehmen kannst, ist damit noch lange nicht gesagt.
Hallo Robert ich hänge erst mal ein normales asm und die dazugehörige
include file. Bitte teile mit ob das funktioniert hat.
Gehe einfach auf http://www.sprut.de/
da habe ich vieeeellll gelernt.
Hallo Robert,
falls Du mit der bisherigen Software nicht weiterkommen solltest,
insbesondere falls "relocatable Code" Dir noch nicht geläufig sein
sollte, könnte ich Dir ein für den PIC16F877 geschriebenes ASM-File
(absoluter Code) und HD44780.INC (LCD-Initialisierung) hier einstellen.
Wie ich das sehe, müsste lediglich der Header (Prozessor, INC-File,
Config-Word)
und PORTA ADCON1 ->> ANSEL angepasst werden.
mfG Ottmar
@ wil1
Ich benutze ein "Batron BTHQ 21605VSS-15" Display, wenn ich mich nicht
irre ist darin ein Samsung KS0070, ist dieser mit dem HD44780 identisch?
Leider finden ich in den Weiten kein Datenblatt für dieses Display um
sicher zu gehen das auch wirklich dieser Chip verbaut ist. Aber ich wäre
auf alle Fälle an diese Code interessiert.
***lg Pielo***
Robert Manzke schrieb:> Es wäre lieb wenn ihr mir ein paar Tipps bzw. Anregungen gebt, was das> Problem sein könnte.
Laß lieber den PortA frei für andere Zwecke und betreibe das LCD im 4
Bit Modus. Dann kannst du es komplett mit nur dem PortB betreiben.
Ich häng dir mal ein Beispiel dran. Die LCD-Routinen daraus kannst du
übernehmen, allenfalls mußt du ne "Stil"-Anpassung auf deinen Assembler
vornehmen.
W.S.
Hallo Robert,
beiliegend das ASM-File und die LCD-Initialisierung. Meiner Erinnerung
nach hatte bei mir ein BATRON-LCD mit der HD44780-initialisierung
funktioniert.
Du brauchst im ASM-File lediglich den PIC16F887-spezifischen Teil und
#define-Anweisungen hinsichtlich der PORT- und PIN-Zuweisungen
anzupassen.
Die LCD-initialisierung verwendet den 4Bit-Datenbus D4 - D7 am LCD. Wie
viele andere auch, habe ich zum LCD (und anderem) bei
[http://www.sprut.de] kräftig abgeschaut. Die Initialisierung wurde mti
dem Timing für fosc 4MHz erstellt, funktioniert aber bei mir bis fosc
10MHz.
Zur Sicherheit, dass das Timing auch klappt, empfehle ich im Abschnitt
"Labels & Constants" diese Anpassung einzufügen:
FOSC equ .20 ;aktuelle fosc eintragen (z.B. 20MHz)
FOSC_MULT equ FOSC/4 ;Multiplikator für Delays
Delay aufrufen:
movlw .10*FOSC_MULT ;Delaytime an aktuelle fosc anpassen.
CALL Delay1ms
Ich hoffe, dass ich Dir ein wenig weiterhelfen konnte.
mfG Ottmar
Danke für eure zahlreichen Tipps und Infos.
Ich habe es jetzt entlich geschafft. Ich habe das Voltmeter
(http://pic-projekte.de/phpBB3/viewtopic.php?f=14&t=25), welches ich vor
paar Monaten schon mal auf den 887 umgebastelt habe, auf das geringste
gekürtzt und für mich angepasst.
Kann man da noch was Verbessern, was würdet ihr besser machen?
Jetzt habe ich aber mal noch die ein oder andere Frage dazu, damit ich
auch vollkommen nachvollziehen kann was ich da genau getan habe. Ich
weiß zwar nicht ob ich das jetzt hier reinschreiben kann oder ob ich ein
neues Thread eröffnen soll.
Und zwar:
In diesem Programm verwendet Nico ein Linker Script, für was wird dieses
verwendet, bzw. wann verwendet man sowas?
Was bedeutet "MYUDATA UDATA 0x20"?
Variablen werden mit z.b. "warten RES 1" deklariert, ich kenne aber nur
den Befehl "warten EQU 0x20" wo ist da der Unterschied bzw. woher weiß
der µC welche Speicherzelle für welchen Befehl zugewiesen wird?
Besteht die Möglichkeit die Buchstaben auch irgendwie mit einmal zu
übertragen, gerade wenn man längere Texte übertragen möchte ist es ja
ziemlich umfangreich. Oder besteht diese Möglcihkeit nur bei der
C-Programmierung?
Ich denke mal das waren erstmal meine Fragen, wenn noch mehr dazu kommen
melde ich mich noch mal.
***lg Pielo***
Robert Manzke schrieb:> Was bedeutet "MYUDATA UDATA 0x20"?
Nachstehende Infos sind bei Weitem nicht vollständig! Das Thema
"relocatable code" kann hier nur angerissen werden!
Bei der Assemblerprogrammierung mit MPLAB unterscheidet man 2
Möglichkeiten:
a)Absolute Code
b)Relocatable Code
Absolute Code
Es gibt ein Sourcefile z.B. "Voltmeter.ASM" In diesem befinden sich alle
Initialisierungen und Unterprogramme.
Zusätzlich können noch KOMPLETTE Include-Files "*.INC" an beliebiger
Stelle im ASM-File mit der Direktive " include "LCD_Init.INC" eingefügt
werden, was vom Compiler beim Assemblieren erledigt wird. Es werden
jedoch alle Subroutinen des *.INC-Files eingefügt auch wenn diese im
speziellen Fall nicht benötigt werden.
Relocatable Code
Man schreibt weiterhin die Software "Voltmeter.ASM". Zusätzlich verfügt
man z.B. über ein ASM-File "MATH.ASM" mit allen möglichen
Unterprogrammen z.b. 32-Bit Division, Additionen usw. Hieraus wird z.B.
nur die 16-Bit-Multiplikations-Sub "Mult16" benötigt.
MATH.ASM wird daher als Sourcefile mit in das Projekt, zusätzlich zu
"Voltmeter.ASM" eingefügt.
Mittels der Direktive "GLOBAL Mult16" ist diese Sub in MATH.ASM (neben
anderen) explizit zur globalen Verwendung freigegeben. Ebenso die
zugehörigen Variablen "global VarXY".
Ebenso explizit wird im "Voltmeter.ASM" mittels der Direktive
"EXTERN Mult16" die Sub bekannt gemacht, Natürlich auch die zugehörigen
Variable "extern VarXY".
In "MATH.ASM" befinden sich diese Direktiven
My_Udata: UDATA_SHR ;Mx_Udata ist ein x-beliebiger Label
VarXY res 1 ;reserviert 1 Byte für diese Variable
die "shared"(=SHR) VarXY kann jetzt aus anderen ASM-Files heraus
aufgerufen werden.
labelXY: UDATA 0x20
VarAZ res 1
weist den Compiler an, 1 Byte im Speicher für die Variable VarAZ
explizit an Adresse 0x20 bereitzustellen.
Beim Assemblieren sorgt der Compiler dann selbstständig dafür, dass nur
die bezeichneten Unterprogramme und Variablen, die angegebenen
Speicherbereiche usw. verwendet werden.
Der Clou ist, dass Du in Voltmeter.ASM, aber auch in MATH.ASM
gleichnamige Variablen verwenden kannst. Man kann Speicherbereiche
reservieren usw. Wenn man es einmal geblickt hat ist das gar nicht so
schwierig.
Auf jeden Fall entbindet es einen immer wieder gleichlautende
Unterprogramme zu schreiben, man kann sich so eine "Bibliothek" z.B. für
Mathematik, LCD-Ausgabe usw zulegen und immer wieder darauf - wenn
einmal erstellt - einfach und wenig zeitaufwendig zugreifen.
In der Hilfe zu MPLAB, bzw. im Handbuch dazu ist dieses Vorgehen,
allerdings in englischer Sprache recht gut und verständlich beschrieben.
Wenn Du Interesse hast, kann ich Dir eine von mir erstellte Ausarbeitung
zum relocatable code als persönliche Mail zusenden.
mfG Ottmar
Danke für die ausführliche Erklärung. Ich werde mich aber erstmal mit
den "einfachen" Weg beschäftigen, quasi nur ein asm-File. Ich werde dir
trotz alle dem mal meine E-Mail schicken, damit ich mich mal ein wenig
in diese Geschichte einlesen kann.
Jetzt werde ich mich mal daran machen Tasterabfrage mit LCD Anzeige zu
vereinen.
***lg Pielo***
Ich habe an das Display jetzt 2 Taster, mit den ich den Curser nach
links und nach rechts schieben kann. Jetzt würde ich aber gern mit 2
weiteren Tastern das Alphabet vorwarts bzw. rückwärts schalten können.
Dazu habe ich mich entschieden die Position des Cursers mit zu zählen
und dann dem Wert der in dem Register steht an dem der Curser sich
befindet einfach 1 zu addieren bzw. subtrahieren. Dazu habe ich hier im
Forum ein Code-Schnipsel gefunden, der aber leider in avr-asm
geschrieben ist. Wäre es möglich das mir jemand ein paar Komentare
dahinter schreibt, damit ich es in pic-asm um dichten kann. Befehle wie
"SETB", "ANL" oder "ORL" finde ich irgendwie in keiner Dokumentation.
Klaus schrieb im Beitrag "Re: LCD Zeichen auslesen":
> ; -------------------------------------------------------------> ; LCD_GetChar> ; -------------------------------------------------------------> ; Beschreibung: Liest ein Zeichen von der aktuellen Cursor Position> ; LCD_buffer enthält empfangens Zeichen> ; -------------------------------------------------------------
was anders...
ist es irgendwie möglich einen Zählerwert festen Zeichen zuzuweisen?
D.h.:
Speicherzelle "0x25" hat den Wert "3" -> festgelegt ist für 3 der
Buchstabe "C" -> jetzt das "C" ins Arbeitsregister übergeben -> dann
ausgeben?
***lg Pielo***
Hallo Robert,
beiliegend eine Richtungsangabe wie Du zur Ausgabe eines Buchstabens per
Tastendruck verfahren könntest. Ich hab den Code nicht getestet, einfach
mal hingeschrieben, wie es gemacht werden könnte.
Evtl. kannst Du das dann auch in einen eigenen Code umsetzen.
mfG Ottmar
Robert Manzke schrieb:> Speicherzelle "0x25" hat den Wert "3" -> festgelegt ist für 3 der> Buchstabe "C" -> jetzt das "C" ins Arbeitsregister übergeben -> dann> ausgeben?
Klar geht das mit indirekter Adressierung. Lies doch dazu im Datenblatt
des 16F628 diesen Abschnitt: "3.4 Indirect Addressing, INDF and FSR
Registers"
In Register schreiben:
movlw 0x22 ;Adressezeiger z.B. 0x22 über das WREG
movwf FSR ;ins Register "FSR" (FileSelectRegister) kopieren
movlw "A" ;Wert ins WREG
movwf INDF ;und ins virtuelle Register übertragen, damit enthält
dann
;zugleich das Register 0x22 nun den Ascii-Wert von "A"
;nächstes Register belegen
incf FSR,f ;Adresszeiger+1
movlw "B" ;nächsten Wert übertragen
movwf INDF :Ascii-Wert von B steht nun in Adresse 0x23
Aus Register lesen, der umgekehrte Vorgang, im Prinzip wie vorstehend:
movlw 0x22
movwf FSR
movf INDF,w ;kopiert Inhalt Adresse 22h ins WREG
movwf Variable ;Variable enthält nun die K0pie des Wertes
; in Adresse 0x22 -> "A"
incf FSR,f
movf INDF,w
movwf Variable ;Variable enthält nun die Kpie des Wertes
in Adresse 0x23 -> "B"
Das lässt sich natürlich in eine Schleife gefasst mit weniger Code und
dazu übersichtlicher erledigen.
mfG Ottmar
Ottmar K. schrieb:> Hallo Robert,>> beiliegend eine Richtungsangabe wie Du zur Ausgabe eines Buchstabens per> Tastendruck verfahren könntest. Ich hab den Code nicht getestet, einfach> mal hingeschrieben, wie es gemacht werden könnte.> Evtl. kannst Du das dann auch in einen eigenen Code umsetzen.>> mfG Ottmar
Danke für die gute Erklärung.
Leider hapert es noch ein wenig bei mir an der Umsetzung, ich komme
einfach nicht dahinter für was "pointer_H" und "pointer_L" da sind.
Und mit dem "PLCATH" hab ich mich vorher auch noch nie beschäftigt, da
probiere ich gerade diesen Abschnitt zu verstehen.
-> http://www.sprut.de/electronic/pic/grund/adress.htm#progmem
Ich habe jetzt ein wenig Durchblick, dadurch habe ich jetzt mit der
Simulation auch einen Fehler im Ablauf gefunden.
Er springt nach "ABC_Char:" (vor dem "return") an einen willkürlichen
Punkt, meistens zu Taster_links.
Ich geh mal davon aus das ich den Codeteil falsch eingebaut habe, oder
liegt das Problem wo anders?
Die Pausen habe ich nur für die Simulation ausgeblendet bzw. verkleinert
***lg Pielo***
Autor: Ottmar K. (wil1)
Datum: 18.10.2013 18:06
Robert Manzke schrieb:
> ich komme> einfach nicht dahinter für was "pointer_H" und "pointer_L" da sind.
Also Pointer_H könnte auch
"Zeiger_auf_HByte_der_Adresse_von_Register_XYZ"
oder sonst wie benannt werden. Es handelt sich hier um einen beliebigen
Variablennamen. Es ist halt üblich einen Zeiger mit dem englischen Wort
"pointer" zu benennen.
Also angenommen die Variable heißt "Finde_Mich" und liegt infolge der
Anweisung
CBLOCK 0x0020
Finde_Mich
ENDC
an Adresse 0x0020, also 20h. Dann ist in diesem Fall das H-Byte der
Adresse 0x00 und das Low-Byte 0x20.
Mit dem Code
movlw high Finde_Mich"
movwf Zeiger_H
wird der Compiler beim Assemblieren angewiesen über das WREG der
Variablen "Zeiger_H" den Wert des Adress-HIGH-Bytes des Registers mit
dem "Decknamen" "Finde_Mich" also 00h, zuzuweisen.
Mit dem Code
movlw low Finde_Mich"
movwf Zeiger_L
wird der Compiler beim Assemblieren angewiesen über das WREG der
Variablen "Zeiger_L" den Wert des Adress-LOW-Bytes des Registers mit dem
"Decknamen" "Finde_Mich" also 20h, zuzuweisen.
Siehe dazu auch 2.3 PCL and PCLATH im Datenblatt des PIC16F887!
Der Programmzähler beim PIC besteht ebenfalls aus H-Byte, das sind die
unteren Bit 4:0 des Register PCLATH und dem Low-Byte das ist das
Register PCL.
Folglich kann mann mit 13 Bit einen Speicherbereich von 0 - 8191 = 8192
Bytes adressieren.
Die Zuweisung
movlw Zeiger_H
movwf PCLATH
movlw Zeiger_L
movwf PCL
bewirkt bei Ausführung von "movwf PCL" dass der Programmzähler an die
Adresse der Variablen "Finde_Mich" springt. Natürlich würde das in
diesem Falle zu Unsinn führen, denn mit der Variablen kann je das
Programm weiter nichts anfangen.
Nich jedoch wenn die indirekte Adressierung per FSR und INDF (habe schon
was dazu geschrieben) ins Spiel kommt.
Eine Tabelle kann dann so ausgelesen werden (zu "dt - Define Table"
bitte die Hilfe zu MPLAB - Assembler lesen):
Sprungziel_1:
dt "Volt"
Sprungziel_2
dt "Ampere@"
Zeiger_H und Zeiger_L werden auf "Sprungziel_1" gerichtet, was ja nichts
anderes als die vollständige Adresse des 1.Buchstabens im String "Volt"
ergibt.
Wird PCL nach dem Lesen von "V" incrementiert (+1) kann Buchstaben für
Buchstaben ausgelesen und z.B. im LCD ausgegeben werden. Im Programm
muss durch mitzählen festgestellt werden wann der letzte Buchstabe "t"
gelesen wurde. Man kann aber z.B. wie beim "Sprungziel_2" ein Zeichen
(@) als Schlussmarke verwenden. Wird dieses gelesen, ist die Ausgabe
beendet.
Soviel mal zu diesem Thema, kannst ja wieder fragen.
mfG Ottmar