Arduino Dot-Matrix

Fra Kommunikation-IT Holstebro HTX
Skift til: navigering, søgning
Dot Matrix modul

Grundlæggende forudsætninger

Modulet er baseret på en MAX7219 driver, der kan styres af 3 serielle signaler.

Man kunne vælge at basere det på en færdigskrevet bibliotek[1], som ville gøre det enkelt at gå til LED-Matrix-modulet. I stedet er det baseret på software skrevet fra bunden til at styre modulet med. Den grundlæggende software er beskrevet her, og er udviklet ud fra databladet til MAX7219.

Modulet er købt ved aliexpress.com[2].

Datablad

Databladene der kan fås går på selve driver-chippen der omsætter de serielle signaler til signaler der kan styre en matrix.

Databladet søges blot på MAX7219 datasheet[3]

Databladet bærer tydeligt præg af at kredsen oprindeligt er designet til at styre 8 stk. 7-segment-display

Tilslutning til Arduinoen

Der er 5 tilledninger i bunden af modulet, hvor de to er GND og +5V, der kan forsynes fra Arduioen.

De 3 sidste signaler er CS, CLK og D-IN, der kan styre kredsen så man får adgang til de registre de ligger i MAX7219 kredsen.

For at kunne styre de 3 signaler skal de sættes til output i Arduino-programmet.

Til testen kobles Dot-matrix displayet til Arduinoen som vist her:

Dot-Matrix-display-setup.png
Opkobling af Dot-matrix display til Arduinoen

På toppen af modulet er der også 5 tilledninger, hvor GND, +5V og CLK løber lige igennem. Det burde være således at man kan koble videre, og styre flere moduler med disse signaler - dette er ikke implementeret i dette tilfælde, så på det tidspunkt hvor der skal flere moduler kobles til samme Arduino som illustreret i Arduino Lys-avis, så anvendes D-IN som et fælles signal, og CS kobles til hver sin pin.

Dot-Matrix-display-praktisk.jpg
Praktisk opkobling af Dot-matrix display til Arduinoen

Princippet i kommunikationen med MAX7219

For at kunne kommunikere med MAX7219 anvendes de 3 signaler som beskrevet her oven over.

Man skal sende 16 bit til kredsen hver gang, hvor de 4 første bit i denne sammenhæng ikke betyder noget, men de næste 4 angiver adressen på hvilket register man vil skrive til, og de sidste 8 bit er det man skriver i registeret. Kommunikationen med kredsen kan illustreres som vist her:

timing diagram for seriel kommunikation med MAX7219
timing diagram for seriel kommunikation med MAX7219[3]

Som det ses på timing-diagrammet trækkes CS først lav, og de 16 bit clockes over til kredsen, hvorefter CS sættes høj igen.

Grundlæggende test af Dot-matrix

For at teste igennem at der er hul igennem til Dot-matrix modulet opbygges en test-software der kan hentes i denne ZIP-fil. Den grundlæggende test ligger i Dot_Matrix_grundl.

Først defineres de 3 ben der kommunikeres på:

const int din = 2;
const int cs = 3;
const int clk = 4;

Disse sættes op til output, hvor CS og CLK sætte til start-niveauerne. Til slut anvendes en procedure til at initialisere kredsen, hvor det angives at kredsen skal kunne outputte alle 8 bit og ellers fungere normalt - dog med lav display-styrke for at spare på strømmen til senere eksperimenter.

void setup() {
  // put your setup code here, to run once:
  pinMode (din, OUTPUT);
  pinMode (cs, OUTPUT);
  pinMode (clk, OUTPUT);
  digitalWrite(cs, HIGH);
  digitalWrite(clk, LOW);
  disp(0x0B, 0x07);  // Scan Limit - Display alle bit
  disp(0x09, 0x00);     // Decode Mode - Ingen dekodning
  disp(0x0C, 0x01);  // Shutdown - Normal operation
  disp(0x0F, 0x00);  // Display Test - Slået fra
  disp(0x0A, 0x01);  // Intensity - low level
}

For at kunne sende både disse initialiserings-kommandoer, men også senere reelle data til displayet, så etableres de to følgende rutiner, hvor den første kan clocke en byte ind i kredsen, den næste rutine angiver hvilket register der skal lagres i inde i kredsen, hvilket kræver to parametre til rutinen, en med adresse og en med data.

sendByte sender en byte, som en del af det at kommunikere med kredsen. Dette sker ved at clocke de 8 bit der er i byten ind i kredsen.

void sendByte(byte data) {
  for (int n = 0; n < 8; n++) {
    digitalWrite(din, data & 0x80);
    data <<= 1;
    digitalWrite(clk, HIGH);
    digitalWrite(clk, LOW);
  }
}

disp skal have en adresse og en databyte, hvor den så vil henvende sig til det register der er angivet en adresse på og sende databyten til adressen.

void disp(byte adr, byte data) {
  digitalWrite(cs, LOW);
  sendByte(adr);
  sendByte(data);
  digitalWrite(cs, HIGH);
}

