Today, we’re going to build faces using LEDs and a joystick. Previously, we’ve wired up LEDs and learned how to control individual lights, how to draw pictures, and how to use a joystick. Today, we’re gonna put them all together to make a set of emotions based on the direction we push the joystick. Again, we’ve got the debounce, so the emotion will stay on our screen until we push the stick in a new direction.
What you’ll need:
- 8×8 LED grid
- Joystick
- Female to Male wies
We need to figure out what emotions we want to work. Let’s start with some of the standard stuff – I’ve chosen neutral, happy, sad, angry, and scared, but anything can work as long as you’re comfortable drawing them out. Here’s a brief example of my neutral face:
0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,
0,1,0,0,0,0,1,0,
0,1,0,0,0,0,1,0,
0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,
0,1,1,1,1,1,1,0,
0,0,0,0,0,0,0,0,
Each of the numbers is a light (hence 8×8), and the “1”s are the LEDs are going to light up. You can see I’ve got two eyes and a closed mouth. You can honestly draw out whatever you want – but again, I’ve stuck to the ordinary. I draw the rest of my faces out. Let’s get started with the code:
//screen size #define SCREEN_W (8) #define SCREEN_H (8) // joystick center area where nothing happens #define DEADZONE (30) // types of mood #define NEUTRAL 0 #define HAPPY 1 #define SAD 2 #define ANGRY 3 #define SCARED 4 // Arduino pins and their connection to the 8x8 LED grid. // y values int anodes[] = { 9,4,A5,6,10,A4,11,A2 }; // x values int cathodes[] = { 5,12,13,8,A3,7,3,2 }; // the current state int mood=NEUTRAL; // pictures of each mood. 1 means turn the light on, 0 means keep the // light off. char face_neutral[] = { 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,1,0,0,0,0,1,0, 0,1,0,0,0,0,1,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,1,1,1,1,1,1,0, 0,0,0,0,0,0,0,0, }; char face_happy[] = { 0,0,0,0,0,0,0,0, 0,1,0,0,0,0,1,0, 0,1,0,0,0,0,1,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,1,0,0,0,0,1,0, 0,0,1,1,1,1,0,0, 0,0,0,0,0,0,0,0, }; char face_sad[] = { 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,1,0,0,1,0,0, 0,1,0,0,0,0,1,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,1,1,1,1,0,0, 0,1,0,0,0,0,1,0, }; char face_angry[] = { 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,1,0,0,0,0,1,0, 0,0,1,0,0,1,0,0, 0,0,0,0,0,0,0,0, 0,0,0,1,1,0,0,0, 0,0,1,0,0,1,0,0, 0,1,0,0,0,0,1,0, }; char face_scared[] = { 0,0,0,0,0,0,0,0, 0,1,1,0,0,1,1,0, 0,1,0,0,0,0,1,0, 0,0,0,0,0,0,0,0, 0,0,0,1,1,0,0,0, 0,0,1,0,0,1,0,0, 0,0,1,0,0,1,0,0, 0,0,0,0,0,0,0,0, }; // the order of the faces matches the order of the #defines // for the moods. // faces[HAPPY] == face_happy, and so on. char *faces[] = { face_neutral, face_happy, face_sad, face_angry, face_scared }; // old joystick state int old_joystick=0; void setup() { int i; for(i=0;i<8;++i) { // send data on all pins pinMode(anodes[i],OUTPUT); pinMode(cathodes[i],OUTPUT); // turn off all the lights digitalWrite(anodes[i],LOW); digitalWrite(cathodes[i],HIGH); } } // turn on one light for a few microseconds. void draw_dot_at(int x,int y) { digitalWrite(cathodes[y],LOW); digitalWrite(anodes[x],HIGH); digitalWrite(anodes[x],LOW); digitalWrite(cathodes[y],HIGH); } // turn on all the lights that are marked as '1' in a face // mood picture. void draw_face() { char *f = faces[mood]; int x,y; for(y=0;y<SCREEN_H;++y) { for(x=0;x<SCREEN_W;++x) { if(f[y*SCREEN_W+x]==1) { draw_dot_at(x,y); } } } } // most of this is figuring out which emotion to show next. void loop() { // which way is the joystick moving? int vx = analogRead(0) - 512; int vy = analogRead(1) - 512; if(old_joystick==0) { // joystick was at center if( abs(vx) > DEADZONE || abs(vy) > DEADZONE ) { // joystick moved out of dead zone old_joystick=1; if( abs(vx) > abs(vy) ) { // left/right => happy/sad if(vx>0) { // left if(mood==NEUTRAL) mood = SAD; else if(mood!=NEUTRAL) mood = NEUTRAL; } else { // right if(mood==NEUTRAL) mood = HAPPY; else if(mood!=NEUTRAL) mood = NEUTRAL; } } else { // up/down => angry/scared if(vy>0) { // up if(mood==NEUTRAL) mood = ANGRY; else if(mood!=NEUTRAL) mood = NEUTRAL; } else { // down if(mood==NEUTRAL) mood = SCARED; else if(mood!=NEUTRAL) mood = NEUTRAL; } } } } else { // joystick outside dead zone if( abs(vx) < DEADZONE && abs(vy) < DEADZONE ) { // joystick returned to dead zone old_joystick=0; } } draw_face(); }
Great! We’ve got a set of 5 expressions now.
Questions
- Get more advanced! You don’t have only one distinct face when you’re happy, right? Give me differently or varying levels of happiness. One where you’ve been given a dollar. Another one where you’ve been given ten, or a hundred. Give emotion two levels.
- Animate! Give me an eyebrow wink or something. Lick your lips.