Aktuelle Zeit: 23 Okt 2017 03:14:48


LCD_T 4bit Klasse mit Framepuffer und Timerupdate

New external libraries or developments.
Neue externe Bibliotheken oder Weiterentwicklungen.
  • Autor
  • Nachricht
Offline

de0508

  • Beiträge: 2073
  • Registriert: 02 Okt 2012 18:18:30
  • Wohnort: Hessen, Deutschland

LCD_T 4bit Klasse mit Framepuffer und Timerupdate

Beitrag13 Feb 2016 22:13:39

Hallo Forum,

ich habe für die Community auf Basis des LCD4 Interface eine LCD_T 4bit Klasse mit Framepuffer erstellt.

Hier schreibt man in einen Framepuffer mit maximaler Geschwindigkeit, so dass das eigentliche Programm nicht blockiert.

Der Framepuffer wird zyklisch, in meinem Beispiel alle 1ms (1000Hz) über Timer2, ausgelesen und genau ein Zeichen auf das angeschlossene LCD im 4 Bitmodus geschrieben.
Die Klassen-Implementierung ist so angelegt, dass alle übergebenen LCD Koordinaten überprüft werden und das LCD-Zeilenende überwacht wird.
Der Schreib-Frame-Cursor wandert immer von links nach rechts.
Am Zeilenende wird eine Zeilenumbruch durchgeführt und das nächste Zeichen in die nächste Zeile geschrieben.
Die Nutzung ist an das LCD4 Interface angelegt, das ich nebenbei noch überarbeitet habe.
Wir legen also die Abmessung und die Output Pins des LCD fest.
Code: Alles auswählen
'---------------------------------------
' LCD_T Klasse
' lavrc version 2015.r1.6 (build 8413)
'---------------------------------------
#library "Library/Lcd4.interface"
#define lcd_columns as 16
#define lcd_rows   as  2

' only correct for my atmega32 testboard
lcd4.PinDB4 = porta.3
lcd4.PinDB5 = porta.4
lcd4.PinDB6 = porta.5
lcd4.PinDB7 = porta.6
lcd4.PinEN    = porta.2
lcd4.PinRW = porta.1
lcd4.PinRS = porta.0

Danach können wir die Klasse schon initialisieren.
Code: Alles auswählen
LCD_T.Init() ' call Lcd4.Init() too

Wenn wir nun noch benutzerdefinierte Zeichen vorliegen haben, so können wir nun diese in das LCD schreiben.
Code: Alles auswählen
LCD_T.DefChar(LCD_CHAR_0,0)
LCD_T.DefChar(LCD_CHAR_1,1)
LCD_T.DefChar(LCD_CHAR_2,2)
LCD_T.DefChar(LCD_CHAR_3,3)
LCD_T.DefChar(LCD_CHAR_4,4)
LCD_T.DefChar(LCD_CHAR_5,5)
LCD_T.DefChar(LCD_CHAR_6,6)
LCD_T.DefChar(LCD_CHAR_7,7)

Natürlich sitzen die Daten der benutzerdefinierte Zeichen hinter dem Hauptprogramm, also der Main-Loop.
Code: Alles auswählen
data LCD_CHAR_0
' symbol bargraph 0
.db 0b11111,
.db 0b00000,
.db 0b00000,
.db 0b00000,
.db 0b00000,
.db 0b00000,
.db 0b00000,
.db 0b11111
enddata

data LCD_CHAR_1
' symbol bargraph 1
.db 0b11111,
.db 0b00000,
.db 0b00000,
.db 0b10000,
.db 0b10000,
.db 0b00000,
.db 0b00000,
.db 0b11111
enddata

data LCD_CHAR_2
' symbol bargraph 2
.db 0b11111,
.db 0b00000,
.db 0b00000,
.db 0b11000,
.db 0b11000,
.db 0b00000,
.db 0b00000,
.db 0b11111
enddata

data LCD_CHAR_3
' symbol bargraph 3
.db 0b11111,
.db 0b00000,
.db 0b00000,
.db 0b11100,
.db 0b11100,
.db 0b00000,
.db 0b00000,
.db 0b11111
enddata

