Hi Guys,
I’ve had this OpenHeart for many years, but I’m just now getting around to putting it to some use. I’m having some issues getting it to interface with my arduino, and I’m not sure what is going on.
Here is the original code as provided by the designer:
//**************************************************************//
// Name : Charlieplexed Heart control //
// Author : Jimmie P Rodgers www.jimmieprodgers.com //
// Date : 08 Feb, 2008 Last update on 02/13/08 //
// Version : 1.3 //
// Notes : Uses Charlieplexing techniques to light up //
// : a matrix of 27 LEDs in the shape of a heart //
// : project website: www.jimmieprodgers.com/openheart //
//****************************************************************
// 02/13/08 - v1.3
// I've changed the delay function to delayMicroseconds()
// Which dramatically improves the brightness of the
// displayed LEDs, while at the same time lowers the number
// of run cycles needed for a clean display. This is all
// around a substantial improvement that also add the
// control of color possibilities. I'll put that into v2
// along with the new play functions that will allow input.
// 02/12/08 - v1.2
// I found a solution for the array size issue with
// PROGMEM. Basically, using the <avr/pgmspace.h>
// library (included in the Arduino library) you can
// write directly to the Flash memory. Granting you
// access to the full 16k of storage. With this fix
// you can now have over 500 frames of animation, and
// still have plenty of room for your program.
// 02/11/08 - v1.1
// By making all the arrays const values, it increases
// the number of frames in the animation to 30. It will
// now run all the original animations at the same time.
#include <avr/pgmspace.h> //This is in the Arduino library
int opin = 13;
int owpin = 12;
int gpin = 11;
int gwpin = 10;
int bpin = 9;
int bwpin = 8;
const int pins[] = {
opin,owpin,gpin,gwpin,bpin,bwpin};
const int heartpins[27][2] ={
{gpin,opin},
{opin,gpin},
{bpin,opin},
{opin,bpin},
{gwpin,gpin},
{gwpin,opin},
{opin,gwpin},
{opin,owpin},
{bwpin,opin},
{opin,bwpin},
{bpin,bwpin},
{gpin,gwpin},
{gpin,owpin},
{owpin,gpin},
{owpin,opin},
{bpin,owpin},
{owpin,bpin},
{bwpin,bpin},
{gwpin,owpin},
{owpin,gwpin},
{bpin,gpin},
{bwpin,owpin},
{owpin,bwpin},
{bwpin,gwpin},
{gpin,bpin},
{gwpin,bwpin},
{gpin,bwpin}
};
int blinkdelay = 200; //This basically controls brightness. Lower is dimmer
int runspeed = 50; //smaller = faster
byte heart[][27] PROGMEM ={ // This stores the array in Flash ROM. You can easily have 500+ frames.
//
// You can actually arrange the lines in a way that it mimics the heart shape and it will
// run just fine. I use this for programming the animations, then reduce it to lines later.
// Example:
// { 1,1, 1,1,
// 1,1,1,1,1,1,1,
// 1,1,1,1,1,1,1,
// 1,1,1,1,1,
// 1,1,1,
// 1},
// { 0,0, 0,0,
// 0,0,0,0,0,0,0,
// 0,0,0,0,0,0,0,
// 0,0,0,0,0,
// 0,0,0,
// 0},
//Blinks all on and off
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
//Fills the heart up from the bottom
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,1,1,1},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,1,1,0,1,1,1,1},
{0,0,0,0,0,0,0,1,0,0,0,0,0,1,1,1,0,0,1,1,1,1,1,1,1,1,1},
{0,0,0,0,0,0,1,1,1,0,0,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1},
{0,1,1,0,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
//Parts fall off the bottom
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,0},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,1,0,1,1},
{1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,0,1,0,0,1,0,1,0,0,1,0,0},
{1,1,1,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,1,0,1,0,1,1,0,1,1},
{1,1,1,1,0,0,1,0,1,0,0,0,1,0,1,0,1,0,0,1,0,1,0,0,1,0,0},
{0,1,1,0,0,1,0,1,0,1,0,1,0,1,0,1,0,1,1,0,1,0,1,1,0,1,1},
{0,0,0,0,0,0,1,0,1,0,0,0,1,0,1,0,1,0,0,1,0,1,0,0,1,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,1,0,1,0,1,1,0,1,1},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,1,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,1},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
//Fills up from the center
{0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,1,0,0,0,0,0,0},
{0,0,0,0,0,1,1,0,1,1,0,0,1,1,1,1,1,0,0,1,1,1,0,0,1,0,0},
{1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1,1,0,1,1,1,1,1,1},
{1,1,1,1,1,0,0,1,0,0,1,1,0,0,0,0,0,1,1,0,0,0,1,1,0,1,1},
{1,1,1,1,1,0,0,1,0,0,1,1,0,0,0,0,0,1,1,0,0,0,1,1,0,1,1},
//Kill line
{2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
};
void setup()
{
// blinkall(2); // useful for testing
}
void loop()
{
// sequenceon(); // useful for testing
play();
}
void turnon(int led)
{
int pospin = heartpins[led][0];
int negpin = heartpins[led][1];
pinMode (pospin, OUTPUT);
pinMode (negpin, OUTPUT);
digitalWrite (pospin, HIGH);
digitalWrite (negpin, LOW);
}
void alloff()
{
for(int i = 0; i < 6; i++)
{
pinMode (pins[i], INPUT);
}
}
void play()
{
boolean run = true;
byte k;
int t = 0;
while(run == true)
{
for(int i = 0; i < runspeed; i++)
{
for(int j = 0; j < 27; j++)
{
k = pgm_read_byte(&(heart[t][j]));
if (k == 2)
{
run = false;
}
else if(k == 1)
{
turnon(j);
delayMicroseconds(blinkdelay);
alloff();
}
else if(k == 0)
{
delayMicroseconds(blinkdelay);
}
}
}
t++;
}
}
void blinkall(int numblink)
{
alloff();
for(int n = 0; n < numblink; n++)
{
for(int i = 0; i < runspeed; i++)
{
for(int j = 0; j < 27; j++)
{
turnon(j);
delay(blinkdelay);
alloff();
}
}
delay(500);
}
}
void sequenceon()
{
for(int i = 0; i < 27; i++)
{
turnon(i);
delay(800);
alloff();
delay(800);
}
}
This code doesn’t even compile for me. After a little bit of googling, I found that the likely culprit was the way the heart variable was assigned. So after a bit of fiddling I ended up changing this:
byte heart[][27] PROGMEM ={
To this:
char heart[][27] ={
This lets it compile, but it still doesn’t run correctly. Even after changing the pinouts around to make things more obvious to me, it still doesn’t work. If I run the code posted below, I just get a single LED that lights up, LED22.
//**************************************************************//
// Name : Charlieplexed Heart control //
// Author : Jimmie P Rodgers www.jimmieprodgers.com //
// Date : 08 Feb, 2008 Last update on 02/13/08 //
// Version : 1.3 //
// Notes : Uses Charlieplexing techniques to light up //
// : a matrix of 27 LEDs in the shape of a heart //
// : project website: www.jimmieprodgers.com/openheart //
//****************************************************************
// 02/13/08 - v1.3
// I've changed the delay function to delayMicroseconds()
// Which dramatically improves the brightness of the
// displayed LEDs, while at the same time lowers the number
// of run cycles needed for a clean display. This is all
// around a substantial improvement that also add the
// control of color possibilities. I'll put that into v2
// along with the new play functions that will allow input.
// 02/12/08 - v1.2
// I found a solution for the array size issue with
// PROGMEM. Basically, using the <avr/pgmspace.h>
// library (included in the Arduino library) you can
// write directly to the Flash memory. Granting you
// access to the full 16k of storage. With this fix
// you can now have over 500 frames of animation, and
// still have plenty of room for your program.
// 02/11/08 - v1.1
// By making all the arrays const values, it increases
// the number of frames in the animation to 30. It will
// now run all the original animations at the same time.
#include <avr/pgmspace.h> //This is in the Arduino library
int pin1 = 2;
int pin2 = 3;
int pin3 = 4;
int pin4 = 5;
int pin5 = 6;
int pin6 = 7;
const int pins[] = {
pin1,pin2,pin3,pin4,pin5,pin6};
const int heartpins[27][2] ={
{pin3,pin1}, {pin1,pin3}, {pin2,pin1}, {pin1,pin2},
{pin3,pin4}, {pin4,pin1}, {pin1,pin4}, {pin1,pin5}, {pin6,pin1}, {pin1,pin6}, {pin6,pin2},
{pin4,pin3}, {pin3,pin5}, {pin5,pin3}, {pin5,pin1}, {pin2,pin5}, {pin5,pin2}, {pin2,pin6},
{pin4,pin5}, {pin5,pin4}, {pin3,pin2}, {pin6,pin5}, {pin5,pin6},
{pin4,pin6}, {pin2,pin3}, {pin6,pin4},
{pin4,pin2}
};
int blinkdelay = 200; //This basically controls brightness. Lower is dimmer
int runspeed = 50; //smaller = faster
char heart[][27] ={ // This stores the array in Flash ROM. You can easily have 500+ frames.
//
// You can actually arrange the lines in a way that it mimics the heart shape and it will
// run just fine. I use this for programming the animations, then reduce it to lines later.
// Example:
// { 1,1, 1,1,
// 1,1,1,1,1,1,1,
// 1,1,1,1,1,1,1,
// 1,1,1,1,1,
// 1,1,1,
// 1},
// { 0,0, 0,0,
// 0,0,0,0,0,0,0,
// 0,0,0,0,0,0,0,
// 0,0,0,0,0,
// 0,0,0,
// 0},
//Blinks all on and off
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
//Fills the heart up from the bottom
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,1,1,1},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,1,1,0,1,1,1,1},
{0,0,0,0,0,0,0,1,0,0,0,0,0,1,1,1,0,0,1,1,1,1,1,1,1,1,1},
{0,0,0,0,0,0,1,1,1,0,0,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1},
{0,1,1,0,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
//Parts fall off the bottom
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,0},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,1,0,1,1},
{1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,0,1,0,0,1,0,1,0,0,1,0,0},
{1,1,1,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,1,0,1,0,1,1,0,1,1},
{1,1,1,1,0,0,1,0,1,0,0,0,1,0,1,0,1,0,0,1,0,1,0,0,1,0,0},
{0,1,1,0,0,1,0,1,0,1,0,1,0,1,0,1,0,1,1,0,1,0,1,1,0,1,1},
{0,0,0,0,0,0,1,0,1,0,0,0,1,0,1,0,1,0,0,1,0,1,0,0,1,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,1,0,1,0,1,1,0,1,1},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,1,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,1},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
//Fills up from the center
{0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,1,0,0,0,0,0,0},
{0,0,0,0,0,1,1,0,1,1,0,0,1,1,1,1,1,0,0,1,1,1,0,0,1,0,0},
{1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1,1,0,1,1,1,1,1,1},
{1,1,1,1,1,0,0,1,0,0,1,1,0,0,0,0,0,1,1,0,0,0,1,1,0,1,1},
{1,1,1,1,1,0,0,1,0,0,1,1,0,0,0,0,0,1,1,0,0,0,1,1,0,1,1},
//Kill line
{2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
};
void setup()
{
// blinkall(2); // useful for testing
}
void loop()
{
// sequenceon(); // useful for testing
play();
}
void turnon(int led)
{
int pospin = heartpins[led][0];
int negpin = heartpins[led][1];
pinMode (pospin, OUTPUT);
pinMode (negpin, OUTPUT);
digitalWrite (pospin, HIGH);
digitalWrite (negpin, LOW);
}
void alloff()
{
for(int i = 0; i < 6; i++)
{
pinMode (pins[i], INPUT);
}
}
void play()
{
boolean run = true;
byte k;
int t = 0;
while(run == true)
{
for(int i = 0; i < runspeed; i++)
{
for(int j = 0; j < 27; j++)
{
k = pgm_read_byte(&(heart[t][j]));
if (k == 2)
{
run = false;
}
else if(k == 1)
{
turnon(j);
delayMicroseconds(blinkdelay);
alloff();
}
else if(k == 0)
{
delayMicroseconds(blinkdelay);
}
}
}
t++;
}
}
void blinkall(int numblink)
{
alloff();
for(int n = 0; n < numblink; n++)
{
for(int i = 0; i < runspeed; i++)
{
for(int j = 0; j < 27; j++)
{
turnon(j);
delay(blinkdelay);
alloff();
}
}
delay(500);
}
}
void sequenceon()
{
for(int i = 0; i < 27; i++)
{
turnon(i);
delay(800);
alloff();
delay(800);
}
}
So I fiddled around even more, and finally got a piece of code that does something that makes sense. This piece of code just counts through the LEDs one at a time, in order. But even with this, I still haven’t been able to figure out how to get it to blink through the animations the original code contained.
//**************************************************************//
// Name : Charlieplexed Heart control //
// Author : Jimmie P Rodgers www.jimmieprodgers.com //
// Date : 08 Feb, 2008 Last update on 02/13/08 //
// Version : 1.3 //
// Notes : Uses Charlieplexing techniques to light up //
// : a matrix of 27 LEDs in the shape of a heart //
// : project website: www.jimmieprodgers.com/openheart //
//****************************************************************
// 02/13/08 - v1.3
// I've changed the delay function to delayMicroseconds()
// Which dramatically improves the brightness of the
// displayed LEDs, while at the same time lowers the number
// of run cycles needed for a clean display. This is all
// around a substantial improvement that also add the
// control of color possibilities. I'll put that into v2
// along with the new play functions that will allow input.
// 02/12/08 - v1.2
// I found a solution for the array size issue with
// PROGMEM. Basically, using the <avr/pgmspace.h>
// library (included in the Arduino library) you can
// write directly to the Flash memory. Granting you
// access to the full 16k of storage. With this fix
// you can now have over 500 frames of animation, and
// still have plenty of room for your program.
// 02/11/08 - v1.1
// By making all the arrays const values, it increases
// the number of frames in the animation to 30. It will
// now run all the original animations at the same time.
#include <avr/pgmspace.h> //This is in the Arduino library
int pin1 = 2;
int pin2 = 3;
int pin3 = 4;
int pin4 = 5;
int pin5 = 6;
int pin6 = 7;
const int pins[] = {
pin1,pin2,pin3,pin4,pin5,pin6};
const int heartpins[27][2] ={
{pin3,pin1}, {pin1,pin3}, {pin2,pin1}, {pin1,pin2},
{pin3,pin4}, {pin4,pin1}, {pin1,pin4}, {pin1,pin5}, {pin6,pin1}, {pin1,pin6}, {pin6,pin2},
{pin4,pin3}, {pin3,pin5}, {pin5,pin3}, {pin5,pin1}, {pin2,pin5}, {pin5,pin2}, {pin2,pin6},
{pin4,pin5}, {pin5,pin4}, {pin3,pin2}, {pin6,pin5}, {pin5,pin6},
{pin4,pin6}, {pin2,pin3}, {pin6,pin4},
{pin4,pin2}
};
int blinkdelay = 200; //This basically controls brightness. Lower is dimmer
int runspeed = 500; //smaller = faster
char heart[][27] ={ // This stores the array in Flash ROM. You can easily have 500+ frames.
//
// You can actually arrange the lines in a way that it mimics the heart shape and it will
// run just fine. I use this for programming the animations, then reduce it to lines later.
// Example:
// { 1,1, 1,1,
// 1,1,1,1,1,1,1,
// 1,1,1,1,1,1,1,
// 1,1,1,1,1,
// 1,1,1,
// 1},
// { 0,0, 0,0,
// 0,0,0,0,0,0,0,
// 0,0,0,0,0,0,0,
// 0,0,0,0,0,
// 0,0,0,
// 0},
//Fills up from the center
{0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,1,0,0,0,0,0,0},
{0,0,0,0,0,1,1,0,1,1,0,0,1,1,1,1,1,0,0,1,1,1,0,0,1,0,0},
{1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1,1,0,1,1,1,1,1,1},
{1,1,1,1,1,0,0,1,0,0,1,1,0,0,0,0,0,1,1,0,0,0,1,1,0,1,1},
{1,1,1,1,1,0,0,1,0,0,1,1,0,0,0,0,0,1,1,0,0,0,1,1,0,1,1},
};
void setup()
{
// blinkall(2); // useful for testing
}
void loop()
{
sequenceon(); // useful for testing
// play();
}
void turnon(int led)
{
int pospin = heartpins[led][0];
int negpin = heartpins[led][1];
pinMode (pospin, OUTPUT);
pinMode (negpin, OUTPUT);
digitalWrite (pospin, HIGH);
digitalWrite (negpin, LOW);
}
void alloff()
{
for(int i = 0; i < 6; i++)
{
pinMode (pins[i], INPUT);
}
}
void play()
{
boolean run = true;
byte k;
int t = 0;
while(run == true)
{
for(int i = 0; i < runspeed; i++)
{
for(int j = 0; j < 27; j++)
{
k = pgm_read_byte(&(heart[t][j]));
if (k == 2)
{
run = false;
}
else if(k == 1)
{
turnon(j);
delayMicroseconds(blinkdelay);
alloff();
}
else if(k == 0)
{
delayMicroseconds(blinkdelay);
}
}
}
t++;
}
}
void blinkall(int numblink)
{
alloff();
for(int n = 0; n < numblink; n++)
{
for(int i = 0; i < runspeed; i++)
{
for(int j = 0; j < 27; j++)
{
turnon(j);
delay(blinkdelay);
alloff();
}
}
delay(500);
}
}
void sequenceon()
{
for(int i = 0; i < 27; i++)
{
turnon(i);
delay(800);
alloff();
delay(800);
}
}
Does anyone have any ideas what I can try? I’m sure I could eventually figure out how to make these animations work, but I I’m really not sure where to begin to figure out how to store them while working with charlieplexing, this is all a bit new to me.