mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik KS0066U oder Ähnliche --- LCD Treiber


Autor: Claudio H. (hedie)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo

An all jene die gerne ein LCD mit einem KS0066U Controller ansteuern 
möchten jedoch das Tutorial nicht geht, Ich hab die Lösung :D

Im anhang befindet sich eine LCD Routine für den KS0066U die Garantiert 
Funktioniert!!!!

Viel spass

bei fragen, bitte direktes Mail an claudio.hediger@gmail.com

: Verschoben durch Moderator
Autor: Claudio H. (hedie)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Sorry Anhang vergessen :D

Autor: Turbogen (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Kann mir jemand erklären wie die Variable "DelayCount1" deklariert 
werden soll? DANKE

Autor: Paul (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Leute,

kann es sein, dass das überhaupt nicht funktionieren kann!?
Da fehlen vorneweg mal die 30ms, die der KS060 sich nach dem Power up 
gönnt!?

Hat den code jmd zum laufen gebracht?

Viele Grüße
Paul

Autor: Smoke (Gast)
Datum:

Bewertung
-2 lesenswert
nicht lesenswert
Hallo,

könnte mir woll jemand den oben aufgeführten Assembler code in C 
umschreiben? das Wäre echt super.

Autor: Ralf J. (cosmicos)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo zusammen,

der Beitrag ist zwar schon älter aber aus dem Assembler-Tutorial hier im 
Board wird noch immer auf ihn verwiesen, daher aktualisiere ich mal die 
Informationen.

Hintergrund: Ich arbeite mich gerade durch das Tutorial und scheiterte 
an der Inbetriebnahme eines Bona MC2004-01 4x20 Displays.

Es handelt sich um dieses Display (ich habe beide): 
http://www.arduino-projekte.de/index.php?n=9

Mit dem Code aus dem Tutorial funktioniere das Ganze jedoch nicht und so 
stieß ich auf diesen Thread.

Der Code von Adam Swann funktioniert tatsächlich. Es gelang mir damit 
auf Anhieb, die Displays zu betreiben!

Der Themenersteller hat jedoch nicht den kompletten Code gepostet, das 
sei hiermit nachgeholt:

Hauptprogramm:
; ******************************************************************
;    L C D    D I S P L A Y    D E M O
; ******************************************************************
;
;   Provides the entry point for a simple "Hello World" impelmentation
;   using my LCD routines.
;
;   Author:   Adam Swann 
;   Homepage: http://www.velocity2.com/~adam/
;
;   http://www.adamswann.com/projects/avr-lcd/
;
;   See LCD.asm for more information.
;
; ******************************************************************

  .nolist
  .include "m8def.inc"
;  .include "m48def.inc"
  .list

  .cseg



.def   Temp      = r16
.def   Temp2     = r17

; Define generic port names (change the 'A' to whatever you're using)
.equ  LCD_PORT  = PORTD
.equ  LCD_DDR    = DDRD
.equ  LCD_PIN    = PIND

; Define the pin numbers
.equ  LCD_E    = 1
.equ  LCD_RW    = 2
.equ  LCD_RS    = 3

.def  DelayTime = r20
.equ  DelayCount1 = 128


    .org  0
    rjmp  RESET

RESET:  ldi     Temp, low(RAMEND)
      out     SPL, Temp
      ldi     Temp, high(RAMEND)
      out     SPH, temp    ; Initialize Stackpointer

    ldi     Temp, 0x00
    out     LCD_PORT, Temp     ; Clear the outputs

    ldi     Temp, 0xFF
    out     LCD_DDR, Temp     ; Set the direction to output

    ldi     DelayTime, 255    ; Set the default delay length
            ; (see my delay.asm)

    rcall  LCD_Init

    rcall   DELAY

    ldi     r30, low(strInit1*2)
    ldi     r31, high(strInit1*2)
    ldi     Temp2,  20
    rcall  LCD_PrintPM

    ; *** Send the cursor to beginning of second line
    ldi     Temp, 0b11000000
    rcall   LCD_SendCmd

    ldi     r30, low(strInit2*2)
    ldi     r31, high(strInit2*2)
    ldi     Temp2,  20
    rcall  LCD_PrintPM


    rcall   DELAY



FOREVER:  rjmp   FOREVER

strInit1:  .db  "Hello World!        "
strInit2:  .db  "It worked!!!        "

.include "lcd-routines.asm"


LCD-Routinen:
; ******************************************************************
;    L C D    D I S P L A Y    R O U T I N E S
; ******************************************************************
;
;   Interfaces the AVR '8515 microcontroller with LCDs controlled
;   by the Samsung KS0066U (and similiar) LCD driver.
;
;   Author:   Adam Swann 
;   Homepage: http://www.velocity2.com/~adam/
;
;   The code below is fairly straightforward and well-documented.
;   See my Web site or e-mail me if you need further instructions.
;
;   I used an 8515 at 4 MHz.  My LCD is Jameco Part #171715.
;
;  Addendum: The Code is also tested on AtMega8 and AtMega48
;  (by cosmicos at gmx.net)
;
;   I wired the LCD display as follows (onto Port D)
;     AVR   LCD
;      0 --> no connection
;      1 --> Enable on LCD
;      2 --> R/W on LCD
;      3 --> RS on LCD
;      4 --> Data4
;      5 --> Data5
;      6 --> Data6
;      7 --> Data7
;
;   References: (URLs may be wrapped)
;    o KS0066U Datasheet 
;
; ******************************************************************

; *** LCD_Init: Routine to initialize the LCD.
LCD_Init:  push  Temp

    ldi  DelayTime, 255

    ; Put the LCD in 8-bit mode.  Even though we want the display to
    ; operate in 4-bit mode, the only way to guarantee that our commands
    ; are aligned properly is to initialize in 8-bit.  (The user might have
    ; hit reset between nibbles of a dual 4-bit cycle.)
    ldi  Temp, 0b00110000
    out  LCD_PORT, Temp
    rcall  LCD_PulseE

    rcall  DELAY
    rcall  DELAY

    ; Now it's safe to go into 4-bit mode.
    ldi  Temp, 0b00100000
    out  LCD_PORT, Temp
    rcall  LCD_PulseE

    rcall   DELAY
    rcall  DELAY

    ; *** Send the 'FUNCTION SET' command
    ;       +------ Data:  0 = 4-bit; 1 = 8-bit
    ;       |+----- Lines: 0 = 1; 1 = 2
    ;       ||+---- Font:  0 = 5x8; 1 = 5x11
    ldi  Temp, 0b00101100
    rcall   LCD_SendCmd

    ; *** Send the 'CURSOR/DISPLAY SHIFT' command
    ;        +----- S/C:  0 = cursor; 1 = display
    ;        |+---- R/L:  0 = left; 1 = right
    ldi  Temp, 0b00010100
    rcall   LCD_SendCmd

    ; *** Send the 'DISPLAY ON/OFF' command
    ;         +---- Display: 0 = off; 1 = on
    ;         |+--- Cursor: 0 = off; 1 = on
    ;         ||+-- Blink: 0 = off; 1 = on
    ldi  Temp, 0b00001111
    rcall   LCD_SendCmd

    ; *** Send the 'ENTRY MODE' command
    ;          +--- Direction: 0 = left; 1 = right
    ;          |+-- Shift Dislay: 0 = off; 1 = on
    ldi  Temp, 0b00000110
    rcall   LCD_SendCmd

    rcall   LCD_Clear

    pop   Temp
    ret

; *** LCD_PrintMem: Prints from memory.
;       Put the starting memory location in Z (r31:r30)
;       Put the number of characters to print in Temp2
;  After execution, Z is at the character AFTER the last to be printed
;                   and Temp2 is zero.
;       This function will not wrap if you the string is bigger than the LCD.

LCD_PrintMem:  push  Temp

   LCD_MemRead: ld  Temp, Z+
    rcall  LCD_SendChar
    dec  Temp2
    brne  LCD_MemRead

    pop  Temp
    ret

; *** LCD_PrintPM: Prints from program memory
LCD_PrintPM:  push  r0
    push  Temp

    LCD_PMRead: lpm
        mov  Temp, r0
    rcall  LCD_SendChar
    adiw  r30, 1
    dec  Temp2
    brne  LCD_PMRead

    pop  Temp
    pop  r0
    ret



; *** LCD_Clear: Clears the display and sends the cursor home.

LCD_Clear:  push   Temp

    ; *** Clear the display
    ldi  Temp, 0b00000001
    rcall   LCD_SendCmd

    ; *** Send the cursor home
    ldi  Temp, 0b00000010
    rcall   LCD_SendCmd

    pop  Temp
    ret

; *** LCD_SendCmd: Routine to write a command to the instruction register.
;       The value to be written should be stored in Temp.
;       The value is sent 4 bits at a time.

LCD_SendCmd:  push   Temp
    push   Temp2

    rcall  LCD_WaitBusy

    mov   Temp2, Temp    ; Make a backup copy
    andi   Temp2, 0b11110000  ; Only use the upper nibble
    out  LCD_PORT, Temp2    ; Send it
    rcall   LCD_PulseE    ; Pulse the enable

    swap  Temp      ; Swap upper/lower nibble
    andi   Temp, 0b11110000  ; Only use the upper nibble
    out  LCD_PORT, Temp    ; Send it
    rcall   LCD_PulseE    ; Pulse the enable

    pop   Temp2
    pop   Temp
    ret
; *** LCD_SendChar: Routine to write a character to the data register.
;       The value to be written should be stored in Temp.
;       The value is sent 4 bits at a time.

LCD_SendChar:  push   Temp
    push   Temp2

    mov   Temp2, Temp    ; Make a backup copy
    rcall  LCD_WaitBusy
    mov   Temp, Temp2    ; Make a backup copy

    andi   Temp2, 0b11110000  ; Only use the upper nibble
    ori  Temp2,  0b00001000
    out  LCD_PORT, Temp2    ; Send it
    rcall   LCD_PulseE    ; Pulse the enable

    swap  Temp      ; Swap upper/lower nibble
    andi   Temp,  0b11110000  ; Only use the upper nibble
    ori  Temp,  0b00001000
    out  LCD_PORT, Temp    ; Send it
    rcall   LCD_PulseE    ; Pulse the enable

    pop   Temp2
    pop   Temp
    ret

; *** LCD_WaitBusy: Wait for the busy flag to go low.
;       Waits for the busy flag to go low.  Since we're in 4-bit mode,
;       the register has to be read twice (for a total of 8 bits).  The
;       second read is never used.
;       If you need more code space, this function could be replaced with
;       a simple delay.

LCD_WaitBusy:  push   Temp

    ldi  Temp, 0b00001111  ; Disable data bit outputs
    out  LCD_DDR, Temp

    ldi  Temp, 0x00    ; Clear all outputs
    out  LCD_PORT, Temp

LCDWaitLoop:  ldi  Temp, 0b00000100  ; Enable only read bit
    out  LCD_PORT, Temp
    sbi  LCD_PORT, LCD_E    ; Raise the Enable signal.
    nop
    nop
    in  Temp, LCD_PIN    ; Read the current values
    cbi  LCD_PORT, LCD_E    ; Disable the enable signal.
    rcall   LCD_PulseE    ; Pulse the enable (the second nibble is discarded)
    sbrc  Temp, 7      ; Check busy flag
    rjmp  LCDWaitLoop

    ldi  Temp, 0b11111111  ; Enable all outputs
    out  LCD_DDR, Temp

    pop  Temp
    ret

LCD_PulseE:  sbi  LCD_PORT, LCD_E
    nop
    nop
    cbi  LCD_PORT, LCD_E
    ret

; *** Provide millisecond delay (DelayTicks specifies number of ms)
DELAY:  push DelayTime
  push r25

  ldi  r25, DelayCount1

DELAY1:  dec r25
  brne DELAY1
  dec DelayTime
  brne DELAY1

  pop r25
  pop DelayTime
  ret

Der Code funktioniert nicht nur für 8515, sondern ebenfalls problemlos 
mit dem AtMega8 bzw. AtMega48. Getestet bei 4Mhz und 8Mhz.

Ich habe den Code aus einem Thread bei AVRFreaks: 
http://www.avrfreaks.net/forum/attiny2313-lcd-hd44...

Der Code ist dort allerdings nicht unumstritten.

Für mich ist er dennoch eine große Erleichterung, da er auch mit meiner 
Hardware funktioniert (im Gegensatz zum Code aus dem Tutorial). So macht 
mir das weitere Lernen im Tutorial einfach mehr Spaß, da ich die 
Resultate auch auf dem Display ausgeben kann und so ein besseres 
Feedback habe :-)

Grüße
Ralf

: Bearbeitet durch User
Autor: Ralf J. (cosmicos)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hier noch ein Foto:

Autor: Ralf J. (cosmicos)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Die Kritik bei AVRFreaks bezog sich übrigens auf eine nicht 
datenblattkonforme Initialisierungssequenz. Die Initialisierung muss 
insgesamt 3x durchlaufen werden. Dies ist im Tutorial-Code ebenso der 
Fall.

Ich habe das nun analog zum Tutorial eingebaut und der Code läuft damit 
besser. Zuvor zerhackte ein Reset die Displayausgabe, es musste immer 
spannungsfrei gemacht werden und funktionierte erst beim erneuten 
Einschalten wieder.

Mit der dreifachen Init-Sequenz klappt nun auch der Reset...
    ; Put the LCD in 8-bit mode.  Even though we want the display to
    ; operate in 4-bit mode, the only way to guarantee that our commands
    ; are aligned properly is to initialize in 8-bit.  (The user might have
    ; hit reset between nibbles of a dual 4-bit cycle.)
    ldi  Temp, 0b00110000
    out  LCD_PORT, Temp
    rcall  LCD_PulseE  ; x1
    rcall  DELAY
    rcall  LCD_PulseE  ; x2
    rcall  DELAY
    ; Now it's safe to go into 4-bit mode.
    ldi  Temp, 0b00100000
    out  LCD_PORT, Temp
    rcall  LCD_PulseE  ; x3
    rcall  DELAY

Autor: spess53 (Gast)
Datum:

Bewertung
-1 lesenswert
nicht lesenswert
Hi

>Mit der dreifachen Init-Sequenz klappt nun auch der Reset...

Da fehlt aber in deinem Programm etwas.

MfG Spess

Autor: Ralf J. (cosmicos)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
spess53 schrieb:

> Da fehlt aber in deinem Programm etwas.

Wie gesagt: Ich bin noch Anfänger, arbeite gerade das Tutorial durch. 
Mit solch nebulösen Andeutungen kann ich nichts anfangen.

Helfen würde hingegen wenn du konkret benennen könntest was ich anders 
oder besser machen könnte.

Die Veränderung, die ich an Adam Swanns Code vorgenommen habe, habe ich 
analog zur Kritik auf AVR-Freaks und analog zum Code des Tutorials 
vorgenommen. In meinen Anwendungsfall mit Erfolg bzw. mit einer 
spürbaren Verbesserung...

Ich lerne gerne weiter dazu :)

Danke vorab und Gruß
Ralf

Autor: spess53 (Gast)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
HI

>Wie gesagt: Ich bin noch Anfänger, arbeite gerade das Tutorial durch.
>Mit solch nebulösen Andeutungen kann ich nichts anfangen.


Dann vergleiche doch mal dein Original (02.05.2017 11:29)
    ldi  Temp, 0b00110000
    out  LCD_PORT, Temp
    rcall  LCD_PulseE

    rcall  DELAY
    rcall  DELAY

mit deinem Auszug (02.05.2017 12:52)
    ldi  Temp, 0b00110000
    out  LCD_PORT, Temp
    rcall  LCD_PulseE  ; x1
    rcall  DELAY
    rcall  LCD_PulseE  ; x2
    rcall  DELAY

Was ich in deinem Programm allerdings vermisse ist die Verzögerung nach 
dem Einschalten des Displays.

Datenblatt vom KS0066:

Wait for more than 30 ms
after Vdd rises to 4.5 v

MfG Spess

Autor: Ralf J. (cosmicos)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
spess53 schrieb:

>
> Dann vergleiche doch mal dein Original (02.05.2017 11:29)
>
> mit deinem Auszug (02.05.2017 12:52)

Du meinst die doppelten Delays?? Klappt bei mir sowohl als auch...
Ich schaue mir das aber noch einmal genauer an. Ich möchte die Delays 
gerne unabhängig von der Taktfrequenz der MCU machen.

>
> Was ich in deinem Programm allerdings vermisse ist die Verzögerung nach
> dem Einschalten des Displays.

Wie gesagt: Es ist nicht "mein" Programm. Der Code stammt von Adam 
Swann...

>
> Datenblatt vom KS0066:
>
> Wait for more than 30 ms
> after Vdd rises to 4.5 v
>

Stimmt! Ich versuche mal, das einzubauen.
Gute Übung... :-)

Danke für die konkreten Hinweise!
Gruß
Ralf

Autor: spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

>Du meinst die doppelten Delays?? Klappt bei mir sowohl als auch...

Unter welchen Umständen getestet? Also auch z.B. Start aus dem 
stromlosen Zustand.

MfG Spess

Autor: Ralf J. (cosmicos)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
So, ich habe nun analog zum Tutorial-Code die Delays an die Taktfrequenz 
gekoppelt und außerdem ein 30ms Delay zu Beginn eingebaut...

Es gibt wieder eine spürbare Verbesserung in der Funktion. Bislang 
führte ein Reset zu einer deutlich wahrnehmbaren Veränderung des 
Displays (Störungen etc.) bevor sich der Inhalt wieder aufbaute.

Nun gibt es keine Störungen mehr. Ein Reset bewirkt einen sauberen 
Neuaufbau des Displayinhaltes!

Des Weiteren habe ich die Ansteuerung der 4 Displayzeilen etwas 
vereinfacht.

Hier der Code...

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.