Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Code for MakeUseOf.com Weatherproof High Tech Christmas Wreath project.
/* This code was modified from the Beating Heart tutorial here: http://arduino-er.blogspot.de/2015/02/beating-heart-animation-on-8x8-led.html
* It works with an 8 x 8 LED Matrix and requires no 74HC595 chip. Details on how to build the matrix, and create the Character Maps
* can be found at www.makeuseof.com if you have any questions about the code or the project, leave a comment under the article "Make Your Own High-Tech Christmas Wreath"
* Ian Buckley, December 2016
*/
//First, we need an array of our row pins - D2 through D9
const int row[8] = {
2,3,4,5,6,7,8,9 //Arduino Nano pins D2 through D9
};
//We need the same for out column pins. If you find in testing that the screen displays
//backwards, reversing these values my be a quick fix!
const int col[8] ={
10,11,12,14,15,16,17,18 //Arduino Nano pins D10 through D12, and A0 through A4
};
//We'll also need a pin and a couple fo variables for our motion sensor
int pirPin = 19; //which is the same as A5 on the nano.
int pirState = LOW;
int val = 0; // abritrary value to check the pirState against
bool pirTrigger = false;
const int pirLockTime = 12000; // this determins how long your message will play for, play around with this number
//to get it to end when you would like
int pirCountdown = pirLockTime;
//now we declare a 2d array of pixels, 8x8. We will use this to change the state
//of any pixel in the grid later
int pixels[8][8];
//we will create a constant variable for the speed the screen refreshes, if you want to
//change the speed, you only need to change this value
const int refreshSpeed = 500;
//and another to decrement in our loop method
int countDown = refreshSpeed;
//We need a variable to store an index for what is currently on the screen, to iterate through later
int currentCharIndex = 0;
//Here, we are defining a type. Don't worry if you don't fully understand it, it just keeps things
//a little neater when refering to our character maps. The capitals are totally optional here.
typedef bool CHAR_MAP_NAME[8][8];
//this is where we actually store our character bool maps, each 1 and 0 represents on or off,
//but you could as easily think of them as True or False, or HIGH or LOW.
//you can use the excel spreadsheet provided to create these quickly.
const CHAR_MAP_NAME blank = {
{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 , 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 , 0 , 0},
{0 , 0 , 0 , 0 , 0 , 0 , 0 , 0},
};
const CHAR_MAP_NAME threedownthreein = {
{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 , 0 , 0 , 0 , 0 , 0},
{0 , 0 , 0 , 0 , 0 , 0 , 0 , 0},
{0 , 0 , 0 , 0 , 0 , 0 , 0 , 0},
};
//this integer represents the number of frames, in this case it is 4, as we display
//each character map twice.
const int noOfFrames = 5;
//this is the first confusing part. We are declairing a pointer which points
//to the character map positions in memory, and puts them in an array in the order
//we want to display them. The number here must always match our number of frames for it to work.
const CHAR_MAP_NAME *charMap[noOfFrames] ={
&blank,
&threedownthreein,
&blank,
&blank,
&threedownthreein
};
void setup(){
// lets initialise our pins
for (int i=0;i<8;i++){
pinMode(row[i], OUTPUT); //initialising our 8 rows
pinMode(col[i],OUTPUT); //initialised the 8 collumns
//motion sensor
pinMode(pirPin, INPUT);
digitalWrite(col[i], LOW); //making sure all of our column pins start off.
}
}
//Now we create a function to set up what will be displayed on our LED screen.
//every time we want to change what is displayed, this function will get called.
void screenSetup(){
//We need to grab the character map name for our current character index,
//we can get this from the *charMap array we just created
const CHAR_MAP_NAME *thisMap = charMap[currentCharIndex];
//now we loop over our 8x8 grid in both x and y directions
for (int x = 0; x < 8; x++)
{
for (int y = 0; y < 8; y++)
{
//we create a bool here to determine whether the position in the character map is
//1 - on or 0 - off
bool on = (*thisMap)[x][y];
//if it is meant to be on, set pin HIGH, else set them to LOW
if(on)
{
pixels[x][y] = HIGH;
}
else
{
pixels[x][y] = LOW;
}
}
}
//finally in this method we need to increment our current character index so that
//it moves on to the next character map, and reset it if it reaches the end of our sequence
currentCharIndex++;
if(currentCharIndex>=noOfFrames){
currentCharIndex = 0;
}
}
//Once we have determined what should be on our screen, we need a function to actually
//refresh the display
void refreshScreen(){
//we iterate over our rows, setting them to LOW, and for each row interate over the
//columns and check the state of each pixel in the array we populated in our screenSetup function
for (int currentRow = 0; currentRow < 8; currentRow++){
digitalWrite(row[currentRow], LOW);
for (int currentCol = 0; currentCol < 8; currentCol++){
int thisPixel = pixels[currentRow][currentCol];
//now we can write the HIGH or LOW value of thisPixel to the LED pixel.
digitalWrite(col[currentCol], thisPixel);
//If we turned the pixel on, we turn it of again to reset the screen before the next time refreshScreen gets called
//from our loop function
if (thisPixel == HIGH) {
digitalWrite(col[currentCol], LOW);
}
}
//We then turn the whole row back to high to reset it, ready for the next call from the loop funtion
digitalWrite(row[currentRow], HIGH);
}
}
void loop(){
//Our loop function waits for movement to be detected, and triggers the screen when it is.
//the decrementing of our countdown happens in loop, along with the
//refreshing and setting up of our screen.
//refresh screen gets called every loop, and if the countdown reaches 0 we setup a new screen to be displayed.
val = digitalRead(pirPin);
if (val == HIGH){ // if movement is detected, trigger the screen
pirTrigger = true;
}
//if there is no more movement, and the pirCountdown cool off is over, reset.
else if (val == LOW && pirCountdown <=0)
{
pirTrigger=false;
pirCountdown = pirLockTime;
}
//keep updating the display for the duration of the pirCountdown
if(pirTrigger==true && pirCountdown > 0)
{
refreshScreen();
countDown--;
pirCountdown--;
if(countDown <= 0)
{
countDown = refreshSpeed;
screenSetup();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.