3

I'm trying to build a (very basic) pinball machine with an Arduino Uno. This part of the code will detect when a ball passes 3 lanes. When a lane is passed, it will activate the lane(laneState), reward a score(+10) and light up an LED.

The Expected Result:

  • When all 3 lanes are LIT, assign a score of the lane passage(+10), assign a bonus score(+100) and reset all laneStates to 0 and turn all leds to LOW.
  • 110 points are being added in total

Actual Result:

  • the last lane passed lights back up as active (while I set all of them to inactive)
  • 120 points are being added in total (instead of 110?)

Any hints on why I see this behaviour are very welcome!


The sketch and board can be found here: https://circuits.io/circuits/2739062-poc-lane-passage-001/ Turn on 'Code Editor' and enable the Serial Monitor to see the scores.


More info: I looked into using interrupts, but that is not an option here (the Uno only has 2 pins for interrupts, I need 3)

Thanks!

EDIT: added the code here too:

// Scores
int totalScore = 0;
const int lanePassageScore = 10; // 10 points for passing a lane
const int allLaneActiveBonus = 100; // 100 points for activating ALL lanes

// Digital pins to detect the state of the buttons
const int laneButtonPin[] = {2,3,4};
const int laneStateLedPin[] = {10,11,12};

// all three lanes are 'inactive' at the start of the game
int laneButtonState[] = {0,0,0};
int lastLaneButtonState[] = {0,0,0};
int laneState[] = {0,0,0};


void setup() {
  Serial.begin(9600); // for debugging
}

void loop() {
  // detect if lanes 1 to 3 were activated
  detectLaneButtonPassage(0); // Lane 1
  checkAllLanesLit();
  detectLaneButtonPassage(1); // Lane 2
  checkAllLanesLit();
  detectLaneButtonPassage(2); // Lane 3
  checkAllLanesLit();

  Serial.println(totalScore); // for debugging

  delay(5);
}

void detectLaneButtonPassage(int laneId){
  // Check state of the button
  laneButtonState[laneId] = digitalRead(laneButtonPin[laneId]);
  if(laneButtonState[laneId] != lastLaneButtonState[laneId]){
    if(laneButtonState[laneId] == HIGH){
      // The lane button change to an ON position, toggle the lane state
      if(laneState[laneId] == 0){
        // lane was not yet active, it becomes active now
        laneState[laneId] = 1;
        digitalWrite(laneStateLedPin[laneId], HIGH);
        rewardScore(lanePassageScore);
      }else{
        // lane was already active, it becomes inactive now
        laneState[laneId] = 0;
        digitalWrite(laneStateLedPin[laneId], LOW);
        rewardScore(lanePassageScore/2);
      }
    }
  }
  lastLaneButtonState[laneId] = laneButtonState[laneId];
}

void rewardScore(int score){
  totalScore += score;
}

void checkAllLanesLit(){
  // Check if ALL lanes are activated
  if(laneState[0]==1 && laneState[1]==1 && laneState[2]==1){
    // reset all buttons and states
    for(int laneId=0; laneId<=2; laneId++){
      laneButtonState[laneId] = 0;
      lastLaneButtonState[laneId] = 0;
      laneState[laneId] = 0;
      digitalWrite(laneStateLedPin[laneId], LOW); //Turn off led
    }
    rewardScore(allLaneActiveBonus);
  }
}
1

There are 2 lines of code that need to be removed from the checkAllLanesLit() function in order for your code to work as desired:

  laneButtonState[laneId] = 0;
  lastLaneButtonState[laneId] = 0;

Explanation:
What is happening is that the detectLaneButtonPassage() is firing as normal. Then checkAllLanesLit() runs and clears the lastLaneButtonState flag.

The program loops around again and the lane button is still pressed. However, the detectLaneButtonPassage() fires again because lastLaneButtonState has been reset and it appears to the program as a rising edge. Hence the extra 10 points.


On a side note, the following 2 lines could be reduced down to a single line:

if(laneButtonState[laneId] != lastLaneButtonState[laneId]){
    if(laneButtonState[laneId] == HIGH){

The above lines of code are detecting a rising edge. They can be expressed as:

if(laneButtonState[laneId] && !lastLaneButtonState[laneId]){

For the if statement to fire laneButtonState must be high and lastLaneButtonState must be low.

| improve this answer | |
  • 1
    I'll try this asap. Thanks for your time already. – Cagy79 Sep 21 '16 at 9:27
  • Works perfect! Now it makes sense to not have those lines there. I'm also not that experienced/efficient yet with condensing 2 lines of code in one. But i'll definitely keept this in mind for later! Thx again! – Cagy79 Sep 21 '16 at 12:25
1

Looks like a timing issue.

Which ever order you hit the buttons in the last one always stays lit (and you get an extra 10 points added).

I set a breakpoint at:

rewardScore(allLaneActiveBonus);

...and just waited a sec and then continued and your code worked as expected.

So I think that you are setting all lines to LOW in checkAllLanesLit() and then only have a short delay (5mS) before looping round and checking again (at which point the button is still HIGH as you haven't taken your finger off it quickly enough) - resulting in the additional 10 points and that lane being lit again.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.