128 x 16 LED Dot Matrix board

Hi I have a 128 x 16 Dot Matrix board but the code I have is only for 64 boards; therefore it is repeating the same message on both of the 64 boards.

I was wondering if anyone could help? I cannot paste the full code as it is longer than 9000 characters :frowning:

#include <avr/pgmspace.h>
#include "pins_arduino.h"

// based on myMatrix Arduino Library
// by Silviu - www.openhardware.ro
// MIT License (MIT)

// Connections to board
const byte pinSTB=8;
const byte pinClock=12;
const byte pinRed=10;
const byte pinGreen=11;
const byte pinOE=2;
const byte pinRowA=3;
const byte pinRowB=4;
const byte pinRowC=5;
const byte pinRowD=6;

byte scanRow = 0;
unsigned long counter;

//Insert message here ("message ")
char message[] = "        Hello        ";

// ---------------------------------------------------------------------------------------------------
const byte RED    = 0b10;
const byte GREEN  = 0b01;
const byte YELLOW = 0b11;
const byte BLACK  = 0b00;

struct Color {
  byte R;
  byte G;
};

#define BUFFER_INIT_128 BUFFER_INIT_100 BUFFER_INIT_10 BUFFER_INIT_10 BUFFER_INIT_8
#define BUFFER_INIT_100 BUFFER_INIT_50 BUFFER_INIT_50
#define BUFFER_INIT_50  BUFFER_INIT_10 BUFFER_INIT_10 BUFFER_INIT_10 BUFFER_INIT_10 BUFFER_INIT_10
#define BUFFER_INIT_10  BUFFER_INIT_2 BUFFER_INIT_2 BUFFER_INIT_2 BUFFER_INIT_2 BUFFER_INIT_2
#define BUFFER_INIT_8   BUFFER_INIT_2 BUFFER_INIT_2 BUFFER_INIT_2 BUFFER_INIT_2
#define BUFFER_INIT_2   BUFFER_INIT_1 BUFFER_INIT_1
#define BUFFER_INIT_1   {0x00, 0x00},

Color buffer[128] = {BUFFER_INIT_128};
// ---------------------------------------------------------------------------------------------------

 (then there's font information)


// function to colorize a pixel
// color 2 Bit, (R)ed (G)reen 0b000000RG
void setPixel(uint8_t x ,uint8_t y, uint8_t color)
{
  uint8_t myindex = (y*8)+x/8;  // 8 segments per row
  uint8_t mybitmask = 7 -(x % 8);
  bitWrite(buffer[myindex].R, mybitmask, (color & 0b00000010));  // red
  bitWrite(buffer[myindex].G, mybitmask, (color & 0b00000001));  // green
}


// function to print a character at column
void printChar(uint8_t x_offset, uint8_t fg_color, uint8_t bg_color, byte ch) {
  if (0 != (x_offset % 8)) return;    // x_offset not a multiple of 8
  if ((ch>9) && (ch<32)) return; // invalid character
  const uint8_t y_offset = 0;
  for (uint8_t y=0; y<16; y++){
    for (uint8_t i=0; i<8; i++){
      if(bitRead(pgm_read_byte(&font8x16_basic[ch-32][y]),7-i)) setPixel(x_offset+i, y_offset+y, fg_color);
      else setPixel(x_offset+i, y_offset+y, bg_color);        
    }
  }  
}


// function to scroll the text message to the left
void hScroll(uint8_t fg_color, uint8_t bg_color, char *mystring){
  // offset starts with 0
  // this means text starts in upper left corner
  for (int offset=0; offset < ((lenString(mystring)-8)*8-1); offset++){
    for (byte x=0; x<64; x++){
      for (byte y=0; y<16; y++){
        byte color=bg_color;
        if (getPixelMessage(x+offset,y,mystring)) color=fg_color;
        setPixel(x,y,color);
      }
    }
    delay(40);  
  }
}


byte getPixelMessage(uint16_t x, uint16_t y, char *p){
  p=p+x/8;
  return getPixelChar(x%8, y, *p);
}


byte getPixelChar(uint8_t x, uint8_t y, char ch){
  return bitRead(pgm_read_byte(&font8x16_basic[ch-32][y]),7-x);
}


// length of the message string
uint8_t lenString(char *p){
  unsigned int retVal=0;
  while(*p!='\0'){ 
   retVal++;
   p++;
  }
  return retVal;
}

void drawRectangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint8_t color){
    drawHLine(x1,x2,y1,color);
    drawHLine(x1,x2,y2,color);  
    drawVLine(x1,y1,y2,color);
    drawVLine(x2,y1,y2,color);
}

