Feedback!

Heart Matrix

Views: 2906 Difficulty: 1 Status: Complete
Heart_matrix_d

Standalone programmable Heart-Shaped LED display.

The standalone version of our unique heart-shaped LED display, the Heart Matrix. This loving little gadget can display whatever text you want. It is fully programmable via the free Arduino software. The Heart Matrix LEO is packed with capabilities! It can be a clock, sense sound, communicate over USB and serial, and do just about anything else an Arduino Leonardo can do.

A Throng of Heart Matrices

Heart_matrix_5_hearts
The heart matrices traveling in a pack.

The Heart Matrix LEO in action.

See the heart Matrix getting re-programmed and displaying its sound-sensing mode.

Heart Matrix Hello Code

To get started let's send some text to the Heart Matrix. You can edit the text inside the hm.set_message() function to send your own message.
   hm.set_message(" Your message here! ");
Notice how we set the scroll speed in the line:
  hm.set_scroll_wait(max(20, analogRead(0)/4)); 
Here we are making the thumb wheel potentiometer control the speed the text is scrolling. We use the max function so that it the delay will never be less than 20 milliseconds. Remember the larger the number you give to the hm.set_scroll_wait function the slower the text goes. This is the inverse of speed. See the entire sketch below:
/* LucidTronix Heart Matrix LEO LED Display.
 * Text on the Heart Matrix
 * For instructions details and schematic, See:
 * http://www.lucidtronix.com/tutorials/57  */
#include <MsTimer2.h>
#include <HeartMatrix.h>

HeartMatrix hm = HeartMatrix(5,6,7); // dataPin is on 5, Latch is on 6, and clock is on 7

void displayer2(){  
  hm.displayer();
}

void setup()
{
   MsTimer2::set(1,displayer2); 
   MsTimer2::start(); 
   hm.set_message(" Hello I'm the Heart Matrix from LucidTroniX! ");
}
   
void loop(){
  hm.on();
  hm.set_scroll_wait(max(20, analogRead(0)/4)); 
}

Heart Matrix Sample Code

This program has three modes: clock, sound and text. The mode button toggles between the different modes. The code for each mode is explained in more detail in their respective tutorials: see the Heart Matrix Clock and the Sound Sensing Heart Matrix tutorials for example. Here we wrap the clock and sound logic in their own functions. This allows us to have a very simple main loop that dispatches to the proper function based on the current mode:
void loop() {
  if(mode == 0) sound_display();
  else if(mode == 1) clock_display();
  else if(mode == 2) text_display();
  check_buttons();
}
The check_buttons() function checks to see if the mode button was pressed or if the potentiometer was spun to change the scrolling speed:
void check_buttons(){
 if(digitalRead(9) == HIGH && millis() - last_press > 250){
   mode = ++mode % num_modes;
   last_press = millis();
 }
 hm.set_scroll_wait(max(20, analogRead(0)/4)); 
}
The variable last_press is an unsigned long and it is used to debounce the button press. This is necessary because the arduino is looping through the main function far faster than our fingers move over the buttons. So the check_Buttons function might be called many times during a single button push. The last_press variable and the check:
millis() - last_press > 250
in the if statement prevents the mode from changing if it has already changed once in the past 250 milliseconds. See the entire code below.
/* LucidTronix Heart Matrix LEO LED Display.
 * Demoing the heart matrix clock and sound sensor
 * For instructions details and schematic, See:
 * http://www.lucidtronix.com/tutorials/57
 */
#include <Wire.h>
#include <MsTimer2.h>
#include <HeartMatrix.h>
#include <MCP79410.h>

// dataPin is on 5, Latch is on 6, and clock is on 7
HeartMatrix hm = HeartMatrix(5,6,7);

MCP79410 clock = MCP79410();

int mode = 0;
int num_modes = 3;
unsigned long last_press = 0;

// clock global variables
String stime = "";
unsigned int last_update = 0;

// sound global variables
const int buffer_size = 15;
int noises[buffer_size];
const int num_cols = 10;
int volumes[num_cols];

int cur_index = 0;
unsigned long last_shift = 0;
int mic_pin = 1;
int delay_speed = 40;
unsigned long max_var = 0;
unsigned long min_var = 99999999;

void setup() {
   Serial.begin(9600);
   MsTimer2::set(1,displayer2);
   MsTimer2::start();
   for (int i = 0 ; i < num_cols; i++) volumes[i] = 8;
   for (int i = 0 ; i < buffer_size; i++) noises[i] = random(300,612);
   hm.animate();
   
   Wire.begin(); 
   //clock.setDateTime(__DATE__,__TIME__);
}

void loop() {
  if(mode == 0) sound_display();
  else if(mode == 1) clock_display();
  else if(mode == 2) text_display();
  check_buttons();
}

void displayer2(){
  hm.displayer();
}

void check_buttons(){
 if(digitalRead(9) == HIGH && millis() - last_press > 250){
   mode = ++mode % num_modes;
   if(mode == 0) hm.animate();
   if(mode == 2) hm.set_message(" Hello I'm the Heart Matrix! "); 
   last_press = millis();
 }
 hm.set_scroll_wait(max(20, analogRead(0)/4)); 
}

