Pages: 1 [2] 3 4 ... 25   Go Down
Author Topic: Arduino to 384 LED display module (MCU Interface)  (Read 38508 times)
0 Members and 1 Guest are viewing this topic.
SF Bay Area (USA)
Offline Offline
Tesla Member
***
Karma: 135
Posts: 6763
Strongly opinionated, but not official!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

The last bits are some character displays (A-Z, 0-9) and "life" (can't have a graphics display without life, eh?)

Then factor the code a bit better so that only functions dependent on the chip details get ht1632_ in front of them, and "device independent graphics" get plot_ or something, and the demo routines get demo_, and a whole separate text document explaining at least the bottom level...
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 12
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Excellent! Looking forward to the new stuff!
Logged

UK
Offline Offline
Sr. Member
****
Karma: 1
Posts: 491
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

First of all, enormous thanks to webobject for tipping us off to these display boards and to westfw for doing the hard work of writing the code. And now as suggested, Conway's Life powered by an Arduino Nano (cool!):

[media]http://uk.youtube.com/watch?v=Zbz-X-qCqGA[/media]
( )

Andrew

PS code to follow very shortly
« Last Edit: December 06, 2008, 10:45:20 am by Andrew » Logged

UK
Offline Offline
Sr. Member
****
Karma: 1
Posts: 491
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

And here's the code:

Quote

/*
* matrix_16x24_life
* Andrew Hedges
* Dec, 2008
* Adapted from code by Bill Westfield ("WestfW")
*/

#include "ht1632.h"
#define X_MAX 23
#define Y_MAX 15
#define X_SIZE 24
#define Y_SIZE 16

#define ASSERT(condition) //nothing


/*
* Set these constants to the values of the pins connected to the SureElectronics Module
* NOTE - these are different from the original demo code by westfw
*/
static const byte ht1632_data = 3;  // Data pin (pin 7)
static const byte ht1632_wrclk = 4; // Write clock pin (pin 5)
static const byte ht1632_cs = 6;    // Chip Select (1, 2, 3, or 4)
// The should also be a common GND.
// The module with all LEDs like draws about 200mA,
//  which makes it PROBABLY powerable via Arduino +5V

#define DEMOTIME 30000  // 30 seconds max on each demo is enough.
#define DISPDELAY 40    // Each "display" lasts this long
#define LONGDELAY 1000  // This delay BETWEEN demos

/*
* ht1632_writebits
* Write bits (up to smiley-cool to h1632 on pins ht1632_data, ht1632_wrclk
* Chip is assumed to already be chip-selected
* Bits are shifted out from MSB to LSB, with the first bit sent
* being (bits & firstbit), shifted till firsbit is zero.
*/
void ht1632_chipselect(byte chipno)
{
  DEBUGPRINT("\nHT1632(%d) ", chipno);
  digitalWrite(chipno, 0);
}

void ht1632_chipfree(byte chipno)
{
  DEBUGPRINT(" [done %d]", chipno);
  digitalWrite(chipno, 1);
}

void ht1632_writebits (byte bits, byte firstbit)
{
  DEBUGPRINT(" ");
  while (firstbit) {
    DEBUGPRINT((bits&firstbit ? "1" : "0"));
    digitalWrite(ht1632_wrclk, LOW);
    if (bits & firstbit) {
      digitalWrite(ht1632_data, HIGH);
    }
    else {
      digitalWrite(ht1632_data, LOW);
    }
    digitalWrite(ht1632_wrclk, HIGH);
    firstbit >>= 1;
  }
}

static void ht1632_sendcmd (byte command)
{
  ht1632_chipselect(ht1632_cs);  // Select chip
  ht1632_writebits(HT1632_ID_CMD, 1<<2);  // send 3 bits of id: COMMMAND
  ht1632_writebits(command, 1<<7);  // send the actual command
  ht1632_writebits(0, 1);       /* one extra dont-care bit in commands. */
  ht1632_chipfree(ht1632_cs); //done
}

static void ht1632_senddata (byte address, byte data)
{
  ht1632_chipselect(ht1632_cs);  // Select chip
  ht1632_writebits(HT1632_ID_WR, 1<<2);  // send ID: WRITE to RAM
  ht1632_writebits(address, 1<<6); // Send address
  ht1632_writebits(data, 1<<3); // send 4 bits of data
  ht1632_chipfree(ht1632_cs); // done
}

void setup ()  // flow chart from page 17 of datasheet
{
  pinMode(ht1632_cs, OUTPUT);
  digitalWrite(ht1632_cs, HIGH);       /* unselect (active low) */
  pinMode(ht1632_wrclk, OUTPUT);
  pinMode(ht1632_data, OUTPUT);
  ht1632_sendcmd(HT1632_CMD_SYSDIS);  // Disable system
  ht1632_sendcmd(HT1632_CMD_COMS11);  // 16*32, PMOS drivers
  ht1632_sendcmd(HT1632_CMD_MSTMD);       /* Master Mode */
  ht1632_sendcmd(HT1632_CMD_SYSON);       /* System on */
  ht1632_sendcmd(HT1632_CMD_LEDON);       /* LEDs on */
  for (byte i=0; i<128; i++)
    ht1632_senddata(i, 0);  // clear the display!
  delay(LONGDELAY);
}

/*
* we keep a copy of the display controller contents so that we can
* know which bits are on without having to (slowly) read the device.
* Note that we only use the low four bits of the shadow ram, since
* we're shadowing 4-bit memory.  This makes things faster, but we
* COULD do something with the other half of our bytes !
*/
byte ht1632_shadowram[96];  // our copy of the display's RAM

/*
* plot a point on the display, with the upper left hand corner
* being (0,0), and the lower right hand corner being (23, 15).
* Note that Y increases going "downward" in contrast with most
* mathematical coordiate systems, but in common with many displays
* No error checking; bad things may happen if arguments are out of
* bounds!  (The ASSERTS compile to nothing by default
*/
void plot (char x, char y, char val)
{
  char addr, bitval;

  ASSERT(x >= 0);
  ASSERT(x <= X_MAX);
  ASSERT(y >= 0);
  ASSERT(y <= y_MAX);

  /*
  * The 4 bits in a single memory word go DOWN, with the LSB
  * (last transmitted) bit being on top.  However, writebits()
  * sends the LSB first, so we have to do a sort of bit-reversal
  * somewhere.  Here, this is done by shifting the single bit in
  * the opposite direction from what you might expect.
  */
  bitval = 8>>(y&3);  // compute which bit will need set
  addr = (x<<2) + (y>>2);  // compute which memory word this is in
  if (val) {  // Modify the shadow memory
    ht1632_shadowram[addr] |= bitval;
  }
  else {
    ht1632_shadowram[addr] &= ~bitval;
  }
  // Now copy the new memory value to the display
  ht1632_senddata(addr, ht1632_shadowram[addr]);
}

byte world[X_SIZE][Y_SIZE][2];
long density = 50;

void setupLife() {
  randomSeed(analogRead(5));
  for (int i = 0; i < X_SIZE; i++) {
    for (int j = 0; j < Y_SIZE; j++) {
      if (random(100) < density) {
        world[j][0] = 1;
      }
      else {
        world[j][0] = 0;
      }
      world[j][1] = 0;
    }
  }
}

void life() {
  while (1) {
    // Display current generation
    for (int i = 0; i < X_SIZE; i++) {
      for (int j = 0; j < Y_SIZE; j++) {
        plot(i, j, world[j][0]);
      }
    }
    delay(DISPDELAY);

    // Birth and death cycle
    for (int x = 0; x < X_SIZE; x++) {
      for (int y = 0; y < Y_SIZE; y++) {
        // Default is for cell to stay the same
        world
  • [y][1] = world
  • [y][0];
int count = neighbours(x, y);
        if (count == 3 && world
  • [y][0] == 0) {
// A new cell is born
          world
  • [y][1] = 1;
       }
        if ((count < 2 || count > 3) && world
  • [y][0] == 1) {
// Cell dies
          world
  • [y][1] = 0;
       }
      }
    }
  
    // Copy next generation into place

[continued in next post]
« Last Edit: December 06, 2008, 11:02:17 am by Andrew » Logged

UK
Offline Offline
Sr. Member
****
Karma: 1
Posts: 491
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

... and the rest:

Quote

 

    // Copy next generation into place
    for (int x = 0; x < X_SIZE; x++) {
      for (int y = 0; y < Y_SIZE; y++) {
        world
  • [y][0] = world
  • [y][1];
     }
    }
  }
}

int neighbours(int x, int y) {
 return world[(x + 1) % X_SIZE][y][0] +
         world
  • [(y + 1) % Y_SIZE][0] +
        world[(x + X_SIZE - 1) % X_SIZE][y][0] +
         world
  • [(y + Y_SIZE - 1) % Y_SIZE][0] +
        world[(x + 1) % X_SIZE][(y + 1) % Y_SIZE][0] +
         world[(x + X_SIZE - 1) % X_SIZE][(y + 1) % Y_SIZE][0] +
         world[(x + X_SIZE - 1) % X_SIZE][(y + Y_SIZE - 1) % Y_SIZE][0] +
         world[(x + 1) % X_SIZE][(y + Y_SIZE - 1) % Y_SIZE][0];
}

void loop ()
{
  setupLife();
  life();
}


 
Logged

UK
Offline Offline
Sr. Member
****
Karma: 1
Posts: 491
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

For a seasonal flavour (for those of us in the Northern hemisphere anyway), replace the appropriate bits of code with the following:

Quote

 #define NUMFLAKES 7
byte flakes[NUMFLAKES][2];

void snowflakes() {
  for (int i = 0; i < NUMFLAKES; i++) {
    flakes
  • = random(X_MAX + 1);
        flakes[1] = random(Y_MAX + 1);
      }
      while (1) {
        // Display flakes
        for (int i = 0; i < NUMFLAKES; i++) {
          plot(flakes
    • , flakes[1]-1, 1);
         plot(flakes
    • +1, flakes[1], 1);
         plot(flakes
    • , flakes[1]+1, 1);
         plot(flakes
    • -1, flakes[1], 1);
       }
        delay(DISPDELAY * 2);

        // Erase flakes
        for (int i = 0; i < NUMFLAKES; i++) {
          plot(flakes
    • , flakes[1]-1, 0);
         plot(flakes
    • +1, flakes[1], 0);
         plot(flakes
    • , flakes[1]+1, 0);
         plot(flakes
    • -1, flakes[1], 0);
       }
      
        // Move down
        for (int i = 0; i < NUMFLAKES; i++) {
          flakes[1] = flakes[1] + 1;
          if (random(10) > 7) {
            flakes
    • = flakes
      • + (random(3) - 1);
              }
              if (flakes[1] > (Y_MAX + 1)) {
                flakes[1] = -1;
                flakes
        • = random(X_MAX + 1);
                }
              }
            }
          }


          void loop ()
          {
            snowflakes();
          }
           
Andrew
Logged

SF Bay Area (USA)
Offline Offline
Tesla Member
***
Karma: 135
Posts: 6763
Strongly opinionated, but not official!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

BTW, my version of life ran significantly faster if I only updated the pixels that changed...  Though I'm not sure that running life faster is necessarily better (and I left the demo code in "slow" update-every-pixel mode, since I claimed that I was demonstrating the performance of doing that...)

For animation in general, you might want to investigate the "multiple write" capability of the chip (as seen in the latest code dump in ht1632_clear())
Code:
/*
 * ht1632_clear
 * clear the display, and the shadow memory, and the snapshot
 * memory.  This uses the "write multiple words" capability of
 * the chipset by writing all 96 words of memory without raising
 * the chipselect signal.
 */
void ht1632_clear()
{
  char i;

  ht1632_chipselect(ht1632_cs);  // Select chip
  ht1632_writebits(HT1632_ID_WR, 1<<2);  // send ID: WRITE to RAM
  ht1632_writebits(0, 1<<6); // Send address
  for (i = 0; i < 96/2; i++) // Clear entire display
    ht1632_writebits(0, 1<<7); // send 8 bits of data
  ht1632_chipfree(ht1632_cs); // done
  for (i=0; i < 96; i++)
    ht1632_shadowram[i] = 0;
}

(my; this worked out pretty nicely.  I got a display and a pleasant diversion, and the code works and seems to be usable, and assorted others have taken off and done additional neat things with it!)
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 4
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Wow. I mean, WOW. You are all geniuses. I have been beating my brains out trying to figure this thing out. The board expands out to 4 and I wanted something I could tinker with and build on because the price is outstanding. And to learn to use the Arduino to command it is priceless.

I'm still not clear on the connections between the Arduino and the board. Is there anyway a quickie schematic can be drawn up? That would be much appreciated.

I want to especially thank webobject, westfw and Andrew for sharing your code.
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 4
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I read the source and your notes and was able to successfully connect the arduino to the display board. Thank you, again!

Andrew, I am curious about your comments regarding the "multiple write" capabilities of the ht1632. Could you elaborate on that? Would that mean that you can pre-load the graphics/text data before commanding the board to begin display?

What about text? Do I need to design my own font or does the chip have one on board?
Logged

SF Bay Area (USA)
Offline Offline
Tesla Member
***
Karma: 135
Posts: 6763
Strongly opinionated, but not official!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

The complete code is getting a bit big to post here, but you should be able to get it from http://www.geocities.com/westfw/demo16x24.zip
This version has some 5x7 text capability, with a font for A-Z and 0-9 (the chip does NOT have any internal character generator.)

I'm trying to add some text and explanations to get the whole thing into a more "article-like" publication.  Assuming I get it finished, I'll put a note here and eventually try getting it up on the playgroup as well.  (it is, however, somewhat painful to have working code and sketches and be faced with writing mere text.  Sigh.)

The multiple-write thing is a speedup.  Normally you send a "write data" command, followed by 7 bits of address, followed by 4 bits of data, and then you start a new command.  Most of the library code I wrote does that, so the display is always updated 4bits at a time, taking a good 16-odd "pin wiggles" for each pixel you change.  In the demo program, it seems like that is "fast enough" for most of the things I tried, so I didn't do a lot of additional work.  However, if you send an additional 4 bits of data after the first set, the ht1632 will increment the address and put those in the next word, and so on, for as many words of data as you provide.  That means that you COULD update the entire display in about 12 + (96*4) ~= 400 wiggles instead of 384*16 ~= 6000 wiggles; a rather impressive improvement...

Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 20
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Could you please tell us what is the licence of the code you have posted here?
I'd like to use it on my personal pinball machine project. For that purpose, I intend to host modified versions of this code at Google Code.
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 20
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

this is the Google Code page for my Pinball Fantasies / Party Land Remake project: http://code.google.com/p/how-to-build-a-pinball/

also there is a video here:
and some photos here: http://www.flickr.com/photos/felipesanches
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 20
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Oh! I just noticed the licensing statement on the header!

In my project, I intend to concatenate a series of displays so that I can have a 168x16 dot matrix display. I have some ideas on how to proceed, in order to do that. I will host this code at google code and then I can give you write access to the svn if you wish to contribute there.
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 20
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

give me your username at google and I will add you as a contributor, westfw.

then you can follow these instructions:
http://code.google.com/p/how-to-build-a-pinball/source/checkout
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 2
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi !
Big thanks for westfw !
Just playing with arduino since a week .. and i am in love with it !

I made a little librairie

Need to do more work.. but it's working

How to use
Code:
#include <Led_matrix.h>

matrix lmatrix(10,11,12);//Data, write, cs
void setup()
{
  delay(1000);
  lmatrix.setup();
}

void loop()
{
  for( int i=0;i<24;i++)//24lignes
  {
    int r=random(0,7);
    int n;
    if(i>12)
    {
      n=(23-i);
    }
    else
    {
      n=i;
    }
    float BarSize=sin(n*(1.57/12))*r;
    lmatrix.DrawLine(i,(8+BarSize),i,(8-BarSize),55 );
  
  }
  //lmatrix.DrawString("ee",1,8);
  lmatrix.ShadowDsp();
  delay(100);
}


Edit: Link in next thread
« Last Edit: December 16, 2008, 01:23:07 pm by Ced2911 » Logged

Pages: 1 [2] 3 4 ... 25   Go Up
Jump to: