This is an example of a program I wrote that detects when a push-button is pressed, and lights up an LED while it is pressed. I created the 'buttonState' function in the universal scope to use just as a shortcut to allow me to not have to write 'digitalRead(BUTTON_PIN)' in the 'void loop'. This worked perfectly well in this specific program, but not in one I will show afterward. Here is the first program...
# define BUTTON_PIN 2
# define LED_PIN 11
int buttonState() {
return digitalRead(BUTTON_PIN);
}
void setup() {
Serial.begin(9600);
pinMode(BUTTON_PIN, INPUT);
pinMode(LED_PIN, OUTPUT);
}
void loop() {
if (buttonState() == HIGH) {
Serial.println("Button is pressed!");
digitalWrite(LED_PIN, HIGH);
}
else {
Serial.println("Button is not pressed.");
digitalWrite(LED_PIN, LOW);
}
delay(100);
}
Next, I wanted to create a program with three LED lights, where every time the button was clicked, the next light would turn on and the previous one would turn off. However, if the button was held down, then the lights would not change. They would only change once the button was lifted and then pressed again. Using the logic from the 'StateChangeDetection' example program in the Arduino IDE, I wrote this program...
# define BUTTON_PIN 2
# define LED_RED 9
# define LED_GREEN 10
# define LED_BLUE 11
int prevButtonState = 0;
int ledIndex = 0;
int delayTime = 50;
int ledArray[3] = {LED_RED, LED_GREEN, LED_BLUE};
int buttonState() {
return digitalRead(BUTTON_PIN);
}
void ledState(int index, int state) {
digitalWrite(ledArray[index], state);
}
void setup() {
pinMode(BUTTON_PIN, INPUT);
for (int led = 0; led < 3; led++) {
pinMode(ledArray[led], OUTPUT);
}
}
void loop() {
if (buttonState() != prevButtonState) {
if (buttonState() == HIGH) {
ledState(ledIndex, HIGH);
if (ledIndex == 0) {
ledState(2, LOW);
}
else {
ledState(ledIndex - 1, LOW);
}
if (ledIndex == 2) {
ledIndex = 0;
}
else {
ledIndex++;
}
}
delay(delayTime);
}
prevButtonState = buttonState();
}
Unfortunately, this did not have the desired effect. It almost functioned, but was extremely unreliable, with the LED lights not always changing when they were supposed to. So, I decided to use the method from the 'StateChangeDetection' example program I mentioned earlier, in order to properly read the state of the push button. I modified the previous program and created this one, which had the desired effect and worked flawlessly...
# define BUTTON_PIN 2
# define LED_RED 9
# define LED_GREEN 10
# define LED_BLUE 11
int buttonState = 0;
int prevButtonState = 0;
int ledIndex = 0;
int delayTime = 50;
int ledArray[3] = {LED_RED, LED_GREEN, LED_BLUE};
void ledState(int index, int state) {
digitalWrite(ledArray[index], state);
}
void setup() {
pinMode(BUTTON_PIN, INPUT);
for (int led = 0; led < 3; led++) {
pinMode(ledArray[led], OUTPUT);
}
}
void loop() {
buttonState = digitalRead(BUTTON_PIN);
if (buttonState != prevButtonState) {
if (buttonState == HIGH) {
ledState(ledIndex, HIGH);
if (ledIndex == 0) {
ledState(2, LOW);
}
else {
ledState(ledIndex - 1, LOW);
}
if (ledIndex == 2) {
ledIndex = 0;
}
else {
ledIndex++;
}
}
delay(delayTime);
}
prevButtonState = buttonState;
}
The difference between the two examples is that in the first, I created a function called 'buttonState' to read the state of the push-button, while in the second, I created a variable called 'buttonState', assigned it a value of zero, and reassigned it a value of 'digitalRead(BUTTON_PIN)' at the beginning of the 'void loop' (at least this is what I think is going on. I am still a beginner so I'm not sure if my explanation of the logic is accurate). So, my first question is, why does the function method not work while the variable method works flawlessly? What is it about the road map that does not allow the function I created to work with the three LED project, even though it worked just fine in the first project with just one LED?
My second question is regarding the nature of the second method used in my three LED project (the method that succeeded, with the variable 'buttonState'). How exactly does this variable work? Why do I assign it the value of 0 in the universal scope? I fiddled around with it, and this method also seemed to work...
# define BUTTON_PIN 2
# define LED_RED 9
# define LED_GREEN 10
# define LED_BLUE 11
int prevButtonState = 0;
int ledIndex = 0;
int delayTime = 50;
int ledArray[3] = {LED_RED, LED_GREEN, LED_BLUE};
void ledState(int index, int state) {
digitalWrite(ledArray[index], state);
}
void setup() {
pinMode(BUTTON_PIN, INPUT);
for (int led = 0; led < 3; led++) {
pinMode(ledArray[led], OUTPUT);
}
}
void loop() {
int buttonState = digitalRead(BUTTON_PIN);
if (buttonState != prevButtonState) {
if (buttonState == HIGH) {
ledState(ledIndex, HIGH);
if (ledIndex == 0) {
ledState(2, LOW);
}
else {
ledState(ledIndex - 1, LOW);
}
if (ledIndex == 2) {
ledIndex = 0;
}
else {
ledIndex++;
}
}
delay(delayTime);
}
prevButtonState = buttonState;
}
In this method, I did not declare the 'buttonState' variable in the universal scope and assign it a value of zero. Instead, I did everything at the start of the 'void loop', declaring the variable for the first time, while specifying how to read the state of the push-button. This method works just the same as the previous one, so why did the 'StateChangeDetection' example program use the first method, with declaring the variable at the beginning and assigning it a value of 0? I kept fiddling around with this, and tried putting the line from the start of the 'void loop' in the universal scope, like this...
# define BUTTON_PIN 2
# define LED_RED 9
# define LED_GREEN 10
# define LED_BLUE 11
int buttonState = digitalRead(BUTTON_PIN);
int prevButtonState = 0;
int ledIndex = 0;
int delayTime = 50;
int ledArray[3] = {LED_RED, LED_GREEN, LED_BLUE};
void ledState(int index, int state) {
digitalWrite(ledArray[index], state);
}
void setup() {
pinMode(BUTTON_PIN, INPUT);
for (int led = 0; led < 3; led++) {
pinMode(ledArray[led], OUTPUT);
}
}
void loop() {
if (buttonState != prevButtonState) {
if (buttonState == HIGH) {
ledState(ledIndex, HIGH);
if (ledIndex == 0) {
ledState(2, LOW);
}
else {
ledState(ledIndex - 1, LOW);
}
if (ledIndex == 2) {
ledIndex = 0;
}
else {
ledIndex++;
}
}
delay(delayTime);
}
prevButtonState = buttonState;
}
This method did not work. In this method, I simply moved declaration and instructions of the variable from the void loop into the universal scope. I really do not understand why there is a difference between these two methods! Shouldn't variables in the universal scope function the same in any scope within it, such as the 'void setup' or 'void loop'? Why don't the instructions within the variable carry over into the 'void loop'?
My overall point is this. I originally created the 'buttonState' function because I did not know that variables could carry instructions. If I wanted to use an input pin to read a value, I thought I would need to create an entire function to do so. However, this is clearly not the case. Any answers to any of my numerous specific questions within this post would be greatly appreciated! I think the main issue is that I do not understand how variables containing instructions work, especially because they behave differently depending on the scope they are created and/or used in. Any resources regarding this type of variable and how to use it would also be appreciated tremendously! Thank you so much for reading through this long post, and I hope some of you can offer me some help!
Edit: Here is an image of my wiring, for anyone wondering!