Baco Led Matrix

Dit topic is gesloten


Baco heeft een vrij groot led-matrixboard in de aanbieding. Ik heb er vier van gekocht.

http://www.baco-army-goods.nl/homepage/ledmatrix-bord-fds-184.html

Ik probeer het ding te ontcijferen, daarvoor heb ik hulp nodig. Waar ik me zorgen over maak is dat er een CPLD (programmable logic) van het type IM4A5-64 in zit.

Nu heb ik alleen ervaring met het programmeren van AVR's (Arduino). Nu is mijn vraag, is dit chippie gewoon een soort van voorgeprogammeerde bus-expander, of moet ik een nieuwe taal/chip gaan bestuderen voordat ik dit ding kan gebruiken?

Ik zal morgen schema's posten.
Is iets later geworden, wel hoge resolutie!
http://www.uploadarchief.net/files/download/fds184.pdf
In die surtronic lichtkranten zaten toch ook FDS-borden? Ik heb hier een pdf-je van een FDS101-bord, die zal zo'n display wel kunnen aansturen. Vermoedelijk zal de optische link hetzelfde zijn:

"The display boards
are driven by means of a fiber optic datalink (Toslink). Other interfaces are optional.

DISPLAY CONTROL CIRCUITRY
The function of the control logic is to send and control the data to the display boards.
This is achieved by sending out ‘packets’ of data, the number of such packets being
equal to the number of rows to be scanned in the display board(s). Each stage involves
the shifting of data to the display board, called burst mode, followed by the showing of
that data on the selected row, called display mode.
This is accomplished using PLD U11, a parallel in / serial out shift register U8 and the
fibre optic output circuit TOTX111 (CN11). Each byte which is to be sent to the display
board is converted from parallel to serial using register U8. The output of the register is
connected to the PLD input pin 33.
The PLD controls the serial input signal and feeds it to the input of the transmission
circuit for the display boards. On the FDS101 controller board three different interfaces
are available to transport the serial data to the display boards:
2.5.1 FIBRE OPTIC
This makes use of a connectorless fibre optic
transmitter (CN11, TOTX111). The nylon
fibre must be cut squarely with a sharp knife
and plugged directly into the TOTX111. To
insert or release the nylon fibre, simply press
the clamp release ring. (see sketch)."
Rob W.

Golden Member

Op 7 maart 2013 22:50:48 schreef roosmcd:
In die surtronic lichtkranten zaten toch ook FDS-borden? Ik heb hier een pdf-je van een FDS101-bord, die zal zo'n display wel kunnen aansturen. Vermoedelijk zal de optische link hetzelfde zijn:


Ding! Ding! U gaat door voor de koelkast!

Dit zijn inderdaad Surtronic borden. Die uit de startpost zijn afkomstig van de displays die op Amsterdam CS hebben gehangen.

Ohja, de voedingspanning is 7.5 Volt voor de leds. Weet even niet uit mijn hoofd of ze ook nog een aparte logic spanning hebben. Als dat er wel op zit zal die 5 volt moeten zijn.

[Bericht gewijzigd door Rob W. op 7 maart 2013 23:02:27 (16%)]

"Any sufficiently advanced technology is indistinguishable from magic."
@JesperR,

Hmm, blijkbaar voldoe je dan niet aan de sequentie die het bord verwacht om de lijn weer te geven wat in de schuif registers zit.

roosmcd heeft een stukje uit een manual ge copy paste die spreekt over packets. Dus misschien moet je voldoen aan een of ander packet formaat. Als je bv, garbage erin stuurt, zie je dan ook de spi richting de schuifregisters klokken? Wanneer klokt hij eigenlijk? Heb je een logic analyser waarin je lange traces kan opslaan die getriggerd worden op de latch enable van de schuifregisters?

Heeft die CPLD een doorlusstand of stuurt hij alles door naar de schuif registers en klokt hij alles in naderhand?

Als alles lijn georienteerd gebeurt moet er een soort "synchroniserende sequentie" zijn om de lijn selectie te resetten, je weet bij poweron niet waar die teller mogelijk zou zitten.

Ik vermoed dat de CPLD meer dan alleen de data slicing en doorlussen doet maar wat meer intelligentie bevat.
A byte walks into a bar and orders a pint. Bartender asks him "What's wrong?" Byte says "Parity error." Bartender nods and says "Yeah, I thought you looked a bit off."
Op 7 maart 2013 22:50:48 schreef roosmcd:
In die surtronic lichtkranten zaten toch ook FDS-borden? Ik heb hier een pdf-je van een FDS101-bord, die zal zo'n display wel kunnen aansturen. Vermoedelijk zal de optische link hetzelfde zijn:

"The display boards
are driven by means of a fiber optic datalink (Toslink). Other interfaces are optional.

DISPLAY CONTROL CIRCUITRY
The function of the control logic is to send and control the data to the display boards.
This is achieved by sending out ‘packets’ of data, the number of such packets being
equal to the number of rows to be scanned in the display board(s). Each stage involves
the shifting of data to the display board, called burst mode, followed by the showing of
that data on the selected row, called display mode.
This is accomplished using PLD U11, a parallel in / serial out shift register U8 and the
fibre optic output circuit TOTX111 (CN11). Each byte which is to be sent to the display
board is converted from parallel to serial using register U8. The output of the register is
connected to the PLD input pin 33.
The PLD controls the serial input signal and feeds it to the input of the transmission
circuit for the display boards. On the FDS101 controller board three different interfaces
are available to transport the serial data to the display boards:
2.5.1 FIBRE OPTIC
This makes use of a connectorless fibre optic
transmitter (CN11, TOTX111). The nylon
fibre must be cut squarely with a sharp knife
and plugged directly into the TOTX111. To
insert or release the nylon fibre, simply press
the clamp release ring. (see sketch)."


