ArSid - Arduino Sid Synthesizer

Sat 20-Apr-24
04:37:48


Lib: Lcd-Display

Datum: Sun 17 February 2019
Samenvatting: Het afhandelen van het Lcd Display.
Soort Artikel: Software
Status: Afgerond


[Tekst] [Afbeeldingen] [Aansluitingen] [Broncodes]
lib_lcd_01-lcd.jpg
1/7: lib_lcd_01-lcd.jpg.
lib_lcd_02-initialisatie.jpg
2/7: lib_lcd_02-initialisatie.jpg.
lib_lcd_03-instructies.jpg
3/7: lib_lcd_03-instructies.jpg.
lib_lcd_04-check.jpg
4/7: lib_lcd_04-check.jpg.
lib_lcd_05-overloop.jpg
5/7: lib_lcd_05-overloop.jpg.
lib_lcd_06-2x40_display.jpg
6/7: lib_lcd_06-2x40_display.jpg.
Meer
[Tekst] [Afbeeldingen] [Aansluitingen] [Broncodes]

Om het schrijven naar het Lcd-Display te vergemakkelijken is er een Library gemaakt met routines erin om deze taak te realiseren. Ook neemt deze Library ook het initialiseren van het display voor zijn rekening.

Er zit niet alleen een eenvoudige funktie voor het schrijven van een teken in deze Library, maar het bevat ook routines voor het schrijven van nummers, om de cursor op het display "aan te sturen", maar ook om het display te wissen en de achtergrond verlichting aan te sturen.

Uiteraard is deze Library speciaal voor de ArSid zelf ontwikkeld.

Een LCD heeft twee registers, een Data Register en een Commando Register. Welke ervan de data op de aansluitingen D0..D7 gaat ontvangen, hangt af van de aansluiting Rs (Register Select). Is deze aansluiting LAAG, dan gaat de data naar het Commando Register. Bij HOOG gaat de data naar het Data Register. Dit aansturen gebeurt via de Latch op adres 3, bit 0.

Meer Hardware gegevens staan in het stuk over het Lcd-Display.

Het Commando Register.

Het Commando Register regelt diverse instellingen en algemene funkties van de LCD (waaronder Blink, ClearScreen, GotoXY, HomeCursor).

D7 D6 D5 D4 D3 D2 D1 D0 Timing (sec) Omschrijving:
0 0 0 0 . 0 0 0 1 1.640m  ClearScreen & Home Cursor.
0 0 0 0 . 0 0 1 * 1.640m  Home Cursor, of te wel de Cursor gaat naar de eerste positie op het scherm en de Scherm verschuiving wordt op 0 gezet.
0 0 0 0 . 0 1 I/D S 40µ Instellen Cursor Richting I/D=LAAG Verlagen | I/D=HOOG Verhogen
S=LAAG Zonder Scherm Shift | S=HOOG Met Scherm Shift
0 0 0 0 . 1 D C B 40µ D=LAAG Zet Display Uit | D=HOOG Zet Display Aan
C=LAAG Zet Cursor Uit | C=HOOG Zet Cursor Aan
B=LAAG Geen Cursor Blink | B=HOOG Blink Cursor Positie.
0 0 0 1 .S/CR/L * * 40µ S/C=LAAG Cursor Verplaatsen | S/C=HOOG Scherm Verschuiven
R/L=LAAG Schuif naar Links | R/L=HOOG = Schuif naar Rechts
0 0 1 DL . N F * * 40µ DL=LAAG 4-bits Data | DL=HOOG 8-bits Data
N=LAAG 1/8 of 1/11 Duty | N=HOOG 1/16 Duty (2 regels)
F=LAAG 5*7 Pixel Tekens | F=HOOG 5*10 Pixel Tekens.
0 1 Cg5Cg4.Cg3Cg2Cg1Cg0 40µ Cg5..Cg0 = Adres Character Ram (voor zelf gedefinieerde tekens).
1 Dd6Dd5Dd4.Dd3Dd2Dd1Dd0 40µ Dd6..Dd0 = Adres Data Cursor (soort van GotoXY) in tekens vanaf linksboven.

