www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik LCD mit interupts


Autor: MySystem (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
hallo,
ich weiß ich bin nicht der erste und vermutlich nicht der letzte der 
Probleme mit lcd's Displays hat.
momentan folge ich dem avr tut und bin bei dem Display angekommen ,geht 
auch soweit, nur störte mich an der lcd-routines das der µC immer 5ms 
warte und das sind bekannter maßen welten also habe ich versucht die 
pausen mit hilfe von timern und interupts zu realisieren.

Problem:
wen das Display mal an war funktioniert alles und ich kann problemloses 
die Anzeige ändern  in dem ich den Inhalt des rams ändere. Das Problem 
ist ich habe ist das das Display nur in 30% alles fälle richtig 
Initialisierung wird...

wobei ich noch zur Initialisierung die normalen Zeitschleifen des tut’s 
nutze weil wenn der µC ne halbe Sekunde braucht bis er läuft ist mir das 
noch egal(ich arbeit mit µC's seid dienstags).

hier mal der Code vom eigentlichem Programm:
.include "m8515def.inc"


.def temp1 = r16
.def temp2 = r17
.def temp3 = r18

//----------------Interupts------------------
Vector:

       rjmp Reset             ;Program Reset:1
       rjmp VECInt0           ;External IRQ 0:2
       rjmp VECInt1           ;External IRQ 1:3
       rjmp VECTmr1_Capt      ;Timer/Ctr 1 Capture Event:4
       rjmp VECTmr1_CompA     ;Timer/Ctr 1 Compare Match A:5
       rjmp VECTmr1_CompB     ;Timer/Ctr 1 Compare Match B:6
       rjmp VECTmr1_Ovf       ;Timer/Ctr 1 Overflow:7
       rjmp VECTmr0_Ovf       ;Timer/Ctr 0 Overflow:8
       rjmp VECSPI_STC        ;Serial Transfer Complete:9
       rjmp VECUART_RX        ;UART, RX Complete:10
       rjmp VECUART_UDRE      ;UART, Data Register Empty:11
       rjmp VECUART_TX        ;UART, TX Complete:12
       rjmp VECAna_Comp       ;Analog Comparator:13
  
Reset:
     rjmp Init
VECInt0:
   reti
VECInt1:
     reti
VECTmr1_Capt:
     reti
VECTmr1_CompA: 
   reti
VECTmr1_CompB:
     reti
VECTmr1_Ovf:
     reti
VECTmr0_Ovf:
     rjmp timer0_overflow
VECSPI_STC:
     reti
VECUART_RX:
     reti
VECUART_UDRE:
     reti
VECUART_TX:
     reti
VECAna_Comp:
     reti




Init:
//------------------Stack--------------------
             ldi temp1, LOW(RAMEND)      ; LOW-Byte der obersten RAM-Adresse
             out SPL, temp1
             ldi temp1, HIGH(RAMEND)     ; HIGH-Byte der obersten RAM-Adresse
             out SPH, temp1


             ldi     temp1,     0xFF            ; alle Pins am Ausgabeport auf Ausgang
             out     DDRC,     temp1
      ldi     temp1,     0xFF
      out    PORTC,    temp1
//-------------------RAM---------------------
      ldi    r30,  0x60

      ldi    temp1,   't'
      ST Z+,  temp1
      ldi    temp1,   'e'
      ST Z+,  temp1
      ldi    temp1,   's'
      ST Z+,  temp1
      ldi    temp1,   't'
      ST Z+,  temp1
      ldi    temp1,   ' '
      ST Z+,  temp1
      ldi    temp1,   't'
      ST Z+,  temp1
      ldi    temp1,   'e'
      ST Z+,  temp1
      ldi    temp1,   's'
      ST Z+,  temp1
      ldi    temp1,   't'
      ST Z+,  temp1
      
      ldi    temp1,   ' '
      ST Z+,  temp1
      ldi    temp1,   't'
      ST Z+,  temp1
      ldi    temp1,   'e'
      ST Z+,  temp1
      ldi    temp1,   's'
      ST Z+,  temp1
      ldi    temp1,   't'
      ST Z+,  temp1
      ldi    temp1,   ' '
      ST Z+,  temp1
      ldi    temp1,   't'
      ST Z+,  temp1
      ldi    temp1,   'e'
      ST Z+,  temp1
      ldi    temp1,   's'
      ST Z+,  temp1
      ldi    temp1,   't'
      ST Z+,  temp1

      ldi    temp1,   ' '
      ST Z+,  temp1
      ldi    temp1,   't'
      ST Z+,  temp1
      ldi    temp1,   'e'
      ST Z+,  temp1
      ldi    temp1,   's'
      ST Z+,  temp1
      ldi    temp1,   't'
      ST Z+,  temp1
      ldi    temp1,   ' '
      ST Z+,  temp1
      ldi    temp1,   't'
      ST Z+,  temp1
      ldi    temp1,   'e'
      ST Z+,  temp1
      ldi    temp1,   's'
      ST Z+,  temp1
      ldi    temp1,   't'
      ST Z+,  temp1
            
      ldi    temp1,   't'
      ST Z+,  temp1
      ldi    temp1,   'e'
      ST Z+,  temp1
      ldi    temp1,   's'
      ST Z+,  temp1
      ldi    temp1,   't'
      ST Z+,  temp1
      ldi    temp1,   ' '
      ST Z+,  temp1
      ldi    temp1,   't'
      ST Z+,  temp1
      ldi    temp1,   'e'
      ST Z+,  temp1
      ldi    temp1,   's'
      ST Z+,  temp1
      ldi    temp1,   't'
      ST Z+,  temp1
      ldi    temp1,   ' '
      ST Z+,  temp1
      ldi    temp1,   't'
      ST Z+,  temp1

      ldi   temp1,   0xFF  
      ST Z+,  temp1
      

//-----------------LCD INIT------------------

             rcall   lcd_init     ; Display initialisieren
             rcall    lcd_clear    ; Display löschen
      rcall    set_timer_30ms
      sei

//=================Main Programm==================
main:

             rjmp   main




//------------------Display-------------------

         
       




.include "LCD-Routinen.asm" 




meine lcd-routines:
.equ LCD_PORT = PORTD
.equ LCD_DDR  = DDRD
.equ PIN_E    = 5
.equ PIN_RS   = 4

.equ disp_ram_start = 0x60
.equ z_pointer     = 0x88


 ; sendet einen Befehl an das LCD
 
lcd_command:                                ; wie lcd_data, nur RS=0
             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
             ret
 
 ; erzeugt den Enable-Puls
lcd_enable:
             sbi   LCD_PORT,   PIN_E            ; Enable high
             nop                              ; 3 Taktzyklen warten
      nop
      nop
      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
             ldi    temp1,     $21
WGLOOP0:     ldi    temp2,     $C9
      nop
      nop
WGLOOP1:     dec    temp2
             brne   WGLOOP1
      nop
      nop
             dec    temp1
             brne   WGLOOP0
             ret                              ; wieder zurück

; Sendet den Befehl zur Löschung des Displays
lcd_clear:
           ldi   temp1, 0b00000001      ; Display löschen
           rcall lcd_command
           rcall delay5ms
           ret

 ; Initialisierung: muss ganz am Anfang des Programms aufgerufen werden
lcd_init:
           ldi   temp1, 0xFF            ; alle Pins am Ausgabeport auf Ausgang
           out   LCD_DDR, temp1
 
           ldi   temp3,0x06
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 Bot, 2 Zeilen
           rcall lcd_command
           ldi   temp1, 0b00001100      ; Display on, Cursor off
           rcall lcd_command
           ldi   temp1, 0b00000100      ; endlich fertig
           rcall lcd_command
           ret
             

//------------------Timer 30ms------------------
set_timer_30ms:
            ldi     temp1,     0b00000101      ; CS00 setzen: Teiler 1024
          out     TCCR0,     temp1
 
          ldi     temp1,     0x02          ; TOIE0: Interrupt bei Timer Overflow
          out     TIMSK,     temp1
 
       ldi    temp1,    0xFF      ;flag reset
      out    TIFR,    temp1

       ldi    temp1,     0x16        ; count start bei 1 (5ms = 211 = D3)
          out    TCNT0,     temp1      ; 10ms = 171 A6

      inc    r20
      out    PORTC,    r20

      ret

//------------------Timer 50us------------------
set_timer_50us:
      ldi     temp1,     0b00000010      ; CS00 setzen: Teiler 8
          out     TCCR0,     temp1

          ldi     temp1,     0x02          ; TOIE0: Interrupt bei Timer Overflow
          out     TIMSK,     temp1

      ldi    temp1,    0xFF      ;flag reset
      out    TIFR,    temp1 

      ldi    temp1,     0x00        ; count start bei 206 (50µ = 213 = 0xD5)
          out    TCNT0,     temp1      ; 30ms = 0x16

      ret

//----------------------Disp Home----------------------
disp_home:  
      ldi     temp1,     0b00000010  ; Display Home
      rcall  lcd_command
      
      ldi    temp1,    0xFE
      ldi    r30,     0x88    ;Z-pointer = 0x88
      ST Z,  temp1
      rjmp   disp_next

//--------------------Disp 50u Timer--------------------
disp_timer_set:
      rcall   set_timer_50us

      ldi    temp1,    0x60
      ldi    r30,     0x88    ;Z-pointer = 0x88
      ST Z,  temp1

      rjmp   disp_next

timer0_overflow:
      
      ldi    r30,    z_pointer
      LD    temp1, Z          ;0010 in temp1 laden

      cpi   temp1,     0xFF
      BREQ    disp_home

      cpi   temp1,     0xFE
      BREQ    disp_timer_set



//--------------------Schreiben-------------------------
disp_schreiben:
      ldi   r30,    0x88
      LD     r30,     Z
      LD     temp1,     Z+
      
        
             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   set_timer_50us

      mov    temp1,     r30        
      ldi   r30,    0x88
      ST Z,   temp1                  
          
      cpi     temp1,     0x88
      brne  disp_next
            
      ldi    r30,    0x88
      ldi    temp1,    0xFF
      ST Z,   temp1
      
      rcall   set_timer_30ms
                    
disp_next:

      reti



ich benutze ein AtMega8515 auf einem STK500 und einer takt Frequenz von 
1MHz, reiset delay = 64ms und einem Standart 2x20 Display.

ich hoffe das ich den Fehler nicht sehe weil er einfach zu 
offensichtlich ist.

mfg MySystem

Autor: jack (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Au weia, so was sollte man eigentlich als Anhang posten.

Ich habe mir das Programm nicht durchgelesen, nur so viel dazu:

Schreib Deinen Text, den Du ausgeben willst ins RAM.
In einer Interruptroutine (alle 100µs) gibst Du dann jeweils ein Zeichen
an das LCD aus (das gilt nicht für die Initialisierung).

Autor: holger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>In einer Interruptroutine (alle 100µs)

Alle 1ms reicht völlig.

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ MySystem (Gast)

>ich weiß ich bin nicht der erste und vermutlich nicht der letzte der
>Probleme mit lcd's Displays hat.

Und vor allem mit der Rechtschreibung.

http://www.apostroph.de/

Und mit der Netiquette.

Autor: spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

Als Allererstes solltest du folgendes machen: Im AVR-Studio unter 
Tools->Options->Editor folgendes einstellen:
   'Replace Tabs with Space' und Tabwidth=1.
Und wenn du es ganz gut machen willst schaltest du unter 'Edit' mit 
'Show Whitespace' die nicht sichtbaren Zeichen ein und schmeisst die 
Tabulatoren raus. Dann kann man deinen Quelltext in jedem Editor ohne 
Augenschmerzen betrachten. Und am besten, beim Programmieren die Finger 
von der Tabulatortaste lassen.

>Das Problem ist ich habe ist das das Display nur in 30% alles fälle >richtig 
Initialisierung wird...

Wenn dem so ist, warum schreibst du erst so ein Programm, um das zu 
merken.

So etwas macht man erst, wenn die grundlegenden Routinen sicher 
funktionieren.

Interruptroutinen so lang wie nötig, aber so kurz wie möglich machen.
Deine Aussgaberoutine gehört in die Main. In der IR nur ein Flag setzen
das in der Main abgefragt wird. Wenn gesetzt Routine ausführen,Flag 
zurücksetzen und weiter warten.

....

MfG Spess

Autor: Thomas P. (topla)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
MySystem wrote:

> nur störte mich an der lcd-routines das der µC immer 5ms
> warte und das sind bekannter maßen welten also habe ich versucht die
> pausen mit hilfe von timern und interupts zu realisieren.

Ich habe mir das mit den Zeitschleifen gleich am Anfang wieder abgewöhnt 
und frage bis auf die Initialisierung immer das Busy-Bit ab; ist auch 
nicht schwer und die schnellstmögliche Ausgabe auf das LCD ist so auch 
gewährleistet.

Gruß
Thomas

Autor: spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

>Ich habe mir das mit den Zeitschleifen gleich am Anfang wieder abgewöhnt
>und frage bis auf die Initialisierung immer das Busy-Bit ab;

Du sprichst mir aus der Seele. Aber es gibt noch eine starke Fraktion, 
die noch nicht gemerkt haben, das die Zeit der HD44780 100%-kompatiblen 
Displays vorbei sind. Trotzdem wird Anfängern immer noch 
Minimalvarianten angeraten. Leider noch kein Fall für den Staatsanwalt.

MfG Spess

Autor: Michael Appelt (micha54)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich spendiere 80 Bytes als Puffer und aktualisiere zyklisch im 5ms 
Timer-Interrupt.
Die Ausgabe selbst ist ja nur 1-2us.
Einen Reset im laufenden Betrieb brauch ich nicht, bzw. lasse ich den 
mit Warteschleifen in der init-Function ablaufen.

Gruss,
Michael

Autor: spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

>lasse ich den mit Warteschleifen in der init-Function ablaufen.

Und wann willst du ein richtiges Programm schreiben?

MfG Spess

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
spess53 wrote:
> Du sprichst mir aus der Seele. Aber es gibt noch eine starke Fraktion,
> die noch nicht gemerkt haben, das die Zeit der HD44780 100%-kompatiblen
> Displays vorbei sind. Trotzdem wird Anfängern immer noch
> Minimalvarianten angeraten. Leider noch kein Fall für den Staatsanwalt.

Interessant, mit welcher Verbissenheit manche nur ihre eigene Lösung als 
die einzig Wahre akzeptieren und alle anderen ohne Begründung als 
grundsätzlich schlecht abkanzeln.


Ich benutze die Minimallösung und habe keinerlei Probleme damit.
Die CPU-Auslastung ist trotz Wartezeitmethode weit unter 1%, also wozu 
unnütz nen Portpin verschwenden?

Manchmal benutze ich auch die Interruptmethode (ein Zeichen je 1ms 
ausgeben), da wäre das Busybit eh völlig unnütz.
Diese Methode ist vorteilhaft, wenn man viel Ausgaben in 
unterschiedlichen Bereichen des LCD anzeigen will. Man kann gleich 
direkt in den Bildspeicher im SRAM schreiben, ohne erst umständlich 
positionieren zu müssen.

Ich habe früher auch LCDs mit 3 Pins und 74HC164 im 8Bit-Modus 
angesteuert. Jetzt benutze ich aber ausschließlich die Ansteuerung im 
4Bit-Modus mit 6 Pins.

In der Initialisierung benutze ich selbstverständlich die Delay-Macros, 
da ja nach dem Poweron nicht sofort zeitkritische Tasks auszuführen 
sind. Das Delay stört also in keinster Weise.

Ich benutze auch nicht die Clear-Funktion, sondern überschreibe immer 
den alten Text. Die Clear-Funktion hat neben der langen Wartezeit noch 
den Nachteil, daß ein deutliches Flackern zu sehen ist.


Peter

Autor: juppi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Und vor allem mit der Rechtschreibung.

Das war nicht erforderlich

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.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

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