@roosmcd: Ik heb even gegoogled maar niets gevonden, is die manual vrij beschikbaar? Kan je deze naar geinteresseerden sturen of in het upload archief zetten? Zou veel tijd schelen qua reverse engineering.
A byte walks into a bar and orders a pint. Bartender asks him "What's wrong?" Byte says "Parity error." Bartender nods and says "Yeah, I thought you looked a bit off."
blurp

Golden Member

Hallo,

Ik heb gister weer een paar commando's voor de originele CPLD gevonden:
0x0211 : Blokker schuifregister updates
0x020f : Sta schuifregisterupdates weer toe

Behalve 0x0211 zijn er nog een paar codes die hetzelfde lijken te doen. Of die ook hetzelfde zijn (zuinige decodeerlogica in de CPLD) of stiekem wat anders betekenen is een open vraag.

Verder vermoed ik dat het commando voor "Lijn blijft aan staan na het selecteer-lijn-commando(0x02a<x>)" wat ingewikkelder is, een voor een alle 256 0x02xx commando's proberen heeft hem niet boven water gehaald.
Na het lezen van veel info van jullie over de FDS-132 matrixborden op Circuits Online en het Nedrlands Arduino Forum heb ik ook 3 van deze borden bij Baco besteld.
1 was er kapot: schuifregister chip vanaf gebroken. Baco heeft me zonder kosten een nieuwe gestuurd (terwijl ik, voordat ik er achter kwam dat de oude kapot was, de CPLD er al vanaf had gebrand...). Dat is echt service!

Ik heb veel van jullie programma's en libraries gedownload en nog meer geprobeerd om er achter te komen hoe het bord werkt.
Uiteindelijk door inspiratie van o.a. blurp, zerobase, Rudi en Rolo (en vele anderen) een toepassing gemaakt voor mijn zoon: een Klok met diverse acties.
Gebaseerd op de originele lichtkrant van Rolo, uitbreiding met RTC en wat leuke schermacties als random text, curtain close (scherm zwart maken als gordijn sluiten) en een space invader die je scherm leeg komt eten.
Waarschijnlijk niet de beste code, maar het functioneert en wellicht kan het iemand helpen ook wat leuke dingen te doen met het LED board.

Verdere uitbreidingen die ik nog wil doen: proportional font(s) ( als in lib van Bart De Waal), ombouw maken zodat klok kan hangen, koppelen UNO met PC via RS323 om data te laten zien, scrollende tekst op 1 Row.

Een foto van UNO met RTC aangesloten
http://www.uploadarchief.net/files/download/uno_rtc2.jpg

en een filmpje van het scherm en de acties
http://www.youtube.com/watch?v=czUkzuXeas8


Hierbij de code:

code:
// Timer 1 Info :  http://playground.arduino.cc/code/timer1
// Using PROGMEM : http://arduino.cc/en/Reference/PROGMEM


// The matrix board is controlled by timer0 overflow interrupt. This gives a steady image and the display can be handled like a static type.
// The main code does not have to control the board, just set or clear bits in the data array to put some led's on or off.
// Logically it's organized in colums, 270 in total. This sofware defines column 0 as the upper left column and 271 is the right bottom column.
// This makes it more easy to arrange the text on the board. There is no checking if the text fits on the display.
//
// Column layout :    Line 0 : 0 to 89
//                    Line 1 : 90 to 179     
//                    Line 2 : 180 to 271
//
//
//
#include <DS1307RTC.h>
#include <Time.h>
#include <Wire.h>
#include <avr/pgmspace.h>             // Include pgmspace so data tables can be stored in program memory, see PROGMEM info
#include <SPI.h>                      // Include SPI comunications, used for high speed clocking to display shiftregisters
#include "TimerOne.h"                 // Include Timer1 library, used for timer overflow interrupt                                    
                                                        
const int strobePin = 10;             // Define I/O pins connected to the display board                 
const int clockPin = 13;                               
const int dataPin = 11;                                
const int resredPin = 9;                               
const int row_a = 5;                                      
const int row_b = 6;                                    
const int row_c = 7;                                     
const int rtcPlusPin = 17;            // +5V RTC module.  
const int rtcMinPin = 16;             // gnd RTC module.  
const int ClockPin = 2;
const int ClockPinMin = 1;

String tijd;
int blinkToggle=1;
int blinks=0;
String topText = "De tijd is";
int willekMinuut = random(0,59);     // generate random number between 0 en 59 
int willekMinuut2 = random(0,59);    // generate random number between 0 en 59  

byte Space1[7]; 


int RowCount = 0;             // Counter for the current row, do not change this value in the main code, it's handeld in the interrupt routine  
int teller=0;
unsigned long tijdNu=millis();

#include "font75.h";         // Standard 5x7 font ASCII Table

byte ColumnBytes[8][34];     // This is the data array that is used as buffer. The display data is in this buffer and the timeroverflow routine scans this
                             // buffer and shows it on the display. So read and write to this buffer to change display data.
                             // No strings are stored here, its the raw bit data that has to be shifted into the display.
                         
byte ColumnBytesBuffer[8][34];  // Backup for ColumnBytes[8][34]

