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....
Danke für die fixe Antwort. Upps!!! Da hab ich wohl irgendwie durchs rumprobieren alles durcheinander gebracht. Habe es jetzt wieder berichtigt.
1 | LCD_DATA equ PORTB |
2 | LCD_DATA_TRIS equ TRISB |
3 | LCD_CTRL equ PORTA |
4 | LCD_CTRL_TRIS equ TRISA |
5 | |
6 | LCD_RS equ 3 |
7 | LCD_RW equ 1 |
8 | LCD_E equ 0 |
Leider muss da irgendwo noch ein Fehler drin.
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 ;-)
Ich habe die Init jetzt nochmal ein wenig überarbeitet.
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 zu Bank0 zum Register PortA |
7 | CLRF PORTA ;Init PORTA |
8 | BANKSEL ANSEL ;springe direkt zu Bank3 zum Register Ansel |
9 | CLRF ANSEL ;setze PortA auf digital I/O |
10 | BSF STATUS,RP0 ;springe zu Bank1 |
11 | MOVLW b'00001011' ;schreibe Wert Inputs ins W-Reg |
12 | MOVWF TRISA ;schreibe Wert aus W-Reg in TristateA |
13 | MOVLW b'00000000' ;schreibe Wert Outputs ins W-Reg |
14 | MOVWF TRISB ;schreibe Wert aus W-Reg in TristateB |
15 | BSF STATUS,RP1 ;springe zu Bank3 |
16 | CLRF ANSELH ;setze PortB auf digital I/O |
17 | BCF STATUS,RP0 ;springe zu Bank2 |
18 | BCF STATUS,RP1 ;springe zu Bank0 |
19 | |
20 | RETURN |
Ich hoffe das sieht jetzt besser aus. Leider versteckt sich aber immernoch irgendwo ein Fehler :-(
:
Bearbeitet durch User
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 |
17 | CLRF ANSELH ;setze PortB auf digital I/O |
18 | BCF STATUS,RP0 ;springe zu Bank2 |
19 | BCF STATUS,RP1 ;springe zu Bank0 |
20 | |
21 | RETURN |
Wenn Du es nicht gebacken bekommt ich habe dafür eine Library um den 887 anzusteuern. Frag mich einfach wenn Du diese haben möchtest
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.
:
Bearbeitet durch User
Danke ats3788, leider fehlt noch die LCDMacros.inc um das Prog zu builden.
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***
:
Bearbeitet durch User
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***
:
Bearbeitet durch User
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 > ; -------------------------------------------------------------
1 | $Region "Ein Zeichen aus dem LCD auslesen" |
2 | LCD_GetChar: |
3 | |
4 | MOV LCD_Port,#00111111b |
5 | CALL LCD_Pause_4ms |
6 | SETB LCD_EN |
7 | MOV A,LCD_Port |
8 | SWAP A |
9 | ANL A,#0F0h |
10 | CLR LCD_EN |
11 | MOV LCD_buffer,A |
12 | NOP |
13 | SETB LCD_EN |
14 | MOV A,LCD_Port |
15 | ANL A,#0Fh |
16 | CLR LCD_EN |
17 | ORL LCD_buffer,A |
18 | CLR LCD_RW |
19 | CLR LCD_RS |
20 | RET |
***lg Pielo***
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
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.