I am trying to duplicate a project I did with my BS2e (BASIC Stamp II model E), except this time, I am making it more complex, I'm using more LED's, a screen, a CdS light sensor, and a 74HC595 shift register. I have never used shift registers before. I needed to use one this time because of all the LED's I was using, and all the extra knobs and whistles. This game has two options: 1) "Light-Stopper"; this game is like those games you find at an arcade where there is a huge plastic dome with lights in a circle, and you have to get the lights to stop on the one bulb closest to you (I think it's called jackpot). 2) "Simon"; just like the memory-testing game, Simon. I am currently developing the "Light-Stopper" part, But I am having some problems. First off, here's how this game works:
There are 7 LED's, arranged in a horizontal line. In the middle is a RGB LED (so I guess you could say the total amount of LEDs is 9). One LED lights up at a time from left to right, and right to left (only one LED is on at any given time. To make i clearer, the pattern just looks like the light is getting 'bounced' back and forth, from right to left, and vice-versa). The shift register only controls the 3 LEDs on the left, and the 3 on the right. The middle RGB is controlled directly via 3 of the ATmega168's analog pins. Don't worry about the four LEDs for the simon game now. There is a IR detector for input. When the user presses any button on a remote (just any IR remote from a TV, VCR, etc), it 'stops' the movement of the pattern (one LED is now lit, and stays lit). If they happen to get the timing right, and they stop the pattern when the middle RGB LED is lit, then they win. Pretty simple, but the programming is actually much more complicated with the shift register involved.
Lucky for me, there was sample code on the Arduino website on the 595 shift register. I implemented it into this project.
Here's the original code I used for my BASIC Stamp II:
' {$STAMP BS2e}
' {$PBASIC 2.5}
LED1 PIN 4
LED2 PIN 1
LED3 PIN 8
LED4 PIN 14
LED5 PIN 5
LED6 PIN 10
LED7 PIN 12
IR PIN 13
BTN1 PIN 3
BTN2 PIN 7
S0 PIN 2
S1 PIN 0
IN PIN 15
BUZZ PIN 9
ENDLEFT VAR Bit
ENDRIGHT VAR Bit
Slot1 VAR Bit
Slot2 VAR Bit
Slot3 VAR Bit
Slot5 VAR Bit
Slot6 VAR Bit
Slot7 VAR Bit
CNTR VAR Nib
PREV VAR Nib
i VAR Byte
TIME VAR Byte
TIMER VAR Word
FREQOUT BUZZ, 400, 1000
PAUSE 400
FREQOUT BUZZ, 400, 1000
PAUSE 400
FREQOUT BUZZ, 400, 1000
PAUSE 400
FREQOUT BUZZ, 500, 3000
Main:
TIME = 20
Start:
GOSUB Blink_Left
DO
IF BTN2 = 0 THEN
GOTO Main
ENDIF
IF ENDLEFT = 1 THEN
GOSUB Blink_Right
ENDLEFT = 0
ELSEIF ENDRIGHT = 1 THEN
GOSUB Blink_Left
ENDRIGHT = 0
ENDIF
LOOP
Blink_Left:
GOSUB Check_Slot7
IF BTN1 = 0 THEN
CNTR = 0
TIMER = 0
GOSUB Level_Up
ENDIF
GOSUB Check_Slot6
GOSUB Check_Slot5
IF BTN1 = 0 THEN
CNTR = 0
TIMER = 0
GOSUB Level_Up
ENDIF
GOSUB Check_Center
GOSUB Check_Slot3
IF BTN1 = 0 THEN
CNTR = 0
TIMER = 0
GOSUB Level_Up
ENDIF
GOSUB Check_Slot2
GOSUB Check_Slot1
IF BTN1 = 0 THEN
CNTR = 0
TIMER = 0
GOSUB Level_Up
ENDIF
ENDLEFT = 1
RETURN
Blink_Right:
GOSUB Check_Slot1
IF BTN1 = 0 THEN
CNTR = 0
TIMER = 0
GOSUB Level_Up
ENDIF
GOSUB Check_Slot2
GOSUB Check_Slot3
IF BTN1 = 0 THEN
CNTR = 0
TIMER = 0
GOSUB Level_Up
ENDIF
GOSUB Check_Center
GOSUB Check_Slot5
IF BTN1 = 0 THEN
CNTR = 0
TIMER = 0
GOSUB Level_Up
ENDIF
GOSUB Check_Slot6
GOSUB Check_Slot7
IF BTN1 = 0 THEN
CNTR = 0
TIMER = 0
GOSUB Level_Up
ENDIF
ENDRIGHT = 1
RETURN
Check_Slot1:
HIGH LED1
FOR i = 1 TO TIME
IF IR = 0 THEN
Slot1 = 1
GOSUB Loser
ENDIF
NEXT
LOW LED1
RETURN
Check_Slot2:
HIGH LED2
FOR i = 1 TO TIME
IF IR = 0 THEN
Slot2 = 1
GOSUB Loser
ENDIF
NEXT
LOW LED2
RETURN
Check_Slot3:
HIGH LED3
FOR i = 1 TO TIME
IF IR = 0 THEN
Slot3 = 1
GOSUB Loser
ENDIF
NEXT
LOW LED3
RETURN
Check_Center:
HIGH LED4
FOR i = 1 TO TIME
IF IR = 0 THEN
GOSUB Winner
ENDIF
NEXT
LOW LED4
RETURN
Check_Slot5:
HIGH LED5
FOR i = 1 TO TIME
IF IR = 0 THEN
Slot5 = 1
GOSUB Loser
ENDIF
NEXT
LOW LED5
RETURN
Check_Slot6:
HIGH LED6
FOR i = 1 TO TIME
IF IR = 0 THEN
Slot6 = 1
GOSUB Loser
ENDIF
NEXT
LOW LED6
RETURN
Check_Slot7:
HIGH LED7
FOR i = 1 TO TIME
IF IR = 0 THEN
Slot7 = 1
GOSUB Loser
ENDIF
NEXT
LOW LED7
RETURN
Winner:
HIGH LED4
PAUSE 50
LOW LED4
PAUSE 50
HIGH LED4
PAUSE 50
LOW LED4
PAUSE 50
HIGH LED4
PAUSE 50
LOW LED4
HIGH LED1
HIGH LED7
PAUSE 500
HIGH LED2
HIGH LED6
PAUSE 500
HIGH LED3
HIGH LED5
PAUSE 500
HIGH LED4
PAUSE 1000
FOR i = 1 TO 40
HIGH LED4
PAUSE 20
LOW LED4
NEXT
LOW LED1
LOW LED2
LOW LED3
LOW LED5
LOW LED6
LOW LED7
FREQOUT BUZZ, 100, 1500
PAUSE 5
FREQOUT BUZZ, 100, 1300
PAUSE 5
FREQOUT BUZZ, 100, 1500
PAUSE 5
FREQOUT BUZZ, 200, 3000
PAUSE 100
FOR i = 1 TO 20
IF i = 5 THEN
HIGH LED2
ELSEIF i = 10 THEN
LOW LED2
HIGH LED6
ELSEIF i = 15 THEN
LOW LED6
HIGH LED2
ELSEIF i = 20 THEN
LOW LED2
HIGH LED6
ELSEIF i = 25 THEN
LOW LED6
HIGH LED2
ELSEIF i = 30 THEN
LOW LED2
HIGH LED6
ELSEIF i = 35 THEN
LOW LED6
HIGH LED2
ELSEIF i = 40 THEN
LOW LED2
HIGH LED6
ELSEIF i = 45 THEN
LOW LED6
HIGH LED2
ELSEIF i = 50 THEN
LOW LED2
HIGH LED6
ENDIF
HIGH LED1
HIGH LED7
PAUSE 25
LOW LED1
LOW LED7
HIGH LED3
HIGH LED5
PAUSE 25
LOW LED3
LOW LED5
PAUSE 50
NEXT
RETURN
Loser:
IF Slot1 = 1 THEN
LOW LED1
PAUSE 200
HIGH LED1
PAUSE 200
LOW LED1
Slot1 = 0
ELSEIF Slot2 = 1 THEN
LOW LED2
PAUSE 200
HIGH LED2
PAUSE 200
LOW LED2
Slot2 = 0
ELSEIF Slot3 = 1 THEN
LOW LED3
PAUSE 200
HIGH LED3
PAUSE 200
LOW LED3
Slot3 = 0
ELSEIF Slot5 = 1 THEN
LOW LED5
PAUSE 200
HIGH LED5
PAUSE 200
LOW LED5
Slot5 = 0
ELSEIF Slot6 = 1 THEN
LOW LED6
PAUSE 200
HIGH LED6
PAUSE 200
LOW LED6
Slot6 = 0
ELSEIF Slot7 = 1 THEN
LOW LED7
PAUSE 200
HIGH LED7
PAUSE 200
LOW LED7
Slot7 = 0
ENDIF
FREQOUT BUZZ, 100, 1500
PAUSE 100
FREQOUT BUZZ, 200, 1000
PAUSE 100
GOTO Start
Level_Up:
PAUSE 100
FREQOUT BUZZ, 100, 2500
PAUSE 20
FREQOUT BUZZ, 100, 2500
PAUSE 20
FREQOUT BUZZ, 100, 2500
PAUSE 500
LOW LED1
LOW LED2
LOW LED3
LOW LED4
LOW LED5
LOW LED6
LOW LED7
PAUSE 1000
DO
PREV = CNTR
IF BTN1 = 0 THEN
PAUSE 300
CNTR = CNTR + 1
ENDIF
IF CNTR > PREV THEN
TIMER = 0
ENDIF
IF CNTR = 1 THEN
HIGH LED1
TIMER = TIMER + 1
TIME = 50
ELSEIF CNTR = 2 THEN
HIGH LED1
HIGH LED2
TIMER = TIMER + 1
TIME = 40
ELSEIF CNTR = 3 THEN
HIGH LED1
HIGH LED2
HIGH LED3
TIMER = TIMER + 1
TIME = 30
ELSEIF CNTR = 4 THEN
HIGH LED1
HIGH LED2
HIGH LED3
HIGH LED4
TIMER = TIMER + 1
TIME = 20
ELSEIF CNTR = 5 THEN
HIGH LED1
HIGH LED2
HIGH LED3
HIGH LED4
HIGH LED5
TIMER = TIMER + 1
TIME = 10
ELSEIF CNTR = 6 THEN
HIGH LED1
HIGH LED2
HIGH LED3
HIGH LED4
HIGH LED5
HIGH LED6
TIMER = TIMER + 1
TIME = 8
ELSEIF CNTR = 7 THEN
HIGH LED1
HIGH LED2
HIGH LED3
HIGH LED4
HIGH LED5
HIGH LED6
HIGH LED7
TIMER = TIMER + 1
TIME = 6
ENDIF
LOOP UNTIL TIMER > 650
TIMER = 0
CNTR = 0
GOTO Start
yea, that was too many characters, so I had to post it in a second post.
I want the Arduino (ATmega168) to mimic that code. But that's really hard with this shift register. Basically, I need it to check the IR detector input every time it lights up an LED. How do I do that? And it's really finicky with this IR detector, too. You have to put the "pinMode(irPin, INPUT)" before every reading is taken, or it does not work. AND you have to pause about 100ms after declaring the pin as an input before taking a reading. That's going to slow this down too much!
So there's a few problems I need to solve:
The finicky IR detector readings
How to take readings from the IR detector at each lighting of an LED
(also; I'm adding this) Get the middle RGB LED to light up right after the ones next to it to complete the pattern (remember, this LED is controlled directly by the ATmega168, not the shift register.
(I'm adding this too) How to light up just one LED with the shift register??
int btnPin = 2; // Digital 2 ; 'Toggle' Button
int irPin = 3; // Digital 4 ; IR Detector
int bryPin = 5; // Digital 5 ; Bottom Right Yellow LED
int trgPin = 6; // Digital 6 ; Top Right Green LED
int blgPin = 7; // Digital 7 ; Bottom Left Green LED
int tlyPin = 8; // Digital 8 ; Top Left Yellow LED
int clockPin = 9; // Digital 9 ; SH_CP on Shift Register
int latchPin = 10; // Digital 10 ; ST_CP on Shift Register
int dataPin = 11; // Digital 11 ; DATA on Shift register
int blPin = 0; // Analog 0 ; Blue RGB LED
int cdsPin = 2; // Analog 2 ; CdS Cell
int rdPin = 3; // Analog 3 ; Red RGB LED
int gnPin = 4; // Analog 4 ; Green RGB LED
int irval = 1;
int btnval = 1;
int cdsval = 0;
int pos = 0;
int i = 0;;
void setup()
{
Serial.begin(9600);
pinMode(latchPin, OUTPUT);
pinMode(btnPin, INPUT);
//pinMode(irPin, INPUT);
pinMode(bryPin, OUTPUT);
pinMode(trgPin, OUTPUT);
pinMode(tlyPin, OUTPUT);
pinMode(blPin, OUTPUT);
pinMode(rdPin, OUTPUT);
pinMode(gnPin, OUTPUT);
clearLCD();
Serial.print(0xFE, BYTE);
Serial.print(0x0C, BYTE);
determineBacklight();
delay(100);
selectLineOne();
delay(100);
Serial.print("Main Menu");
delay(500);
for(i = 0; i < 10; i++) {
scrollLeft();
delay(100);
}
delay(1000);
}
void loop()
{
clearLCD();
pos = 130;
selectLineCustom();
Serial.print("Select Menu");
pos = 197;
selectLineCustom();
Serial.print("Option");
delay(700);
for(i = 0; i < 15; i++) {
scrollLeft();
delay(100);
}
clearLCD();
mainMenu();
}
void selectLineOne(){ //puts the cursor at line 0 char 0.
Serial.print(0xFE, BYTE); //command flag
Serial.print(128, BYTE); //position
}
void selectLineTwo(){ //puts the cursor at line 0 char 0.
Serial.print(0xFE, BYTE); //command flag
Serial.print(192, BYTE); //position
}
void selectLineCustom() {
Serial.print(0xFE, BYTE);
Serial.print(pos, BYTE);
pos = 0;
}
void scrollRight() {
Serial.print(0xFE, BYTE);
Serial.print(0x1C, BYTE);
}
void scrollLeft() {
Serial.print(0xFE, BYTE);
Serial.print(0x18, BYTE);
}
void clearLCD(){
Serial.print(0xFE, BYTE); //command flag
Serial.print(0x01, BYTE); //clear command.
}
void determineBacklight() {
cdsval = analogRead(cdsPin);
if(cdsval < 500) {
backlightOn();
}
else if(cdsval > 500) {
backlightOff();
}
}
void backlightOn(){ //turns on the backlight
Serial.print(0x7C, BYTE); //command flag for backlight stuff
Serial.print(157, BYTE); //light level.
}
void backlightOff(){ //turns off the backlight
Serial.print(0x7C, BYTE); //command flag for backlight stuff
Serial.print(128, BYTE); //light level for off.
}
void serCommand(){ //a general function to call the command flag for issuing all other commands
Serial.print(0xFE, BYTE);
}
void End() {
delay(500);
End();
}
void mainMenu() {
Serial.print("Press toggle to switch options");
delay(2000);
clearLCD();
Serial.print("Press select to select an option");
delay(2000);
clearLCD();
Serial.print("Light-Stopper");
option1();
}
void option1() {
pinMode(irPin, INPUT);
delay(100);
irval = digitalRead(irPin);
btnval = digitalRead(btnPin);
if(irval == 0 && btnval == 0) {
clearLCD();
Serial.print("??");
}
else if(irval == 0 && btnval == 1) {
clearLCD();
Serial.print("Light-Stopper");
lightStopper();
}
else if(irval == 1 && btnval == 0) {
clearLCD();
Serial.print("Simon");
option2();
}
else if(irval == 1 && btnval == 1) {
option1();
}
}
void option2() {
pinMode(irPin, INPUT);
delay(100);
irval = digitalRead(irPin);
btnval = digitalRead(btnPin);
if(irval == 0 && btnval == 0) {
Serial.print("??");
}
else if(irval == 0 && btnval == 1) {
clearLCD();
Serial.print("Simon");
Simon();
}
else if(irval == 1 && btnval == 0) {
clearLCD();
Serial.print("Light-Stopper");
option1();
}
else if(irval == 1 && btnval == 1) {
option2();
}
}
void Simon() {
Serial.print("Under Construction!");
delay(1000);
Simon();
}
void lightStopper() {
// light each pin one by one using a function A
for (int j = 8; j > 0; j--) {
lightShiftPinA(j);
delay(20);
}
// light each pin one by one using a function A
for (int j = 0; j < 8; j++) {
lightShiftPinB(j);
delay(20);
}
lightStopper();
}
void lightShiftPinA(int p) {
//defines a local variable
int pin;
//this is line uses a bitwise operator
//shifting a bit left using << is the same
//as multiplying the decimal number by two.
pin = 1<< p;
//ground latchPin and hold low for as long as you are transmitting
digitalWrite(latchPin, 0);
//move 'em out
shiftOut(dataPin, clockPin, pin);
//return the latch pin high to signal chip that it
//no longer needs to listen for information
digitalWrite(latchPin, 1);
}
//This function uses that fact that each bit in a byte
//is 2 times greater than the one before it to
//shift the bits higher
void lightShiftPinB(int p) {
//defines a local variable
int pin;
//start with the pin = 1 so that if 0 is passed to this
//function pin 0 will light.
pin = 1;
for (int x = 0; x < p; x++) {
pin = pin * 2;
}
//ground latchPin and hold low for as long as you are transmitting
digitalWrite(latchPin, 0);
//move 'em out
shiftOut(dataPin, clockPin, pin);
//return the latch pin high to signal chip that it
//no longer needs to listen for information
digitalWrite(latchPin, 1);
}
void shiftOut(int myDataPin, int myClockPin, byte myDataOut) {
// This shifts 8 bits out MSB first,
//on the rising edge of the clock,
//clock idles low
//internal function setup
int i=0;
int pinState;
pinMode(myClockPin, OUTPUT);
pinMode(myDataPin, OUTPUT);
//clear everything out just in case to
//prepare shift register for bit shifting
digitalWrite(myDataPin, 0);
digitalWrite(myClockPin, 0);
//for each bit in the byte myDataOut?
//NOTICE THAT WE ARE COUNTING DOWN in our for loop
//This means that %00000001 or "1" will go through such
//that it will be pin Q0 that lights.
for (i=7; i>=0; i--) {
digitalWrite(myClockPin, 0);
//if the value passed to myDataOut and a bitmask result
// true then... so if we are at i=6 and our value is
// %11010100 it would the code compares it to %01000000
// and proceeds to set pinState to 1.
if ( myDataOut & (1<<i) ) {
pinState= 1;
}
else {
pinState= 0;
}
//Sets the pin to HIGH or LOW depending on pinState
digitalWrite(myDataPin, pinState);
//register shifts bits on upstroke of clock pin
digitalWrite(myClockPin, 1);
//zero the data pin after shift to prevent bleed through
digitalWrite(myDataPin, 0);
}
//stop shifting
digitalWrite(myClockPin, 0);
}