Måden der så testes på om der kommer noget igennem til Dot-matrix displayet er ved at lave en variabel, som tælles en op hver gang der clockes noget nyt ud til modulet. Dette foretaget i en for-loop, hvor adressen tælles fra 1 til og med 8, så alle 8 adresser rammes. Ved at dette løber igennem nok gange, så prøves alle punkter i Dot-matrixen af.

Dette foretages med følgende kode:

byte d = 0;

void loop() {
  for (int n = 1; n <= 8; n++) {
    disp(n, d);
    d++;
    delay(100);
  }
}

Yderligere test af et display-modul

For at udfordre funktionen i displayet lidt, så forsøges at æave det sådan at en dot "løber" rundt i kanten, for senere at "spirale" sig ind mod midten, hvorefter der startes forfra, så prikken hele tiden løber ind mod midten, og starter forfra når den nås.

I første omgang blev dette forsøgt ved at tilpasse nogle loops i koden, men uanset hvordan det blev gjort, så løb den enten skævt eller sprang enkelte dots over. Årsagen til dette er at der hele vejen indad skal løbes to gange med samme antal, og at det antal skal formindskes indtil det når midten - det mønster fungerer, lige bortset fra den yderste kant, hvor der skal løbes 7 prikker igennem 3 gange efter hinanden.

For at etablere dette på en anden måde, så opbygges en datastruktur som følger:

const byte man [16] [3] = { {0, 2, 7},  // Definition af de 16 sider der skal tegnes
                            {1, 1, 7},  // Betydningen af de 3 tal i siderne er:
                            {0, 0, 7},  // x-flytning 
                           {-1, 1, 6},  // y-faktor
                            {0, 2, 6},  // Antal i siden 
                            {1, 1, 5}, 
                            {0, 0, 5}, 
                           {-1, 1, 4}, 
                            {0, 2, 4}, 
                            {1, 1, 3}, 
                            {0, 0, 3}, 
                           {-1, 1, 2}, 
                            {0, 2, 2}, 
                            {1, 1, 1}, 
                            {0, 0, 1}, 
                            {0, 1, 1} };

Datastrukturen er opbygget på den måde at hver sæt punkter har en linje med 3 tal. De første 15 er til de reeddel flytninger, mens den sidste bare er en dummy til at få vist sidste element i den forrige.

  • Første tal er hvad der skal lægges til x-placeringen i displayet hver gang punktet flyttes.
  • Andet tal er hvad der skal ganges med i y-tallet, dog med den lille specielle ting, at der hvor der står 0 betyder det at der skal divideres med 2, da man ikke kan angive 0.5 i en byte-variabel.
  • Tredje tal er antallet af gange den aktuelle linje skal udføres

Til at angive postionen af prikken, så sættes en x og en y-koordinat, der i starten begge er på 1.

Værdi-området for de to variabler er forskelligt, da x angiver hvilken kolonne data skal placeres i, så den går fra 1 til 8 og y angiver data der skal overføres, hvor 1 betyder den mindst betydende bit tændt, og ved at gange med 2, så flyttes bitten en position. På denne måde bliver de mulige værdier er 1, 2, 4, 8, 16, 32, 64 og 128.

byte y = 1;
byte x = 1;

Koden der afvikles i loop ser ud som følger:

void loop() {
  for (int i = 0; i < 16; i++) {  // gennemløb alle 16 sider
    for (int n = 0; n < man[i][2]; n++) {  // gennemløb antal punkter i en side
      // Vis de ønskede punkt
      disp(x, y);
      delay(50);
      disp(x, 0);
      // Skift til næste punkt der skal vises
      x += man[i][0];
      if (man[i][1] > 0) {
        y *= man[i][1];
      } else {
        y /= 2;
      }
    }
    // Til test
    Serial.print(y);
    Serial.print("\t");
    Serial.println(x);
  }
  Serial.println("--------------");
  // Start forfra
  y = 1;
  x = 1;
}

Koden laver et komplet gennemløb af hele displayet hver gang loop kaldes.

Den første for-loop vælger de 16 linjer i datastrukturen, en efter en.

Den næste for-loop afvikles for hver linje, og den gennemføres det antal gange der er angivet i data-strukturen.

Da x og y har en startværdi der skal vises, så vises den aktuelle værdi i 50 ms. Dette gøres ved hjælp af de rutiner der blev skitseret i den foregående test. Efter visningen slukkes prikken igen, ved at displaye værdien 0.

Herefter ændre x- og y-værdien som det er angivet i data-strukturen. I dette eksempel flyttes kun den ene, og hver gang kun med et enkelt trin.

Før loop afsluttes, så stilles x- og y-værdierne tilbage på 1, så de er klar til næste kald af loop.

Visning af testen

For at vise funktionen af denne test, så er der en lille video her:


Direkte link

Flere moduler sammen

For at give mere mulighed for at vise noget, så kan man koble flere moduler til Arduinoen. Dette er vist i Arduino Lys-avis.

Referencer

  1. Henvisning til GitHUB LED-matrix Bibliotek
  2. Købsside ved aliexpress.com til modulet
  3. 3,0 3,1 Databladet på en MAX7219 og MAX7221