Ansteuern eines KS0066 Controllers

Aus PIC-Projekte
Wechseln zu: Navigation, Suche
Ambox notice.png Die Routinen sind in Assembler und C (Compiler C18 und XC8) vorhanden!
Diese Dokumentation bezieht sich auf die Assembler Variante. Im Download-Bereich sind die Ansteuerungsroutinen aber auch in C vorhanden!


Inhaltsverzeichnis

Allgemein

LCD Display
Hier geht es um die Ansteuerung eines HD44780 kompatiblen LCD Displays. Um genau zu sein habe ich das EA DIPS082-HN gewählt. Hierbei handelt es sich um ein 2x8 Zeichen LCD von electronik Assembley. Bei Reichelt gibt es das Modul für ca. 15€ inklusive LED Hintergrundbeleuchtung. Das Display eignet sich hervorragend für kleinere Projekte. Ich habe das Display auch schon bei meinem Roboter eingesetzt um die Akkuspannung einzublenden.
Wem diese Art der Ansteuerung zuwider ist, der kann ja mal die Variante mit den C18-Libraries versuchen. Eine Beschreibung wie das funktioniert findet ihr hier.

Programm Beschreibung

Bitte beachten: Die Assembler Routinen werden nicht mehr gepflegt!

Das Programm beginnt mit der Initialisierung des Displays. Wie auch bei einem Grafik LCD gibt es auch bei einem alpha Numerischen Display gewisse Steuerleitung. Die da wären RS, RW und die Enable Leitung. Zunächst einmal werden alle drei Steuerleitungen auf Low ( =0V ) gezogen um einen definierten Zustand der Steuerleitungen zu gewährleisten und eine Warteschleife durchlaufen. Dies ist wichtig da LCDs nach anlegen der Versorgungsspannung nicht sofort Einsatzbereit sind man muss eine Gewisse Zeit abwarten bis man sie ansprechen kann. Wie lange, das kann man im Datenblatt des Controllers nachlesen.

Steuerleitungen

Enable Wird benötigt um dem LCD zu signalisieren, dass sich Daten/Befehle auf der Steuerleitung befinden.
RS Ist zum wählen zwischen Daten (1) und Befehlen(0).
R/W Zum unterscheiden zwischen Lesen(1) und Schreiben (0) wobei die Methode des Lesens im wesentlichen kaum gebraucht wird.

Die Initialisierung des LCD Displays

;••••••••••••••••••••••
Init_LCD
;••••••••••••••••••••••
 
	Bcf 	LCD_E
	Bcf 	LCD_RS
	Bcf 	LCD_RW
 
                                ;WARTEZEIT von 15ms
	movlw	D'255'		;Schreibt (dezimal) 255 ins Arbeitsregister
	movwf	Wartezeit	;Schreibt das Arbeitsregister nach “Wartezeit”
	call	Warten		;Ruft das Unterprogramm “Warten” auf
 
 
    ;Es wird zunächst 3 mal das Display in den 8 Bit Modus versetzt
    ;um sicher zustellen, dass man ohne Komplikationen in den 4 Bit Modus
    ;übergehen kann. Dies ist notwendig, da man nie weiß in welchem Zustand
    ;sich das Display im Aufganblick befindet!
    ;Unbedingt angepasst werden müssen die Wartezeiten!
 
    ;#1
	Movlw	B'00110000'
	Movwf	PORTB
	Call	LCD_Enable
                                ;WARTEZEIT von 5ms
	movlw	D'255'		;Schreibt (dezimal) 255 ins Arbeitsregister
	movwf	Wartezeit	;Schreibt das Arbeitsregister nach “Wartezeit”
	call	Warten		;Ruft das Unterprogramm “Warten” auf
    ;#2
	Movlw	B'00110000'
	Movwf	PORTB
	Call	LCD_Enable
                                ;WARTEZEIT von 1ms
	movlw	D'255'		;Schreibt (dezimal) 255 ins Arbeitsregister
	movwf	Wartezeit	;Schreibt das Arbeitsregister nach “Wartezeit”
	call	Warten		;Ruft das Unterprogramm “Warten” auf
    ;3#
	Movlw	B'00110000'
	Movwf	PORTB
	Call	LCD_Enable
                                ;WARTEZEIT von 1ms
	movlw	D'255'		;Schreibt (dezimal) 255 ins Arbeitsregister
	movwf	Wartezeit	;Schreibt das Arbeitsregister nach “Wartezeit”
	call	Warten		;Ruft das Unterprogramm “Warten” auf
 
                                ;Jetzt kann das Display in den 4 Bit Modus versetzt werden
	Movlw	B'00100000'
	Movwf	PORTB
	Call	LCD_Enable
	movlw	D'255'		;Schreibt (dezimal) 255 ins Arbeitsregister
	movwf	Wartezeit	;Schreibt das Arbeitsregister nach “Wartezeit”
	call	Warten		;Ruft das Unterprogramm “Warten” auf
 
	Movlw	0x28		; Functionset
	Call	LCD_Command			
	Movlw	0x0C		; Display on
	Call	LCD_Command		
	Movlw	0x01		; Display clear
	Call	LCD_Command		
	Movlw	0x06		; Entry Mode
	Call	LCD_Command			
 
