Zelf ontworpen karakters op het HD44780 display

Karakters van displays kunnen opgebouwd zijn uit 5x8 of uit 5x10 puntjes (= dots) zie hieronder de A, waar het in dit voorbeeld een 5x8 puntjes display betreft.
Deze verschijnt op het display met PRINT 65 (de ASCII code van hoofdletter A) of natuurlijk gewoon met PRINT "A".

   of  

De eerste 64 geheugenadressen (= geheugenplaatsen) (adressen 64 ... 127) van het CGRAM* van het HD44780 display zijn vrij om 8 eigen ontworpen karakters in op te slaan (van 8 bytes per karakter, dus 8x8=64 adressen).
Je kunt bijvoorbeeld een Smiley () ontwerpen en dat op het display laten zien.
We gaan nu eerst twee Smileys ontwerpen:

*) CGRAM = Character Generator RAM


Smiley lacht

Smiley boos

Als je goed kijkt is de Smiley ook in de binaire notatie rechts naast de Smiley te herkennen.
De zwarte puntjes (dots) zijn geactiveerd, dus 1, de overige 0.
De binaire notatie reken je om naar hexadecimale of decimale notatie.
Er zit hiervoor in de PIC Basic editor een handige rekenmachine.
In de tabel rechts naast de binaire notatie staat de hexadecimale notatie, te herkennen aan het dollarteken ($) dat voor de cijfers staat, en tussen haakjes de decimale notatie.



De ingebouwde rekenmachine.
Klik View > Plugin > Programs > Calculator.

Meer info over de ingebouwde wetenschappelijke rekenmachine (= calculator).


Ergens bovenin je programma zet je de volgende regel:
PRINT $FE, $40, $00, $0A, $0A, $00, $11, $0E, $00, $00
Hierdoor wordt de ontworpen lachende Smiley naar de eerste 8 vrij programmeerbare ruimte van het display geschreven, het wordt dus nog niet op het display afgebeeld.
Om dit teken op het display te krijgen schrijf je in het hoofdprogramma PRINT 0, want we hebben de Smiley in het eerste vrije geheugen van het display gezet (0 is de eerste, 1 de tweede ... 7 is de achtste vrij programmeerbare ruimte).
Bovenstaande voorbeeldregel staat in de hexadecimale notatie.
Je kunt het natuurlijk ook decimaal of binair invoeren, maar hexadecimaal is overzichtelijker.
PRINT 254, 64, 0, 10, 10, 0, 17, 14, 0, 0 geeft dezelfde Smiley, alleen geschreven in decimale notatie.
Ook mag het binair, maar voor PIC Basic IDE Lite is dit af te raden omdat je dan snel aan je limiet van 50 programmaregels zit, tenzij je de underscore gebruikt.

DEVICE 16F628A                ;Gebruik een 16F628A type
CONFIG INTRC_OSC_NOCLKOUT, WDT_OFF, PWRTE_ON, LVP_OFF, MCLRE_OFF

CLEAR                         ;Wis alle RAM geheugen
DELAYMS 500                   ;LCD stabilisering 

PRINT $FE, $40                               ;Schrijf naar HD44780 chip, vanaf eerste adres 
PRINT $00, $0A, $0A, $00, $11, $0E, $00, $00 ;Smiley lacht (oproepen met PRINT 0)


;Hoofdprogramma
CLS                           ;Scherm wissen
PRINT 0                       ;Zet eerste karakter op display (= CHR(0) )

END                           ;Einde programma

Bovenstaand programma stuurt eerst $FE naar het display, waardoor de HD44780 chip weet dat de aankomende codes van één of meer vrij programmeerbare karakters zijn.
De code die daarop volgt is het startadres vanwaar het eerste byte van het karakter moet komen, voor het eerste karakter is dat $40.
Vervolgens komen de 8 bytes $00, $0A, $0A, $00, $11, $0E, $00 en $00 van het karakter zelf.
Ga je daarna nog meer bytes verzenden dan zijn die voor het volgend karakter, zie het voorbeeld hieronder:

DEVICE 16F628A                ;Gebruik een 16F628A type
CONFIG INTRC_OSC_NOCLKOUT, WDT_OFF, PWRTE_ON, LVP_OFF, MCLRE_OFF

CLEAR                         ;Wis alle RAM geheugen
DELAYMS 500                   ;LCD stabilisering 

PRINT $FE, $40                               ;Schrijf naar HD44780 chip, vanaf eerste adres 
PRINT $00, $0A, $0A, $00, $11, $0E, $00, $00 ;Smiley lacht (oproepen met PRINT 0)
PRINT $00, $0A, $0A, $00, $0E, $11, $00, $00 ;Smiley boos  (oproepen met PRINT 1)


;Hoofdprogramma
CLS                           ;Scherm wissen
PRINT 0                       ;Zet eerste karakter op display (= CHR(0) )
PRINT AT 2, 4, 1              ;Zet op regel 2, positie 4, tweede karakter er neer (= CHR(1) ) 

END                           ;Einde programma