// =========================================================================================
// Setup routine, mandatory.
// =========================================================================================

 void setup() {   
  pinMode (strobePin, OUTPUT);                              // Define IO          
  pinMode (clockPin, OUTPUT);  
  pinMode (dataPin, OUTPUT);  
  pinMode (row_c, OUTPUT);  
  pinMode (row_b, OUTPUT);  
  pinMode (row_a, OUTPUT);  
  pinMode (resredPin, OUTPUT);  
  pinMode (rtcMinPin, OUTPUT);  
  pinMode (rtcPlusPin, OUTPUT);  
  digitalWrite(rtcMinPin, LOW);                       // 0V (gnd) voor RTC module.  
  digitalWrite(rtcPlusPin, HIGH);                     // +5V voor RTC module.  
  digitalWrite (resredPin, LOW);                       
  digitalWrite (strobePin, LOW);                        
  //Serial.begin(9600);                               // Include serial routine, used for debugging and testing
  SPI.begin();                                        // Start SPI comunications
  SPI.setBitOrder(LSBFIRST);                          // Initialize SPI comunications
  Timer1.initialize(2000);                            // initialize timer1, overflow timer1 handles the display driver, period (in microseconds)
  Timer1.attachInterrupt(DisplayControl);             // attaches timer1 overflow interrupt routine
  randomSeed(analogRead(0));                          // voedt de randomgenerator aan de hand van waarde niet aangesloten analoge poort.  

   Space1[0]=B00011000;                               // create sprite Space Invaders
   Space1[1]=B00111100; 
   Space1[2]=B01111110; 
   Space1[3]=B11011011; 
   Space1[4]=B01111110; 
   Space1[5]=B11000011; 
   Space1[6]=B01100110;

 
// Start code here
  ClearDisplay();
  PlaceText(topText,17); 

 }  

// =========================================================================================
// loop routine, mandatory
// Take notice when using time crititical code the interrupt is running to control 
// the display.
// =========================================================================================

void loop()  
{  
   tmElements_t tm;  //activate RTC lib
   String uren;
   String minuten;
   String seconden;
   
   if (RTC.read(tm)) {                                                                     //read RTC
     if (tm.Hour<=9){uren="0"+String(tm.Hour);}else{uren=String(tm.Hour);}                 //leading zero's
     if (tm.Minute<=9){minuten="0"+String(tm.Minute);}else{minuten=String(tm.Minute);}     //if 
     if (tm.Second<=9){seconden="0"+String(tm.Second);}else{seconden=String(tm.Second);}   //UU,MM,SS < 10
 
     tijd = uren+":"+minuten+":"+seconden;
     PlaceText(tijd,110);
   }

     // put date in Row 3
     String maand[13] = {"leeg", "jan", "feb", "mrt", "apr", "mei", "jun", "jul", "aug", "sep", "okt", "nov", "dec"};
     String datum = String(tm.Day)+ " "+ maand[tm.Month]+ " "+ String(tmYearToCalendar(tm.Year)); 
     PlaceText (datum, 192);
 
   if (tm.Second == 10) randomText();                   // just for fun: show screen actions every minute
   if (tm.Second == 15) Curtain();                      // delete these 3 lines and use following functions
   if (tm.Second == 25) PlaceSprite();                  // to show them at random times

/*
   if (tm.Minute == willekMinuut && tm.Second < 1){      // put Random text in Row1
     randomText();   
     int willekMinuut = random(0,59);                    // generate randow number between 0 en 59.  
   }
 
   if (tm.Minute == willekMinuut2 && tm.Second < 1){    // Show sprite
     PlaceSprite();
     willekMinuut2 = random(0,59);                       // generate randow number between 0 en 59. 
   }

   if (tm.Minute == willekMinuut2 + 14 && tm.Second < 1){ // Clear like curtain
     Curtain();
   }
*/
}



// =========================================================================================
// Timer1 overflow intterupt routine, 
// Does the Display shifting and muliplexing
// =========================================================================================

 void DisplayControl()  
 {  
     digitalWrite(strobePin, LOW);                        // StrobePin LOW, so led's do not change during clocking
     digitalWrite (resredPin, LOW);                       // Display off to prevent ghosting  
 
       for (int q = 0; q<34; q++) {                       // Shift the bytes in for the current Row
       SPI.transfer(ColumnBytes[RowCount][q]);}
    
     digitalWrite (row_a, RowCount & 1);                  // Switch the current column on, will be on until next interrupt
     digitalWrite (row_b, RowCount & 2);                
     digitalWrite (row_c, RowCount & 4);            
     
     digitalWrite(strobePin, HIGH);                       // Strobe the shiftregisters so data is presented to the LED's 
     digitalWrite (resredPin, HIGH);                      // Display back on 

     RowCount++;                                          // Increment Row 
     if (RowCount == 7) RowCount = 0 ;                    // Row is 0 to 6
 }  

// =========================================================================================
// Place text on display, uses the standard 5x7 font
// Call this routine with the text to display and the starting column to place the text
// Example : PlaceText("FDS132",27); Places the text "FDS132" starting on column 27
// =========================================================================================