Return

Wie ich bereits oben erwähnt habe muss dem Display eine gewisse Vorlaufzeit gewährt werden bevor es angesprochen werden kann. Hierfür rufe ich eine kleine Warteschleife auf (call Warten). Im Anschluss wird auf den Datenport der Code für den 4 Bit Modus gelegt, da ich nur 4 der 8 Datenleitungen verwenden möchte. Dies spart IOs am PIC. Grundsätzlich lässt sich jedes LCD Display mit einem HD44780 Controller im 4 Bit Modus betreiben. Dies hat allerdings einen Hacken, wenn man das überhaupt so nennem will. Die Software wird ein klein wenig aufwendiger, da jetzt die Information in zwei Paketen übermittelt werden muss. Aber das ist kein Problem und ist schnell geschehen.

Damit der Controller jetzt weiß, dass sich die Informationen auf der Datenleitung befinden muss ihm ein "Strobbe" gesendet werden. Das heisst am Enable Pin des Displays muss ein Impuls erfolgen. Dann weiß der Controller, dass er die Daten vom Port einlesen kann.

Das Enable Strobbe

;••••••••••••••••••••••
LCD_Enable
;••••••••••••••••••••••
 
	Bsf	LCD_E
	movlw	D'20'				;Schreibt (dezimal) 255 ins Arbeitsregister
	movwf	Wartezeit			;Schreibt das Arbeitsregister nach “Wartezeit”
	call	Warten				;Ruft das Unterprogramm “Warten” auf
 
	Bcf	LCD_E
	movlw	D'20'				;Schreibt (dezimal) 255 ins Arbeitsregister
	movwf	Wartezeit			;Schreibt das Arbeitsregister nach “Wartezeit”
	call	Warten				;Ruft das Unterprogramm “Warten” auf
 
Return

Hier wird lediglich die Enable Leitung auf High ( =5V ) angehoben eine kurze Zeit gewartet und danach wieder auf Low ( =0V ) gezogen, danach wird wieder eine Warteschleife durchlaufen und zurück zum Ursprungsort gekehrt. Das Enable Unterprogramm ist dafür da, dem LCD Controller mitzuteilen, dass sich Steuer/Daten-Informationen auf dem ( 4 Bit ) Datenbus befinden und abgerufen werden sollen und dies geschieht durch einen so genannten "Enable Strobbe" einem Impuls gewisser Länge und dies ist natürlich auch wieder im Datenblatt nachzulesen. Nachdem mit dem Code dem Controller gesagt wurde, dass das Display im 4 Bit Modus arbeitet ( 4 Bit Modus heißt, dass nur 4 Leitungen zum Display führen ), werden noch die restlichen Konfigurationen für das Display durchgeführt. Es müssen folgende