Met PRINT $FE, $40, $00, $0A, enz. plaats je de bytes van je ontworpen karakter in de HD44780 chip.
Om het ontworpen karakter daadwerkelijk op het display te krijgen schrijf je PRINT 0 (...7) op de plaats waar je het hebben wilt.

DEVICE 16F628A                ;Gebruik een 16F628A type
CONFIG INTRC_OSC_NOCLKOUT, WDT_OFF, PWRTE_ON, LVP_OFF, MCLRE_OFF

SYMBOL SmileyLacht = 0        ;De naam 'SmileyLacht' is hetzelfde als een 0
SYMBOL SmileyBoos  = 1        ;De naam 'SmileyBoos'  is hetzelfde als een 1 

CLEAR                         ;Wis alle RAM geheugen
DELAYMS 500                   ;LCD stabilisering 

PRINT $FE, $40                               ;Schrijf naar HD44780 chip, vanaf eerste adres 
PRINT $00, $0A, $0A, $00, $11, $0E, $00, $00 ;Smiley lacht (oproepen met PRINT 0)
PRINT $00, $0A, $0A, $00, $0E, $11, $00, $00 ;Smiley boos  (oproepen met PRINT 1)


;Hoofdprogramma
CLS                           ;Scherm wissen
PRINT SmileyLacht             ;Zet eerste karakter op display (= CHR(0) )
PRINT AT 2, 4, SmileyBoos     ;Zet op regel 2, positie 4, tweede karakter er neer (= CHR(1) ) 

END                           ;Einde programma

Bovenstaande programma is precies hetzelfde als het programma daarvoor, alleen hebben we met SYMBOL de 'SmileyLacht' de waarde 0 gegeven en 'SmileyBoos' de waarde 1.
Hierdoor is het programma veel overzichtelijker, terwijl dit geen extra geheugen van de PIC kost.
Als je namelijk gaat compileren, dan is het eerste wat de compiler doet, alle namen van de constanten, vervangen door de waarden die je met SYMBOL aan die namen hebt gegeven.
Dus eerst wordt PRINT SmileyLacht, omgezet naar PRINT 0, want SmileyLacht is hetzelfde als de waarde 0.

Wat nu als je bijvoorbeeld alleen het vierde karakter (= PRINT 3) wilt veranderen?
Het eerste karakter (PRINT 0) begint zoals gezegd op adres 64, hexadecimaal is dat $40.
In onderstaand tabel staan de start adressen van de 8 vrij programmeerbare karakters.

PRINT nr:
Startadres:
PRINT 0
$40
PRINT 1
$48
PRINT 2
$50
PRINT 3
$58
PRINT 4
$60
PRINT 5
$68
PRINT 6
$70
PRINT 7
$78

 

DEVICE 16F628A                ;Gebruik een 16F628A type
CONFIG INTRC_OSC_NOCLKOUT, WDT_OFF, PWRTE_ON, LVP_OFF, MCLRE_OFF

DIM Snelheid AS BYTE          ;Deze geeft de snelheid aan
DIM Hoger    AS BIT           ;Dit bit houdt bij of er omhoog of omlaag geteld wordt

CLEAR                         ;Wis alle RAM geheugen
DELAYMS 500                   ;LCD stabilisering 

PRINT $FE, $40                               ;Schrijf naar HD44780 chip, vanaf eerste adres
PRINT $00, $0A, $0A, $00, $11, $0E, $00, $00 ;Smiley lacht (oproepen met PRINT 0)
PRINT $00, $0A, $0A, $00, $0E, $11, $00, $00 ;Smiley boos  (oproepen met PRINT 1)
SYMBOL SmileyLacht = 0
SYMBOL SmileyBoos  = 1


;Hoofdprogramma
Snelheid = 50                 ;Startwaarde van Teller
CLS                           ;Scherm wissen

WHILE 1 = 1                   ;Oneindige lus
  PRINT AT 1, 1, "Snelheid: ", DEC Snelheid, "km/u" ;Zet snelheid vooraan op regel 1
  CURSOR 2, 11                ;Cursor op regel 2, positie 11 (onder snelheid) klaar zetten

  IF Snelheid > 50 THEN       ;Als 'Snelheid' boven de 50 komt dan...
    PRINT SmileyBoos          ;...Smiley boos
  ELSE                        ;anders...
    PRINT SmileyLacht         ;...Smiley lacht
  ENDIF

  DELAYMS 500                 ;Tel snelheid

  IF Snelheid < 46 THEN Hoger = 1 ;Als 'Snelheid' kleiner is dan 46, dan weer omhoog tellen 
  IF Snelheid > 54 THEN Hoger = 0 ;Als 'Snelheid' groter  is dan 54, dan weer omlaag tellen

  IF Hoger = 1 THEN           ;Als hoger = TRUE dan...
    INC Snelheid              ;...omhoog tellen
  ELSE                        ;anders...
    DEC Snelheid              ;...omlaag tellen
  ENDIF
WEND                          ;Terug naar WHILE

END

De SYMBOL heb ik hier wat lager in het programma dan normaal omdat de 2 SYMBOL's bij de 3 PRINT regels horen.
Je mag die 2 regels natuurlijk ook gewoon bovenaan neerzetten, zoals normaal.