Voor de Adres Character Ram zijn maar 6 bits gereserveerd. Dit betekent dus dat er maar 64 lokaties mogelijk zijn. Dit verklaart ook dat er maar 8 eigen tekens (van 8 pixels hoog = 8 bytes) opgegeven kunnen worden. Met wat creativiteit zijn er hier heel wat leuke dingen op het scherm te realiseren.

Voor de Adres Data Cursor zijn maar 7 bits gereserveerd. Dit betekent dus dat er maar 128 lokaties mogelijk zijn. Ruim voldoende voor dit 4x20 displays.

Het Commando Register kan ook uitgelezen worden, maar in de ArSid wordt dit niet benut.

Enkele constante waardes en Latch-aansluitingen.

Voor het verhogen van de leesbaarheid zijn er enkele constantes gedefinieerd en wel:

  • const byte lcd_mask = 0b00000100; // Mask Lcd Ready Signal. - (*) Op moment van schrijven: (nog) niet in gebruikt.
  • const byte Lcd_timer = 0b00000100; // Lcd bit at the Controlbus.
  • const byte Lcd_register = 0b00000001; // Lcd register Select.
  • const byte Lcd_enable = 0b00001000; // Lcd Enable.
Ze hebben allemaal te maken met welke bitjes bepaalde display-dingen worden aangestuurd. Ze worden bepaald door de aansluitingen op de print Latches. In het kort zijn dit:

Latch Bit Aangesloten op: Constante:
2 0..7 Lcd: Data 0..7 -
3 0  Lcd: Register Lcd_register
3 3  Lcd: Enable Lcd_enable
LAAG -  Lcd: Read/ Write (niet gebruikt) -
Poort Pin Aangesloten op: Constante:
- -  Lcd: Enable => Timer Reset -
- -  Timer counts (about) 42µsec-
G 2  Timer: Counted => Stop Timer Lcd_timer

