Here's some more demo code to play with. Now has "plot(x,y)" function, and line drawing.
The brightness "problem" is more serious than I thought since LEDs start to dim when more than one third are lit in any particular ROW (my initial statement suggest 1/3 of all the LEDs, which was silly given than only one row is actually illuminated at any one time. Sigh.) As a result, for example, a horizontal line and a vertical line have significantly different brightnesses. This shows up in the "Cross" part of the demo.
It looks like the top 8 levels of PWM dimming are all about the same brightness when used with the displays in this board.
/*
* demo16x24.c - Arduino demo program for Holtek HT1632 LED driver chip,
* As implemented on the Sure Electronics DE-DP016 display board
* (16*24 dot matrix LED module.)
* Nov, 2008 by Bill Westfield ("WestfW")
*/
#include "ht1632.h"
#define X_MAX 23
#define Y_MAX 15
#define ASSERT(condition) //nothing
/*
* Set these constants to the values of the pins connected to the SureElectronics Module
*/
static const byte ht1632_data = 10; // Data pin (pin 7)
static const byte ht1632_wrclk = 11; // Write clock pin (pin 5)
static const byte ht1632_cs = 12; // 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 8) 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]);
}
/*
* scan()
* scan all the leds one at a time,
* using the plot() function, so as to demonstate the limits
* of "plot" performance.
*/
void scan ()
{
byte x,y, bits;
for (y=0; y<=Y_MAX; y++) {
for (x=0; x <= X_MAX; x++) {
plot(x,y,1);
delay(DISPDELAY);
plot(x,y,0);
}
}
}
/*
* random_walk()
* have a single LED walk all over the display, randomly.
*/
void random_walk ()
{
char x,y, dx, dy;
dx = dy = 1;
byte change;
for (int i=0; i < (DEMOTIME/DISPDELAY); i++) {
plot(x,y,1); // draw a point
delay(DISPDELAY); // wait a bit.
change = random(1,32);
/*
* figure out where to go next. This code is a bit
* random in more senses than one, but it seems to
* have results that are more or less what I had in
* mind for this portion of the demo.
*/
if (change < 9) {
// do nothing
}
else if (change == 10) {
dx = -dx;
}
else if (change == 11) {
dy = -dy;
}
else if (change == 12) {
dx = dy = 0;
}
else if (change == 13) {
dx = dy = 1;
}
else if (change == 14) {
dx = dy = -1;
}
plot(x,y,0); // erase the point
x = x + dx;
y = y+ dy;
if (x > X_MAX) {
dx = -1;
x = X_MAX;
}
else if (x < 0) {
x = 0;
dx = 1;
}
if (y > Y_MAX) {
y = Y_MAX;
dy = -1;
}
else if (y < 0) {
y = 0;
dy = 1;
}
}
}
// end of part 1