Stel je zo'n bord voor in de bebouwde kom.
Als je sneller rijdt dan 50km/u dan wordt de Smiley boos en anders lacht de Smiley.
Bovenstaand programma pendelt automatisch heen en weer tussen 45 en 55.

Om de Smiley onder PRINT 3 te brengen schrijf je:
PRINT $FE, $58, $00, $0A, $0A, $00, $11, $0E, $00, $00.
De eerste waarde is $FE (= adres 254) en geeft aan de HD44780 chip door dat de volgende codes naar zijn display RAM geheugen moeten worden geschreven.
De tweede waarde bevat het startadres, vanaf waar er geschreven moet worden.
Aangezien we de Smiley onder PRINT 3 willen brengen, moeten we $58 opgeven.
Daarna de 8 bytes van het getekende karakter.

Voor de duidelijkheid: de getekende karakters worden met PRINT $FE naar het geheugen van de HD44780 chip geschreven, niet naar de PIC.
Als dit alles wat te ingewikkeld is, sla je dit gedeelte maar zolang over en oefen je eerst met gewone tekst op het display.


Een andere mogelijkheid is om dit Windows programmaatje te downloaden en te installeren.
Met dit programma kun je eenvoudig eerst het karakter tekenen.
Door met de muis op de vakjes te klikken kun je de dots aan/uit schakelen.
Daarna selecteer je 1 van de 8 CHR vakjes, onder welk nummer dit karakter in je Basic programma moet komen.
CHR(0) voor PRINT 0 t/m CHR(7) voor PRINT 7.
De waarden voor in je Basic programma staan onderin het vakje in hexadecimale notatie.
Door dit vakje met de muis te selecteren en met CTRL + C te kopiëren, plak je het met CTRL + V zo in je Basic programma.

Download chr karakter generator voor Windows

 


Het is mogelijk om meer dan 8 karakters die door jezelf zijn ontworpen in 1 programma te hebben.
Alleen kun je er maar 8 tegelijkertijd op het display laten zien.
Het volgende programma laat steeds 5 karakters tegelijkertijd zien.
Maar in totaal komen er 10 verschillende eigen ontworpen karakters langs.

TIP: Door het programmavoorbeeld te selecteren (linker muisknop ingedrukt houden en dan van onderaf 'slepen' naar boven) en met CTRL + C te kopiëren naar het klembord, kun je het in de PIC Basic editor met CTRL + A, en dan CTRL + V weer plakken, dat scheelt een hoop typewerk en voorkomt vergissingen.

DEVICE 16F628A                ;Gebruik een 16F628A type
CONFIG INTRC_OSC_NOCLKOUT, WDT_OFF, PWRTE_ON, LVP_OFF, MCLRE_OFF

SYMBOL Snelheid = 200         ;Snelheid loop effect

DELAYMS 500                   ;LCD stabilisering

CLS                           ;Wis scherm en zet cursor links bovenaan 
PRINT 0, 1, 2, 3, 4           ;Laat eerste 5 karakters zien

WHILE 1 = 1
  ;Plaatje 1
  PRINT $FE,$40,$07,$0F,$1C,$18,$18,$1C,$0F,$07,$00,$00,$00,$00,_
        $00,$00,$1F,$1F,$1F,$1F,$00,$00,$00,$00,$1F,$1F,$1F,$1F,_
        $00,$00,$00,$00,$00,$00,$1C,$1E,$07,$03,$03,$07,$1E,$1C
  DELAYMS Snelheid

  ;Plaatje 2
  PRINT $FE,$40,$07,$0F,$1C,$18,$18,$1C,$0F,$07,$1F,$1F,$00,$00,_
        $00,$00,$1F,$1F,$00,$00,$00,$00,$00,$00,$00,$00,$1F,$1F,_
        $00,$00,$00,$00,$1F,$1F,$1C,$1E,$07,$03,$03,$07,$1E,$1C
  DELAYMS Snelheid

  ;Plaatje 3
  PRINT $FE,$40,$07,$0F,$1C,$18,$18,$1C,$0F,$07,$1F,$1F,$00,$00,_
        $00,$00,$00,$00,$1F,$1F,$00,$00,$00,$00,$1F,$1F,$00,$00,_
        $00,$00,$00,$00,$1F,$1F,$1C,$1E,$07,$03,$03,$07,$1E,$1C
  DELAYMS Snelheid

  ;Plaatje 4
  PRINT $FE,$40,$07,$0F,$1C,$18,$00,$00,$00,$00,$1F,$1F,$00,$00,_
        $00,$00,$1F,$1F,$1F,$1F,$00,$00,$00,$00,$1F,$1F,$1F,$1F,_
        $00,$00,$00,$00,$1F,$1F,$00,$00,$00,$00,$03,$07,$1E,$1C
  DELAYMS Snelheid

  ;Plaatje 5
  PRINT $FE,$40,$00,$00,$00,$00,$18,$1C,$0F,$07,$1F,$1F,$00,$00,_
        $00,$00,$1F,$1F,$1F,$1F,$00,$00,$00,$00,$1F,$1F,$1F,$1F,_
        $00,$00,$00,$00,$1F,$1F,$1C,$1E,$07,$03,$00,$00,$00,$00
  DELAYMS Snelheid