void PlaceText(String text, int ColPos) {
    byte displayByte;  
    char CurChar;
    int bitpos;
    int bytepos;
    int pixelpos;
    int charCount = text.length();
    int store = ColPos;

   for (int i = 0; i < charCount; i++) {                                     // Loop for all the characters in the string
    CurChar = text.charAt(i);                                                // Read ascii value of current character
    CurChar = CurChar - 32;                                                  // Minus 32 to get the right pointer to the ascii table, the first 32 ascii code are not in the table    
     
     for (int y = 0; y<7; y++) {                                             // y loop is used to handle the 7 rows
       for (int x = 0; x<5; x++) {                                           // x loop is the pointer to the indiviual bits in the byte from the table 
         displayByte = (pgm_read_word_near(Font75 + (CurChar*7)+y));         // Read byte from table 
         pixelpos = abs(ColPos - 271);                                       // Calculate start position to place the data on display
         bytepos = ((pixelpos)/8);                                           
         bitpos = (pixelpos) - (bytepos*8);
         boolean bitStatus = bitRead(displayByte, x);                        // Probe the bits   
         if(bitStatus == 0) bitClear(ColumnBytes[y][bytepos], bitpos);       // And set or clear the corrosponding bits in de display buffer   
         if(bitStatus == 1) bitSet(ColumnBytes[y][bytepos], bitpos);       
         ColPos++;                                                           
      }
       ColPos = store;                                                       // Reset the column pointer so the next byte is shown on the same position 
     }
    ColPos = ColPos + 6;                                                     // 6 is used here to give one column spacing between characters (one character is 5 bits wide)
    store = ColPos;                                                          // For more space between the characters increase this number 
 }
}      

// =========================================================================================
// Make a sprite clear the screen from Row3 to Row2
// =========================================================================================
void PlaceSprite() {
    byte displayByte;  
    char CurChar;
    int bitpos;
    int bytepos;
    int pixelpos;
    int ColPos = 269;
    int store = ColPos;
    int Sbytepos;
    int Sbitpos;

    for (int z = 0; z < 189; z++){      
     for (int y = 0; y < 7; y++) {                                           // y loop is used to handle the 7 rows
      for (int x = 0; x < 8; x++) {                                          // x loop is the pointer to the indiviual bits in the byte from the table 
         displayByte = Space1[y];                                            // Read byte from table 
         pixelpos = abs(ColPos + z - 271);                                   // Calculate start position to place the data on display
         if (pixelpos > 180) pixelpos = 180;                                 // only move on the bottom 2 bars
         bytepos = ((pixelpos)/8);                                           
         bitpos = (pixelpos) - (bytepos*8);
         boolean bitStatus = bitRead(displayByte, x);                        // Probe the bits   
         if(bitStatus == 0) bitClear(ColumnBytes[y][bytepos], bitpos);       // And set or clear the corrosponding bits in de display buffer   
         if(bitStatus == 1) bitSet(ColumnBytes[y][bytepos], bitpos);
         if(x < 1){ 
            Sbytepos = bytepos;
            Sbitpos = bitpos;
         }
         ColPos++;                                                           
      }
       ColPos = store;                                                       // Reset the column pointer so the next byte is shown on the same position 
     }
      delay(50);
      for (int d = 0; d < 7; d++){                                           // clear trailing set bits
        bitClear(ColumnBytes[d][Sbytepos],Sbitpos);
      }
  } 
 delay(500);
}      


// =========================================================================================
// Clears the screen like curtain
// =========================================================================================
void Curtain() {

  for (int i = 0; i < 35; i++){                //use byte ColumnBytesBuffer[8][34] as backup
      for (int j = 0; j < 7; j++){ 
        ColumnBytesBuffer[j][i] = ColumnBytes[j][i];
      }
    }  
  
   for (int k = 0; k < 6; k++){
     for (int l = 0; l < 8; l++){
      for (int m = 0; m < 7; m++){
       bitClear(ColumnBytes[m][k],l);            // clear right to left Row1
       bitClear(ColumnBytes[m][11-k],7-l);       // clear left to right Row1
       bitClear(ColumnBytes[m][11+k],l);         // clear right to left Row2
       bitClear(ColumnBytes[m][22-k],7-l);       // clear left to right Row2
       bitClear(ColumnBytes[m][22+k],l);         // clear right to left Row3
       bitClear(ColumnBytes[m][33-k],7-l);       // clear left to right Row3
       delay(20);
      }
     }
    delay (50);
   } 
   delay(500);
   for (int i = 0; i < 35; i++){                 // put buffer back
     for (int j = 0; j < 7; j++){ 
       ColumnBytes[j][i] = ColumnBytesBuffer[j][i];
     }
   }  
}


// =========================================================================================
// Put Random Text in centre of top row
// =========================================================================================
void randomText(){
  ClearDisplay();

  String topText[5] = {"Goeiedag!", "Hallo Alex", "Het is nu:", "Is het al tijd?", "De tijd is:"}; 
  int wilTop = random(0,4);
  
  int offsTop = (90 - topText[wilTop].length() * 6)/2;  // calculate offset to centre the text
  PlaceText (topText[wilTop], offsTop);
}


// =========================================================================================
// Clear display
// All bytes in buffer are set to zero
// =========================================================================================
void ClearDisplay() {
    for (int y = 0; y<8; y++) {     
       for (int x = 0; x<34; x++) {     
         ColumnBytes[y][x] = 0;
       }
    }     
}  


// =========================================================================================
// Clear Row1 (topRow)
// All bytes in topRow are set to zero (almost)
// =========================================================================================
void ClearRow1() {
    for (int y = 0; y<8; y++) {     
       for (int x = 22; x<34; x++) {     
         ColumnBytes[y][x] = 0;
       }
    }     
}  