Parameter geklärt/eingestellt werden:

  • 8/4 Bit Datenlänge (=Anzahl der Zuleitungen)
  • Anzahl der Zeilen des Displays (in unserem Fall 2)
  • Ob der Cursor ein/aus und blinkend sein soll
  • Cursor auto- Inkrement (Automatisch eine Stelle weiter gehen)
  • Display ein/aus und löschen

Nachdem die restlichen Einstellungen (grüner Kasten) erledigt sind (siehe Init) ist das Display schon fertig initialisiert und man kann los legen es voll zu schreiben. Und etwas auf dem Display anzuzeigen ist wirklich total einfach, auch weil das Display schon einen Font Genrator integriert hat (Das bedeutet es sind bereits Buchstaben, Zahlen und Sonderzeichen vorgegeben und können einfach im ASCII Format übertragen werden). Und geschrieben wird am Ende so:

	Movlw	'B'			;Schreibt das ASCII Zeichen 'B' in das W-Reg
	Call	LCD_Output		;Ruft das UP 'LCD-Output' auf
	Movlw	'a'
	Call	LCD_Output
	Movlw	't'
	Call	LCD_Output
	Movlw	't'
	Call	LCD_Output
	Movlw	'e'
	Call	LCD_Output
	Movlw	'r'
	Call	LCD_Output
	Movlw	'i'
	Call	LCD_Output
	Movlw	'e'
	Call	LCD_Output

Wenn man etwas auf dem Display anzeigen möchte wird das Unterprogramm - LCD_Output - aufgerufen. Das Zeichen, welches man darstellen möchte, wird dem Unterprogramm mit "übergeben" indem wir es vorher in das Arbeitsregister speichern. Also wird bei dem Beispiel oben auf dem Display geschrieben - Batterie.

Unterprogramm zur Ausgabe von Daten/Text

;••••••••••••••••••••••
LCD_Output
;••••••••••••••••••••••
 
	Movwf	LCD_Daten			;Die Eingangsinformation sichern
 
	Bcf	LCD_E
	Bsf 	LCD_RS
	Bcf 	LCD_RW	
 
	                                        ;Warten um Busyabfrage zu umgehen
	movlw	D'255'				;Schreibt (dezimal) 255 ins Arbeitsregister
	movwf	Wartezeit			;Schreibt das Arbeitsregister nach “Wartezeit”
	call	Warten				;Ruft das Unterprogramm “Warten” auf
 
	                                        ;Obere Hälfte des Datenpakets übertragen
	Movfw	LCD_Daten			;Die Eingangsdaten zurück holen
	Movwf	PORTB				;Und auf PORTB ausgeben
	Call	LCD_Enable
 
	                                        ;Untere Hälfte des Datenpakets übertragen
	Swapf	LCD_Daten,0			;Die Daten umdrehen, da die unteren 4 Bit zuerst gesendet werden
	Movwf	PORTB				;Und auf PORTB ausgeben
	Call	LCD_Enable
 
Return

Wir erinnern uns zurück, dass wir zuvor die Information (das Zeichen, welches dargestellt werden soll) in das Arbeitsregister gespeichert haben und das erste was in diesem UP gemacht wird ist, den Inhalt des W-Reg in die Variable "LCD_Daten" zu schreiben. Als nächstes werden die Steuerleitungen so eingestellt, dass wir Daten schreiben können. Anschließend wird eine Warteschleife eingeleitet (nur um nicht die Busyabfrage machen zu müssen). Wenn die Warteschleife komplett durchlaufen ist, können wir sicher sein, dass das LCD bereit ist um neue Informationen aufzunehmen und starten mit der Übertragung des 1. Paketes. Zunächst übertragen wir die obere Hälfte des Datenports (also RB7-4) und anschließend wird der Inhalt von "LCD_Daten" gedreht und die untere Hälfte übertragen. So haben wir es geschafft die gesamten 8 Bit mit nur 4 Leitungen zu übertragen! Wichtig ist, dass nach jedem Datenpaket (4 Bit) einmal ein Enable Strobbe durch geführt wird.

Das Unterprogramm zum Übertragen von Befehlen unterscheidet sich von dem für Daten nur in einem Punkt und ihr könnt Euch wahrscheinlich auch schon denken in welchem. Genau! Die Steuerleitung RS.