void drawVLine(uint16_t x, uint16_t y1, uint16_t y2, uint8_t color){
    for (uint16_t y = y1; y <= y2; y++) {
        setPixel(x,y,color);      
    }
}

void drawHLine(uint16_t x1, uint16_t x2, uint16_t y, uint8_t color){
    for (uint16_t x = x1; x <= x2; x++) {
          setPixel(x,y,color);      
    }  
}

void clearScreen(){
    for (uint8_t i=0; i<128; i++)  // buffer size
    {
      buffer[i].R=0;
      buffer[i].G=0; 
    }
}




// helper function to paint one row
void shiftOut(uint8_t row) {
  const uint8_t bitRed = digitalPinToBitMask(pinRed);
  volatile uint8_t *outRed = portOutputRegister(digitalPinToPort(pinRed));

  const uint8_t bitGreen = digitalPinToBitMask(pinGreen);
  volatile uint8_t *outGreen = portOutputRegister(digitalPinToPort(pinGreen));

  const uint8_t bitClock = digitalPinToBitMask(pinClock);
  volatile uint8_t *outClock = portOutputRegister(digitalPinToPort(pinClock));

  const uint8_t bitRowA = digitalPinToBitMask(pinRowA);
  volatile uint8_t *outRowA = portOutputRegister(digitalPinToPort(pinRowA));

  const uint8_t bitRowB = digitalPinToBitMask(pinRowB);
  volatile uint8_t *outRowB = portOutputRegister(digitalPinToPort(pinRowB));

  const uint8_t bitRowC = digitalPinToBitMask(pinRowC);
  volatile uint8_t *outRowC = portOutputRegister(digitalPinToPort(pinRowC));

  const uint8_t bitRowD = digitalPinToBitMask(pinRowD);
  volatile uint8_t *outRowD = portOutputRegister(digitalPinToPort(pinRowD));

  const uint8_t bitOE = digitalPinToBitMask(pinOE);
  volatile uint8_t *outOE = portOutputRegister(digitalPinToPort(pinOE));

  const uint8_t bitSTB = digitalPinToBitMask(pinSTB);
  volatile uint8_t *outSTB = portOutputRegister(digitalPinToPort(pinSTB));  
  
  *outOE |= bitOE;  // Turn off display  // digitalWrite(pinOE,HIGH);
  // select row
  if (bitRead(row, 0)) *outRowA |= bitRowA; else *outRowA &= ~bitRowA;
  if (bitRead(row, 1)) *outRowB |= bitRowB; else *outRowB &= ~bitRowB;
  if (bitRead(row, 2)) *outRowC |= bitRowC; else *outRowC &= ~bitRowC;
  if (bitRead(row, 3)) *outRowD |= bitRowD; else *outRowD &= ~bitRowD;

  for(uint8_t column=0; column<8; column++){  // 8 segments
    uint8_t index = column + (row*8);  // 8 segments
    for(uint8_t i=0; i<8; i++) {    
      if (buffer[index].R & (1<<(7-i))) *outRed &= ~bitRed;
      else *outRed |= bitRed;
      
      if (buffer[index].G & (1<<(7-i))) *outGreen &= ~bitGreen;
      else *outGreen |= bitGreen;
      
      //Clock Pulse
      *outClock |= bitClock; //CLK, HIGH
      *outClock &= ~bitClock; //CLK, LOW
    }
  }

  *outSTB &= ~bitSTB;  // digitalWrite(pinSTB,LOW);
  *outSTB |= bitSTB;   // digitalWrite(pinSTB,HIGH);
  *outOE &= ~bitOE;    // Turn on display  // digitalWrite(pinOE,LOW);
}