en de font-code van Rolo
code:
// ASCII Table
PROGMEM  prog_uchar Font75[]  = {
0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,     //  
0x04 ,0x04 ,0x04 ,0x04 ,0x00 ,0x00 ,0x04 ,     // !
0x0A ,0x0A ,0x0A ,0x00 ,0x00 ,0x00 ,0x00 ,     // "
0x0A ,0x0A ,0x1F ,0x0A ,0x1F ,0x0A ,0x0A ,     // #
0x04 ,0x1E ,0x05 ,0x0E ,0x14 ,0x0F ,0x04 ,     // $
0x03 ,0x13 ,0x08 ,0x04 ,0x02 ,0x19 ,0x18 ,     // %
0x06 ,0x09 ,0x05 ,0x02 ,0x15 ,0x09 ,0x16 ,     // &
0x06 ,0x04 ,0x02 ,0x00 ,0x00 ,0x00 ,0x00 ,     // '
0x08 ,0x04 ,0x02 ,0x02 ,0x02 ,0x04 ,0x08 ,     // (
0x02 ,0x04 ,0x08 ,0x08 ,0x08 ,0x04 ,0x02 ,     // )
0x00 ,0x04 ,0x15 ,0x0E ,0x15 ,0x04 ,0x00 ,     // *
0x00 ,0x04 ,0x04 ,0x1F ,0x04 ,0x04 ,0x00 ,     // +
0x00 ,0x00 ,0x00 ,0x00 ,0x06 ,0x04 ,0x02 ,     // Comma
0x00 ,0x00 ,0x00 ,0x1F ,0x00 ,0x00 ,0x00 ,     // -
0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x06 ,0x06 ,     // .
0x00 ,0x10 ,0x08 ,0x04 ,0x02 ,0x01 ,0x00 ,     // Slash
0x0E ,0x11 ,0x19 ,0x15 ,0x13 ,0x11 ,0x0E ,     // 0
0x04 ,0x06 ,0x04 ,0x04 ,0x04 ,0x04 ,0x0E ,     // 1
0x0E ,0x11 ,0x10 ,0x08 ,0x04 ,0x02 ,0x1F ,     // 2
0x1F ,0x08 ,0x04 ,0x08 ,0x10 ,0x11 ,0x0E ,     // 3
0x08 ,0x0C ,0x0A ,0x09 ,0x1F ,0x08 ,0x08 ,     // 4
0x1F ,0x01 ,0x0F ,0x10 ,0x10 ,0x11 ,0x0E ,     // 5
0x0C ,0x02 ,0x01 ,0x0F ,0x11 ,0x11 ,0x0E ,     // 6
0x1F ,0x10 ,0x08 ,0x04 ,0x02 ,0x02 ,0x02 ,     // 7
0x0E ,0x11 ,0x11 ,0x0E ,0x11 ,0x11 ,0x0E ,     // 8
0x0E ,0x11 ,0x11 ,0x1E ,0x10 ,0x08 ,0x06 ,     // 9
0x00 ,0x06 ,0x06 ,0x00 ,0x06 ,0x06 ,0x00 ,     // :
0x00 ,0x06 ,0x06 ,0x00 ,0x06 ,0x04 ,0x02 ,     // ;
0x08 ,0x04 ,0x02 ,0x01 ,0x02 ,0x04 ,0x08 ,     // <
0x00 ,0x00 ,0x1F ,0x00 ,0x1F ,0x00 ,0x00 ,     // =
0x02 ,0x04 ,0x08 ,0x10 ,0x08 ,0x04 ,0x02 ,     // >
0x0E ,0x11 ,0x10 ,0x08 ,0x04 ,0x00 ,0x04 ,     // ?
0x0E ,0x11 ,0x10 ,0x16 ,0x15 ,0x15 ,0x0E ,     // @
0x0E ,0x11 ,0x11 ,0x11 ,0x1F ,0x11 ,0x11 ,     // A
0x0F ,0x11 ,0x11 ,0x0F ,0x11 ,0x11 ,0x0F ,     // B
0x0E ,0x11 ,0x01 ,0x01 ,0x01 ,0x11 ,0x0E ,     // C
0x07 ,0x09 ,0x11 ,0x11 ,0x11 ,0x09 ,0x07 ,     // D
0x1F ,0x01 ,0x01 ,0x0F ,0x01 ,0x01 ,0x1F ,     // E
0x1F ,0x01 ,0x01 ,0x0F ,0x01 ,0x01 ,0x01 ,     // F
0x0E ,0x11 ,0x01 ,0x1D ,0x11 ,0x11 ,0x1E ,     // G
0x11 ,0x11 ,0x11 ,0x1F ,0x11 ,0x11 ,0x11 ,     // H
0x0E ,0x04 ,0x04 ,0x04 ,0x04 ,0x04 ,0x0E ,     // I
0x1C ,0x08 ,0x08 ,0x08 ,0x08 ,0x09 ,0x06 ,     // J
0x11 ,0x09 ,0x05 ,0x03 ,0x05 ,0x09 ,0x11 ,     // K
0x01 ,0x01 ,0x01 ,0x01 ,0x01 ,0x01 ,0x1F ,     // L
0x11 ,0x1B ,0x15 ,0x15 ,0x11 ,0x11 ,0x11 ,     // M
0x11 ,0x11 ,0x13 ,0x15 ,0x19 ,0x11 ,0x11 ,     // N
0x0E ,0x11 ,0x11 ,0x11 ,0x11 ,0x11 ,0x0E ,     // O
0x0F ,0x11 ,0x11 ,0x0F ,0x01 ,0x01 ,0x01 ,     // P
0x0E ,0x11 ,0x11 ,0x11 ,0x15 ,0x09 ,0x16 ,     // Q
0x0F ,0x11 ,0x11 ,0x0F ,0x05 ,0x09 ,0x11 ,     // R
0x1E ,0x01 ,0x01 ,0x0E ,0x10 ,0x10 ,0x0F ,     // S
0x1F ,0x04 ,0x04 ,0x04 ,0x04 ,0x04 ,0x04 ,     // T
0x11 ,0x11 ,0x11 ,0x11 ,0x11 ,0x11 ,0x0E ,     // U
0x11 ,0x11 ,0x11 ,0x11 ,0x11 ,0x0A ,0x04 ,     // V
0x11 ,0x11 ,0x11 ,0x15 ,0x15 ,0x15 ,0x0A ,     // W
0x11 ,0x11 ,0x0A ,0x04 ,0x0A ,0x11 ,0x11 ,     // X
0x11 ,0x11 ,0x11 ,0x0A ,0x04 ,0x04 ,0x04 ,     // Y
0x1F ,0x10 ,0x08 ,0x04 ,0x02 ,0x01 ,0x1F ,     // Z
0x0E ,0x02 ,0x02 ,0x02 ,0x02 ,0x02 ,0x0E ,     // [
0x00 ,0x01 ,0x02 ,0x04 ,0x08 ,0x10 ,0x00 ,     // Backslash
0x0E ,0x08 ,0x08 ,0x08 ,0x08 ,0x08 ,0x0E ,     // ]
0x04 ,0x0A ,0x11 ,0x00 ,0x00 ,0x00 ,0x00 ,     // ^
0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x1F ,     // _
0x02 ,0x04 ,0x08 ,0x00 ,0x00 ,0x00 ,0x00 ,     // High Comma 
0x00 ,0x00 ,0x0E ,0x10 ,0x1E ,0x11 ,0x1E ,     // a
0x01 ,0x01 ,0x0D ,0x13 ,0x11 ,0x11 ,0x0F ,     // b
0x00 ,0x00 ,0x0E ,0x01 ,0x01 ,0x11 ,0x0E ,     // c
0x10 ,0x10 ,0x16 ,0x19 ,0x11 ,0x11 ,0x1E ,     // d
0x00 ,0x00 ,0x0E ,0x11 ,0x1F ,0x01 ,0x0E ,     // e
0x0C ,0x12 ,0x02 ,0x07 ,0x02 ,0x02 ,0x02 ,     // f
0x00 ,0x1E ,0x11 ,0x11 ,0x1E ,0x10 ,0x0E ,     // g
0x01 ,0x01 ,0x0D ,0x13 ,0x11 ,0x11 ,0x11 ,     // h
0x04 ,0x00 ,0x06 ,0x04 ,0x04 ,0x04 ,0x0E ,     // i
0x08 ,0x00 ,0x0C ,0x08 ,0x08 ,0x09 ,0x06 ,     // j
0x01 ,0x01 ,0x09 ,0x05 ,0x03 ,0x05 ,0x09 ,     // k
0x06 ,0x04 ,0x04 ,0x04 ,0x04 ,0x04 ,0x0E ,     // l
0x00 ,0x00 ,0x0B ,0x15 ,0x15 ,0x11 ,0x11 ,     // m
0x00 ,0x00 ,0x0D ,0x13 ,0x11 ,0x11 ,0x11 ,     // n
0x00 ,0x00 ,0x0E ,0x11 ,0x11 ,0x11 ,0x0E ,     // o
0x00 ,0x00 ,0x0F ,0x11 ,0x0F ,0x01 ,0x01 ,     // p
0x00 ,0x00 ,0x16 ,0x19 ,0x1E ,0x10 ,0x10 ,     // q
0x00 ,0x00 ,0x0D ,0x13 ,0x01 ,0x01 ,0x01 ,     // r
0x00 ,0x00 ,0x0E ,0x01 ,0x0E ,0x10 ,0x0F ,     // s
0x02 ,0x02 ,0x07 ,0x02 ,0x02 ,0x12 ,0x0C ,     // t
0x00 ,0x00 ,0x11 ,0x11 ,0x11 ,0x19 ,0x16 ,     // u
0x00 ,0x00 ,0x11 ,0x11 ,0x11 ,0x0A ,0x04 ,     // v
0x00 ,0x00 ,0x11 ,0x11 ,0x15 ,0x15 ,0x0A ,     // w
0x00 ,0x00 ,0x11 ,0x0A ,0x04 ,0x0A ,0x11 ,     // x
0x00 ,0x00 ,0x11 ,0x11 ,0x1E ,0x10 ,0x0E ,     // y
0x00 ,0x00 ,0x1F ,0x08 ,0x04 ,0x02 ,0x1F ,     // z
0x08 ,0x04 ,0x04 ,0x02 ,0x04 ,0x04 ,0x08 ,     // {
0x04 ,0x04 ,0x04 ,0x00 ,0x04 ,0x04 ,0x04 ,     // |
0x02 ,0x04 ,0x04 ,0x08 ,0x04 ,0x04 ,0x02 ,     // }
0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,     // ~ 
0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,     // Block 
};