Het schrijven naar het Lcd-Display.

  • Lcd_Out(byte rs, byte bb): Dit is de basis-routine om alles naar het display te schrijven. Of er naar het commando-register, of naar het data-register geschreven moet worden, wordt opgegeven door bit 0 van de variabele RS (van RegisterSelect). Hier wordt op gecontroleerd met behulp van een eenvoudige AND-bewerrking.

    Met de parameter BB (van Byte) wordt de waarde meegegeven die naar het display gestuurd moet worden. In combinatie met de parameter RS zijn alle gegevens naar het Display te schrijven.

    Maar voordat het zover is, moet er eerst gekeken worden OF het display al klaar is. Hier zijn enkele populaire truken voor:

    1. Kijken naar de BusyFlag van het Display (Commando Register Bit 7). Hierbij is het gebruik van het R/W-signaal nodig, terwijl deze in de ArSid niet wordt gebruikt.
    2. Gewoon enige tijd wachten (typical: 40µ-seconden). Dit kan worden gedaan met:
      • Met een Delay()-funktie maar dan weet men zeker dat er niets anders in de tussentijd kan worden gedaan.
      • Een Arduino timer gebruiken dat vertelt wanneer deze tijd voorbij is. Hiervoor is een beter begrip van de Timers nodig, die ik op dit moment nog niet heb.
      • Een externe hardware mechanisme dat vertelt wanneer deze tijd voorbij is.

    In de ArSid wordt de laatste methode gebruikt. Een externe Timer (zie de Decoder-print) geeft een signaal naar de Arduino Mega terug (Poort G, bit 2) wanneer de benodigde tijd verstreken is. Het voordeel met de "Lees BusyFlag"-methode is dat dit minder programma-tijd in beslag neemt en het totale programma dus sneller bezig kan zijn met zijn hoofd-taak. De tijdsduur van de hardware timer, wordt in de ArSid zichtbaar gemaakt op het (rode) "Panel Check"-scherm (om alle potentiometers en schakelaars te testen). De waarde staat rechtsboven op het display en ligt nu tussen de 40µsec en 44µsec.

    In de funktie Lcd_Out(byte rs, byte bb) wordt (op het moment van schrijven), vlak voordat er een nieuwe waarde naar het lcd-Display gestuurd moet worden, continue met een WHILE-statement gekeken naar Bit 2 van Poort G. Dit gebeurt continue, totdat het signaal gelijk is aan 0 (NUL). Pas dan gaat de funktie Lcd_Out() verder.

    Wat daarna volgt is het volgende: Het Lcd-Display wordt (POKE(3,)) Enable gemaakt, met de juiste register (Commando (LAAG) of Dat (HOOG)). De waarde wordt naar het Display gestuurd (POKE(2,)). Het Lcd-Display wordt weer niet-Enable gemaakt (POKE(3,)).

    De POKE() (beschreven in de Library I/O) regelt dan alle timing-zaken naar het schrijven naar de registers 2 en 3.

    De Initialisatie van het display.

  • Lcd_Init(): De initialisatie van de LCD-unit is tijdgevoelig, als in: dit mag niet te snel gebeuren. Er zijn extra vertragingen nodig, terwijl er eerst 3 keer de 8bit-interface moet worden opgegeven.

    De extra vertragingen worden gerealiseerd met de standaard Delay()-funktie. Daarna worden er precies de waardes naar het display gestuurd (met Lcd_Out()) die de documentatie aangeeft (zie foto's).

    Daarna worden de benodigde instellingen aan het Display gegeven, en wel:

    • %0011.1000 - Schakel het display op 8-bits, 2-lines, 5x8-font, , .
    • %0000.1000 - Schakel het display Uit, Cursor Uit, Blinking Uit.
    • %0000.1100 - Schakel het display Aan, Cursor Uit, Blinking Uit.
    • %0001.0100 - Schakel verschuiven op Cursor, Verschuif naar rechts, , .
    • %0000.0100 - Schakel Cursor richting op Optellen (= naar rechts), Zonder scherm verschuiving.

    Daarna wordt het display gewist. Het wissen van het display kost 1.64 milli seconden (omgerekend 1640micro;sec). Dit duurt net zo lang als het schrijven van (1640 ÷ 40 =) 41 tekens schrijven. Vandaar de extra vertraging met Delay(2).

    Het wissen van het scherm.

    Hiervoor is het nodig om slechts 1 waarde naar het display te schrijven, namelijk %0000.0001 naar het Commando-Register. Maar dan moet er wel rekening worden gehouden met de verlengte verwerkingstijd van 1.64 milli seconden.

  • Lcd_Clr(): En dat is precies wat deze funktie doet, inclusief Delay(2).

    Het verplaatsen van de cursor.

    Na het schrijven van elk teken op het display wordt de cursor (ook al is deze niet zichtbaar) 1 plaats naar rechts verplaats. Op zich is dit prima ... maar soms moeten gegevens ook midden op een regel (of midden op een display) worden geplaatst. Het display voorziet daarvoor in een "Commando" dat heet: "DDRAM Address Set", binair %1xxx.xxxx.

    Er gebeurt ook iets onverwachts bij het verplaatsen van de cursor. Na het volschrijven van de eerste (tweede) regel, gaat de cursor naar de derde (vierde) regel. Is deze regel vol, dan sprint de cursor weer terug naar de tweede (vierde) regel. Hierdoor lijkt het display zich voor te doen als een display met 2 regels van van 40 tekens, maar dat de tweede helft is losgeknipt en geplakt is onder de eerste regel. Dat ziet er dan uit als volgt:

    RegelX-posities op een regel X Optelling:Y Optelling:Totaal:
    0 0-000-010-020-030-040-050-060-070-080-090-100-110-120-130-140-150-160-170-180-19 + 0 + 0 + 0
    1 1-001-011-021-031-041-051-061-071-081-091-101-111-121-131-141-151-161-171-181-19 + 0 +64 +64
    2 0-200-210-220-230-240-250-260-270-280-290-300-310-320-330-340-350-360-370-380-39 +20 + 0 +20
    3 1-201-211-221-231-241-251-261-271-281-291-301-311-321-331-341-351-361-371-381-39 +20 +64 +84

    Er is dus een omzetting nodig. Nu blijkt ook dat de regel-nummering eenvoudig geregeld wordt met bit 6 van het Cursor-Commando: "DDRAM Address Set", of te wel binair %1yxx.xxxx. Is deze bit LAAG dan gaat de cursor naar de eerste of de derde regel (= regel 0 en 2) en is deze HOOG dan gaat de cursor naar de tweede of vierde regel (= regel 1 en 3).

    Om deze omzetting gemakkelijk te realiseren (tijdens het programmeren van de vele Lcd-teksten wil je je niet bezig hoeven te houden met een aparte cursor-nummering), is er hiervoor voorzien in een funktie.

  • Lcd_Gotoxy(byte x, byte y): Eerst wordt er gecontroleerd (funktie minmax()) op de waarde van de Cursor positie. Met linksboven de positie (0;0), loopt de X vanaf 0 tot en met 19 en de Y vanaf 0 tot en met 3.

    Met maar 4 mogelijke waardes voor de Y is een CASE-statement gebruikt voor het omzetten van de regel-nummering. En dan is het een questie van een eenvoudige optelling om de juiste waarde te krijgen. Hierbij moet nog de juiste "Commando"-bit (%1000.0000 = $80) worden opgeteld en dan kan de waarde naar het display wordt gestuurd.

    Plaatsen van teksten en nummers op het display.

    Voor het eenvoudig plaatsen van teksten en nummers op het display zijn ook fonkties gemaakt.

    • Lcd_Print (char* ss): Er wordt een string opgegeven en de tekst hierin wordt op het scherm geplaatst. Dit gaat net zo lang door totdat de tekst-terminatie teken met waarde #00 is bereikt.

    • Lcd_Number (unsigned long vv, byte num): Een nummer VV (van Value) wordt (in decimale notatie) op het display getoond. Men kan opgeven (NUM) hoeveel cijfers er getoond moeten worden. Er worden hierbij twee arrays gebruikt: Power10[] om de decimalen uit het getal te halen en Cijfer[] als een korte omzetting van het cijfer naar ASCII (0..9).

      Er vindt een controle plaats op de parameter NUM (met minmax() en daarna worden de cijfers (met een FOR-staement) 1 voor 1 uit het getal gehaald en op het display getoond (met Lcd_Out()).

    • Lcd_HexNumber (unsigned long vv, byte num): Een nummer VV (van Value) wordt (in hexadecimale notatie) op het display getoond. Men kan opgeven (NUM) hoeveel cijfers er getoond moeten worden. Er worden hierbij twee arrays gebruikt: Power16[] om de hexadecimalen uit het getal te halen en Hex[] als een korte omzetting van het cijfer naar ASCII (0..9 en A..F).

      Er vindt een controle plaats op de parameter NUM (met minmax() en daarna worden de cijfers (met een FOR-staement) 1 voor 1 uit het getal gehaald en op het display getoond (met Lcd_Out()).

    Display Achtergrond Verlichting.

    De RGB-Achtergrond Verlichting van het Display moet ook nog eenvoudig worden aangestuurd. Zoals bij het Lcd-Display is vermeld, is de Achtergrond verlichting rechtstreeks op de Mega aangesloten op de "digitale" pinnen 11, 12 en 13. Het argument is bij deze het volgende: In geval van zware storing (in de voeding of zo), kan de Mega via een RGB-code (of zo) laten zien dat er iets aan de hand is. Deze eventuele toekomstige uitbreiding lijkt mij op dit moment wel heel handig om alvast "in te bouwen".

    Nu blijken deze pinnen 11, 12 en 13 ook nog naast elkaar op een Arduino Mega poort te zitten en wel op Port B, de bitjes 5 tot en met 7. Dus in plaats van via losse aanroepen met de funktie DigitalWrite(), kunnen de bitjes met 1 oproep naar PORTB worden gestuurd. En dat is precies wat de volgende funktie doet.

  • Write_Lcdback(byte LL): De parameter LL (van Licht, of Light) bevat de RGB-informatie van de kleur die het display moet krijgen. Na een controle (met een AND-bewerking &) worden de bitjes ge-inverteerd (EXOR-bewerking ^).

    De betreffende bitjes van de DDRB (Data Direction Register) worden op UITGANG gezet (HOOG gemaakt). Na een filtering van de al aanwezige bitjes op PORTB (AND-bewerking) wordt de RGB-informatie er bij toegevoegd (OR-bewerking) en naar de PORTB teruggestuurd.

    Een heel verhaal voor maar 4 regeltjes met korte recht-toe-recht-aan code.

    Toekomstige Optie - Interrupt gebruiken om het display te beschrijven.

    Blijkt het schrijven naar het Lcd-Display toch nog te veel tijd in te nemen, in vergelijking met de andere functies van het programma, dan zijn er al gedachten om dit via een Interrupt te laten verrichten. De Hardware is er immers voor aanwezig.

    Het basis-idee is om de tekens (van de funktie Lcd_Out()) in een buffer te schijven, bestaande uit twee arrays van 8 bits, namelijk 1 voor het Register nummer RS en 1 voor de waardes (en tekens) BB.

    Was de buffer leeg, dan wordt de waarde direkt naar het display geschreven en wordt de Hardware Timner (Automatisch Hardware-matig (zie Decoder-print)) gestart.

    Elke volgende waarde die naar het Display toe moet, wordt in deze buffer geplaatst.

    Na de 40µsec geeft de Hardware Timer een puls naar de Arduino Mega (via een Interrupt-Pin - hier zijn diverse Pinnen voor beschikbaar). Er wordt een Interrupt-routine gestart, die de volgende Register-nummer (Commando of Data) en waarde naar het Display toe stuurt. De Hardware Timer wordt weer (Automatisch) gestart.

    Dit herhaalt zich totdat de buffer leeg is. Dan is er geen informatie meer om naar het Display toe te sturen en wordt de Hardware Timer niet meer gestart ... Totdat een volgende waarde "in de buffer" wordt gebracht.

    Voordeel hiervan is dat het programma alleen tot een lange pauze komt, wanneer de Buffer vol raakt. En dan moet er een oplossing komen om dit netjes af te handelen, zonder dat er (bijvoorbeeld) Midi-informatie verloren gaat. Elke Lcd schrijf-aktie kost toch zo'n 40µsec - tegen een Midi-byte dat met ongeveer 320µsec binnen komt.

    Maar de invoering van deze Interrupt-akties komt pas wanneer het ArSid programma duidelijk problemen heeft met de afhandeling van het Display.

    Memo-vak:
    Zie Source-codes voor een interrupt voorbeeld, wat getriggerd wordt met twee Digital-Port aansluitingen.


  • [Tekst] [Afbeeldingen] [Aansluitingen] [Broncodes]

    Afbeeldingen

    lib_lcd_01-lcd.jpg
    1/7: lib_lcd_01-lcd.jpg.
    lib_lcd_02-initialisatie.jpg
    2/7: lib_lcd_02-initialisatie.jpg.
    lib_lcd_03-instructies.jpg
    3/7: lib_lcd_03-instructies.jpg.
    lib_lcd_04-check.jpg
    4/7: lib_lcd_04-check.jpg.
    lib_lcd_05-overloop.jpg
    5/7: lib_lcd_05-overloop.jpg.
    lib_lcd_06-2x40_display.jpg
    6/7: lib_lcd_06-2x40_display.jpg.
    lib_lcd_07-fonttabel.jpg
    7/7: lib_lcd_07-fonttabel.jpg.

    [Tekst] [Afbeeldingen] [Aansluitingen] [Broncodes]
    Broncode: [1: Lib: Lcd-Display (.cpp)] [2: Lib: Lcd-Display (.h)] [3: Interrupt Voorbeeld]

    1: De broncode van Lib: Lcd-Display (.cpp)

    (Sun 17 February 2019) ArSid_Lcd.cpp: Het afhandelen van het Lcd Display.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    //=======================================================================================
    //
    // ArSid_Lcd - The ArSid_Lcd Library
    //
    // All Functions, needed For Writing Data To The Lcd.
    // Here is used an LCD-display with RGB-backlight in 8-bit mode.
    //
    //=======================================================================================

    #ifndef ARSID_LCD_CPP
    #define ARSID_LCD_CPP

    // Include some ArSid_ Libraries
    #include "Arduino.h"
    #include "ArSid_Lcd.h"
    #include "Basic_Funk.h"
    #include "ArSid_IO.h"

    //=====================================================================================

    //  33              333333      33333333
    //  33            33      33    33      33
    //  33            33            33      33
    //  33            33            33      33
    //  33            33            33      33
    //  33            33      33    33      33
    //  3333333333      333333      33333333

    const byte lcd_mask     = 0b00000100;   // Mask Lcd Ready Signal.
    const byte Lcd_timer    = 0b00000100;   // Lcd bit at the Controlbus
    const byte Lcd_register = 0b00000001;   // Lcd register Select.
    const byte Lcd_enable   = 0b00001000;   // Lcd Enable.

    void Write_Lcdback(byte LL)
    { // Write byte to the Lcd Backlight
      LL = LL & 0b00000111;
      LL = LL ^ 0x07;
      DDRB = DDRB | 0b11100000;             // Make Pin 11, 12, 13 output. The LCD-backlights are connected to these pins.
      PORTB = (PORTB & 0x1F) | ( LL << 5);  // Write the RGB-code
    }

    void Lcd_Init()
    { // Initialize The Lcd Display
      Poke(3,0b00000000);           // Make Lcd-Enable Low
      delay(20);                          // Wait while the LCD-unit itself is initialized
      // Sent Lcd Initialisation, 3 times (as described in the datasheet).
      Lcd_Out(0,0b00111000); delay(5);   // 1st LCD write (set 8bits interface)
      Lcd_Out(0,0b00111000); delay(1);   // 2nd LCD write (set 8bits interface)
      Lcd_Out(0,0b00111000); delay(1);   // 3rd LCD write (set 8bits interface)
      // Sent Lcd Instructions
      Lcd_Out(0,0b00111000);    // Function-Set 8-bits, 2-lines, 5x8-font, <none>, <none>
      Lcd_Out(0,0b00001000);    // Set Display On/Off Control: Cursor, Blinking
      Lcd_Out(0,0b00001100);    // Set Display On/Off Control: Cursor, Blinking
      Lcd_Out(0,0b00010100);    // Set Cursor/ Display Shift: Shift/Cursor, Right/Left, <none>, <none>
      Lcd_Out(0,0b00000110);    // Entry Mode Set: Inc/Dec, DisplShift
      Lcd_Out(0,0b00000001);    // Clear Display
      delay(2);
      Lcd_Out(0,0b10000000);    // GotoXY(1,0)
    }

    void Lcd_Clr()
    { // Clear the Lcd Display
      Lcd_Out(0,0b00000001);    // Clear Display
      delay(2);
    }

    void Lcd_Gotoxy(byte x, byte y)
    { // Place cursor at position (x,y) (left-up is (0,0))
      byte bb=0;
      x = minmax (x, 0, 19);
      y = minmax (y, 0,  3);
      switch (y)
        { case 0: { bb = 0x80 +  0 + x;
                    break;
                  }
          case 2: { bb = 0x80 + 20 + x;
                    break;
                  }
          case 1: { bb = 0x80 + 64 + x;
                    break;
                  }
          case 3: { bb = 0x80 + 84 + x;
                    break;
                  }
        }
      Lcd_Out(0,bb);
    }

    void Lcd_Print (char* ss)
    { // Print a string with characters
      byte qq = 0;
      while ( ss[qq] != 0 )
        { // check every char if it is in the table.
          Lcd_Out(1,ss[qq]);
          qq=qq+1;
        }
    }

    void Lcd_Number (unsigned long vv, byte num)
    { // Print a number VV on the display in NUM numbers (1..10)
      const long power10 [11] = {1, 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 };
      const char cijfer[10] = "0123456789";
      num = minmax (num, 1, 10);
      byte ss=0;
      for (byte qq = num; qq > 0; qq = qq - 1)
        { ss = ( vv / power10 [qq] ) % 10;
          Lcd_Out (1,cijfer[ss]);
        }
    }

    void Lcd_HexNumber (unsigned long vv, byte num)
    { // Print a number VV on the display in NUM numbers (1..10)
      const long power16 [9] = {0x01, 0x01, 0x10, 0x0100, 0x1000, 0x00010000, 0x00100000, 0x01000000, 0x10000000 };
      const char hex [16] = "0123456789ABCDEF";
      num = minmax (num, 1, 8);
      byte ss=0;
      for (byte qq = num; qq > 0; qq = qq - 1)
        { ss = ( vv / power16[qq] ) % 16;
          Lcd_Out (1,hex[ss]);
        }
    }

    void Lcd_Out(byte rs, byte bb)
    { // Rs  0  %00000000 = Instruction Register
      // Rs  1  %00000001 = Data Register
      // En  0  %00000000 = Enable     (Falling Edge)
      // En  1  %00001000 = Not Enable (Raising Edge) = Lcd_enable
      rs=rs & Lcd_register;
      // Wait until the Lcd-Timer has ended
      while (PING & Lcd_timer) == 0)         // PING = P Input port G
        { // Do Nothing
        }

      Poke(3,Lcd_enable | rs); // Make Enable High
      Poke(2,bb);
    //  delayMicroseconds(1);
      Poke(3,0b00000000 | rs); // Make Enable Low
    //  delayMicroseconds(1);
    }

    //=====================================================================================

    #endif // ARSID_LCD_CPP

    Broncode: [1: Lib: Lcd-Display (.cpp)] [2: Lib: Lcd-Display (.h)] [3: Interrupt Voorbeeld]

    2: De broncode van Lib: Lcd-Display (.h)

    (Sun 17 February 2019) ArSid_Lcd.h: Het afhandelen van het Lcd Display.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    //=======================================================================================
    //
    // ArSid_Lcd - The ArSid_Lcd Library
    //
    // All Functions, needed For Writing Data To The Lcd.
    // Here is used an LCD-display with RGB-backlight in 8-bit mode.
    //
    //=======================================================================================

    #ifndef ARSID_LCD_H
    #define ARSID_LCD_H

    #include "Arduino.h"

    //=====================================================================================

    void Write_Lcdback(byte LL);
      // Write byte naar Lcd Backlight

    void Lcd_Init();
      // Initialize The Lcd Display

    void Lcd_Clr();
      // Clear the Lcd Display

    void Lcd_Gotoxy(byte x, byte y);
      // Place cursor at position (x,y) (left-up is (0,0))

    void Lcd_Print (char* ss);
      // Print a string with characters

    void Lcd_Number (unsigned long vv, byte num);
      // Print a number VV on the display in NUM numbers (1..10)

    void Lcd_HexNumber (unsigned long vv, byte num);
      // Print a number VV on the display in NUM numbers (1..10)

    void Lcd_Out(byte rs, byte bb);
      // Write a Byte-Char BB to the Lcd into register RS

    //=====================================================================================

    #endif // ARSID_LCD_H

    Broncode: [1: Lib: Lcd-Display (.cpp)] [2: Lib: Lcd-Display (.h)] [3: Interrupt Voorbeeld]

    3: De broncode van Interrupt Voorbeeld

    (Sun 17 February 2019) Voorbeeld voor het implementeren van een Hardware Pin-gegenereerde Interrupt.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    Noot Vooraf: Dit is slechts een voorbeeld van hoe een Interrupt ge-implementeerd kan worden. Het hier
    gegeven voorbeeld gaat over het afhandelen van een "Roteer-knop" (Rotary-Knob) met behulp van Interrupts.

    ================================================================================================================
    See also: https://www.arduino.cc/reference/en/language/functions/external-interrupts/attachinterrupt/
    for Attaching Interupts to a function.
    =================================================================================================================

    /*  roto_jw4.ino -- JW, 29 September 2015 --
     *
     *  A 4-state state-machine implementation of rotary encoding for KY-040 rotary knobs.  The state-machine
     *  picture at https://e2e.ti.com/support/microcontrollers/hercules/f/312/t/318762 in a Feb 4, 2014 7:40 PM
     *  post by Anthony Seely shows counts increasing on transitions 10 -> 11 -> 01 -> 00 -> 10 and decreasing on
     *  transitions the other way.  Transitions between 00 and 11 or 10 and 01 are invalid.
     *
     *  This code detects valid transitions by (abOld xor abNew) equaling 1 or 2.  It detects up-count events by
     *  the tri-bit value ABA' (where A' is the new reading on pin A) being equal to 1, 2, 5, or 6 (a bit mask of
     *  0x66)
    , and down-count events by ABA' being equal to 0, 3, 4, or 7 (a bit mask of 0x99).
     *
     *  On a KY-040 unit I tested, there are 30 detent positions per turn. With this unit the code generates 60
     *  counts per turn, which can be seen individually as one turns the rotor slowly.  Odd counts appear between
     *  detents, even counts at detents.
     *
     *  Set quadrature-signal pin numbers, via PinA and PinB constants. Set IPINMODE to INPUT_PULLUP if there are
     *  no external pull-ups on encoder AB pins, else set IPINMODE to INPUT
     *
     */


    enum { PinA=2, PinB=3, IPINMODE=INPUT };

    static   byte abOld;    // Initialize state
    volatile int count;     // current rotary count
             int old_count; // old rotary count

    void setup()
    { pinMode(PinA, IPINMODE);
      pinMode(PinB, IPINMODE);
      attachInterrupt(0, pinChangeISR, CHANGE); // Set up pin-change interrupts
      attachInterrupt(1, pinChangeISR, CHANGE);
      abOld = count = old_count = 0;
      Serial.begin(115200);
      Serial.println("Starting Rotary Encoder Test");
    }

    void loop()
    { if (old_count != count)
         { Serial.print(millis());
           Serial.print("  ");
           Serial.println(count);
           old_count = count;
         }
    }

    // On interrupt, read input pins, compute new state, and adjust count
    void pinChangeISR()
    { enum { upMask = 0x66, downMask = 0x99
           };
      byte abNew = (digitalRead(PinA) << 1) | digitalRead(PinB);
      byte criterion = abNew ^ abOld;
      if (criterion==1 || criterion==2)
         { if ( upMask & ( 1 << (2*abOld + abNew/2) ) )
              count++;
           else count--;       // upMask = ~downMask
         }
      abOld = abNew;           // Save new state
    }


    Broncode: [1: Lib: Lcd-Display (.cpp)] [2: Lib: Lcd-Display (.h)] [3: Interrupt Voorbeeld]
    [Tekst] [Afbeeldingen] [Aansluitingen] [Broncodes]