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.