WEND

END

Misschien kijk je vreemd op omdat er maar één keer PRINT 0, 1, 2, 3, 4 staat en dat ook nog buiten de lus.
Het programma werkt ook anders dan de anderen.
Met PRINT 0, 1, 2, 3, 4 worden de eerste 5 (van de 8) vrij programmeerbare geheugenadressen van de HD44780 chip op het display afgebeeld.
Daar komen we verder niet meer aan.

Met PRINT $FE, $40, $07, enz. sturen we nu steeds opnieuw zelf ontworpen karakters naar de 5 geheugenadressen van de HD44780 chip.
De afbeelding op het display verandert nu omdat we het (zichtbare) displaygeheugen steeds wijzigen.

Er zijn 5 verschillende plaatjes die steeds na elkaar worden getoond.
Elk plaatje bestaat weer uit 5 zelf ontworpen karakters.


Underscore ( _ )
Soms wordt een programmaregel extreem lang zoals in bovenstaand programma.
In het programma hierboven is elke PRINT instructie daarom uitgesmeerd over 3 regels.
Met een underscore oftewel een onderstrepings karakter ( _ ) kun je de programmaregel afbreken en verdergaan op de volgende regel.
Een underscore mag je alleen direct na een komma plaatsen en werkt niet alleen bij de PRINT instructie, maar bij alle instructies met komma's.

Meer info underscore


Logo's en dergelijke op een numeriek (= niet grafisch) display tekenen kan (beperkt) met meerdere karakters, die samen één logo vormen.
Om bijvoorbeeld grote dobbelsteenogen op een display met twee regels te krijgen teken je eerst onderstaande karakters.


0

1

2

3

4

5

6

Met deze 7 karakters zijn alle 6 mogelijke dobbelsteen waarden te tekenen.
Om nu bijvoorbeeld het cijfer 5 op het display te krijgen schrijf je in je programma:
PRINT AT
1, 1, 0, 6, 3
PRINT AT 2, 1, 4, " ", 5

Als je goed kijkt kun je zien hoe het dobbelsteen '5' is opgebouwd.
PRINT AT 1, 1, betekent zoals gewoonlijk regel 1, positie 1.
Daarna 0, 6, 3, oftewel, plaats na elkaar de zelfgemaakte karakters CHR(0), daarnaast CHR(6) en dan nog CHR(3).

De onderste twee stippen van het dobbelsteen komen op displayregel 2 (PRINT AT 2, 1,...)
Op de eerste positie CHR(4), dan voor het lege vakje een spatie (" ") en tot slot CHR(5).

Het resultaat is dan

Het HD44780 display is zo gemaakt, dat de ruimte tussen de karakters (zowel links-rechts als boven-onder) even groot is als de dots van het karakter zelf, waardoor je, als je het goed uitkient, kleine tekeningen en logo's kunt tekenen waar de lege ruimtes precies in vallen.

In cursus deel 10 staan een paar voorbeelden van dobbelsteen "gooi" programma's.


Het volgende voorbeeld laat het woord G O A L in het groot op het display zien, waarbij elke letter is opgebouwd uit vier karakters (2 karakters breed en 2 karakters hoog).
Aangezien elke grote letter hier uit vier karakters bestaat en het woord GOAL zelf ook uit vier letters bestaat, zijn er 4 × 4 = 16 eigengemaakte karakters nodig, terwijl het HD44780 maar ruimte heeft voor 8 eigengemaakte karakters, je kunt het woord GOAL dus nooit continu op het display laten zien.
Ná elkaar kan wel.

Het eerste voorbeeld hiervan laat de letters na elkaar zien, als ware het een looplicht:

DEVICE 16F628A                ;Gebruik een 16F628A type
CONFIG INTRC_OSC_NOCLKOUT, WDT_OFF, PWRTE_ON, LVP_OFF, MCLRE_OFF

SYMBOL Snelheid = 100         ;Snelheid loop effect

DELAYMS 500                   ;LCD stabilisering

CLS                           ;Wis scherm en zet cursor links bovenaan

