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.