data LCD_CHAR_4
' symbol bargraph 4
.db 0b11111,
.db 0b00000,
.db 0b00000,
.db 0b11110,
.db 0b11110,
.db 0b00000,
.db 0b00000,
.db 0b11111
enddata

data LCD_CHAR_5
' symbol bargraph 5
.db 0b11111,
.db 0b00000,
.db 0b00000,
.db 0b11111,
.db 0b11111,
.db 0b00000,
.db 0b00000,
.db 0b11111
enddata

data LCD_CHAR_6
' symbol euro
.db    0x3,0x4,0x1e,0x8,0x1e,0x8,0x7
enddata

data LCD_CHAR_7
' symbol speaker
.db    0x1,0x3,0xf,0xf,0xf,0x3,0x1
enddata

Hier noch ein kleiner Auszug der implementierten Funktionen. Alle findet man in der LCD_T Klasse.
Ich habe mich dazu entschlossen, die Y,X Positionen von 0 an zu zählen.
Somit gilt für ein 2 Zeilen x 16 Zeichen LCD: X E {0,..,15} und Y E {0,1}
X ist die Spalte (column) und Y ist Zeile (row).

LCD_T.TextDYX(y,x,<String im Flash>) Ausgabe fester Strings aus dem Flashspeicher an Position (Y,X).
Code: Alles auswählen
LCD_T.TextDYX(0,0,"lcd4 timer class")

LCD_T.TextD( <String im Flash> ) Ausgabe fester Strings aus dem Flashspeicher.
Code: Alles auswählen
LCD_T.TextD( "(c) DE0508, Uwe" )

LCD_T.TextYX(y,x,<string>) Ausgabe dynamischer Strings an Position (Y,X).
Code: Alles auswählen
dim s as string
s = "12345"
LCD_T.TextDYX(0,0,s)

LCD_T.Text( <string> ) Ausgabe dynamischer Strings.
Code: Alles auswählen
dim s as string
s = "12345"
LCD_T.TextD( s )

Natürlich kann man auch einzelne Zeichen ausgeben.
LCD_T.CharYX(y,x,<char>) Schreibt das Zeichen <char> an Position (Y,X).
Code: Alles auswählen
LCD_T.CharYX(0,0, asc("!") )

LCD_T.Char(<char>) Gibt das Zeichen <char> aus.
Code: Alles auswählen
LCD_T.Char( asc("!") )

Wir können sehr einfach nur eine LCD Zeile (row) löschen.
Code: Alles auswählen
LCD_T.ClrLine( <row> )

Oder auch das gesamte LCD löschen.
Code: Alles auswählen
LCD_T.ClrScreen()

Sehr enfach kann man auch den Frame-Cuursor auf den Anfangsposition (Home) setzen.
Code: Alles auswählen
LCD_T.Home()

Oder den Frame-Cursor setzen.
Code: Alles auswählen
LCD_T.setCursor( Y, X )

Wie wir oben schon gesehen haben verfügen alle Zeichenausgabe-Methoden .TextD, .Text und .Char auch über die Möglichkeit des direkten setzen des Frame-Cursors an Position (Y,X).
Diese sind .TextDYX, .TextYX und .CharYX

Mein angehängtes Beispielpogramm enthält noch einige deaktivierte Debugausgaben, die man einfach wieder aktivieren kann.
Wichtig das aktuelle LCD4 Interface muss installiert werden.
Das vollständige Beispielpogramm ist im Angang.
Es zeigt die Anwendung einer Uhr mit Zeit- und Datumausgabe auf dem LCD.
Der 1 Sekunden Zeitstempel wird auch durch Timer2 ausgelöst.
Code: Alles auswählen
'---------------------------------------
' file: lcd4-test.luna
' (C) de0508, Uwe
'---------------------------------------
' 2016-02-13 start
'  run on atmega32 testboard
' lavrc version 2015.r1.6 (build 8413)
'---------------------------------------
' http://www.quinapalus.com/hd44780udg.html
' https://omerk.github.io/lcdchargen/
'---------------------------------------