WHILE 1 = 1
  ;Letter G
  PRINT $FE,$40,$03,$07,$0C,$18,$18,$18,$18,$18,_
                $18,$1C,$06,$03,$03,$00,$00,$00,_
                $18,$18,$18,$18,$18,$18,$0F,$07,_
                $0F,$0F,$03,$03,$03,$03,$1E,$1C
  PRINT AT 1, 1, 0, 1, "         " ;Regel 1, positie 1, karakter 0 en 1, spaties wist vorige
  PRINT AT 2, 1, 2, 3, "         " ;Regel 2, positie 1, karakter 2 en 3, spaties wist vorige
  DELAYMS Snelheid

  ;Letter O
  PRINT $FE,$40,$03,$07,$0C,$18,$18,$18,$18,$18,_
                $18,$1C,$06,$03,$03,$03,$03,$03,_
                $18,$18,$18,$18,$18,$0C,$07,$03,_
                $03,$03,$03,$03,$03,$06,$1C,$18
  PRINT AT 1, 1, "   ", 0, 1  ;Regel 1, positie 1, spaties wist oude letter, karakter 0 en 1
  PRINT AT 2, 1, "   ", 2, 3  ;Regel 2, positie 1, spaties wist oude letter, karakter 2 en 3
  DELAYMS Snelheid

  ;Letter A
  PRINT $FE,$40,$03,$07,$0C,$18,$18,$18,$18,$18,_
                $18,$1C,$06,$03,$03,$03,$03,$03,_
                $1F,$1F,$18,$18,$18,$18,$18,$18,_
                $1F,$1F,$03,$03,$03,$03,$03,$03
  PRINT AT 1, 4, "   ", 0, 1  ;Regel 1, positie 4, spaties wist oude letter, karakter 0 en 1
  PRINT AT 2, 4, "   ", 2, 3  ;Regel 2, positie 4, spaties wist oude letter, karakter 2 en 3
  DELAYMS Snelheid

  ;Letter L
  PRINT $FE,$40,$18,$18,$18,$18,$18,$18,$18,$18,_
                $00,$00,$00,$00,$00,$00,$00,$00,_
                $18,$18,$18,$18,$18,$18,$1F,$1F,_
                $00,$00,$00,$00,$00,$00,$1F,$1F
  PRINT AT 1, 7, "   ", 0, 1  ;Regel 1, positie 7, spaties wist oude letter, karakter 0 en 1
  PRINT AT 2, 7, "   ", 2, 3  ;Regel 2, positie 7, spaties wist oude letter, karakter 2 en 3 
  DELAYMS Snelheid
WEND

Experimenteer met de waarde van 'Snelheid' om het effect naar wens in te stellen.
Als je de snelheid heel hoog zet (bijvoorbeeld Snelheid = 30) dan worden de letters heel snel na elkaar weergegeven.
Echt duidelijk worden de letters dan niet, omdat elke letter natuurlijk maar 25% van de tijd zichtbaar is.

Het volgende voorbeeld doet het iets beter, omdat deze de letters 50% van de tijd weergeven.
De letters G/A en O/L worden hier om en om weergegeven:

DEVICE 16F628A                ;Gebruik een 16F628A type
CONFIG INTRC_OSC_NOCLKOUT, WDT_OFF, PWRTE_ON, LVP_OFF, MCLRE_OFF

SYMBOL Snelheid = 40          ;Snelheid loop effect

DELAYMS 500                   ;LCD stabilisering

CLS                           ;Wis scherm en zet cursor links bovenaan

WHILE 1 = 1
  ;Letter G en A
  ;Regel 1, positie 1, karakter 0 en 1, spaties wissen O, karakters 4 en 5, spaties wissen L
  PRINT AT 1, 1, 0, 1, "    ", 4, 5, "   "
  ;Regel 1, positie 1, karakter 2 en 3, spaties wissen O, karakters 6 en 7, spaties wissen L
  PRINT AT 2, 1, 2, 3, "    ", 6, 7, "   "
  PRINT $FE,$40,$03,$07,$0C,$18,$18,$18,$18,$18,_ ;karakter 0 (G)
                $18,$1C,$06,$03,$03,$00,$00,$00,_ ;karakter 1 (G)
                $18,$18,$18,$18,$18,$18,$0F,$07,_ ;karakter 2 (G)
                $0F,$0F,$03,$03,$03,$03,$1E,$1C,_ ;karakter 3 (G)
                $03,$07,$0C,$18,$18,$18,$18,$18,_ ;karakter 4 (A)
                $18,$1C,$06,$03,$03,$03,$03,$03,_ ;karakter 5 (A)
                $1F,$1F,$18,$18,$18,$18,$18,$18,_ ;karakter 6 (A)
                $1F,$1F,$03,$03,$03,$03,$03,$03   ;karakter 7 (A)
  DELAYMS Snelheid

  ;Letter O en L
  ;Regel 1, positie 1, spaties wissen G, karakter 0 en 1, spaties wissen A, karakters 4 en 5
  PRINT AT 1, 1, "   ", 0, 1, "    ", 4, 5
  ;Regel 1, positie 1, spaties wissen G, karakter 2 en 3, spaties wissen A, karakters 6 en 7 
  PRINT AT 2, 1, "   ", 2, 3, "    ", 6, 7
  PRINT $FE,$40,$03,$07,$0C,$18,$18,$18,$18,$18,_ ;karakter 0 (O)
                $18,$1C,$06,$03,$03,$03,$03,$03,_ ;karakter 1 (O)
                $18,$18,$18,$18,$18,$0C,$07,$03,_ ;karakter 2 (O)
                $03,$03,$03,$03,$03,$06,$1C,$18,_ ;karakter 3 (O)
                $18,$18,$18,$18,$18,$18,$18,$18,_ ;karakter 4 (L)
                $00,$00,$00,$00,$00,$00,$00,$00,_ ;karakter 5 (L)
                $18,$18,$18,$18,$18,$18,$1F,$1F,_ ;karakter 6 (L)
                $00,$00,$00,$00,$00,$00,$1F,$1F   ;karakter 7 (L)
  DELAYMS Snelheid