Unterprogramm zur Übertragung von Befehlen

;••••••••••••••••••••••
LCD_Command
;••••••••••••••••••••••
 
	Movwf	LCD_Daten			;Die Eingangsinformation sichern
 
	Bcf		LCD_E
	Bcf 	LCD_RS
	Bcf 	LCD_RW	
 
	;Warten um Busyabfrage zu umgehen
	movlw	D'255'				;Schreibt (dezimal) 255 ins Arbeitsregister
	movwf	Wartezeit			;Schreibt das Arbeitsregister nach “Wartezeit”
	call	Warten				;Ruft das Unterprogramm “Warten” auf
 
	;Obere Hälfte des Datenpakets übertragen
	Movfw	LCD_Daten			;Die Eingangsdaten zurück holen
	Movwf	PORTB				;Und auf PORTB ausgeben
	Call	LCD_Enable
 
	;Untere Hälfte des Datenpakets übertragen
	Swapf	LCD_Daten,0			;Die Daten umdrehen, da die unteren 4 Bit zuerst gesendet werden
	Movwf	PORTB				;Und auf PORTB ausgeben
	Call	LCD_Enable
 
Return

Busy Abfrage

Ich habe in diesem Programm auf die Busy Abfrage verzichtet und an Stelle dessen eine einfache Warteschleife eingebaut. Also was ist eigentlich diese "Busy Abfrage"? Eigentlich sagt es der Name schon: Man fragt beim Display (bzw. beim Controller) nach ob er derzeit beschäftigt (=busy) ist. Denn wir dürfen ihm nur neue Daten übermitteln, wenn er nicht busy ist. Die Abfrage läuft immer im selben Schema ab: Man setzt die Steuerleitungen für Lesen! und gibt einen Enable Strobbe aus. Jetzt schaltet man den Datenport um auf Eingang (Tris) und fragt eine der Datenleitungen ab (beim HD44780 DB7). Wechselt der Zustand auf "Bereit für Daten", kann fort gefahren werden. Nicht vergessen die Tris Bits wieder auf Ausgang zu stellen.


Wie komme ich in die 2. Zeile?

Ein LCD Display ist in Adressen unterteilt so kann man verschiedene Positionen erreichen. In der Regel stehen die Adressen im Datenblatt (halten Sie Ausschau nach DD-RAM).

So gelangen Sie in die 2. Zeile

Movlw 0xC0
Call LCD_Command

Der Wert ist deshalb 0xC0 und nicht 0x40, da bei dem Befehl zum ändern der DD-RAM Adresse das Bit 7 gesetzt sein muss!


DD-RAM Adressen beim 2*8 LCD

Display Position   0x00  0x01  0x02  0x03  0x04  0x05  0x06  0x07
DDRAm Adresse      0x40  0x41  0x42  0x43  0x44  0x45  0x46  0x47


Die DD-RAM Adressen für andere Displaytypen entnehmen Sie bitte dem Datenblatt

Was tun, wenn es nicht funktioniert

Wenn Sie sich zu 100% sicher sind, dass sie die Programmierung richtig haben, dann kontrollieren sie noch einmal alle Leitungen vom PIC zum Display und gehen Sie dabei behutsam vor. Überprüfen Sie auch ob zwischen einzelnen Leitungen ein Kurzschluss besteht. Wenn auch das alles in Ordnung war, dann überprüfen Sie die Kontrastspannung des Displays. Wenn ihr trotz aller Bemühung nicht weiter kommt, dann könnt ihr euch gerne im Forum melden und werdet mit Sicherheit unterstützt.

Befehls- und ASCII Tabelle

Download ( ASM/C (C18 und XC8) )

Download.gif Routinen in Assembler Download

Download.gif Routinen in C (C18) Download


Verwendet ihr den XC8 Compiler, so nutzt bitte diesen Download: Download.gif Routinen in C Download

Bitte beachten: In der aktuellen Verion (1.5.xc8) müssen im 4 Bit Modus die Datenleitungen auf den unteren 4 Bit des gewählten Ports des PIC liegen. Dadurch dürft ihr auch derzeit das Makro MSB_USED nicht setzten! In der nächsten Version wird dies automatisch umschaltbar sein!