'---------------------------------------
' System Settings
'---------------------------------------
const F_CPU = 14745600
avr.device    = atmega32
avr.clock   = avr.F_CPU
avr.stack   = 42

'---------------------------------------
' Macros
'---------------------------------------
#define BV(n)   as (1<<(n))
#define NBV(n)   as (not BV(n))

#define USE_LCD_DEFCHAR as 0


'---------------------------------------
' Typedef
'---------------------------------------
#define char_t as byte
#define bool_t as byte

'---------------------------------------
' Konstanten
'---------------------------------------

'---------------------------------------
' LCD_T Klasse
'---------------------------------------
#library "Library/Lcd4.interface"
#define lcd_columns as 16
#define lcd_rows   as  2

' only correct for my atmega32 testboard
lcd4.PinDB4   = porta.3
lcd4.PinDB5   = porta.4
lcd4.PinDB6   = porta.5
lcd4.PinDB7   = porta.6
lcd4.PinEN   = porta.2
lcd4.PinRW   = porta.1
lcd4.PinRS   = porta.0

LCD_T.Init() ' call Lcd4.Init() too

#if USE_LCD_DEFCHAR
LCD_T.DefChar(LCD_CHAR_0,0)
LCD_T.DefChar(LCD_CHAR_1,1)
LCD_T.DefChar(LCD_CHAR_2,2)
LCD_T.DefChar(LCD_CHAR_3,3)
LCD_T.DefChar(LCD_CHAR_4,4)
LCD_T.DefChar(LCD_CHAR_5,5)
LCD_T.DefChar(LCD_CHAR_6,6)
LCD_T.DefChar(LCD_CHAR_7,7)
#endif

'---------------------------------------
' init timer2
'---------------------------------------
part TIMER2
const T2_FREQUENCY   = 1000 ' kHz == 1ms
const T2_MAX_COUNTER = 256

' TCCR0A: CS02 CS01 CS00
#define T2_PRESCALER_CS0X(a2,a1,a0)   as (((a2)<<CS22) or ((a1)<<CS21) or ((a0)<<CS20))
#define T2_PRELOAD_CALC(n)            as (word(1.0 *avr.F_CPU /(n) /T2_FREQUENCY +.5))
#define T2_PRESCALER_CMP(n)         as (T2_PRELOAD_CALC(n) <= T2_MAX_COUNTER)

' find the right timer2 prescaler
#if T2_PRESCALER_CMP(1)
const T2_PRESCALER = 1
'const T2_PRESCALER_MASK = T2_PRESCALER_CS0X(0,0,1)
const T2_PRELOAD = T2_PRELOAD_CALC(1)
#elseif T2_PRESCALER_CMP(8)
const T2_PRESCALER = 8
'const T2_PRESCALER_MASK = T2_PRESCALER_CS0X(0,1,0)
const T2_PRELOAD = T2_PRELOAD_CALC(8)
#elseif T2_PRESCALER_CMP(32)
const T2_PRESCALER = 32
'const T2_PRESCALER_MASK = T2_PRESCALER_CS0X(0,1,1)
const T2_PRELOAD = T2_PRELOAD_CALC(32)
#elseif T2_PRESCALER_CMP(64)
const T2_PRESCALER = 64
'const T2_PRESCALER_MASK = T2_PRESCALER_CS0X(1,0,0)
const T2_PRELOAD = T2_PRELOAD_CALC(64)
#elseif T2_PRESCALER_CMP(128)
const T2_PRESCALER = 128
'const T2_PRESCALER_MASK = T2_PRESCALER_CS0X(1,0,1)
const T2_PRELOAD = T2_PRELOAD_CALC(128)
#elseif T2_PRESCALER_CMP(256)
const T2_PRESCALER = 256
'const T2_PRESCALER_MASK = T2_PRESCALER_CS0X(1,1,0)
const T2_PRELOAD = T2_PRELOAD_CALC(256)
#else ' prescaler_value  = 1024
const T2_PRESCALER = 1024
'const T2_PRESCALER_MASK = T2_PRESCALER_CS0X(1,1,1)
const T2_PRELOAD = T2_PRELOAD_CALC(1024)
#endif