Veel succes ermee!

Max
Hi Martin01,

Als ik het goed begrijp is het enige probleem dat de dag niet wordt getoond... Nou dat kan ook hoor!
De meeste RTC's (Real Time Clock) hebben ook een DOW (Day Of Week) variabele. Deze heb ik in mijn sketch niet gebruikt, maar is eenvoudig te implementeren en dus kun je ook de weekdag op het display tonen.
Zoiets als dit:
http://www.uploadarchief.net/files/download/2014-01-20%2013.07.09.jpg

Dan is hier de code:
code:
// Timer 1 Info :  http://playground.arduino.cc/code/timer1
// Using PROGMEM : http://arduino.cc/en/Reference/PROGMEM


// The matrix board is controlled by timer0 overflow interrupt. This gives a steady image and the display can be handled like a static type.
// The main code does not have to control the board, just set or clear bits in the data array to put some led's on or off.
// Logically it's organized in colums, 270 in total. This sofware defines column 0 as the upper left column and 271 is the right bottom column.
// This makes it more easy to arrange the text on the board. There is no checking if the text fits on the display.
//
// Column layout :    Line 0 : 0 to 89
//                    Line 1 : 90 to 179     
//                    Line 2 : 180 to 271
//
//
//
#include <DS1307RTC.h>
#include <Time.h>
#include <Wire.h>
#include <avr/pgmspace.h>             // Include pgmspace so data tables can be stored in program memory, see PROGMEM info
#include <SPI.h>                      // Include SPI comunications, used for high speed clocking to display shiftregisters
#include "TimerOne.h"                 // Include Timer1 library, used for timer overflow interrupt                                    
                                                        
