I have written a huge program for Arduino.
I have tested each function individually, and all go fine except the function where I need millis().
Now carry the code block that I encounter any difficulties.
the variable T contains the number in seconds for this is multiplied by 1000
void onResistance(){
Input = sensors.getTempC(tempSensor);
sensors.requestTemperatures(); // prime the pump for the next one - but don't wait
digitalWrite(RelayPin, HIGH);
//more code
Input = sensors.getTempC(tempSensor);
sensors.requestTemperatures(); // prime the pump for the next one - but don't wait
if(Input<Setpoint){ onResistance(); }
else{ digitalWrite(RelayPin, LOW); istru++; return ; }
return ;
}
void statTemp(){
unsigned long currentMillis = millis();
if(currentMillis - previousMillis > ttemp){
previousMillis = currentMillis;
Input = sensors.getTempC(tempSensor);
sensors.requestTemperatures();
lcd.setCursor(0,1);
lcd.print(F("T. Att.:"));
lcd.print(Input);
lcd.write(1);
lcd.print(F("C"));
if (Input<Setpoint) {
digitalWrite(RelayPin, HIGH);
statTemp();
} else if(Input>Setpoint || Input == Setpoint) {
digitalWrite(RelayPin, LOW);
statTemp(); }
} else if(currentMillis - previousMillis < ttemp) { playShortBeep(); istru++; return; }
return ;
}
void startFan(){
Input = sensors.getTempC(tempSensor);
sensors.requestTemperatures(); // prime the pump for the next one - but don't wait
digitalWrite(FAN_PIN, HIGH);
//more code
Input = sensors.getTempC(tempSensor);
sensors.requestTemperatures(); // prime the pump for the next one - but don't wait
if(Input>Tm){ startFan(); }
else{ digitalWrite(FAN_PIN, LOW); istru++; return ; }
return ;
}
void controll(){
if(!start)
return ;
if(start){
if(istru==0){
onResistance();
}
if(istru==1){
ttemp = (T * 1000) + millis() ;
statTemp();
}
if(istru==2){
startFan();
}
if(istru==3){
start =false;
opState = OFF;
playShortBeep();
playShortBeep();
playShortBeep();
istru=0;
}
}
delay(100);
return ;
}
I need for the time T the function statTemp remains running conducting checks if written in it.
sorry for my bad english
So you want to stay in the function statTemp() until time T has passed?
Then something like this might work
void statTemp(){
unsigned long currentMillis;
unsigned long enteringMillis = millis();
while (((currentMillis = millis()) -enteringMillis) < T)
{
if(currentMillis - previousMillis > ttemp){
etc etc etc....
}
return ;
}
Notice the MIGHT. I don't know if millis is updated at every timer interrupt or just in the loop function; in the latter case, you will be stuck forever in the function.
Consequently i suggest you not to do this, but think at another approach: an FSM which handles the function to be executed. It's a cleaner way to proceed and less error-prone.
Bye
EDIT:
Here is a complete working example. In this example, the function myfunc is executed for 10 seconds; during this time the board performs some actions (in this example serial output). When 10 seconds pass, the program goes on, thus repeating the loop function.
unsigned long previousTime;
void myfunc();
void setup() {
Serial.begin(9600);
}
void loop() {
Serial.println("I'm in the loop function");
myfunc();
}
void myfunc()
{
unsigned long currentTime;
unsigned long enteringTime = millis();
while(((currentTime = millis()) - enteringTime) < 10000)
{
if(currentTime - previousTime > 1000)
{
previousTime = currentTime;
Serial.println("I'm in the custom function");
}
}
}
HOWEVER my suggestion is still the same: instead of blocking the execution inside of a function, use a finite state machine; it's much more flexible and easier to understand, implement and edit.
Related
I need a motor to cycle forward, then backward when the user pushes a once. the problem is, the arduino will run in loops after it is presses and wont stop.
How can i make it only cycle through once each time the button is pushed?
Ive tried exit(0), stop_it, etc, but those just exit the loop instead of starting back up when the button is pressed another time.
const int pwm_pin = 9;
const int dir_1a_pin = 8;
const int dir_2a_pin = 7;
int buttonPin = 2;
boolean on=false;
int buttonState = 0;
void setup() {
pinMode(buttonPin, INPUT);
pinMode(pwm_pin, OUTPUT);
pinMode(dir_1a_pin, OUTPUT);
pinMode(dir_2a_pin, OUTPUT);
}
void loop() {
buttonState = digitalRead(buttonPin);
if (buttonState == HIGH){
if (on==true){
on=false;
} else{
on=true;
}
}
if(on == true){
digitalWrite(dir_1a_pin, HIGH);
digitalWrite(dir_2a_pin, LOW);
analogWrite(pwm_pin, 255);
delay (8000);
digitalWrite(dir_1a_pin, LOW);
digitalWrite(dir_2a_pin, HIGH);
analogWrite(pwm_pin, 255);
delay (12000);
}
}
You are making the logic too much complicated. Just read the button state in your loop and if it was HIGH do your motorcycle job. The next time loop runs as you haven't pressed the button it would become LOW and won't go into if statement.
const int pwm_pin = 9;
const int dir_1a_pin = 8;
const int dir_2a_pin = 7;
int buttonPin = 2;
void MotorCycle()
{
digitalWrite(dir_1a_pin, HIGH);
digitalWrite(dir_2a_pin, LOW);
analogWrite(pwm_pin, 255);
delay(8000);
digitalWrite(dir_1a_pin, LOW);
digitalWrite(dir_2a_pin, HIGH);
analogWrite(pwm_pin, 255);
delay(12000);
}
void setup()
{
pinMode(buttonPin, INPUT);
pinMode(pwm_pin, OUTPUT);
pinMode(dir_1a_pin, OUTPUT);
pinMode(dir_2a_pin, OUTPUT);
}
void loop()
{
// if button pressed
if (digitalRead(buttonPin) == HIGH)
{
MotorCycle();
}
}
I assume that the part you want to run once is in the section at the end in the if(on == true) section. If you don't want that to repeat, then how about setting on to false in that section. Then next time loop repeats it won't go into that section.
I have been trying to write a code to basically add points to a score whenever I pressed a button while a certain amount of time is running down. The problem I am finding is that it doesn't detect when the button is pressed while the time is decreasing, in fact it can only detect when the time starts to decrease and then it doesn't matter at which state the button is it will continue to add to the score. Anyway here is the main code:
void loop() {
buttonState01 = digitalRead(button01);
buttonState02 = digitalRead(button02);
buttonState03 = digitalRead(button03);
if (buttonState01){
time = 3000;
while(time > 0){
if (buttonState02){
score += 10;
Serial.println(score);
}
time--;
Serial.println(time);
}
}
}
And here is the full code if needed:
int button01 = 4;
int button02 = 3;
int button03 = 2;
int buttonState01 = 0;
int buttonState02 = 0;
int buttonState03 = 0;
float time;
int score;
void setup() {
score = 0;
time = 0;
pinMode(button01, INPUT);
pinMode(button02, INPUT);
pinMode(button03, INPUT);
Serial.begin(9600);
}
void loop() {
buttonState01 = digitalRead(button01);
buttonState02 = digitalRead(button02);
buttonState03 = digitalRead(button03);
if (buttonState01){
time = 3000;
while(time > 0){
if (buttonState02){
Serial.println("Points");
}
time--;
Serial.println(time);
}
}
}
You should read the status of a button inside the while loop. Like this:
while(time > 0)
{
buttonState02 = digitalRead(button02);
if (buttonState02){
Serial.println("Points");
}
time--;
Serial.println(time);
}
And in your code, there is no logic to add points to the score.
A hardware interrupt would do exactly what you need.
Attach an interrupt routine to the pin your button is linked to, and get it to set the 'score' variable. Make sure you introduce some sort of timeout to avoid button-bounce (I.e. set LastTimeIncremented when you increase the score, and only increment score if LastTimeIncremented is more than 1 second ago)
This way the score will always be set regardless of what else the program may be doing.
Information on this can be found in the Arduino https://www.arduino.cc/en/Reference/attachInterrupt
The example on that page would do exactly what you want, just replace 'blink' with 'incrementScore' and you're pretty much done
const byte ledPin = 13;
const byte interruptPin = 2;
int score = 0;
int increment = 1;
void setup() {
pinMode(ledPin, OUTPUT);
pinMode(interruptPin, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(interruptPin), incScore, RISING);
}
void loop() {
digitalWrite(ledPin, state);
}
void incScore() {
score = score+increment;
// add anti-bounce functionality here
}
I am trying to make my own delay function. Briefly mydelay function is calling toggled function every secs seconds. The code is not well written, i know (this is the first version). But i am just trying to get it work properly. Then i will refactor it. But i have some unexpected bugs. First time the loop in x function is working properly. It is printing "I am in while" for 1 second and then it prints "Im ending mydelay" which is the behaviour i want. But after finishing the loop in x. The second time when it loops. It enters the mydelay function (that is ok). But then it is not printing "I am in while" at all. It just prints "Im ending mydelay" which is not good.
Here is the code:
#include <Arduino.h>
int led = 7;
void setup() {
Serial.begin(9600);
pinMode(led, OUTPUT);
}
void loop() {
x();
Serial.println("Im ending main loop");
}
void x() {
for (int i = 0; i <= 10; i++) {
mydelay(led, 0, 1);
mydelay(led, 1, 1);
}
}
void mydelay(int pin, int hol, int secs) {
int starttime = millis();
while ((millis() - starttime) <= (secs * 1000)) Serial.println("I am in while");
toggled(pin, hol);
Serial.println("Im ending mydelay");
}
void toggled(int pin, int hol) {
digitalWrite(led, hol);
}
Change int starttime = millis(); to unsigned long starttime = millis();. This might be the problem because if you are using an int, your program will go crazy after 32 seconds. That is a problem because an int can only hold a number going from -32,768 to 32,767 .
Also, you might as well try this:
while ((millis() - starttime) <= (secs * 1000))
{
Serial.println("I am in while");
}
maybe you can try to reset the millis using something like this, I don't have an arduino so it's not tested but hopefully it can help.
extern volatile unsigned long timer0_millis;
unsigned long reset = 0;
#include <Arduino.h>
int led = 7;
void setup() {
Serial.begin(9600);
pinMode(led, OUTPUT);
}
void loop(){
x();
Serial.println("Im ending main loop");
setMillis(reset);
}
void setMillis(unsigned long new_millis){
uint8_t oldSREG = SREG;
cli();
timer0_millis = new_millis;
SREG = oldSREG;
}
void x() {
for (int i = 0; i <= 10; i++) {
mydelay(led, 0, 1);
mydelay(led, 1, 1);
}
}
void mydelay(int pin, int hol, int secs) {
int starttime = millis();
while ((millis() - starttime) <= (secs * 1000)) Serial.println("I am in while");
toggled(pin, hol);
Serial.println("Im ending mydelay");
}
void toggled(int pin, int hol) {
digitalWrite(led, hol);
}
I'm doing a calculator with Arduino Uno. I'm using a 4x4 keypad, and 16x2 LCD for display. Here's my question: If the buttons on keypad stays untouched for 1 min, the program will execute a function. How can I do this?
You can use millis() to measure the time and a simple flag boolean with digitalRead() to determine wheter a pushed button is released. It should be something like that (not tested yet):
unsigned long previousMillis = 0;
long interval = 60000;
int buttonPin = 4;
boolean buttonReleased=false;
void setup(){
}
void loop(){
unsigned long currentMillis = millis();
// edit, thanks to frarugi87
if (digitalRead(buttonPin) == LOW){
buttonReleased = true;
previousMillis = currentMillis;
}
if((currentMillis - previousMillis > interval)&&buttonReleased ) {
previousMillis = currentMillis;
buttonReleased =false;
// execute a function
}
}
EDIT: Correct the keypad condition.
The code below is part of a larger project. The intent is to flash an led with a variable on time, reset the on time and accumulate the total "on" time. The on time is changed each time the "on" period has elapsed.
Code below appears to successfully change the "on" time at the end of each "on" time period, but does not accumulate the total time.
I expected ledtime to equal LED_ON on the first pass (for example 1000) and then equal the previous ledtime + LED_ON (for example 1000 + 2538 = 3528) on the second pass etc.
Instead ledtime is always equal to the current LED_ON, so it appears ledtime is always set to zero on each pass, which I don't understand.
I'm new at arduino/C programming and suspect I'm missing something pretty simple/obvious, but have played with this for awhile with no resolution (including moving the ledtime = etc statements to various areas within the blink routine).
long ledtime;
const int LED_PIN = 13;
const int grnled = 11;
unsigned long LED_ON = 800; //milliseconds
int LED_OFF = 2000;
int redled = 10;
int yellowled = 12;
unsigned long ms; //time from millis()
unsigned long msLast;
unsigned long mslast2;//last time the LED changed state
boolean ledState; //current LED state
void setup(void)
{
pinMode(grnled, OUTPUT);
pinMode(redled,OUTPUT);
pinMode(yellowled,OUTPUT);
Serial.begin(9600);
}
void loop(void)
{
while(millis()<5000) {
digitalWrite(redled,HIGH);
digitalWrite(yellowled,LOW);
}
while (millis() >(5000) && millis()< 20000){
ms = millis();
blinkLED();
}
if (millis() > 20000 && millis() < 30000) {
digitalWrite(redled,HIGH);
}
if (millis() > 30000) {
digitalWrite(yellowled,HIGH);
digitalWrite(redled, LOW);
}
}
void blinkLED(void)
{
if (ms - msLast > (ledState ? LED_ON : LED_OFF)) {
digitalWrite(grnled, ledState = !ledState);
msLast = ms;
long ledtime = ledtime + LED_ON; //this does not work
Serial.println("ledtime = ");
Serial.println(ledtime);
if (ms-mslast2> LED_ON) {
LED_ON = random(500,5000); //this works
LED_OFF = 2000;
mslast2 = ms;
Serial.println("LED_ON = ");
Serial.println(LED_ON);
}
}
}
I'm not very sure of what you're trying to do, but with the line you commented, you create a local variable ledtime which has the same name of your global one. And because it's local to your function, it gets erased at the end of your function.
So first initialize ledtime at 0 at its declaration,
Then try to replace this line by
ledtime += LED_ON;