Step 13: Making A 10 Step Animation
First we need to figure out what LEDs we want on and what LEDs we want off at each step. If I'm gonna make a simple bar graph I'll want LED7, LED8 and LED9 to turn on when the sound is at level 1 (the bottom row of blue LEDs). When the sound is at level 2 I will want LED7, LED8, LED9, LED12, LED13 and LED14 to turn on while all the rest turn off (the two bottom rows of blue LEDs). So on so forth, up until we get to the 10th sound level in which we will want all of the blue LEDs on. So here is the function that we will use:
level = (0xF0 & (uint16)PORTD) << 2; //Store the upper nibble of PORTD in 'level' from bit#9 - bit#6
level |= ((0xFC & PORTB) >> 2); //Mask off RB0 and RB1, bit shift the data right two places and store RB2 - RB7 in 'level'
case 0x03FF: SPI_Send_595(0x000000C0); break; //Sound Level 0
case 0x03DF: SPI_Send_595(0xE00000C0); break; //Sound Level 1
case 0x03CF: SPI_Send_595(0xFC0000C0); break; //Sound Level 2
case 0x03C7: SPI_Send_595(0xFF8000C0); break; //Sound Level 3
case 0x03C3: SPI_Send_595(0xFFF000C0); break; //Sound Level 4
case 0x03C1: SPI_Send_595(0xFFFE00C0); break; //Sound Level 5
case 0x03C0: SPI_Send_595(0xFFFFC0C0); break; //Sound Level 6
case 0x01C0: SPI_Send_595(0xFFFFF8C0); break; //Sound Level 7
case 0x00C0: SPI_Send_595(0xFFFFFFC0); break; //Sound Level 8
case 0x0040: SPI_Send_595(0xFFFFFFCC); break; //Sound Level 9
case 0x0000: SPI_Send_595(0xFFFFFFCF); break; //Sound Level 10
**Don't worry about bit#7 and bit#6 that make the 0xC0 right yet, its explained under the next paragraph
You can see that at sound level 0 I don't turn on any LEDs, so it sends out 0x000000C0. At sound level 1 I send out 0xE00000C0 which will turn on LED7, LED8 and LED9. At sound level 2 I send out 0xFC0000C0 which will turn on LED7, LED8, LED9, LED10, LED11 and LED12. And so on. Its quite simple, you just figure out which LEDs you want turned on or off and whatever level of sound, then just put it into the switch statement.
Now do you remember back in step #8 when I told you that we ignore those 4 upper bits of data that is sent to IC4? Well now we are actually going to use 2 of those unused bits when we are passing our 32-bit data value to SPI_Send_74HC595(*data*). You may have noticed in the schematic that we are able to control all of the green LEDs as a whole and all of the yellow LEDs as a whole thanks to the 2x IRL510 MOSFETs that are in the circuit. To turn on all of the green LEDs we simply write a 1 (+5v) to RC2 and to turn on all of the yellow LEDs we write a 1 to RC1. This turns on the IRL510's allowing current to flow through them, thus lighting the LEDs.
In order to turn the bottle and lemon on, when you send your data through the function SPI_Send_595(*data*) you will have to make bit#6 and bit#7 high. Bit#6 controls the bottle and bit#7 controls the lemon. In the SPI_Send_595 function I mask off bit#6 and bit#7 and set the output of RC1 and RC2 according to the state of those bits. The IRL510's are not controlled by the shift registers, don't get that confused. I just use bit#6 and bit#7 in software, they never get transferred to the 74HC595's. As you can see they get masked off when we send out byte #4.
#define LEMON PORTCbits.RC2
#define BOTTLE PORTCbits.RC1
void SPI_Send_595(uint32 data)
LEMON = (data >> 7) & 0x00000001; //Turn the lemon on if bit#7 is high and turn it off if bit#7 is low
BOTTLE = (data >> 6) & 0x00000001; //Turn the bottle on if bit#6 is high and turn it off it bit#6 is low
SPI_Send(data >> 24); //Shift out byte #1 first (IC1)
SPI_Send((data >> 16) & 0x000000FF); //Shift out byte #2 next (IC2)
SPI_Send((data >> 8) & 0x000000FF); //Shift out byte #3 next (IC3)
SPI_Send(data & 0x0000000F); //Shift out byte #4 last (IC4)
LAT_595 = 1; //Latch the data onto the outputs of the 74HC595's
LAT_595 = 0; //Reset the latch to its default state
You may also notice that both RC1 and RC2 are PWM outputs on the PIC18F4550. They have been placed there in case somebody would like to control the brightness of the bottle or the lemon. I think it'd be pretty cool to use the bar graph for an LED animation and for every level of sound have a different brightness of light from the yellow LEDs. That way the lemon would also go to the beat of the music with the blue LEDs.
I ran into trouble when I designed the first version of the PCB and I can't control the LED bottle and lemon separately. I didn't find my error until I had already created and assembled the PCB. No worries for you though, I fixed that mistake in the PCB files as soon as I found it, so if you use my design to make this VU Meter you will be able to control the bottle and the lemon.
I eventually got sick of figuring out values for specific LEDs that I wanted to turn on so I whipped together a small program which will do all of the calculations for us. All we need to do is take that data hex value and put it in SPI_Send_595(*Data here*) and it will light up every LED that it shows on the program. It can be downloaded in the zip file in step #4. As far as I'm concerned this program is a life saver.