C Routinen (C18)

Datei KS0066_C18.c

Bitte beachten: In der aktuellen Verion (1.5.c18) müssen im 4 Bit Modus die Datenleitungen auf den oberen 4 Bit des gewählten Ports des PIC liegen. Dadurch dürft ihr auch derzeit das Makro MSB_USED nicht löschen! In der nächsten Version wird dies automatisch umschaltbar sein!
  1. /* *****************************************************************************
  2.  * File:        KS0066_C18.c
  3.  * Project:     --
  4.  * Author:      Nicolas Meyertöns
  5.  * Version:     1.5.c18
  6.  * Web:         www.PIC-Projekte.de
  7.  * ****************************************************************************/
  8.  
  9. #include "KS0066.h"
  10. #include <p18cxxx.h>
  11.  
  12. void Init_LCD(void)
  13. {
  14.     LCD_RS=LCD_RW=LCD_E=0;
  15.  
  16.     msDelay(15);
  17.  
  18.     /*1*/
  19.     LCD_DATA=0b00110000;        // Auf 8 Bit setzten
  20.     LCD_enable();
  21.     msDelay(5);
  22.  
  23.     /*2*/
  24.     LCD_DATA=0b00110000;        // ...
  25.     LCD_enable();
  26.     msDelay(1);
  27.     /*3*/
  28.     LCD_DATA=0b00110000;        // ...
  29.     LCD_enable();
  30.     msDelay(1);
  31.  
  32.     #if MODE_4_BIT
  33.    	LCD_DATA=0b00100000;    // Auf 4 Bit setzen
  34. 	LCD_enable();
  35. 	msDelay(5);
  36.     #endif
  37.  
  38.     LCD_write(0x28,0);		// Functionset (2 Zeilien)
  39.     LCD_write(0x0C,0);		// Display on
  40.     LCD_write(0x01,0);		// Display clear
  41.     msDelay(2);                 // 2ms Pause
  42.     LCD_write(0x06,0);		// Entry Mode
  43.     msDelay(1);
  44. }
  45.  
  46. /*
  47.  * Kommunikation mit dem Displaycontroller
  48.  *
  49.  * Hinweis:	Für die Datenübertragung werden aktuell
  50.  *		nur(!) die unteren vier Bit eines Ports
  51.  *		verwendet! (v.1.5.c18)
  52.  *
  53.  * Parameter	k: Tooglen zwischen Daten(k=1) und Befehlen(k=0) für das Display
  54.  */
  55.  
  56. void LCD_write(unsigned char Info, unsigned char k)
  57. {
  58.     if (k==0) 
  59. 	LCD_RS=0;
  60.     else 
  61. 	LCD_RS=1;
  62.  
  63.     LCD_RW=0;       
  64.     LCD_busy();
  65.  
  66.     #if MODE_4_BIT
  67. 	// MSB zuerst
  68. 	LCD_DATA= Info&0xF0;	// Daten auf den Bus legen
  69. 	LCD_enable();           // Enable Strobbe durchführen
  70.  
  71. 	// LSB
  72. 	LCD_DATA= (Info<<4)&0xF0;
  73. 	LCD_enable();
  74.     #endif
  75.  
  76.     #if MODE_4_BIT == 0
  77. 	LCD_DATA = Info;
  78. 	enableLCD();
  79.     #endif	
  80. }
  81.  
  82. /*
  83.  * Ausführen eines Enable Impulses
  84.  *
  85.  * Durch den Impuls auf der Enable Leitung übernimmt der LCD Controller die Daten,
  86.  * welche zu diesem Zeitpunkt auf dem Bus liegen.
  87.  */
  88.  
  89. void LCD_enable(void)
  90. {
  91.     LCD_E=1;
  92.     Delay10TCYx(2);       // Etwa 20µs warten
  93.     LCD_E=0;
  94. }
  95.  
  96. /*
  97.  * Warteschleife für ca. 1ms
  98.  *
  99.  * Hinweis:	Das Makro CLK_FREQ in der Datei KS0066_C18.h muss
  100.  *		richtig eingestellt sein, sonst werden die 
  101.  *		Wartezeiten komplett falsch berechnet!
  102.  * Parameter:	time: Anzahl der ms die pausiert werden soll (max. 255)
  103.  */
  104.  
  105. void msDelay(unsigned char time)
  106. {
  107.     unsigned int xWait = CLK_FREQ / 1000;
  108.  
  109.     while( xWait >= 10000)
  110.     {
  111. 	Delay10KTCYx(1);
  112. 	xWait -= 10000;
  113.     }
  114.  
  115.     while( xWait >= 1000)
  116.     { 
  117. 	Delay1KTCYx(1);
  118. 	xWait -= 1000;
  119.     }
  120.  
  121.     while( xWait >= 100)
  122.     {
  123. 	Delay100TCYx(1);
  124. 	xWait -= 100;
  125.     } 
  126.  
  127.     while( xWait >= 10)
  128.     {
  129. 	Delay10TCYx(1);
  130. 	xWait -= 10;
  131.     }
  132. }

