Im an artist, not a programmer. But i'm making a pinball game with an Arduino, and I do not have a programmer, so I'm learning what I can to make this work.
I'm trying to write a code that does this:
- 3 targets (buttons) that when hit, they give points, and light an LED.
- If the same button is hit a second time, it will still give points, and the LED stays lit.
- If ALL 3 lights are lit at the same time, there is a bonus score given, and ALL 3 lights turn off.
I tried using the Arduino forums but the best advice I could get out of them was "Go learn to code."
I have been told to learn about 'arrays' and I have tried but I'm having some serious trouble wrapping my head around it. If it is possible to do this with just 'IF' and 'ELSE' statements I would really prefer to do things the long and inefficient way.
Here is my current code. Currently I have 4 lights on my breadboard. Light #4 (D) is lit right away for debug reasons. Each of the other 3 lights (ABC) will light when their button is pushed. When All 3 lights are lit, (D) light will go out, but (ABC) remain lit. I need them to go out when (D) does. and I don't know why they wont. I know the code recognizes that all 3 are HIGH. Because (D) goes LOW. I don't know why (ABC) won't go LOW as well.
// 3 TARGET SCORE FUNCTION.
// WHEN A TARGET IS HIT IT LIGHTS UP AND PROVIDES POINTS.
// IF A TARGET IS HIT AGAIN WHILE IT IS ALREADY LIT, IT STILL SCORES POINTS AND STAYS LIT.
// WHEN ALL 3 TARGETS ARE LIT THEY FLASH AND PROVIDE A JACKPOT
// WHEN JACKPOT IS PROVIDED ALL LIGHTS TURN OFF. READY TO BE ACTIVATED AGAIN.
int dropButtonA = 2; // the number of the input pin
int dropButtonB = 3;
int dropButtonC = 4;
int dropLightA = 11; // the number of the output pin
int dropLightB = 12;
int dropLightC = 13;
int dropLightD = 10;
int stateA = LOW; // the current state of the output pin
int stateB = LOW;
int stateC = LOW;
int stateD = LOW;
int readingA; // the current reading from the input pin
int readingB;
int readingC;
int previousA = LOW; // the previous reading from the input pin
int previousB = LOW;
int previousC = LOW;
long time = 0; // the last time the output pin was toggled
long debounce = 200; // the debounce time, increase if the output flickers
void setup()
{
pinMode(dropButtonA, INPUT);
pinMode(dropButtonB, INPUT);
pinMode(dropButtonC, INPUT);
pinMode(dropLightA, OUTPUT);
pinMode(dropLightB, OUTPUT);
pinMode(dropLightC, OUTPUT);
pinMode(dropLightD, OUTPUT);
}
void loop()
{
//droptarget_01//
readingA = digitalRead(dropButtonA);
if (readingA == HIGH && previousA == LOW && millis() - time > debounce) {
stateA = HIGH;
time = millis();
}
digitalWrite(dropLightA, stateA);
previousA = readingA;
//droptarget_02//
readingB = digitalRead(dropButtonB);
if (readingB == HIGH && previousB == LOW && millis() - time > debounce) {
stateB = HIGH;
time = millis();
}
digitalWrite(dropLightB, stateB);
previousB = readingB;
//droptarget_03//
readingC = digitalRead(dropButtonC);
if (readingC == HIGH && previousC == LOW && millis() - time > debounce) {
stateC = HIGH;
time = millis();
}
digitalWrite(dropLightC, stateC);
previousC = readingC;
//RESET TARGETS - BONUS SCORE
if (digitalRead(dropLightA)==HIGH && digitalRead(dropLightB)==HIGH && digitalRead(dropLightC)==HIGH)
{
digitalWrite(dropLightA, LOW);
digitalWrite(dropLightB, LOW);
digitalWrite(dropLightC, LOW);
digitalWrite(dropLightD, LOW);
}
else
{
digitalWrite(dropLightD, HIGH);
}
}
The problem is that the variable named "stateX" does not change when ABC goes LOW. You need to add these statements to the "//RESET TARGETS - BONUS SCORE" loop when the condition is true:
stateA = LOW;
stateB = LOW;
stateC = LOW;
stateD = LOW;
IMHO you do not need to use arrays when there are only four items- clarity of code (esp. to the author) has value. However, I think that the variables "stateX" and "previousX" are redundant; if you did not have both you would not have this bug.
Also, I would recommend using the previously read value of the pins for the loop test at "//RESET TARGETS - BONUS SCORE":
if (readingA == HIGH && readingB == HIGH && readingC == HIGH)
With your current code you read the values of the pins twice during the loop. In this case there is a chance the value of the pins could change during the loop and you could get really confusing results.
Related
I am writing some Arduino code that is meant to control my 3D printed robot at a basic level. Everything works fine until the value that I analogWrite() to ledPin (pin 11 on the Nano) is no longer 0. The purpose of this bit of code is to fade some leds ON/OFF based on ambient lighting without using delay() function that pauses the program.
The code here determines whether the ambient light is below threshold, wheter 4 milliseconds have passed and whether the LEDs are at their target brightness yet, then increments/decrements the value to analogWrite() accordingly. It's when this value (lightVal) increases that the whole program freezes and remains in the state it was just before freezing. (The robot becomes unresponsive and serial data stops getting sent.) The moment I comment out the analogWrite(), the freeze does not occur.
timer = millis();
aLightVal = analogRead(LDR);
aLightVal = map(aLightVal, 0, 600, 0, 100);
//Check to see if the ambient light is below threshold
//If LED is not yet at target brightness, fade every 4 milliseconds
if (aLightVal < 40){
if (timer - currentTime > 4){
if (lightVal < 255){
lightVal++;
currentTime = timer;
}
}
}
if (aLightVal >= 40){
if (timer - currentTime > 4){
if (lightVal > 0){
lightVal--;
currentTime = timer;
}
}
}
analogWrite(ledPin, lightVal);
Serial.println(aLightVal);
I am using the Servo.h as well as the Ultrasonic.h libraries in the program if that helps?
I initialised the variables as follows:
const int LDR = A1;
const int ledPin = 11;
unsigned long timer = 0;
unsigned long currentTime = 0;
int aLightVal;
int lightVal = 0;
Any advice? Please let me know, I would really appreciate it!
I am trying to wire up a simple switch to an Arduino, as per the code below, for use in a model trainset.
When the buttonState is high, Serial.print(buttonState) shows 111111111, however, the problem I have is when buttonState should be low: Serial.print(buttonState) "flickers" between 0 and 1 like so: 000111100000101000111001.
Why is it doing this and how do I stop it? I assumed it was connections but when I simply use a wire between the 2 ports, plugging it in for on and unplugging for off I still get this issue.
int RED=6;
int YELLOW=5;
int GREEN=3;
int relaytrig = 10; // trigger on pin 10
int powertoswitch = 9; // powertoswitch
int buttonPin = 12; // switch the button comms with
int buttonState = 0;
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
// inputs
// switch input
pinMode(buttonPin,INPUT);
// outputs
// powerforswitch
pinMode(powertoswitch,OUTPUT);
// track power
pinMode(relaytrig, OUTPUT);
//signal outputs
pinMode(RED,OUTPUT);
pinMode(YELLOW,OUTPUT);
pinMode(GREEN,OUTPUT);
}
void loop() {
// put your main code here, to run repeatedly:
digitalWrite(powertoswitch,HIGH);
buttonState = digitalRead(buttonPin);
if (buttonState == HIGH) {
digitalWrite(relaytrig,LOW);
digitalWrite(GREEN,LOW);
digitalWrite(RED,HIGH);
digitalWrite(YELLOW,LOW);
Serial.print(buttonState);
} else if (buttonState == LOW) {
digitalWrite(relaytrig,HIGH);
digitalWrite(GREEN,HIGH);
digitalWrite(RED,LOW);
digitalWrite(YELLOW,LOW);
Serial.print(buttonState);
}
}
Unplugging it leaves the input pin floating, and noise etc. can make a floating input pin take any value.
Depending on your connection, you need a pull-down or a pull-up resistor on the pin to make it a 1 or a 0 when nothing is connected to it.
From the code, I assume the switching wire is between 5 V (or 3.3 V for some Arduinos) and an input pin. If I'm right, you need to put a, say, 10 kΩ resistor from that input pin to ground. This will keep it 0 when there is no wire connected.
BTW you are using an IO pin (9 aka powertoswitch) to provide the plus for the switch; there's no need and you shouldn't.
Connect one end of the switch to 5 V (or 3.3 V for some Arduinos), and the other end to the input pin. Connect the input pin with the resistor to ground (GND).
There's a picture here, but they use pin 2 as the input pin, and you use pin 12.
Also, your button or wire may need debouncing, but that is another matter.
First a bit of background. I am attempting to make an LED glow and a buzzer produce a tone that sweeps smoothly up and down in frequency, like an air raid siren. I am using an Arduino Uno, connected to an ATTiny85 chip operating at 8hz clock speed. An SPDN contact switch is used to provide input on 4, while 0 and 1 go out to the positive legs of the buzzer and LED respectively. Suitable resistors are being used to limit current, which is 5v from the Arduino board.
Now, my problem. I can produce a constant tone at any frequency I like. I can produce a tone that goes back and forth between two tones like a UK police siren (Dee-Daa-Dee-Daa etc) but I am unable to generate a smooth transition between two tones. The LED works as expected.
What I actually observe is a single tone that does not vary. Once or twice I've managed to produce a tone that varies, but randomly within the given range rather than smoothly.
I am not using the tone() Arduino command and would prefer not to, as it is not best suited for what I am trying to accomplish.
Here is my code:
const float pi2 = 6.28318530717;
const int buzzer = 0;
const int light = 1;
const int button = 4;
// Set up the pins as input and output
void setup() {
pinMode(buzzer, OUTPUT);
pinMode(light, OUTPUT);
pinMode(button, INPUT);
}
bool buzzerState = LOW;
float nextFlip = 0;
// Generates a sine wave for the given uptime, with a period and offset (in milliseconds).
float sineWave(float uptime, float period, float offset, float minimum, float maximum) {
float s = sin(((uptime + offset) * pi2) / period);
// Normalise the result between minimum and maximum
return (s + 1) / 2 * (maximum - minimum) + minimum;
}
// Returns the time between buzzer inversions based on a given system uptime.
float frequency(float uptime) {
return sineWave(uptime, 5000, 0, 1, 10);
}
// Main loop
void loop() {
// Check button state and turn the light on or off
bool buttonDown = digitalRead(button);
digitalWrite(light, buttonDown);
// Check to see if it's time for the next buzzer inversion
float m = micros();
if (!buttonDown || m < nextFlip) return;
// Get the inverse of the current buzzer state
if (buzzerState == HIGH) {
buzzerState = LOW;
} else {
buzzerState = HIGH;
}
// Write the new buzzer state
digitalWrite(buzzer, buzzerState);
// Decide when the next inversion will occur
nextFlip = m + frequency(m);
}
Silly mistake! I finally noticed: I'm reading micros() where I meant to read millis() - in other words, it was oscillating, just a thousand times faster than I intended it to! Multiplying all values up by a factor of 1000 in the sine wave function produced a lovely oscillation.
I need help with debounce of push button. Sometimes it send twice same string to serial link, and I don't know why. Could someone help me, where is a problem?
int reading;
int exbutton= LOW;
unsigned long ddelay= 200;
unsigned long last= 0;
void loop(){
reading= digitalRead(prkgbrake);
if (reading== HIGH && exbutton == LOW && millis() - last> ddelay){
if (brake == 0){
Serial.write("brake:1\n");
while( digitalRead(prkgbrake) == HIGH){
}
}
else{
Serial.write("brake:0\n");
while( digitalRead(prkgbrake) == HIGH){
}
}
last = millis();
}
Thank you in advance.
I hope you didn't copy this code from somewhere, some of the code doesn't make sense.
For instance, what is 'prkgbrake'? What is 'brake'? They are not declared. Why don't you have a 'setup()' function?
Nevertheless, debouncing can be achieved in many ways. I will just fix your code. That way you will understand what you did wrong.
int exbutton = LOW;
unsigned int _delay = 200;
int pushButton = 2;
void setup()
{
// initialize serial communication at 9600 bits per second:
Serial.begin(9600);
pinMode(pushButton, INPUT_PULLUP);
}
void loop()
{
while (digitalRead(pushButton) == LOW && exbutton == LOW)
{
if((millis() - last) > _delay)
{
Serial.println("Button Pressed");
while(digitalRead(pushButton) == LOW);
}
}
last = millis();
}
Explanantion: Assuming your pushbutton is connected with digital pin 2. When you use a digital pin with a button it is better to use pullup/pulldown. You can use external resistor or the internal resistor for that. The internal resistor only supports Pull-up.
To know more about pull-up/-down checkout this Arduino page. The bottom line is when you use a pin as input it acts like an antenna and can capture signals from surroundings, known as floating state. So it is better to keep the pin in a known state. If you use internal pull-up, the pin will be always HIGH. So the button configuration has to be in a way so that when it is pressed the pin should go LOW.
Pull Up Configuration
The code pinMode(pushButton, INPUT_PULLUP); enables the digital pin 2 as input with pull-up enabled.
the loop() should work like this:
1) Check if the button is pressed (i.e. if it is LOW).
2) If not update the last variable.
3) If yes then DONT update last, and enter the while loop.
4) Now keep checking if millis()-last is greater than _delay. If not it will go back to while loop and check if the button is still pressed or not. If yes then it will come back and check if millis()-last is more than _delay or not. It will continue to do so until it passed the mentioned amount of debounce delay.
5) If button get depressed (i.e. goes to HIGH) before the '_delay' time then it will update the last and will check if button is pressed or not and will start counting the delay time.
N.B. Play with the _delay variable. It will define the responsiveness of your button.
It is possible to serial print how milliseconds every output high. Let say i write an code analogRead. If analogread bigger than 600, then digitalwrite 13, high. If output pin 13 high, then capture how millisecond until the pin 13 goto low.
I try millis() but it cannot reset back to zero... It there anyway to reset millis() to zero?
You need a variable to keep track of your millis() count between events, kind of like a stop watch: you need to remember you started counting, so you can measure the difference when you stop.
Here's a quick sketch to illustrate the idea. Code isn't tested on an Arduino, but you should be able to understand the concept from the comments:
long lastTime;
int ledState = 0;
void setup() {
Serial.begin(115200);
pinMode(13,OUTPUT);
}
void loop() {
int analogValue = analogRead(0);
int newLedState = (analogValue > 600);//need to check, hoping boolean will evaluat to 1 when true
if(ledState == 0 && newLedState == 1){//if the led was of, but will be turned on, start the stop watch
lastTime = millis();//store the current time
ledState = newLedState;
}
if(ledState == 1 && newLedState == 0){//if the led was on, but will be turned off, get the difference between the last time we started counting time
long difference = millis() - lastTime; //get the current time, but subtract the last stored time
ledState = newLedState;
Serial.println(difference);
}
digitalWrite(13,ledState);
}
Okay so I think I understand what you want here. You want to capture the time difference between 2 pins changing their electrical state. To do this you can use pulseIn().
Using your example in your question we get...
if (13 == HIGH) {
millis = pulseIn(13, LOW);
}
That will give you the duration between the pin going high and then going low, stored in the variable millis. It's good practice to store it in a long.