void text_display(){
  hm.on();  
}
void clock_display(){
  hm.on();  
  if (millis() - last_update > 1000){
    stime = " ";
    
    byte a_hour = clock.hour24();
    String a_hour_s = String(a_hour,HEX);
    int hour_int = a_hour_s.toInt();
    String ampm = "am  ";
    if (hour_int >= 12){
      ampm = "pm  ";
      hour_int -= 12;
      a_hour_s = String(hour_int);
    }
    if (a_hour == 0 || a_hour == 12 ) stime += String(12); 
    else stime += a_hour_s;  
    stime += ":";
    byte a_min = clock.minute();
    if (a_min < 10 ) stime += String(0);
    stime += String(a_min,HEX);
    stime += ":";
    byte a_sec = clock.second();
    if (a_sec < 10 ) stime += String(0);
    stime += String(a_sec,HEX);
    hm.set_message(stime+ampm );
    last_update = millis();
  }
}

void sound_display(){
   // Get a value from the electret microphone   
   noises[cur_index] = analogRead(mic_pin) ;
   cur_index++;
   if(cur_index == buffer_size) cur_index = 0;
   // Control the scroll speed with a potentiometer on analog pin 0
   delay_speed = max(10, (analogRead(0)/4));
   
   // Shift the waveform over one column
   if (millis() - last_shift > delay_speed){
     last_shift = millis();
     unsigned int avg = average(noises, buffer_size);
     unsigned long var = variance(noises, buffer_size);
     max_var = max(var, max_var);
     min_var = min(var, min_var);
     var = map(var,min_var , max_var, 0, 9);
     for (int i = 1 ; i < num_cols; i++){
      volumes[i-1] = volumes[i];
     }
     volumes[num_cols-1] = var;
   }
   
   // Write the wave form to LED display
   for (int i = 0 ; i < num_cols; i++){
     for (int j = 0 ; j < volumes[i]; j++){
       hm.set_pixel(i, j, true);  
     }
     for (int j = volumes[i] ; j < 8; j++){
       hm.set_pixel(i, j, false);  
     }
   }  
}

int average(int* array, int length){
  int sum = 0;
  int i;
  for(i = 0; i < length ; i++){
    sum += array[i];
  }
  int avg = sum / length ;
  return avg;
}

unsigned long variance(int* array, int length){
  long sum = 0;
  long avg = average(array, length);
  for(int i = 0; i < length ; i++){
    sum += (array[i] - avg)*(array[i] - avg);
  }
  unsigned long var = sum / length;
  return var;	
}

Heart Matrix Arduino Library

MS Timer2 Library

We use the MS Timer2 library to run the Heart Matrix display function as an interrupt function so that the LED matrices get updated quicker than your eye can make out the individual columns of light. The library is the excellent work of Wim Leers, and we host it here for your downloading convenience :).
Click Here to Download: MS Timer2 Library

MCP79410 Real Time Clock Arduino Library

Parts

Title Description # Cost Link Picture
ATMEGA32U4-MU Integrated Circuits MCU AVR 32K FLASH 16MHZ 44-QFN Value: 2.7 V ~ 5.5 V 16MHz 1 $6.04 Link Screen_shot_2012-12-28_at_7.31.41_pm
Clock MCP79410 Real-Time Clock Chip I²C, 2-Wire Serial 1.8 V ~ 5.5 V Alarm, Leap Year, Square Wave Output, SRAM, Unique ID Value: I²C 1 $1.08 Link 8-soic
LED Dot Matrix Displays Dot Matrix Panel 35LED Green Row CA Column CC 12-Pin DIP Value: 2.8v Green 2 $0.99 Link 2005497
Electret Condenser Microphone MIC COND ANALOG OMNI -44DB Value: -44dB ±2dB 20Hz ~ 20kHz 1 $0.96 Link Screen_shot_2012-12-28_at_7.35.36_pm
LM386M IC AMP AUDIO PWR .325W AB 8SOIC Value: 4 V ~ 12 V 1 $0.91 Link 8-soic_751
USB Micro B Female Connector Micro USB Surface Mount, Right Angle, Horizontal 1 $0.72 Link 10103594-0001lf_sml
Shift Register IC SHIFT REGISTER 8BIT 16-SOP Tri-State Serial to Parallel Value: 74HC 3 $0.65 Link Screen_shot_2012-12-28_at_7.32.29_pm
Crystal CRYSTAL 16.00000 MHZ 20PF SMD Value: 16MHz 1 $0.53 Link Ecs-270-20-3x-en-tr
Switch SWITCH SLIDE DPDT 6VDC 0.3A SMT Value: DPDT 1 $0.44 Link Mfg_js202011scqn
Button Tactile switch SMD SPST 0.05A 12V Value: SPST 2 $0.2 Link Fsm4jsma
Capacitor CAP CER 10UF 10V Y5V 0805. Ceramic Capacitor. Value: 10µF 4 $0.16 Link 0805(12_5mm_thickness)
Capacitor CAP CER 0.1UF 50V Y5V 0805 Value: 0.1µF 4 $0.1 Link 0805(6_0mm_thickness)
Resistor Array RES ARRAY 300 OHM 4 RES 1206 Value: 300 3 $0.02 Link Vishay_-_cra06s-8
Permalink: http://lucidtronix.com/tutorials/57
Build your own clock with the MCP79410 chip and 4 7-Segment LED modules....
The Wearable Wayfinder is a totally programmable, beautiful little computer for your wrist packed wit...
Combine an electret microphone, Arduino and a heart matrix for a sound-sensitive wearable device....
Connecting the MCP79410 real-time clock chip and our Heart Matrix you can show the time with love....
Two LED matrices give 70 LEDs to light up a necklace with messages....
Wearable digital compass displays the direction in green LEDs....
Handheld gaming machine, based on the Arduino Leonardo, equipped with joystick, SD card and more....
32 buttons for a fully-functioning hand-held USB keyboard....