// interrupt routine is responsible for painting the screen
ISR(TIMER2_COMPA_vect){
  cli();
  shiftOut(scanRow);
  if (scanRow < 15) scanRow++; else scanRow = 0;
  sei();
}


void setup() {
  // use timer2 as the scanning interrupt timer
  cli(); // clear interrupts
  TCCR2A = 0; TCCR2B = 0; TCNT2  = 0;
  TCCR2B |= (1 << CS12) | (1 << CS10);     // Set 1024 prescaler
               // 160Hz scan rate = 10 frames/second (16 rows)
  OCR2A = 97;  // 97 = (16,000,000 / (1024*160)) - 1
  TCCR2A |= (1 << WGM21); TIMSK2 |= (1 << OCIE2A);
  
  pinMode(pinRed, OUTPUT); 
  pinMode(pinGreen, OUTPUT); 
  pinMode(pinClock, OUTPUT); 
  pinMode(pinRowA, OUTPUT); 
  pinMode(pinRowB, OUTPUT); 
  pinMode(pinRowC, OUTPUT); 
  pinMode(pinRowD, OUTPUT); 
  pinMode(pinOE, OUTPUT); 
  pinMode(pinSTB, OUTPUT); 

  digitalWrite(pinOE, LOW);
  digitalWrite(pinRed, HIGH); digitalWrite(pinGreen, HIGH);
  sei(); //allow interrupts
}


// main loop is responsible for updating the screen
void loop() {  
  //  printChar(0,GREEN,BLACK,'A');
  hScroll(RED,BLACK, message);
}

Thanks,
Simon

Or am I being too adventurous? :')

Simon, there would be quite a few changes because of the way that code was written. So before we embark on that task, how do you know the resulting sketch would work with your 128x8? If it is constructed as two 64x8 daisy-chained together, it probably would. But your matrix might have a completely different design using different chips, and amending that sketch might be a waste of time.

Can you post links to where you found that code, and where you got your 128x8 matrix?

Paul

EDIT: no, it sounds like it would work ok because you are currently getting the same image on the left/right sides of your matrix.

Hi Paul,

Thanks for your reply, this is the link to the code: Led Matrix 16 x 64 three colors · GitHub (he has also done a code for 128 x 16 but for some reason this will not work and just results in a flashing random display)

I got given the dot matrix boards.

Cheers

Can anyone help? Thanks

simonjcox5:
Thanks for your reply, this is the link to the code: Led Matrix 16 x 64 three colors · GitHub

Are you using the same dot matrix display as he is?

If not, there is no point in using his code!

Simon says that code works, but shows the same image on right & left halves of the display. This seems to me to be consistent with what you would expect if the code was written for a display of the same design but half the size. We should be able to adapt the code, but there will be two difficulties. One is that the code has been written "hard-coded" for that size display. It will be neccessary to find every place in the code where that has been done. Some will be obvious a some less so. Second problem is "remote debugging" the code given the OP is not an expert coder, and the experts on this forum do not own one of these displays.

Simon, i will have a stab at it later this evening. It may take a few goes to get right. You will need to be precise with your descriptions of what is happening as changes are made.

OK, attempt #1:

#include <avr/pgmspace.h>
#include "pins_arduino.h"

// based on myMatrix Arduino Library
// by Silviu - www.openhardware.ro
// MIT License (MIT)

// Connections to board
const byte pinSTB=8;
const byte pinClock=12;
const byte pinRed=10;
const byte pinGreen=11;
const byte pinOE=2;
const byte pinRowA=3;
const byte pinRowB=4;
const byte pinRowC=5;
const byte pinRowD=6;

