I am trying to program 2 buttons (w/ an Arduino), one which will start a 5 second cycle and one which can stop the cycle at any point within this time frame. When the "Start" button is pressed "START" is printed to the serial monitor, and if the cycle is allowed to complete, "DONE" will be printed as well, followed by a new line. If the "stop" button is pressed, "STOP" is printed to the serial monitor and the cycle is terminated. At least, in theory this is how it should work. What I'm finding is that after I press the start button about 5 times, even if both buttons function perfectly beforehand, at this point the "DONE" will never be printed to the serial monitor. The last thing printed will be the "START" from the most recent button press. The only way to end this is to press the "stop" button, which prints "STOP." However, after pressing the "start" button after this, the code prints a rapid succession of "START\nDONE" couplets. Can anyone see a problem with the code I have? I thought it was a pretty straightforward task, and maybe it's just a problem with the hardware, but if it is a problem with the code, I can't see it.
int startPin = 4;
int stopPin = 7;
int motorPin = 2;
boolean startState = false;
boolean stopState = false;
void setup()
{
pinMode(startPin, INPUT);
pinMode(stopPin, INPUT);
pinMode(motorPin, OUTPUT);
Serial.begin(9600);
Serial.println("setup");
}
void loop()
{
startState = digitalRead(startPin);
if(startState == false)
{
return;
}
Serial.print("START\n");
int time = millis() + 5000;
while(millis() < time)
{
stopState = digitalRead(stopPin);
if(stopState == true) {
Serial.print("STOP\n");
return;
}
analogWrite(motorPin, 255);
}
analogWrite(motorPin, 0);
Serial.print("DONE\n\n");
}
As a final note- this is my first time using Stack Overflow, so I apologize in advance if this isn't a good question, or if it's already been answered, or if I'm doing something else that will appear overwhelmingly stupid to someone more experience than me. And thank you to anyone who can help me.
To start, change
int time = millis() + 5000;
To
unsigned long time = millis() + 5000;
millis() returns an unsigned long so if you are trying to insert that number + 5000 into a signed int, you are overflowing the int and causing weird calculations in your loop.
Related
hello i try to make an interruption in my arduino code to execute only one time a part of it. i use 2 while loop, the first is suppose to detecte when i press a button and the second when i release it. between the two the code i want to execute only one time for one press.
but even if the condition of the while is good it don't want to stop.
my serial monitor
my code :
void loop()
{
long button = cs_4_6.capacitiveSensor(5);
while(button < 1000)
{
long button = cs_4_6.capacitiveSensor(5);
Serial.println(button);
Serial.println("not ok");
}
if(nbButton[3] == 0)
{
nbButton[counter] = 1;
counter++;
}
else
{
int nbButton[] = {0, 0, 0, 0};
}
while(button > 1000)
{
long button = cs_4_6.capacitiveSensor(5);
Serial.println(button); // print sensor output 2
Serial.println("ok");
}
delay(50);
}
You are declaring long button each time in your while loops. As you are already declaring it at the beginning of your loop there is no need to do it at any other place. The while loops are taking your first declaration, which is not changing, whereas the Serial.print takes the new one defined only in the while loops.
In your two while loops change long button = cs_4_6.capacitiveSensor(5); to button = cs_4_6.capacitiveSensor(5);
Hope it helps,
I need help with an Arduino sketch , I want to repeat the blink sketch for a specified amount of time (3minutes for example) , then Stop .As we know , the loop() keeps runing forever which is not what I want . Any ideas how I can achieve this , blinking an LED for X minutes and Stopping ?
You should probably make use of some timer library. A simple (maybe naive) way to achieve what you want to do is to make use of a boolean that is set to 0 when 3 minutes has passed or simply digitalWrite the led to low when the timer has passed.
Check this link:
http://playground.arduino.cc/Code/Timer
I suggest that you use int after(long duration, callback).
Below is a (very) simple example of how you probably could do:
#include "Timer.h"
Timer t;
LED = 1;
void setup() {
int afterTime = t.after(180000, cancelLED);
}
void loop() {
t.update();
if(LED) {
//The "write HIGH" statement in your sketch here.
}
else {
//Write the led to LOW
}
}
void cancelLED() {
LED = 0;
}
I haven't used the library myself, I just checked the the docs and wrote an example to give you some ideas. Don't expect it to work right away.
I want to read a String in Arduino from the keyboard outside of the loop() method.
I have the following method:
void readFromKeyboard(byte arrayAddress[])
{
int count = 0, i = 0;
while ((count = Serial.available()) == 0);
while (i<count)
{
arrayAddress[i++] = Serial.read();
}
}
In the loop() method I am calling it like:
readFromKeyboard(userInput);
where userInput is a byte[];
The problem is that when I input more than one characters it read the 1st character initially and it call the readFromKeyboard again an then reads the rest.
Example; if I input "asdf":
--the 1st time it will do ==> userInput = "a"
--the 2nd time it will do ==> userInput = "sdf"
I have tryed many things but the same happens again and again...
Any suggestions??
So that's what worked:
In the loop():
while(Serial.available() == 0);
delay(100);
readInputFlag = readFromKeyboard(userInput);`
And in the readFromKeyboard method:
void readFromKeyboard(byte arrayAddress[])
{
int i = 0;
while (Serial.available() > 0)
{
arrayAddress[i++] = Serial.read();
}
}
This delay, in the loop method, somehow makes the Serial get the whole string instead of just the first letter.
I know you got it working, but I wanted to show you something that I use to deal with this issue. This is a two-tiered delay system for catching bytes that come in a bit late for whatever reason. It's designed to minimize the delay needed to accomplish that task.
int received_length = 0;
byte serial_incoming_buffer[200];
while(Serial.available()) {
serial_incoming_buffer[received_length++] = Serial.read();
if(!Serial.available()) {
delay(3);
if(!Serial.available()) {
delay(20);
}
}
}
Sometimes the Arduino falls behind in picking up serial from the sender and sometimes it grabs serial too fast. Sometimes the sender lags a little bit. This code will wait 3 ms for more bytes, and if they come in it goes back to receiving as many as are available having only had that very brief delay. This repeats as necessary, then when 3 ms goes by without anything being available, it waits a bit longer (20 ms here) for more bytes. If nothing comes in after the long delay, then the transmission is most likely done and you can safely move on.
I recommend tweaking the delays based on your baud rate.
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.
I'm trying to work with a simple Arduino circuit that increments a counter variable on pressing a push button in the circuit (connected as INPUT to PIN 8). My code is as simple as follows:
#include <LiquidCrystal.h>
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
int c = 0, btnPIN, btnVal;
void setup ()
{
btnPIN = 8;
pinMode(btnPIN, INPUT);
lcd.begin(16,2);
lcd.clear();
}
void void loop()
{
btnVal = digitalRead(btnPIN);
if (btnVal == LOW)
{
c++;
lcd.clear();
lcd.print(c);
}
}
Problem is the counter increases by more than 1 every time I push the button. A little bit of printing on the serial monitor indicates that each time the button is pressed and the voltage is LOW, the conditional code is executed multiple times and the counter increases by multiple times instead of 1.
Maybe, I need to write some logic that checks if the button was initially unpressed, then pushed and then released again and then these steps would trigger the required action.
The solution I'm currently working with is as under (which works just fine):
int btnStatus = 0;
void loop()
{
btnVal = digitalRead(btnPIN);
if (btnVal == LOW)
btnStatus = 1;
if(btnStatus == 1 && btnVal == HIGH)
{
c++;
lcd.clear();
lcd.print(c);
btnStatus = 0;
}
}
I'm not sure if there's a simpler solution available or if this approach is wrong for other reasons? Any advice would be most welcome!
Another problem you you may be having is that mechanical buttons bounce. That is, they jump between two positions several times quickly before settling to a final position. This is standard operation so it is necessary to "debounce" the button.
There are very many ways to do this, but Here is a tutorial using an Arduino.
The main issue, as you probably figured out, is that the loop function is getting called multiple times while the button is down. This is what is fixed by your code, and yours looks to be a good solution and I don't really see a simpler way. For another way, though, perhaps you could try just adding a call to delay at the end of loop to slow it down a bit. You would have to play with the delay amount a bit, but it could work. Really though, your solution looks just fine.
Your idea is correct, you need to track the previous state of the button to know if it is a new press or if it is simply being held down. Your code could be rewritten to look more like a state machine, however:
typedef enum {
BTN_STATE_RELEASED,
BTN_STATE_PRESSED
} ButtonState;
ButtonState btnStatus = BTN_STATE_RELEASED;
void increment_counter()
{
c++;
lcd.clear();
lcd.print(c);
}
void loop()
{
btnVal = digitalRead(btnPIN);
switch(btnStatus)
{
case BTN_STATE_PRESSED:
// Handle button release
if(btnVal == HIGH)
{
btnStatus = BTN_STATE_RELEASED;
}
break;
case BTN_STATE_RELEASED:
// Handle button press
if(btnVal == LOW)
{
increment_counter();
btnStatus = BTN_STATE_PRESSED;
}
break;
}
}
This was rewritten to use an enum to track the state of the system (a bit overkill for a simple button, but an important concept to know in case your system grows more complex).
The code to update the display was also moved into its own function to make it better separated between the display change and the actual update of the state.