timer2.cmp.isr = timer2_cmp_vect
timer2.pwm.mode = 2      ' CTC with register OCR2

avr.TCNT2 = 0
avr.OCR2 = (T2_PRELOAD-1)

avr.TIFR = BV(OCF2)      ' clear timer2 cmp interrupt request
timer2.cmp.enable         ' enable timer2 cmp interrupt

timer2.clock = T2_PRESCALER
endpart

clock.Init()

'---------------------------------------
' start application
'---------------------------------------
avr.Interrupts.enable

'                   "0123456789012345"
const HELLO_TEXT1 = "lcd4 timer class"
const HELLO_TEXT2 = "(c) DE0508, Uwe "

LCD_T.TextDYX(0,0, HELLO_TEXT1)
LCD_T.TextDYX(1,0, HELLO_TEXT2)
wait 2

dim timer_event_1s as bool_t
timer_event_1s = false
dim s as string

' update display
LCD_T.ClrScreen()
LCD_T.TextYX(0,0, clock.Time( s ))
LCD_T.TextYX(1,0, clock.Date( s ))

do
 if (timer_event_1s) then
  timer_event_1s = false
  clock.Tick()
  LCD_T.TextYX(0,0, clock.Time( s ))
  LCD_T.TextYX(1,0, clock.Date( s ))
 endif
loop

'---------------------------------------
' ISR -- TIMER2
'---------------------------------------
isr timer2_cmp_vect fastauto
const T2_MAX_COUNTER_1S = (1000 * 1000 /T2_FREQUENCY)
dim counter1_s as static word

counter1_s++
if (counter1_s >= T2_MAX_COUNTER_1S) then
counter1_s = 0
timer_event_1s = true
endif

LCD_T.Callback_Task()
endisr

#if USE_LCD_DEFCHAR
data LCD_CHAR_0
' symbol bargraph 0
.db 0b11111,
.db 0b00000,
.db 0b00000,
.db 0b00000,
.db 0b00000,
.db 0b00000,
.db 0b00000,
.db 0b11111
enddata

data LCD_CHAR_1
' symbol bargraph 1
.db 0b11111,
.db 0b00000,
.db 0b00000,
.db 0b10000,
.db 0b10000,
.db 0b00000,
.db 0b00000,
.db 0b11111
enddata

data LCD_CHAR_2
' symbol bargraph 2
.db 0b11111,
.db 0b00000,
.db 0b00000,
.db 0b11000,
.db 0b11000,
.db 0b00000,
.db 0b00000,
.db 0b11111
enddata

data LCD_CHAR_3
' symbol bargraph 3
.db 0b11111,
.db 0b00000,
.db 0b00000,
.db 0b11100,
.db 0b11100,
.db 0b00000,
.db 0b00000,
.db 0b11111
enddata

data LCD_CHAR_4
' symbol bargraph 4
.db 0b11111,
.db 0b00000,
.db 0b00000,
.db 0b11110,
.db 0b11110,
.db 0b00000,
.db 0b00000,
.db 0b11111
enddata

data LCD_CHAR_5
' symbol bargraph 5
.db 0b11111,
.db 0b00000,
.db 0b00000,
.db 0b11111,
.db 0b11111,
.db 0b00000,
.db 0b00000,
.db 0b11111
enddata

data LCD_CHAR_6
' symbol euro
.db    0x3,0x4,0x1e,0x8,0x1e,0x8,0x7
enddata

data LCD_CHAR_7
' symbol speaker
.db    0x1,0x3,0xf,0xf,0xf,0x3,0x1
enddata
#endif

'---------------------------------------
' include class files
'---------------------------------------
#include "class/lcdt.class.luna"
#include "class/clock.class.luna"