byte scanRow = 0;
unsigned long counter;

//Insert message here ("message ")
char message[] = "        Hello        ";

// ---------------------------------------------------------------------------------------------------
const byte RED    = 0b10;
const byte GREEN  = 0b01;
const byte YELLOW = 0b11;
const byte BLACK  = 0b00;

struct Color {
  byte R;
  byte G;
};

#define BUFFER_INIT_256 BUFFER_INIT_128 BUFFER_INIT_128 
#define BUFFER_INIT_128 BUFFER_INIT_100 BUFFER_INIT_10 BUFFER_INIT_10 BUFFER_INIT_8
#define BUFFER_INIT_100 BUFFER_INIT_50 BUFFER_INIT_50
#define BUFFER_INIT_50  BUFFER_INIT_10 BUFFER_INIT_10 BUFFER_INIT_10 BUFFER_INIT_10 BUFFER_INIT_10
#define BUFFER_INIT_10  BUFFER_INIT_2 BUFFER_INIT_2 BUFFER_INIT_2 BUFFER_INIT_2 BUFFER_INIT_2
#define BUFFER_INIT_8   BUFFER_INIT_2 BUFFER_INIT_2 BUFFER_INIT_2 BUFFER_INIT_2
#define BUFFER_INIT_2   BUFFER_INIT_1 BUFFER_INIT_1
#define BUFFER_INIT_1   {0x00, 0x00},

Color buffer[256] = {BUFFER_INIT_256};
// ---------------------------------------------------------------------------------------------------

 (then there's font information)


// function to colorize a pixel
// color 2 Bit, (R)ed (G)reen 0b000000RG
void setPixel(uint8_t x ,uint8_t y, uint8_t color)
{
  uint8_t myindex = (y*16)+x/8;  // 16 segments per row
  uint8_t mybitmask = 7 -(x % 8);
  bitWrite(buffer[myindex].R, mybitmask, (color & 0b00000010));  // red
  bitWrite(buffer[myindex].G, mybitmask, (color & 0b00000001));  // green
}


// function to print a character at column
void printChar(uint8_t x_offset, uint8_t fg_color, uint8_t bg_color, byte ch) {
  if (0 != (x_offset % 8)) return;    // x_offset not a multiple of 8
  if ((ch>9) && (ch<32)) return; // invalid character
  const uint8_t y_offset = 0;
  for (uint8_t y=0; y<16; y++){
    for (uint8_t i=0; i<8; i++){
      if(bitRead(pgm_read_byte(&font8x16_basic[ch-32][y]),7-i)) setPixel(x_offset+i, y_offset+y, fg_color);
      else setPixel(x_offset+i, y_offset+y, bg_color);        
    }
  }  
}


// function to scroll the text message to the left
void hScroll(uint8_t fg_color, uint8_t bg_color, char *mystring){
  // offset starts with 0
  // this means text starts in upper left corner
  for (int offset=0; offset < ((lenString(mystring)-8)*8-1); offset++){
    for (byte x=0; x<128; x++){
      for (byte y=0; y<16; y++){
        byte color=bg_color;
        if (getPixelMessage(x+offset,y,mystring)) color=fg_color;
        setPixel(x,y,color);
      }
    }
    delay(40);  
  }
}


byte getPixelMessage(uint16_t x, uint16_t y, char *p){
  p=p+x/8;
  return getPixelChar(x%8, y, *p);
}


byte getPixelChar(uint8_t x, uint8_t y, char ch){
  return bitRead(pgm_read_byte(&font8x16_basic[ch-32][y]),7-x);
}


// length of the message string
uint8_t lenString(char *p){
  unsigned int retVal=0;
  while(*p!='\0'){ 
   retVal++;
   p++;
  }
  return retVal;
}

void drawRectangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint8_t color){
    drawHLine(x1,x2,y1,color);
    drawHLine(x1,x2,y2,color);  
    drawVLine(x1,y1,y2,color);
    drawVLine(x2,y1,y2,color);
}

