For my "catch the light" game idea, I needed to have a single LED scanning back and forth. I've been a programmer in the medical industry for more than 20 years, but never had to deal much with binary data and never hardware beyond RS232 communications.
This is where my in-experience showed through.
I didn't want to use the arrays. Maybe that was a mistake. I knew easily enough that to count in binary I simply needed to start at one and multiply by 2:
1 = 1
2 = 10
4 = 100
8 = 1000
16 = 10000
32 = 100000
and so on. I thought that I understood that the binary data flowing to the shift registers would cascade pushing (shifting) the bits to the next shift register. I thought that I could simply keep shifting to the left until I got to 32768, then start shifting to the right until I got back to 1. The program that I started with had 2 shift outs to work with the 2 arrays:
shiftOut(dataPin, clockPin, MSBFIRST, seq1[x]); //Send the data byte 1
shiftOut(dataPin, clockPin, MSBFIRST, seq2[x]); //Send the data byte 2
I thought that I would only need 1 shift out and could, in effect, send out 16 bits at one time. So this is what I ended up with:
digitalWrite(latchPin, LOW); //Pull latch LOW to start sending data shiftOut(dataPin,clockPin,MSBFIRST,i); digitalWrite(latchPin, HIGH); //Pull latch HIGH to stop sending data if (left ){ i = i << 1; //shift bit to the left while left=true } else { i = i >> 1; //otherwise, shift right } if (i == 32768 || i == 1){ left = !left; //If we are at either end of the line toggle left }
1 | 1 |
2 | 10 |
4 | 100 |
8 | 1000 |
16 | 10000 |
32 | 100000 |
64 | 1000000 |
128 | 10000000 |
256 | 100000000 |
512 | #NUM! |
1024 | #NUM! |
2048 | #NUM! |
4096 | #NUM! |
8192 | #NUM! |
16384 | #NUM! |
32768 | #NUM! |
So, I figured that if I'm under 255, I can send a zero in one shiftOut() and the value of "i" in the other. I tested this in my spreadsheet in the next column with a simple if() statement:
This resulted in the new column counting to 128 twice. So, while 255 or less I shiftOut() my value for "i" then a zero and when greater than 255, I shift out a zero then the value of "i/256." This is what I ended up with:
void displayLed(){ digitalWrite(latchPin, LOW); //Pull latch LOW to start sending data if (i > 255){ shiftOut(dataPin,clockPin,MSBFIRST,0); shiftOut(dataPin,clockPin,MSBFIRST,i/256); } else { shiftOut(dataPin,clockPin,MSBFIRST,i); shiftOut(dataPin,clockPin,MSBFIRST,0); } digitalWrite(latchPin, HIGH); //Pull latch HIGH to stop sending data }
Now I wanted to see which LED was lit when the button was pushed. I thought I would simply blink the "caught" led 10 times before resuming scanning. I put this code in my interrupt handler:
void pushit(){ long holdIt=0; time=millis(); if (time-lasttime>50){ digitalWrite(12,!state); state=!state; lasttime = time; pauseTime = pauseTime - 2; holdIt = i; for(int loopVar=0;loopVar<10;loopVar++){ i=0; displayLed(); delay(500); i=holdIt; displayLed(); delay(500); } } }
I hold the current value of "i" in "holdIt," then in a loop I set "i" to zero, display it, set "i" back to "holdIt" and display that, 10 times. I tried a 50 ms delay() between the on and off, but couldn't see it blink, even 500 ms wasn't noticable.
It got late, and my boy needed sleep, even though school is finished for the summer. So we stopped there. It was amazing how he caught on the shifting left and right, and even offered intelligent suggestions when something wouldn't compile.
This is where I'm stuck
- Why isn't it blinking?
- Is it because "i" isn't declared as volatile?
- Is it because the interrupt handler doesn't keep running long enough?
- Maybe, I should pass "i" into the displayLed() function?
- Is it because the interrupt is tripping again and starting the handler again before it finishes?
- Should I detachInterrupt() when I get into the handler?
Any suggestions would be helpful!
Here's the whole program:
int dataPin = 10; //Define which pins will be used for the Shift Register control int latchPin = 9; int clockPin = 8; long i = 1; int pauseTime = 100; // byte #2 value bool left = true; volatile int state=LOW; unsigned long time; unsigned long lasttime; void setup() { attachInterrupt(0,pushit,LOW); pinMode(dataPin, OUTPUT); //Configure each IO Pin pinMode(latchPin, OUTPUT); pinMode(clockPin, OUTPUT); pinMode(12,OUTPUT); digitalWrite(12,state); lasttime==millis(); } void loop() { displayLed(); if (left ){ i = i << 1; } else { i = i >> 1; } if (i == 32768 || i == 1){ left = !left; } delay(pauseTime); if (pauseTime <= 0){ pauseTime = 100; } } void pushit(){ long holdIt=0; time=millis(); if (time-lasttime>50){ digitalWrite(12,!state); state=!state; lasttime = time; pauseTime = pauseTime - 2; holdIt = i; for(int loopVar=1;loopVar<10;loopVar++){ i=0; displayLed(); delay(500); i=holdIt; displayLed(); delay(500); } } } void displayLed(){ digitalWrite(latchPin, LOW); //Pull latch LOW to start sending data if (i > 255){ shiftOut(dataPin,clockPin,MSBFIRST,0); shiftOut(dataPin,clockPin,MSBFIRST,i/256); } else { shiftOut(dataPin,clockPin,MSBFIRST,i); shiftOut(dataPin,clockPin,MSBFIRST,0); } digitalWrite(latchPin, HIGH); //Pull latch HIGH to stop sending data }
Leave a comment below or Tweet to @kidbotz.
Looks like a fun blog / story you have here! Anyway, I didn't look at this in tremendous depth but I'm not sure you can successfully call delay() from within an interrupt handler as delay() itself relies on interrupts. Check out this Arduino forum post. http://forum.arduino.cc/index.php/topic,46201.0.html
ReplyDeleteGood to know about the delay(). Couldn't find anything as far as guidlines for interrupt handlers. Thanks for taking the time to read/comment.
Delete