WEND

In het eerste programmablok worden G-spaties-A-spaties op het display gezet.
De spaties tussen G en A wissen dus de O uit en de spaties achter de A wissen de L uit.

In het tweede programmablok wordt spaties-O-spaties-L op het display gezet.
De spaties vóór de O wissen de G, de spaties tussen de O en L wissen de A.
De spaties wissen dus steeds de letters van het vorige programmablok uit.

Maar alle vier grote letters GOAL continu op het display gaat dus helaas niet.


Een tijdsbalk met een hogere resolutie dan met blokjes, is te maken door zelf een aantal karakters te maken:

DEVICE 16F628A                ;Gebruik een 16F628A type
CONFIG INTRC_OSC_NOCLKOUT, WDT_OFF, PWRTE_ON, LVP_OFF, MCLRE_OFF
ALL_DIGITAL TRUE              ;Alle ingangen digitaal

;Algemene constanten
SYMBOL Lengte       = 16      ;Vul hier in hoeveel karakters breed de VU-meter moet zijn

;Variabelen declareren
DIM Half            AS BYTE   ;Bevat de waarde 1,2 of 3 voor het halve karakter | of ||
DIM Som             AS BYTE   ;Bevat de uitkomst van de som: (Teller * Lengte) / 85
DIM Teller          AS BYTE   ;Bevat de waarde van de teller die continu telt van 0...255 
DIM Vol             AS BYTE   ;Bevat het aantal te printen "volle" karakters: |||

CLEAR                         ;Wis alle RAM geheugen
DELAYMS 500                   ;LCD stabilisering

PRINT $FE,$40,$15,$15,$15,$15,$15,$15,$15,$15,_ ;karakter 0 = |||
              $10,$10,$10,$10,$10,$10,$10,$10,_ ;karakter 1 = |
              $14,$14,$14,$14,$14,$14,$14,$14   ;karakter 2 = ||
              

;Hoofdprogramma
CLS                           ;Met een schoon LCD scherm beginnen (LCD wissen dus)

WHILE 1 = 1
  INC Teller                  ;Teller telt continu van 0 tot 255
  DELAYMS 10                  ;Telsnelheid iets vertragen
  PRINT AT 1, 1, @Teller, "  ";Zet actuele stand van 'Teller' op eerste regel

  Som = (Teller * Lengte) / 85;De waarde 85 komt van 256 / 3
  Vol = Som / 3               ;Bereken het aantal volle karakters |||
  Half = Som // 3             ;De uitkomst is de restwaarde van de deling (0, 1 of 2)

  PRINT AT 2, 1, REP 0\Vol    ;Plaats eerst het aantal volle karakters ||| = chr(0)
  IF Half > 0 THEN PRINT Half ;Als de waarde niet 0 is, dan print karakter (1 of 2)
  PRINT REP " "\Lengte - Vol  ;Wis het overige van de barregel
WEND

END                           ;Einde programma

In bovenstaand programma zijn de volgende karakters getekend:

||| 
|
||
Karakter 0  oftewel Chr(0)
Karakter 1  oftewel Chr(1)
Karakter 2  oftewel Chr(2)

Omdat er drie niveaus per displaykarakter weer kan worden gegeven, moet de berekening die berekent hoeveel volle karakters er moet worden weergegeven, worden gedeeld door 3.
De uitkomst van die berekening komt in de variabele 'Vol' te staan.

Is de uitkomst van die deling geen rond getal, dan wordt de restwaarde van die deling in de variabele 'Half' gezet.
Hieruit wordt berekent welk "half" karakter ( | of || ) er nog bij achter moet worden gezet.
Is de restwaarde 1, dan wordt chr(1) erachter geplaatst, is de restwaarde 2, dan wordt chr(2) erachter gezet.
Is de restwaarde 0, dan wordt er (vanwege IF ... THEN) niets geplaatst.


