Created
December 1, 2016 14:37
-
-
Save anonymous/e5508c1ac047ea2f286d1fec4934bf57 to your computer and use it in GitHub Desktop.
Code for MakeUseOf.com Weatherproof High Tech Christmas Wreath project.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* 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