Lightsaber project help!

Hello World :wink:

I'm trying to create a light saber controlled by an arduino uno (well the 328P as a standalone IC). However I am having difficulty with the code. I've got a 3W RGB star LED (common anode powered thorough a small 12v constant current circuit) for the light source, when a push button is triggered I would like the green LED to be lit (through 2n2222 transistor, I've checked the datasheet) and when toggled again for it to deactivate and power the LED off. If possible I would like a second tac switch to toggle the colours while still operating in the normal way. I cannot however seem to figure out how to do this even when searching online for other peoples sketches.
I believe I've got the audio sorted out (adafruit sound board & amplifier) and there will be an acceleromitter for when the light saber is swung (not begun code with that part yet).

If anyone would be able to offer any help or advice on the matter it would be greatly appreciated as I've been on/off with this project for many months now (parental responsibilities keep getting in the way :P).

Many Thanks, Joe

when a push button is triggered

It sounds like you need to detect when a button becomes pressed rather than when it is pressed. That way you can change the system state each time the button becomes pressed. Look at the StateChangeDetection example in the IDE to see how to do it.

Thanks matey, I will give it a try :slight_smile:

Right ive got the example code to work, however I want to change it so that it toggles on and off for every button press as apposed to every 4 in the example. Ive tried changing the '4' in the code below to 1 or even 0 however unsure how to change it to get the result im after? Any help please? :slight_smile:

// turns on the LED every four button pushes by
// checking the modulo of the button push counter.
// the modulo function gives you the remainder of
// the division of two numbers:
if (buttonPushCounter % 4 == 0) {
digitalWrite(ledPin, HIGH);
} else {
digitalWrite(ledPin, LOW);
}


Code so far for LS2 (Light saber Project):

/*
State change detection (edge detection)

Often, you don't need to know the state of a digital input all the time,
but you just need to know when the input changes from one state to another.
For example, you want to know when a button goes from OFF to ON. This is called
state change detection, or edge detection.

This example shows how to detect when a button or button changes from off to on
and on to off.

The circuit:

  • pushbutton attached to pin 2 from +5V
  • 10K resistor attached to pin 2 from ground
  • LED attached from pin 13 to ground (or use the built-in LED on
    most Arduino boards)

created 27 Sep 2005
modified 30 Aug 2011
by Tom Igoe

This example code is in the public domain.

*/

/*
ATMEGA328P Pinout

Red D 09
Green D 10
Blue D 11
LS2 main button (buttonPin) D 02
RX (from audio board) D 01
TX (from audio board) D 00

*/

// this constant won't change:
const int buttonPin = 2; // the pin that the pushbutton is attached to
const int ledPin = 13; // the pin that the LED is attached to
const int red = 9; // green led star
const int green = 10; // green led star
const int blue = 11; // green led star

// Variables will change:
int buttonPushCounter = 0; // counter for the number of button presses
int buttonState = 0; // current state of the button
int lastButtonState = 0; // previous state of the button

void setup() {
// initialize the button pin as a input:
pinMode(buttonPin, INPUT);
// initialize the LED as an output:
pinMode(ledPin, OUTPUT);
pinMode(red, OUTPUT);
pinMode(green, OUTPUT);
pinMode(blue, OUTPUT);
// initialize serial communication:
Serial.begin(9600);

digitalWrite(red, LOW);
digitalWrite(blue, LOW);
digitalWrite(green, LOW);

}

void loop() {

// read the pushbutton input pin:
buttonState = digitalRead(buttonPin);

// compare the buttonState to its previous state
if (buttonState != lastButtonState) {
// if the state has changed, increment the counter
if (buttonState == HIGH) {
// if the current state is HIGH then the button
// wend from off to on:
buttonPushCounter++;
Serial.println("on");
Serial.print("number of button pushes: ");
Serial.println(buttonPushCounter);

digitalWrite(green, HIGH);
digitalWrite(ledPin, HIGH);

} else {
// if the current state is LOW then the button
// wend from on to off:
Serial.println("off");

digitalWrite(green,LOW);
digitalWrite(ledPin, LOW);
}
// Delay a little bit to avoid bouncing
delay(100);
}
// save the current state as the last state,
//for next time through the loop
lastButtonState = buttonState;

// turns on the LED every four button pushes by
// checking the modulo of the button push counter.
// the modulo function gives you the remainder of
// the division of two numbers:
if (buttonPushCounter % 4 == 0) {
digitalWrite(ledPin, HIGH);
} else {
digitalWrite(ledPin, LOW);
}

}

You're looking at the wrong part. The important part is the bit about remembering the last state of the button so you know if it has changed since the last time you read it. You can ditch all the stuff about buttonPushCounter as it really doesn't have anything to do with your project since you aren't counting button pushes. It was just something easy for them to use to illustrate the point.

Im not quite sure I understand which part you mean, would you be able to identify it in the code?
Sorry to be a pain, pretty new to programming

This bit:

if (buttonState != lastButtonState) {

and this bit later:

lastButtonState = buttonState;

You're not trying to copy it or replicate it, that won't work. This isn't something you can blindly copy-paste into your sketch. You need to UNDERSTAND what that is doing and then do it yourself in your program. It may look different in your program, but the concept of remembering the last state of the button and comparing to the current state to see if it has changed is the same.

So literally would just be a case of:

if (buttonState != lastButtonState) {
digitalWrite(green,HIGH);

} else {
digitalWrite(green,LOW);
}

Pretty much. Don't forget to save the new state of the pin in lastButtonState at the end.

Actually, that will turn the led on every time the state changes HIGH to LOW or LOW to HIGH. I thought you only wanted it when the button was pressed, so maybe you'd also want to test which the state was.

if (buttonState != lastButtonState && buttonState == HIGH) { // or LOW as the case may be
 digitalWrite(green,HIGH);

} else {
digitalWrite(green,LOW);
}

Also note that in any pass through loop where the buttonstate has not changed this will turn the led off. Is that what you want? Or do you want it to stay on even while the user holds down the button?

Ideally if the user holds the button down it should not toggle. only when the button is pulled to ground should it change (i think).

Ive changed it to the following but its not happy:

/*
ATMEGA328P Pinout

Red D 09
Green D 10
Blue D 11
LS2 main button (buttonPin) D 02
RX (from audio board) D 01
TX (from audio board) D 00

*/

// this constant won't change:
const int buttonPin = 2; // the pin that the pushbutton is attached to
const int ledPin = 13; // the pin that the LED is attached to
const int red = 9; // green led star
const int green = 10; // green led star
const int blue = 11; // green led star

// Variables will change:
int buttonPushCounter = 0; // counter for the number of button presses
int buttonState = 0; // current state of the button
int lastButtonState = 0; // previous state of the button

void setup() {
// initialize the button pin as a input:
pinMode(buttonPin, INPUT);
// initialize the LED as an output:
pinMode(ledPin, OUTPUT);
pinMode(red, OUTPUT);
pinMode(green, OUTPUT);
pinMode(blue, OUTPUT);
// initialize serial communication:
Serial.begin(9600);

digitalWrite(red, LOW);
digitalWrite(blue, LOW);
digitalWrite(green, LOW);

}

void loop() {

// read the pushbutton input pin:
buttonState = digitalRead(buttonPin);

if (buttonState != lastButtonState && buttonState == HIGH) { // or LOW as the case may be
digitalWrite(green,HIGH);
digitalWrite(ledPin,HIGH);

} else {
digitalWrite(green,LOW);
digitalWrite(ledPin,LOW);
}
// Delay a little bit to avoid bouncing
delay(100);
}
// save the current state as the last state,
//for next time through the loop
lastButtonState = buttonState;

/*
// turns on the LED every four button pushes by
// checking the modulo of the button push counter.
// the modulo function gives you the remainder of
// the division of two numbers:
if (buttonPushCounter % 4 == 0) {
digitalWrite(ledPin, HIGH);
} else {
digitalWrite(ledPin, LOW);
}

*/

if (buttonPushCounter % 4 == 0) {
    digitalWrite(ledPin, HIGH);
  } else {
    digitalWrite(ledPin, LOW);
  }

What's that part still doing in there. I didn't think you were counting button pushes.

if (buttonState != lastButtonState && buttonState == HIGH) { // or LOW as the case may be
 digitalWrite(green,HIGH);
  digitalWrite(ledPin,HIGH);

} else {
digitalWrite(green,LOW);
 digitalWrite(ledPin,LOW);
}

Read this carefully. The loop is running over and over and over, let's just assume once every millisecond.

So the millisecond you push the button down, the state changes (if it is to LOW then maybe that shouldn't be HIGH, that's something you know and I don't) the state changes and the led lights up.

One millisecond later the loop runs again. The button is still pushed so the state hasn't changed this time, so the if isn't true and we hit the else part. What does the else say to do? Turn it back off. So you have the led lit up for about a millisecond. Is that what you want?

Maybe something more like this pseudocode:

if( the button has changed states){
    if(the new state is HIGH){
         // turn your led on or off, whichever HIGH button goes with
    }
    else {   // the new state must be LOW
        // Do whatever you want to do when the button goes LOW
    }
}

That way, if the button hasn't changed states, you take no action.

ive tried your code however the LED turns on then stays on no matter what the button state it:

// read the pushbutton input pin:
buttonState = digitalRead(buttonPin);

if(buttonState){
if(buttonState, HIGH){
// turn your led on or off, whichever HIGH button goes with
digitalWrite(ledPin, HIGH);

}
else { // the new state must be LOW
// Do whatever you want to do when the button goes LOW
digitalWrite(ledPin, LOW);
}
}
}

TechyJoe:
ive tried your code however the LED turns on then stays on no matter what the button state it:

// read the pushbutton input pin:
buttonState = digitalRead(buttonPin);

if(buttonState){
if(buttonState, HIGH){
// turn your led on or off, whichever HIGH button goes with
digitalWrite(ledPin, HIGH);

}
else { // the new state must be LOW
// Do whatever you want to do when the button goes LOW
digitalWrite(ledPin, LOW);
}
}
}

Nope, that's not the pseudocode I wrote. Not even close. You've got if(buttonState) which is essentially the same as if(buttonState == HIGH). I wrote in the first check if (the button state has changed). How can we tell if it has changed? Should we maybe compare it to the last button state to see if it is the same or not?

if(buttonState, HIGH){

Also this is completely wrong. That's not how you check to see if one thing equals another.

if(buttonState == HIGH)

looks more like what we're used to seeing doesn't it.

The reason I changed the example you gave is because it said that 'the button state has changed' was not declared in scope.

So are we saying that the correct way would be; if(buttonState == HIGH)

and so the following should be correct?

if(buttonState == HIGH){
// turn your led on or off, whichever HIGH button goes with
digitalWrite(ledPin, HIGH);

}
else { // the new state must be LOW
// Do whatever you want to do when the button goes LOW
digitalWrite(ledPin, LOW);
}
}
}

TechyJoe:
The reason I changed the example you gave is because it said that 'the button state has changed' was not declared in scope.

OMG!!! No, of course not. What I wrote was pseudocode. Code intentionally written in human language. You were supposed to take (the button state has changed) and figure out what goes there to mean that.

Here's a hint:

pseudocode:
if(the button was pressed)

might turn into the real code:

if(digitalRead(someButtonPin) == LOW)

if the button being pressed would cause that digitaRead to come back LOW.