Datei: KS0066_C18.h

Das Makro CLK_FREQ muss von euch mit der von euch verwendeten Frequenz beschrieben werden (in Hz)!
  1. /* *****************************************************************************
  2.  * File:        KS0066_C18.h
  3.  * Project:     --
  4.  * Author:      Nicolas Meyertöns
  5.  * Version:     1.5.c18
  6.  * Web:         www.PIC-Projekte.de
  7.  * ****************************************************************************/
  8.  
  9. #ifndef KS0066_H
  10. #define	KS0066_H
  11.  
  12. /*
  13.  * Hier müsst ihr die Anpassung, für die von euch gewählte Pinbelegung vornehmen!
  14.  * 
  15.  */
  16.  
  17. #define LCD_RS  	LATAbits.LATA2
  18. #define LCD_RW  	LATBbits.LATB4 
  19. #define LCD_E  		LATAbits.LATA1 
  20. #define LCD_Data  	LATC
  21.  
  22. /*
  23.  * Notwendige Konfigurationen
  24.  *
  25.  * Kurzbeschreibung der Parameter:
  26.  *
  27.  *	MODE_4_BIT:	Die Initialisierung ist standardmäßig auf den 
  28.  *			4 Bit Modus eingestellt. Wenn ihr aber die
  29.  *			Ansteuerung im 8 Bit Modus verwendet möchtet,
  30.  *			dann müsst ihr dieses Makro löschen.
  31.  *
  32.  *	MSB_USED:	Diese Einstellung ist nur notwendig, wenn ihr das
  33.  *			Display im 4 Bit Modus ansteuern möchtet.
  34.  *			Ihr müsst dann angeben ob ihr die Datenleitungen
  35.  *			auf den oberen oder unteren 4 Bit eines Port gelegt
  36.  *			habt. Liegen die Datenleitungen zum Beispiel so:
  37.  *	
  38.  *			->	D7 --> PORTx7
  39.  *			->	D6 --> PORTx6
  40.  *			->	D5 --> PORTx5
  41.  *			->	D4 --> PORTx4
  42.  *
  43.  * 			Dann müsst ihr das MSB_USED setzten!
  44.  */
  45.  
  46. #define MODE_4_BIT	1
  47. #define MSB_USED	1
  48.  
  49. /*
  50.  * Gebt an mit welchem Takt ihr den PIC betreibt (in Hz)
  51.  */
  52.  
  53. #define CLK_FREQ	8000000
  54.  
  55.  
  56. void Init_LCD(void);
  57. void LCD_write(unsigned char Info, unsigned char k);
  58. void LCD_enable(void);
  59. void msDelay(unsigned char time);
  60.  
  61. #endif	KS0066_H

Autoren

Nico 16:51, 19. Aug. 2011 (CEST)

Meine Werkzeuge
Namensräume

Varianten
Aktionen
Navigation
Mikrocontroller
Elektrotechnik
Projekte
Displays
Bauteile
Werkzeuge