void drawVLine(uint16_t x, uint16_t y1, uint16_t y2, uint8_t color){
    for (uint16_t y = y1; y <= y2; y++) {
        setPixel(x,y,color);      
    }
}

void drawHLine(uint16_t x1, uint16_t x2, uint16_t y, uint8_t color){
    for (uint16_t x = x1; x <= x2; x++) {
          setPixel(x,y,color);      
    }  
}

void clearScreen(){
    for (uint16_t i=0; i<256; i++)  // buffer size
    {
      buffer[i].R=0;
      buffer[i].G=0; 
    }
}




// helper function to paint one row
void shiftOut(uint8_t row) {
  const uint8_t bitRed = digitalPinToBitMask(pinRed);
  volatile uint8_t *outRed = portOutputRegister(digitalPinToPort(pinRed));

  const uint8_t bitGreen = digitalPinToBitMask(pinGreen);
  volatile uint8_t *outGreen = portOutputRegister(digitalPinToPort(pinGreen));

  const uint8_t bitClock = digitalPinToBitMask(pinClock);
  volatile uint8_t *outClock = portOutputRegister(digitalPinToPort(pinClock));

  const uint8_t bitRowA = digitalPinToBitMask(pinRowA);
  volatile uint8_t *outRowA = portOutputRegister(digitalPinToPort(pinRowA));

  const uint8_t bitRowB = digitalPinToBitMask(pinRowB);
  volatile uint8_t *outRowB = portOutputRegister(digitalPinToPort(pinRowB));

  const uint8_t bitRowC = digitalPinToBitMask(pinRowC);
  volatile uint8_t *outRowC = portOutputRegister(digitalPinToPort(pinRowC));

  const uint8_t bitRowD = digitalPinToBitMask(pinRowD);
  volatile uint8_t *outRowD = portOutputRegister(digitalPinToPort(pinRowD));

  const uint8_t bitOE = digitalPinToBitMask(pinOE);
  volatile uint8_t *outOE = portOutputRegister(digitalPinToPort(pinOE));

  const uint8_t bitSTB = digitalPinToBitMask(pinSTB);
  volatile uint8_t *outSTB = portOutputRegister(digitalPinToPort(pinSTB));  
  
  *outOE |= bitOE;  // Turn off display  // digitalWrite(pinOE,HIGH);
  // select row
  if (bitRead(row, 0)) *outRowA |= bitRowA; else *outRowA &= ~bitRowA;
  if (bitRead(row, 1)) *outRowB |= bitRowB; else *outRowB &= ~bitRowB;
  if (bitRead(row, 2)) *outRowC |= bitRowC; else *outRowC &= ~bitRowC;
  if (bitRead(row, 3)) *outRowD |= bitRowD; else *outRowD &= ~bitRowD;

  for(uint8_t column=0; column<16; column++){  // 16 segments
    uint8_t index = column + (row*16);  // 16 segments
    for(uint8_t i=0; i<8; i++) {    
      if (buffer[index].R & (1<<(7-i))) *outRed &= ~bitRed;
      else *outRed |= bitRed;
      
      if (buffer[index].G & (1<<(7-i))) *outGreen &= ~bitGreen;
      else *outGreen |= bitGreen;
      
      //Clock Pulse
      *outClock |= bitClock; //CLK, HIGH
      *outClock &= ~bitClock; //CLK, LOW
    }
  }

  *outSTB &= ~bitSTB;  // digitalWrite(pinSTB,LOW);
  *outSTB |= bitSTB;   // digitalWrite(pinSTB,HIGH);
  *outOE &= ~bitOE;    // Turn on display  // digitalWrite(pinOE,LOW);
}