Modulus
Een deling doe je met een slash ( / ), de restwaarde (= modulus) kun je krijgen door een dubbele slash ( // ) te plaatsen.
Zo geeft 100 / 3 als uitkomst 33, de restwaarde van die berekening is 100 // 3 (met als uitkomst 1).

Omdat we zoveel mogelijk met hele getallen werken (berekeningen met variabelen die cijfers achter de komma hebben vréten geheugenruimte), klopt de uitkomst van een deling meestal niet, omdat de cijfers achter de komma weg worden gelaten.
1000 / 6 heeft als uitkomst 166,667, maar BYTE, WORD en DWORD variabelen laten de cijfers na de komma weg, dus geven die 166 als uitkomst.
Feitelijk klopt dat niet, want 166 × 6 = 996, dat is 4 te weinig.
Deze restwaarde is dus te achterhalen door de modulus berekening 1000 // 6, met als uitkomst de restwaarde 4.

Als de deling geen restwaarde heeft, zoals 1000 / 5, dan geeft 1000 // 5 de uitkomst 0.


De modulus berekening kan voor diverse zaken handig zijn.
In het voorbeeld hieronder loopt de tijd in WORD variabele 'Tijd', dus zowel de minuten als de seconden.
Dit is makkelijk als je een timer gaat bouwen, je kunt dan gewoon schrijven:

IF Tijd = 1000 THEN LED = HOOG
IF Tijd = 1130 THEN LED = LAAG

Om 10:00 zal de LED aan gaan en na anderhalve minuut, om 11:30 weer uit.

Maar voor weergave op een display moeten de minuten en seconden gescheiden worden en dat kan met de modulus berekening.

DEVICE 16F628A                ;Gebruik een 16F628A type
CONFIG INTRC_OSC_NOCLKOUT, WDT_OFF, PWRTE_ON, LVP_OFF, MCLRE_OFF
DECLARE ALL_DIGITAL = TRUE    ;Alle ingangen digitaal
DECLARE XTAL        = 4       ;Interne oscillator is 4MHz

;Variabele declareren
;WORD
DIM Tijd            AS WORD   ;Bevat de totale tijd (bijvoorbeeld 2359 = 23:59)
;BYTE
DIM Minuten         AS BYTE   ;Bevat de minuten,  gefilterd uit de tijd met behulp van modulus
DIM Seconden        AS BYTE   ;Bevat de seconden, gefilterd uit de tijd met behulp van modulus

CLEAR                         ;Wis alle RAM geheugen
DELAYMS 500                   ;LCD stabilisering


;Hoofdprogramma
CLS                           ;Met een schoon LCD scherm beginnen (LCD wissen dus)

Tijd = 5855                   ;Start (voor dit voorbeeld) met de tijd op 58:55

WHILE 1 = 1
  IF (Tijd // 100) > 59 THEN Tijd = Tijd + 40 ;Als seconden op 60 komt, dan 40 bij 'Tijd' tellen 
  IF (Tijd /  100) > 59 THEN Tijd = 0 ;Als minuten ook de 59 overschrijdt, dan 'Tijd' resetten

  Minuten  = Tijd / 100       ;Filter de minuten uit de tijd
  Seconden = Tijd // 100      ;Filter de seconden uit de tijd

  PRINT AT 1, 1, "De tijd: ", DEC2 Minuten, ":", DEC2 Seconden  ;Tijd op het display plaatsen

  DELAYMS 1000                ;Wacht 1 seconde
  INC Tijd                    ;Secondenteller verhogen met 1
WEND

END                           ;Einde programma

De minuten worden uit 'Tijd' gefilterd door 'Tijd' te delen door 100 (bijvoorbeeld 2359 / 100 = 23,59) , 'Minuten' is een BYTE dus de cijfers na de komma vervallen, 23 blijft over.
De seconden (de restwaarde) worden uit 'Tijd' gefilterd met modulus 100 (bijvoorbeeld 2359 // 100 = 59).

Bovenstaand voorbeeld telt een uur (van 00:00 tot aan 59:59) en zal dan weer opnieuw beginnen.
Door van 'Tijd' een DWORD variabele te maken, kunnen ook de uren erbij in worden gezet.


In het volgende voorbeeld zal elke 4 seconden de temperatuur van de keuken één seconde op het display getoond worden.
De overige 3 seconden wordt de kamertemperatuur getoond.

Het mag duidelijk zijn dat de temperatuur in de volgende voorbeelden niet echt gemeten wordt, het gaat hier immers om voorbeelden van de modulus berekening.
Voorbeelden van temperatuurmetingen kun je vinden bij de DS1820.

DEVICE 16F628A                ;Gebruik een 16F628A type
CONFIG INTRC_OSC_NOCLKOUT, WDT_OFF, PWRTE_ON, LVP_OFF, MCLRE_OFF
DECLARE ALL_DIGITAL = TRUE    ;Alle ingangen digitaal
DECLARE XTAL        = 4       ;Interne oscillator is 4MHz

;Variabele declareren
DIM Seconde         AS BYTE   ;Bevat de waarde van de teller die de seconden bijhouden 

CLEAR                         ;Wis alle RAM geheugen
DELAYMS 500                   ;LCD stabilisering


;Hoofdprogramma
CLS                           ;Met een schoon LCD scherm beginnen (LCD wissen dus)

WHILE 1 = 1
  IF (Seconde // 4) = 0 THEN       ;Als restwaarde van seconde gedeeld door 4, nul is, dan...
    PRINT AT 1, 1, "Keuken: 19.7"  ;De keukentemperatuur op het display plaatsen
  ELSE                             ;...anders... (dus de overige 3 van de 4 seconden)
    PRINT AT 1, 1, " Kamer: 20.1"  ;De kamertemperatuur op het display plaatsen
  ENDIF

  INC Seconde                      ;Secondenteller verhogen met 1
  IF Seconde > 59 THEN Seconde = 0 ;Secondenteller 0 maken als deze groter dan 59 wil worden
  DELAYMS 1000                     ;Wacht 1 seconde
WEND

END                           ;Einde programma

In de eerste IF...THEN regel wordt de restwaarde van de deling "Seconde gedeeld door 4" met modulus berekent.
Om dit te doen moet dus inderdaad niet Seconde / 4 worden geschreven, maar Seconde // 4 , met een dubbele schuine streep (dubbele slash) dus.
Zo zal er om de 4 seconden een seconde bijzitten die geen "waarde achter de komma" (de restwaarde) oplevert, immers, 4 / 4 = 1, evenals 8 / 4 = 2 en 12 / 4 = 3, enz.


Een ander voorbeeld waarbij de kamertemperatuur nu 4 seconden wordt getoond en de keukentemperatuur 2 seconden.

DEVICE 16F628A                ;Gebruik een 16F628A type
CONFIG INTRC_OSC_NOCLKOUT, WDT_OFF, PWRTE_ON, LVP_OFF, MCLRE_OFF
ALL_DIGITAL TRUE              ;Alle ingangen digitaal

;Variabele declareren
DIM Seconde         AS BYTE   ;Bevat de waarde van de teller die de seconden bijhouden 

CLEAR                         ;Wis alle RAM geheugen
DELAYMS 500                   ;LCD stabilisering


;Hoofdprogramma
CLS                           ;Met een schoon LCD scherm beginnen (LCD wissen dus)

WHILE 1 = 1
  IF (Seconde // 6) < 2 THEN       ;Restwaarde bij Seconde / 6 kleiner dan 2?  Dan...
    PRINT AT 1, 1, "Keuken: 18.6"  ;De keukentemperatuur op het display plaatsen
  ELSE                             ;...anders... (dus de overige 4 van de 6 seconden)
    PRINT AT 1, 1, " Kamer: 19.9"  ;De kamertemperatuur op het display plaatsen
  ENDIF

  INC Seconde                      ;Secondenteller verhogen met 1
  IF Seconde > 59 THEN Seconde = 0 ;Secondenteller 0 maken als deze groter dan 59 wil worden 
  DELAYMS 1000                     ;Wacht 1 seconde
WEND

END                           ;Einde programma

De totaaltijd is 6 seconden, namelijk 4 seconden voor de kamertemperatuur en 2 seconden voor de keukentemperatuur.
Deze waarde staat ingevuld in de modulus berekening.
In de IF...THEN vergelijking wordt vervolgens de 2 seconden voor de keukentemperatuur uitgefilterd.


Ook het knipperen van een karakter op het display is zo eenvoudig te maken als er al een klok in de PIC aanwezig is.
Bij me thuis geeft het display de dagnaam aan door middel van de eerste twee letters, dus MA, DI, WO, DO, enzovoort.
Het automatische huis zorgt hierdoor tevens dat ik gewekt wordt op de werkdagen (ik hoef dus niet zelf meer een wekker te zetten omdat het hier een weektimer betreft).

Wil ik echter niet gewekt worden (bijvoorbeeld vakantie of een snipperdag), dan geef ik dit via een druk op de afstandbediening door aan het huis.
Op de plaats waar normaal de dagnaam verschijnt, zal nu SN (van snipperdag) gaan knipperen op het display.
Het knipperen doe ik door gebruik te maken van de modulus berekening:

DEVICE 16F628A                ;Gebruik een 16F628A type
CONFIG INTRC_OSC_NOCLKOUT, WDT_OFF, PWRTE_ON, LVP_OFF, MCLRE_OFF
ALL_DIGITAL TRUE              ;Alle ingangen digitaal

;Variabele declareren
;BYTE
DIM Seconde         AS BYTE   ;Bevat de waarde van de teller die de seconden bijhouden
;BIT 
DIM Snipperdag      AS BIT    ;TRUE (oftewel '1') als er een snipperdag is 

CLEAR                         ;Wis alle RAM geheugen
DELAYMS 500                   ;LCD stabilisering

Snipperdag = 1                ;Voor het voorbeeld wordt 'Snipperdag' hier op '1' gezet


;Hoofdprogramma
CLS                           ;Met een schoon LCD scherm beginnen (LCD wissen dus)

WHILE 1 = 1
  CURSOR 1, 1                 ;Cursor op regel 1, positie 1 klaar zetten

  IF Snipperdag = 1 THEN      ;Als de huidige dag een snipperdag is, dan... 
    IF (Seconde // 2) = 0 THEN  ;Als 'Seconde' een even getal is, dan... 
      PRINT "SN"              ;De tekst SN op het display plaatsen
    ELSE                      ;...anders...
      PRINT "  "              ;Wis SN
    ENDIF

  ELSE                        ;...anders... (bij geen snipperdag)
    PRINT "ZA"                ;De actuele dagnaam op het display plaatsen (als voorbeeld ZA)
  ENDIF

  INC Seconde                      ;Secondenteller verhogen met 1
  IF Seconde > 59 THEN Seconde = 0 ;Secondenteller 0 maken als deze groter dan 59 wil worden 
  DELAYMS 1000                     ;Wacht 1 seconde
WEND

END                           ;Einde programma

En, zoals te zien in bovenstaand programmavoorbeeld, is met modulus zo ook eenvoudig te bepalen of een getal een even of een oneven getal is.
Want als de seconde even is, dan wordt SN op het display weergegeven, de seconde erna, als deze dan dus oneven is, wordt SN gewist door de twee spaties, waardoor het knippereffect ontstaat.