Edit
* 160214 - Update ZIP-Datei
Du hast keine ausreichende Berechtigung, um die Dateianhänge dieses Beitrags anzusehen.
Grüße Uwe
Offline

de0508

  • Beiträge: 2073
  • Registriert: 02 Okt 2012 18:18:30
  • Wohnort: Hessen, Deutschland

Re: LCD_T 4bit Klasse mit Framepuffer und Timerupdate

Beitrag14 Feb 2016 12:11:16

Guten Morgen,

ich habe noch vergessen ein Interface dem ZIP-File anzuhängen - das FlashData.interface.

Es erzeugt i.a. Inline Code, spart einzeln betrachtet Flashspeicher und ist deshalb schneller.
FlashData.interface

Diese Version unterstützt nur Daten für AVR µC mit max. 64KByte Flashspeicher.
Für AVR µC ab 64KByte Flashspeicher habe ich eine eigenes Interface im Einsatz.

Hier seht ihr die Implementierten Methoden.
INLINE-METHODEN
byte = FlashData.ReadByte ( addr as dobj word, idx as stmp word )
word = FlashData.ReadWord ( addr as dobj word, idx as stmp word )
uint24 = FlashData.ReadUInt24 ( addr as dobj word, idx as stmp word )
long = FlashData.ReadLong ( addr as dobj word, idx as stmp word )

byte = FlashData.ReadByteOffset ( addr as dobj word, idx as stmp word, offset as stmp word )
word = FlashData.ReadWordOffset ( addr as dobj word, idx as stmp word, offset as stmp word )
uint24 = FlashData.ReadUInt24Offset ( addr as dobj word, idx as stmp word, offset as stmp word )
long = FlashData.ReadLongOffset ( addr as dobj word, idx as stmp word, offset as stmp word )

METHODEN
byte = FlashData.GetByte ( addr as dobj word, idx as stmp word )
word = FlashData.GetWord ( addr as dobj word, idx as stmp word )
long = FlashData.GetLong ( addr as dobj word, idx as stmp word )
uint24 = FlashData.GetUInt24 ( addr as dobj word, idx as stmp word )
FlashData.Read ( sram_ptr as sram byte, flash_ptr as dobj word, idx as stmp word )

Mit den Methoden .ReadByteOffset, .ReadWordOffset und .ReadLongOffset kann man einfach auf
Elemente einer Struktur zugreifen, die Struktur ist als Array im Flash abgelegt.
Hier ein Beispiel:
Code: Alles auswählen
struct POINT_t
 byte x
 byte y
endstruct

dim x, y as byte
' 1.tes Strukturelement POINT_t an Position 0
x = FlashData.ReadByteOffset ( DATA_ARRAY_OF_POINTS.addr,  0,  0 )
y = FlashData.ReadByteOffset ( DATA_ARRAY_OF_POINTS.addr,  0,  1 )

' 2.tes Strukturelement POINT_t an Position 1
x = FlashData.ReadByteOffset ( DATA_ARRAY_OF_POINTS.addr,  1,  0 )
y = FlashData.ReadByteOffset ( DATA_ARRAY_OF_POINTS.addr,  1,  1 )

' Main loop
do
loop

' Datenbereich
data DATA_ARRAY_OF_POINTS
 POINT_t{ 0, 0 } ' Index 0
 POINT_t{ 0, 1 } ' Index 1
 POINT_t{ 1, 0 } ' Index 2
 POINT_t{ 1, 1 } ' Index 3
enddata
Du hast keine ausreichende Berechtigung, um die Dateianhänge dieses Beitrags anzusehen.
Grüße Uwe
Offline

de0508

  • Beiträge: 2073
  • Registriert: 02 Okt 2012 18:18:30
  • Wohnort: Hessen, Deutschland

Re: LCD_T 4bit Klasse mit Framepuffer und Timerupdate

Beitrag07 Aug 2017 17:53:30

Hallo Forum,

Das FlashData.interface habe ich überarbeitet und ihr könnt es hier und über LunaShare herunterladen.
Grüße Uwe

Zurück zu Libraries / Bibliotheken

Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 2 Gäste

cron