// interrupt routine is responsible for painting the screen
ISR(TIMER2_COMPA_vect){
  cli();
  shiftOut(scanRow);
  if (scanRow < 15) scanRow++; else scanRow = 0;
  sei();
}


void setup() {
  // use timer2 as the scanning interrupt timer
  cli(); // clear interrupts
  TCCR2A = 0; TCCR2B = 0; TCNT2  = 0;
  TCCR2B |= (1 << CS12) | (1 << CS10);     // Set 1024 prescaler
               // 160Hz scan rate = 10 frames/second (16 rows)
  OCR2A = 97;  // 97 = (16,000,000 / (1024*160)) - 1
  TCCR2A |= (1 << WGM21); TIMSK2 |= (1 << OCIE2A);
  
  pinMode(pinRed, OUTPUT); 
  pinMode(pinGreen, OUTPUT); 
  pinMode(pinClock, OUTPUT); 
  pinMode(pinRowA, OUTPUT); 
  pinMode(pinRowB, OUTPUT); 
  pinMode(pinRowC, OUTPUT); 
  pinMode(pinRowD, OUTPUT); 
  pinMode(pinOE, OUTPUT); 
  pinMode(pinSTB, OUTPUT); 

  digitalWrite(pinOE, LOW);
  digitalWrite(pinRed, HIGH); digitalWrite(pinGreen, HIGH);
  sei(); //allow interrupts
}


// main loop is responsible for updating the screen
void loop() {  
  //  printChar(0,GREEN,BLACK,'A');
  hScroll(RED,BLACK, message);
}

Don't forget to post your font data back in before compiling.

Simon, I had a smilar issue, which possibly the same. I have, 2 64-length boards that connect together. I plugged the arduino into the input between the two boards. Not the more "logical" edge port. Then I connected the edge input to the opposite edge output. The reason being that the boards push the data bits from the opposite side of the board from the input port for each board. Data bits flow into 75hc595 on pin 14 and out to the next chip on pin 9. Use a meter with a continuity beep to trace the flow. Again not sure if the situation is the same, but either way follow the flow of bits.

I was wondering if anyone was able to find a solution to daisy chaining two 64x16 LED Matrix screens together.

I need to be able to send data to two 64x16 screens which are connected together one after the other.

Right now I can send the data to the screens and I just see a copy of the one screen on the other.

I would appreciate the help,

Pericles

plcheng:
I was wondering if anyone was able to find a solution to daisy chaining two 64x16 LED Matrix screens together.

I need to be able to send data to two 64x16 screens which are connected together one after the other.

Right now I can send the data to the screens and I just see a copy of the one screen on the other.

I would appreciate the help,

Pericles

Don't hijack someone's thread which is totally unrelated to your question.

If you note the first post it states exactly the same problem that I am having. Therefore I am not hijacking someone else's thread.

Hi I have a 128 x 16 Dot Matrix board but the code I have is only for 64 boards; therefore it is repeating the same message on both of the 64 boards.

Why are people so keen to judge others before even reading the question?

plcheng:
Hi I have a 128 x 16 Dot Matrix board

That is not what you wrote in reply #9!

You wrote I need to be able to send data to two 64x16 screens which are connected together one after the other..

Next time be absolutely clear on what you have.

hi PaulRB

OK, attempt #1:

with this code of yours i am not able to read from serial monitor when some text is printed on the display.

is there any specific changes i need to do or this is not possible??

thank you

It's not my code. The OP gave the link to it and I made some minor modifications to try to make it work for a different display. It's a year ago and I can't remember what the modifications were. The OP thanked me for my efforts by never responding so it don't know if the code even works. I do not have one of these displays.

I'm not sure what you mean by "read from serial monitor when some text is printed on the display" but the code above does to use serial monitor, so you will not see anything printed there.

I'm not sure what you mean by "read from serial monitor when some text is printed on the display" but the code above does to use serial monitor, so you will not see anything printed there.

actually i made some changes in the code in which i m able to read data from serial monitor and display on to the led matrix