const int strobePin = 10;             // Define I/O pins connected to the display board                 
const int clockPin = 13;                               
const int dataPin = 11;                                
const int resredPin = 9;                               
const int row_a = 5;                                      
const int row_b = 6;                                    
const int row_c = 7;                                     
const int rtcPlusPin = 17;            // +5V RTC module.  
const int rtcMinPin = 16;             // gnd RTC module.  
const int ClockPin = 2;
const int ClockPinMin = 1;

String tijd;
int blinkToggle=1;
int blinks=0;
String topText = "De tijd is";

int RowCount = 0;             // Counter for the current row, do not change this value in the main code, it's handeld in the interrupt routine  
int teller=0;
unsigned long tijdNu=millis();

#include "font75.h";         // Standard 5x7 font ASCII Table

byte ColumnBytes[8][34];     // This is the data array that is used as buffer. The display data is in this buffer and the timeroverflow routine scans this
                             // buffer and shows it on the display. So read and write to this buffer to change display data.
                             // No strings are stored here, its the raw bit data that has to be shifted into the display.
                         

// =========================================================================================
// Setup routine, mandatory.
// =========================================================================================

 void setup() {   
  pinMode (strobePin, OUTPUT);                              // Define IO          
  pinMode (clockPin, OUTPUT);  
  pinMode (dataPin, OUTPUT);  
  pinMode (row_c, OUTPUT);  
  pinMode (row_b, OUTPUT);  
  pinMode (row_a, OUTPUT);  
  pinMode (resredPin, OUTPUT);  
  pinMode (rtcMinPin, OUTPUT);  
  pinMode (rtcPlusPin, OUTPUT);  
  pinMode (ClockPin, INPUT_PULLUP);  
  pinMode (ClockPinMin, OUTPUT);  
  digitalWrite(rtcMinPin, LOW);                       // 0V (gnd) voor RTC module.  
  digitalWrite(rtcPlusPin, HIGH);                     // +5V voor RTC module.  
  digitalWrite (resredPin, LOW);                       
  digitalWrite (strobePin, LOW);                        
  digitalWrite(ClockPinMin, LOW);                     // +5V voor Clock instelknop  
  //Serial.begin(9600);                                       // Include serial routine, used for debugging and testing
  SPI.begin();                                              // Start SPI comunications
  SPI.setBitOrder(LSBFIRST);                                // Initialize SPI comunications
  Timer1.initialize(2000);                                  // initialize timer1, overflow timer1 handles the display driver, period (in microseconds)
  Timer1.attachInterrupt(DisplayControl);                   // attaches timer1 overflow interrupt routine
 
 
// Start code here
  ClearDisplay();

}  

// =========================================================================================
// loop routine, mandatory
// Take notice when using time crititical code the interrupt is running to control 
// the display.
// =========================================================================================

void loop()  
{  
   tmElements_t tm;  //activate RTC lib
   String uren;
   String minuten;
   String seconden;

// zet tijd in bovenste balk   
   if (RTC.read(tm)) {                                                                     //read RTC
     if (tm.Hour<=9){uren="0"+String(tm.Hour);}else{uren=String(tm.Hour);}                 //leading zero's
     if (tm.Minute<=9){minuten="0"+String(tm.Minute);}else{minuten=String(tm.Minute);}     //if 
     if (tm.Second<=9){seconden="0"+String(tm.Second);}else{seconden=String(tm.Second);}   //UU,MM,SS < 10
 
     tijd = uren+":"+minuten+":"+seconden;
     PlaceText(tijd,20);
   }
 // zet DOW in middelste balk
     String DOW[7] = {"zondag", "maandag", "dinsdag", "woensdag", "donderdag", "vrijdag", "zaterdag"};
     String dag = DOW[tm.Wday];   
     PlaceText (dag, 113);
     
 // zet de datum in onderste balk
     String maand[13] = {"leeg", "jan", "feb", "mrt", "apr", "mei", "jun", "jul", "aug", "sep", "okt", "nov", "dec"};
     String datum = String(tm.Day)+ " "+ maand[tm.Month]+ " "+ String(tmYearToCalendar(tm.Year)); 
     PlaceText (datum, 193);
 

}



// =========================================================================================
// Timer1 overflow intterupt routine, 
// Does the Display shifting and muliplexing
// =========================================================================================

 void DisplayControl()  
 {  
     digitalWrite(strobePin, LOW);                        // StrobePin LOW, so led's do not change during clocking
     digitalWrite (resredPin, LOW);                       // Display off to prevent ghosting  
 
       for (int q = 0; q<34; q++) {                       // Shift the bytes in for the current Row
       SPI.transfer(ColumnBytes[RowCount][q]);}
    
     digitalWrite (row_a, RowCount & 1);                  // Switch the current column on, will be on until next interrupt
     digitalWrite (row_b, RowCount & 2);                
     digitalWrite (row_c, RowCount & 4);            
     
     digitalWrite(strobePin, HIGH);                       // Strobe the shiftregisters so data is presented to the LED's 
     digitalWrite (resredPin, HIGH);                      // Display back on 

     RowCount++;                                          // Increment Row 
     if (RowCount == 7) RowCount = 0 ;                    // Row is 0 to 6
 }  

// =========================================================================================
// Place text on display, uses the standard 5x7 font
// Call this routine with the text to display and the starting column to place the text
// Example : PlaceText("FDS132",27); Places the text "FDS132" starting on column 27
// =========================================================================================

void PlaceText(String text, int ColPos) {
    byte displayByte;  
    char CurChar;
    int bitpos;
    int bytepos;
    int pixelpos;
    int charCount = text.length();
    int store = ColPos;

   for (int i = 0; i < charCount; i++) {                                     // Loop for all the characters in the string
    CurChar = text.charAt(i);                                                // Read ascii value of current character
    CurChar = CurChar - 32;                                                  // Minus 32 to get the right pointer to the ascii table, the first 32 ascii code are not in the table    
     
     for (int y = 0; y<7; y++) {                                             // y loop is used to handle the 7 rows
       for (int x = 0; x<5; x++) {                                           // x loop is the pointer to the indiviual bits in the byte from the table 
         displayByte = (pgm_read_word_near(Font75 + (CurChar*7)+y));         // Read byte from table 
         pixelpos = abs(ColPos - 271);                                       // Calculate start position to place the data on display
         bytepos = ((pixelpos)/8);                                           
         bitpos = (pixelpos) - (bytepos*8);
         boolean bitStatus = bitRead(displayByte, x);                        // Probe the bits   
         if(bitStatus == 0) bitClear(ColumnBytes[y][bytepos], bitpos);       // And set or clear the corrosponding bits in de display buffer   
         if(bitStatus == 1) bitSet(ColumnBytes[y][bytepos], bitpos);       
         ColPos++;                                                           
      }
       ColPos = store;                                                      // Reset the column pointer so the next byte is shown on the same position 
     }
    ColPos = ColPos + 6;                                                    // 6 is used here to give one column spacing between characters (one character is 5 bits wide)
    store = ColPos;                                                         // For more space between the characters increase this number 
 }
}      



// =========================================================================================
// Clear display
// All bytes in buffer are set to zero
// =========================================================================================

void ClearDisplay() {
    for (int y = 0; y<8; y++) {     
       for (int x = 0; x<34; x++) {     
         ColumnBytes[y][x] = 0;
       }
    }     
}  




Succes en de groeten aan je schoonmoeder.

Max
@Rolo- Betreft de voeding, is het een vreemde gedachte om te denken dat de 5 volt voor de logic wel standaard 5 volt moet blijven houden, die mag geen PWM power hebben.

Vandaar mijn gedachten de gemeenschappelijke voeding voor de displays los te maken en daar een pwm op met een frequentie van 300 hz of hoger.
Op 2 februari 2014 17:34:37 schreef MaxJ:
Zo de klok loopt en kan wellicht nog wel wat verbeterd worden, maar ik heb nog een FTD-132 bordje staan... en ik wilde er iets anders mee doen... Dus ik heb eens rondgekeken of ik er een VU meter van kon maken (misschien later nog wel een Audio Spectrum Analyser).

En dit is het resultaat van de eerste poging:
http://youtu.be/P7KPvvNcVxk
Op het filmpje ziet het minder goed uit dan live...
Nog veel ruimte voor verbetering...
Hier is de code.
Hier het schema.

Updates volgen!

Ziet erg goed uit ! Leuke toepassing.
Op 2 februari 2014 17:46:41 schreef Opa-knutsel:
@Rolo- Betreft de voeding, is het een vreemde gedachte om te denken dat de 5 volt voor de logic wel standaard 5 volt moet blijven houden, die mag geen PWM power hebben.

Vandaar mijn gedachten de gemeenschappelijke voeding voor de displays los te maken en daar een pwm op met een frequentie van 300 hz of hoger.

Nou ik heb het zo in gedachten, het matrixbord op +7,5 volt zetten, op het matrixbord zit een eigen 5 volt regelaar voor de logic op het bord.
Dan diezelfde +7,5 volt aansluiten op de "RAW" ingang van de Arduino, op het arduino board wordt die dan weer netjes naar 5 Volt geregeld. (of 3.3 indien nodig en het Arduino board dat ondersteunt).

Sterker nog, dit heb ik nu zo aangesloten (regelbare voeding op 7,5 Volt gezet) en dan op de Arduino Pro Mini, met PWM op de resred pin kun je dan de helderheid regelen. Het is nog niet af, maar met een basis opzetje kon ik de helderheid al regelen. Gaat nog wel wat programmeertijd in zitten, maar het ziet er veelbelovend uit.
Vandaar de behoefte aan een "vaste" compacte 7,5 volt voeding.
Zo hoef ik verder niets aan het matrixbord te veranderen.

Ik begrijp niet zo goed hoe jij dan het PWM'en had voorgesteld.
Direct op de voedingspanning ?

Als je eens wilt informeren naar een voeding, graag !

Het schema zou er dan zo uit gaan zien :

http://i10.photobucket.com/albums/a134/Rlnd/Arduino/CO_Klok_pwm_zps889d6c6d.jpg

[Bericht gewijzigd door Henry S. op 3 februari 2014 20:18:49 (48%)]

Dit topic is gesloten