write timer without delay() - c

I wrote this code to send an SMS if an input is HIGH as you can see in it,but the problem is I have 4 inputs and delay()s are fatal and very wrong if I need to do more than one single thing at a time (I use 4 inputs).
So I need to change delay() with millis() or something else in void loop() ,Send_SMS() and initia().
can someone help me,and thank you in advance.
const int DI = 2;
const int DT = 3;
const int DGP1 = 4;
const int DGP2 = 5;
int value1_old = 0;
int value2_old = 0;
int value3_old = 0;
int value4_old = 0;
unsigned long previousMillis = 0;
unsigned long interval=100;
#include<SoftwareSerial.h>
SoftwareSerial SIM900 (7, 8);
void setup() {
pinMode(DI, INPUT);
pinMode(DT, INPUT);
pinMode(DGP1, INPUT);
pinMode(DGP2, INPUT);
SIM900.begin(19200);
SIM900power();
delay(20000);
}
void SIM900power(){
digitalWrite(9 ,HIGH);
delay(1000);
digitalWrite(9 ,LOW);
delay(5000);
}
void initia(){
SIM900.print("AT+CMGF=1\r");
delay(100);
SIM900.println("AT + CMGS = \"+212xxxxxxx\"");
delay(100);
}
void Send_SMS(){
SIM900.println((char)26);
delay(100);
SIM900.println();
delay(100);
SIM900power();
}
void loop() {
int value1 = digitalRead (DI);
int value2 = digitalRead (DT);
int value3 = digitalRead (DGP1);
int value4 = digitalRead (DGP2);
if (value2 != value2_old && value2 == HIGH) {
initia();
SIM900.println("Station 85: Defaut electrique");
delay(100);
Send_SMS();
value2_old = value2;
}
if (value3 != value3_old && value3 == HIGH)
{
initia();
SIM900.println("Station 85: DefautGP1");
delay(100);
Send_SMS();
value3_old = value3;
}
if (value4 != value4_old && value4 == HIGH)
{
initia();
SIM900.println("Station 85:DD>1000");
delay(100);
Send_SMS();
value4_old = value4;
}
value2_old = value2;
value3_old = value3;
value4_old = value4;
}

As mclopez pointed out, is better to provide a good answer rather than pointing out only what are the flaws of the other ones, so... Here we go.
In my opinion the ISR solution is not a good choice, because ISRs block the normal execution. The only feasible implementation using interrupts is to record the pin change and then send the SMSs.
This, however, is not a good solution in my opinion. For this problem, I'd go with a state machine to send the SMSs; since you have states, you can wait the transition while doing other things, like checking the buttons.
I do not know how SIM900 sends the SMS, so I'm taking your workflow and implementing it in a state machine. I'm not sure this is the optimal solution, particularly because I don't think you actually need to reboot the module each time, but you can trim it later.
Now, the workflow has seven actions you have to perform, each followed by a wait. I write it here so it's simpler to see every action:
SIM900.print("AT+CMGF=1\r");
delay(100);
SIM900.println("AT + CMGS = \"+212xxxxxxx\"");
delay(100);
SIM900.println("Message you want");
delay(100);
SIM900.println((char)26);
delay(100);
SIM900.println();
delay(100);
digitalWrite(9 ,HIGH);
delay(1000);
digitalWrite(9 ,LOW);
delay(5000);
So we have eight states: an idle one (when you are waiting for the state machine to start, named SIM_IDLE), followed by five "SEND" states (I name them SIM_SEND1..5) and two states to reset the power (named SIM_POW1 and SIM_POW2). You are normally in idle state; when one or more buttons are pressed, you switch to the first send, cycle through them and then reset the power and go back to idle.
The pressed button changes only state SIM_SEND3 (when you actually send the message), so whenever a button press is detected a boolean variable is set (a button press is detected also during the state machine execution) and is reset only in that state, after the correct message is sent.
Now, here is the code which implements this:
const uint8_t DI = 2;
const uint8_t DT = 3;
const uint8_t DGP1 = 4;
const uint8_t DGP2 = 5;
const uint8_t SIMPOW = 9;
uint8_t value1_old = 0;
uint8_t value2_old = 0;
uint8_t value3_old = 0;
uint8_t value4_old = 0;
boolean value1_changed = false;
boolean value2_changed = false;
boolean value3_changed = false;
boolean value4_changed = false;
/********************************/
// SIM STATES
#define SIM_IDLE 0
//SEND1: SIM900.print("AT+CMGF=1\r");delay(100);
#define SIM_SEND1 1
//SEND2: SIM900.println("AT + CMGS = \"+212xxxxxxx\"");delay(100);
#define SIM_SEND2 2
//SEND3: SIM900.println("Message you want");delay(100);
#define SIM_SEND3 3
//SEND4: SIM900.println((char)26);delay(100);
#define SIM_SEND4 4
//SEND5: SIM900.println();delay(100);
#define SIM_SEND5 5
//POW1: digitalWrite(SIMPOW,HIGH);delay(1000);
#define SIM_POW1 6
//POW2: digitalWrite(SIMPOW,LOW);delay(5000);
#define SIM_POW2 7
/********************************/
unsigned long previousMillis;
uint8_t currentSimState;
#include<SoftwareSerial.h>
SoftwareSerial SIM900 (7, 8);
void setup()
{
pinMode(DI, INPUT);
pinMode(DT, INPUT);
pinMode(DGP1, INPUT);
pinMode(DGP2, INPUT);
pinMode(SIMPOW, OUTPUT);
SIM900.begin(19200);
digitalWrite(SIMPOW,HIGH);
delay(1000);
digitalWrite(SIMPOW,LOW);
delay(25000);
currentSimState = -1; // Force a state transition
}
void loop()
{
uint8_t value1 = digitalRead (DI);
uint8_t value2 = digitalRead (DT);
uint8_t value3 = digitalRead (DGP1);
uint8_t value4 = digitalRead (DGP2);
unsigned long currentMillis = millis();
if (value2 != value2_old && value2 == HIGH)
value2_changed = true;
if (value3 != value3_old && value3 == HIGH)
value3_changed = true;
if (value4 != value4_old && value4 == HIGH)
value4_changed = true;
value1_old = value1;
value2_old = value2;
value3_old = value3;
value4_old = value4;
// Check if a state transition is needed
uint8_t newSimState = currentSimState;
switch (currentSimState)
{
case SIM_IDLE: // Start sending if a value changed
if ((value2_changed) || (value3_changed) || (value4_changed))
newSimState = SIM_SEND1;
break;
case SIM_SEND1: // Wait 100 ms
if ((currentMillis - previousMillis) >= 100)
newSimState = SIM_SEND2;
break;
case SIM_SEND2: // Wait 100 ms
if ((currentMillis - previousMillis) >= 100)
newSimState = SIM_SEND3;
break;
case SIM_SEND3: // Wait 100 ms
if ((currentMillis - previousMillis) >= 100)
newSimState = SIM_SEND4;
break;
case SIM_SEND4: // Wait 100 ms
if ((currentMillis - previousMillis) >= 100)
newSimState = SIM_SEND5;
break;
case SIM_SEND5: // Wait 100 ms
if ((currentMillis - previousMillis) >= 100)
newSimState = SIM_POW1;
break;
case SIM_POW1: // Wait 1000 ms
if ((currentMillis - previousMillis) >= 1000)
newSimState = SIM_POW2;
break;
case SIM_POW2: // Wait 1000 ms
if ((currentMillis - previousMillis) >= 1000)
newSimState = SIM_IDLE;
break;
default:
newSimState = SIM_IDLE;
break;
}
// If there was a transition, do the appropriate action
if (newSimState != currentSimState)
{
case SIM_IDLE:
// Do nothing
break;
case SIM_SEND1:
SIM900.print("AT+CMGF=1\r");
previousMillis = millis();
break;
case SIM_SEND2:
SIM900.println("AT + CMGS = \"+212xxxxxxx\"");
previousMillis = millis();
break;
case SIM_SEND3:
if (value2_changed)
{
SIM900.println("Station 85: Defaut electrique");
value2_changed = false;
}
else if (value3_changed)
{
SIM900.println("Station 85: DefautGP1");
value2_changed = false;
}
else if (value4_changed)
{
SIM900.println("Station 85:DD>1000");
value2_changed = false;
}
else
{
// Should never arrive here. Just in case, you
// can either abort the SMS sending if you can
// or send another message
}
previousMillis = millis();
break;
case SIM_SEND4:
SIM900.println((char)26);
previousMillis = millis();
break;
case SIM_SEND5:
SIM900.println();
previousMillis = millis();
break;
case SIM_POW1:
digitalWrite(SIMPOW,HIGH);
previousMillis = millis();
break;
case SIM_POW2:
digitalWrite(SIMPOW,LOW);
previousMillis = millis();
break;
}
}
// Advance state
currentSimState = newSimState;
}
It may look complicated, but it is indeed very simple. The loop is made by three "blocks".
The first one is the button check. If any button is pressed, the corresponding valueX_changed flag is set. This is a very trivial part, just check if any button has a different state and then set the flag.
The second part is the check for a state transition. In this switch statement the program determines if the state of the state machine needs to be changed. This happens when a button was pressed if the state was idle, or if a specified amount of time has passed if in the process of sending an SMS.
The third part is the action to be performed when a state changes. So if the state changed, do the state action, which means nothing for the idle state, send something for the SIM_SENDx states and change the pin for the SIM_POWx states.
Just a note: in the setup you added a 20 seconds delay not presend in the normal workflow. If you want to remove this, you can just remove the four lines from the setup performing the reset and modify the default case in the first switch to set newSimState = SIM_POW1; instead of SIM_IDLE.
There can be small bugs in this code, since I haven't tested it, but it should do what you wanted

Use the Timer library https://playground.arduino.cc/Code/Timer/. As stated by them:
The disadvantage of the delay approach is that nothing else can go on
while the delay is happening. You cannot update a display, or check
for key presses for example.
So instead of delay, you can use:
t.every(1000, doStuff);
To trigger a function while leaving the loop to do its business meanwhile.
Hope it helps.

Not exactly the answer to the original question...
But for those looking for a simple solution to print seconds without using the delay():
if(millis() % 1000 == 0) {
Serial.println(millis());
}
Simple, isn't it?

The function millis() will fail when the value overflows. As #CPU_Terminator said, use interrupts. There are useful Arduino libraries for that, for example Timer1.
EDIT. Assuming that what you want to do is send an SMS each 100ms if some of your inputs changed, you can use a code like this (I removed some delays that doesn't seem necesary to me, add them again if I'm wrong):
#include <SoftwareSerial.h>
#include "TimerOne.h"
const int DI = 2;
const int DT = 3;
const int DGP1 = 4;
const int DGP2 = 5;
const long interval = 100000; // in microseconds
int value1 = 0;
int value2 = 0;
int value3 = 0;
int value4 = 0;
int value1_old = 0;
int value2_old = 0;
int value3_old = 0;
int value4_old = 0;
boolean changed1 = false;
boolean changed2 = false;
boolean changed3 = false;
boolean changed4 = false;
SoftwareSerial SIM900 (7, 8);
void SIM900power(){
digitalWrite(9, HIGH);
delay(1000);
digitalWrite(9, LOW);
delay(5000);
}
void initia(){
SIM900.print("AT+CMGF=1\r");
SIM900.println("AT + CMGS = \"+212xxxxxxx\"");
}
void Send_SMS(){
SIM900.println((char)26);
SIM900.println();
delay(20);
SIM900power();
}
void isr_timer(){
if (changed2) {
initia();
SIM900.println("Station 85: Defaut electrique");
Send_SMS();
changed2 = false;
}
if (changed3) {
initia();
SIM900.println("Station 85: DefautGP1");
Send_SMS();
changed3 = false;
}
if (changed4) {
initia();
SIM900.println("Station 85:DD>1000");
Send_SMS();
changed4 = false;
}
}
void setup() {
pinMode(DI, INPUT);
pinMode(DT, INPUT);
pinMode(DGP1, INPUT);
pinMode(DGP2, INPUT);
SIM900.begin(19200);
SIM900power();
delay(20000);
Timer1.initialize(interval);
Timer1.attachInterrupt(isr_timer);
}
void loop() {
value1 = digitalRead (DI);
value2 = digitalRead (DT);
value3 = digitalRead (DGP1);
value4 = digitalRead (DGP2);
if (value1 != value1_old && value1 == HIGH) changed1 = true;
if (value2 != value2_old && value2 == HIGH) changed2 = true;
if (value3 != value3_old && value3 == HIGH) changed3 = true;
if (value4 != value4_old && value4 == HIGH) changed4 = true;
value1_old = value1;
value2_old = value2;
value3_old = value3;
value4_old = value4;
// Here the rest of your code
}
This way the function isr_timer() will be executed each 0.1 seconds.

You may try using the code in isr_timer() function:
if (changed2) {
initia();
SIM900.println("Station 85: Defaut electrique");
delay(100);
Send_SMS();
changed2 = false;
}
Best regards

Related

How to store and check if the previous 5 values of the variable are same?

#include <FirebaseESP8266.h>
#include <DNSServer.h>
#include <ESP8266WebServer.h>
#include <WiFiManager.h>
#define FIREBASE_HOST "####"
#define FIREBASE_AUTH "####"
// defines pins numbers
const int trigPin = 2; //D4
const int echoPin = 0; //D3
const int led = 4; //D2
// defines variables
long duration;
int distance = 0;
int wifi = 0;
int water = 0;
int water1 = 0;
//Firebase object..
FirebaseData firebaseData;
WiFiManager wifiManager;
void setup(){
pinMode(trigPin, OUTPUT); // Sets the trigPin as an Output
pinMode(echoPin, INPUT); // Sets the echoPin as an Input
pinMode(led, OUTPUT);
Serial.begin(115200);
wifiManager.autoConnect("Aqua","123456789");
Serial.println();
Serial.print("Connected, IP address:" );
Serial.print(WiFi.localIP());
Firebase.begin(FIREBASE_HOST, FIREBASE_AUTH);
}
void loop(){
//digitalWrite(led, LOW);
if(WiFi.status() != WL_CONNECTED){
wifi = 0;
if (Firebase.setInt(firebaseData, "/Connectivity", wifi)){}
wifiManager.autoConnect("Aqua","123456789");
}
else{
wifi = 1;
if (Firebase.setInt(firebaseData, "/Connectivity", wifi)){}
}
// Clears the trigPin
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
// Sets the trigPin on HIGH state for 10 micro seconds
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
// Reads the echoPin, returns the sound wave travel time in microseconds
duration = pulseIn(echoPin, HIGH);
// Calculating the distance
if (Firebase.setInt(firebaseData, "/Distance", distance)) {
Serial.print("Distance = ");
Serial.println(distance);
Serial.println("\n");
delay(1000);
}
else
Serial.println(firebaseData.errorReason());
distance= duration*0.034/2;
water1 = water;
switch(distance){
case 2:
case 3:water = 500;
break;
case 4:
case 5:
case 6: water = 400;
break;
case 7:
case 8:water = 300;
break;
case 9:
case 10:
case 11:water = 200;
break;
case 12:
case 13:
case 14: water = 100;
break;
case 15: water = 0;
break;
default : water = water1;
break;
}
//I WANT TO STORE DISTANCE'S VALUE AND CHECK IF ITS THE SAME LAST 5 TIMES THEN EXECUTE BELOW CODE
if (Firebase.setInt(firebaseData, "/WaterLevel", water)) {
}
else
Serial.println(firebaseData.errorReason());
}
I WANT TO STORE DISTANCE'S VALUE AND CHECK IF ITS THE SAME LAST 5 TIMES
The distance's value is generated again and again I just want to store the previous 5 value of distance and compare them, and if they are same then execute the last if() condition
Is there a way to store only the previous 5 values generated by the variable "distance" and check if they are same
First, declare a local integer variable at the top:
int distanceSame = 1;
Then another one storing the last value:
int lastDistance = -1;
After this line
distance= duration*0.034/2;
check if the current distance value matches lastDistance variable, and if so, increment the distanceSame, otherwise reset it like this:
if(distance == lastDistance) {
// Increment counter
distanceSame++;
} else {
distanceSame = 1;
}
// prepare lastDistance for next cycle
lastDistance = distance;
And execute your code if the previous 5 values of distance are same.
if(distanceSame >= 5) {
if (Firebase.setInt(firebaseData, "/WaterLevel", water)) {
}
else
Serial.println(firebaseData.errorReason());
}
}

Gaming Function in Arduino

I'm trying to make a Whack-A-Mole game using an Arduino Mega with 10 LEDs (Moles) and 10 Push Buttons (Whack). The electronics are completed and tested, everything works fine. It also has a BLE radio attached which prompts the board to start one of three games I plan to do.
The problem I'm having is this:
In my main loop, I listen for a command from the app coming via BLE. When a "1" is sent by the app (serial pass through), I call the function
playGameOne();
The main thing is that everything loops in the main loop fine, but when I jump to the game function, it runs once and returns back to the main loop again. How can I keep the user looping in the game function until the game is over? Oh - and I'm not trying to use any Interrupts, but I imagine thats one way of doing it.
The latest incarnation of the game function looks like this:
//////////////////////////////////////////////
////////////////// GAME 1 //////////////////
void gameOne(){
//var int eTime;
// inform player game is about to begin
playCountdown();
Serial.println("Game Begun");
// initialize var to count time
elapsedMillis timeElapsed;
if(gameState < 1){
gameOneOne();
Serial.print("Game finished - Your time: ");
Serial.println(timeElapsed);
}
}
void gameOneOne(){
while(digitalRead(btPin31) == LOW){
// turn on LED45
digitalWrite(ledPin45, HIGH);
// wait for user to push corresponding button
if(digitalRead(btPin31) == HIGH){
// turn off the LED and jump to next LED - gameOneTwo()
digitalWrite(ledPin45, LOW);
gameOneTwo();
}
}
}
void gameOneTwo(){
while(digitalRead(btPin39) == LOW){
// turn on LED53
digitalWrite(ledPin53, HIGH);
if(digitalRead(btPin39) == HIGH){
digitalWrite(ledPin53, LOW);
// Finish the game, set state to 1
gameState = 1;
}
}
}
Not only this doesn't work, I highly doubt this is the proper way of coding games. In fact the ideal would be to have a Game Script that can be uploaded dynamically. The game Script would look like:
Header {name of game}
45 {pin of first LED}
500 {how long to keep it on, in ms}
49 {pin of the second LED}
500 {how long to keep it on, in ms}
... and so on
End of File
What is the best resource to learn this properly.
EDIT
Here's my main loop
// included header files
#include <elapsedMillis.h> // Measuring Elapsed Time Library
// Constant - Piezzo Speaker Pin
const int beepPin = 11; // the number of the Piezo Spkr pin
// Constants - Button Pins
const int btPin30 = 30;
const int btPin31 = 31;
const int btPin32 = 32;
const int btPin33 = 33;
const int btPin34 = 34;
const int btPin35 = 35;
const int btPin36 = 36;
const int btPin37 = 37;
const int btPin38 = 38;
const int btPin39 = 39;
// Constants - LED Pins
const int ledPin53 = 53;
const int ledPin52 = 52;
const int ledPin51 = 51;
const int ledPin50 = 50;
const int ledPin49 = 49;
const int ledPin48 = 48;
const int ledPin47 = 47;
const int ledPin46 = 46;
const int ledPin45 = 45;
const int ledPin44 = 44;
//Variable for storing BLUETOOTH received data
char data = 0;
// variables will change:
int buttonState = 0; // variable for reading the pushbutton status
int btPin30State = 0;
int btPin31State = 0;
int btPin32State = 0;
int btPin33State = 0;
int btPin34State = 0;
int btPin35State = 0;
int btPin36State = 0;
int btPin37State = 0;
int btPin38State = 0;
int btPin39State = 0;
// declare game state variable
int gameState = 0;
void setup() {
// initialize Serial Comms for Debug (0) and BT(3)
Serial.begin(9600); //Sets the buad for Serial (debug port)
Serial3.begin(9600); //Sets the baud for Serial3 data transmission
// initialize all button pins as INPUTs
for (int x = 30; x <= 39; x++){
pinMode(x, INPUT);
}
// initialize LED pins as OUTPUTs:
for (int i = 44; i <= 53; i++){
pinMode(i, OUTPUT);
}
// lightup all LEDs
for (int j = 44; j <= 53; j++){
digitalWrite(j, HIGH);
delay(100);
}
// prompt device is ready
Serial.println("Device Ready");
}
void loop() {
// Read Data from Serial3 -- This is to get initial game status/command from app/bluetooth
if(Serial3.available() > 0) { // Send data only when you receive data:
data = Serial3.read();
// See what the command is
if(data == '1') {
Serial.write("Send it to GameOne");
Serial.write("\n");
gameOne();
}
// See what the command is
if(data == '2') {
Serial.write("Send it to GameTwo");
Serial.write("\n");
gameTwo();
}
if(data == '3') {
Serial.write("Send it to GameThree");
Serial.write("\n");
gameThree();
}
if(data == '4') {
Serial.write("Test");
Serial.write("\n");
}
}
btPin30State = digitalRead(btPin30);
btPin31State = digitalRead(btPin31);
btPin32State = digitalRead(btPin32);
btPin33State = digitalRead(btPin33);
btPin34State = digitalRead(btPin34);
btPin35State = digitalRead(btPin35);
btPin36State = digitalRead(btPin36);
btPin37State = digitalRead(btPin37);
btPin38State = digitalRead(btPin38);
btPin39State = digitalRead(btPin39);
// check if the pushbutton is pressed. If it is, the buttonState is HIGH:
if (btPin30State == HIGH) {
digitalWrite(ledPin44, HIGH);
tone(11, 1000, 500);
Serial.println("BTN 30 / LED 44");
gameOne();
} else {
digitalWrite(ledPin44, LOW);
}
if (btPin31State == HIGH) {
digitalWrite(ledPin45, HIGH);
Serial.println("BTN 31 / LED 45");
} else {
digitalWrite(ledPin45, LOW);
}
if (btPin32State == HIGH) {
digitalWrite(ledPin46, HIGH);
Serial.println("BTN 32 / LED 46");
} else {
digitalWrite(ledPin46, LOW);
}
if (btPin33State == HIGH) {
digitalWrite(ledPin47, HIGH);
Serial.println("BTN 33 / LED 47");
} else {
digitalWrite(ledPin47, LOW);
}
if (btPin34State == HIGH) {
digitalWrite(ledPin48, HIGH);
Serial.println("BTN 34 / LED 48");
} else {
digitalWrite(ledPin48, LOW);
}
if (btPin35State == HIGH) {
digitalWrite(ledPin49, HIGH);
Serial.println("BTN 35 / LED 49");
} else {
digitalWrite(ledPin49, LOW);
}
if (btPin36State == HIGH) {
digitalWrite(ledPin50, HIGH);
Serial.println("BTN 36 / LED 50");
} else {
digitalWrite(ledPin50, LOW);
}
if (btPin37State == HIGH) {
digitalWrite(ledPin51, HIGH);
Serial.println("BTN 37 / LED 51");
} else {
digitalWrite(ledPin51, LOW);
}
if (btPin38State == HIGH) {
digitalWrite(ledPin52, HIGH);
Serial.println("BTN 38 / LED 52");
} else {
digitalWrite(ledPin52, LOW);
}
if (btPin39State == HIGH) {
digitalWrite(ledPin53, HIGH);
Serial.println("BTN 39 / LED 53");
} else {
digitalWrite(ledPin53, LOW);
}
}
I think it would be ok to structure it something like this.
play_a_game:
for (some_number_of_times)
{
show_a_mole_and_let_them_wackit();
}
setup:
set up pins
say the game is starting
loop:
do
{
play_a_game();
}
while(game ending button not pressed and less then 10 moles have died);
say the game is over

How to delay switching off the relay (millis)

I'm trying to turn on the relay for 5s when I press the button(U), then turn it off. Then switch on the second one for 10 seconds and turn it off.I would like to use the millis function to control 8 relays at different time intervals.
Please correct my code.
Why doesn't it work?
(code with one relay)
#include <LiquidCrystal.h>
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
int ssr1 = 2;
int ssr2 = 3;
int lcd_key = 0;
int adc_key_in = 0;
#define R 0
#define U 1
#define D 2
#define L 3
#define S 4
#define N 5
unsigned long interval = 5000;
unsigned long previousMillis = 0;
int read_LCD_buttons(){
adc_key_in = analogRead(0);
if (adc_key_in > 1000) return N;
if (adc_key_in < 50) return R;
if (adc_key_in < 250) return U;
if (adc_key_in < 450) return D;
if (adc_key_in < 650) return L;
if (adc_key_in < 850) return S;
return N;
}
void setup(){
lcd.begin(16, 2);
lcd.setCursor(0,0);
lcd.print("Select:");
pinMode(3, OUTPUT);
}
void loop(){
unsigned long currentMillis = millis();
lcd.setCursor(0,1);
lcd_key = read_LCD_buttons();
switch (lcd_key){
case U:{
digitalWrite(3, HIGH);
if ((unsigned long)(currentMillis - previousMillis) >= interval){
digitalWrite(3, LOW);
previousMillis = millis();
}
lcd.print("START");
break;
}
case D:{
digitalWrite(3, LOW);
lcd.print("STOP");
break;
}
case N:{
break;
}
}
}
I suggest you check out various Arduino tutorials.
However, based on your request, I have included example code below.
Please note that this has not been tested. However, you should get an idea of the logic and adapt accordingly.
There are many other ways to achieve the same result.
int relayState = RELAY_STATE_OFF; // track state of the relay
unsigned long relayOnAt = 0; // time at which relay was turned ON
void relay(int turnOn)
{
if( turnOn == ON ) digitalWrite(3,HIGH);
else digitalWrite(3,LOW);
}
void processRelay(int operateRelay)
{
switch(relayState){
case RELAY_STATE_OFF:
if( operateRelay == 1) {
relay(ON);
relayState = RELAY_STATE_ON;
relayOnAt = millis(); // remember when the relay was turned on
}
break;
case RELAY_STATE_ON: // wait here for interval seconds to elapse
if( millis() - relayOnAt >= interval) {
relay(OFF);
relayState = RELAY_STATE_OFF; // go back to checking key input
}
break;
default:
relayState = RELAY_STATE_OFF;
break;
}
}
int operateRelay = 0;
void loop(){
lcd.setCursor(0,1);
lcd_key = read_LCD_buttons();
operateRelay = 0;
if( lcd_key == U ) {
operateRelay = 1;
}
processRelay(operateRelay);
}

Simultaneous blinking LEDs, with separate and inconsistent patterns

I'm trying to run two "Blink"-esque functions simultaneously.
I've found some code elsewhere that lets me do that and modified it! Great.
However, what I am trying to do is have one LED turn on and off every 1000ms as per usual, but have the other blink in an odd pattern, like ON for 3000ms, OFF for 100ms, ON for 100ms, OFF for 200ms then loop back.
To make this happen I tried adding a random function to the code I found but I don't like how it looks. It looks like a blinking LED with interference or something, like on a radio transmitter or whatever. I'm trying to replicate an old flickering lightbulb, meaning it always has to be ON for longer than it is off, Essentially it needs to be ON/HIGH for a "longer" period of time and then interrupted by several short flashes of ON and OFF
So I'm looking for help in how I can orchestrate the 2nd LED to turn on and off in a more specific series of flickers.
Here's the code I'm using so far:
/* Blink Multiple LEDs without Delay
*
* Turns on and off several light emitting diode(LED) connected to a digital
* pin, without using the delay() function. This means that other code
* can run at the same time without being interrupted by the LED code.
*/
int led1 = 13; // LED connected to digital pin 13
int led2 = 12;
int value1 = LOW; // previous value of the LED
int value2 = HIGH; // previous value of the LED
long time1 = millis();
long time2 = millis();
long interval1 = 1000; // interval at which to blink (milliseconds)
void setup()
{
Serial.begin(9600);
randomSeed(analogRead(0));
pinMode(led1, OUTPUT); // sets the digital pin as output
pinMode(led2, OUTPUT);
}
void loop()
{
unsigned long m = millis();
if (m - time1 > interval1){
time1 = m;
if (value1 == LOW)
value1 = HIGH;
else
value1 = LOW;
digitalWrite(led1, value1);
}
long interval2 = random(100,1500);
if (m - time2 > interval2){
time2 = m;
if (value2 == LOW)
value2 = HIGH;
else
value2 = LOW;
digitalWrite(led2, value2);
}
Serial.println(interval2);
}
This will always take less than a second to run so you can get back to your main loop and ensure that you don't miss the 1 second on/off for the other LED:
void flicker(){
boolean state = false;
int r = random(20, 175);
for(int i = 0; i < 5; i++){
digitalWrite(led2, state);
state = !state;
delay(r);
r = random(20, 175);
}
digitalWrite(led2, HIGH);
}
Btw. I'm replacing this toggle code:
if (value2 == LOW)
value2 = HIGH;
else
value2 = LOW;
digitalWrite(led2, value2);
with this:
state = !state;
digitalWrite(led2, state);
Now, call flicker() at random intervals; maybe every 15-45 seconds or whatever you find appropriate/realistic.
Try something like this:
void setup()
{
Serial.begin(9600);
randomSeed(analogRead(0));
pinMode(led1, OUTPUT); // sets the digital pin as output
pinMode(led2, OUTPUT);
}
long interval2 = random(100,1500);
void loop()
{
unsigned long m = millis();
if (m - time1 > interval1){
time1 = m;
if (value1 == LOW)
value1 = HIGH;
else
value1 = LOW;
digitalWrite(led1, value1);
}
if (m - time2 > interval2){
time2 = m;
if (value2 == LOW) {
value2 = HIGH;
interval2 = random(100, 1500);
} else {
value2 = LOW;
interval2 = random(100, 200);
}
digitalWrite(led2, value2);
}

2 timers arduino [ 2x millis() ]

I'm having a problem with this code. I know what the problem is, but I can't find a good solution.
I have two functions using millis() - clock() and time().
The function clock() returns date and time and the function time() returns the time that another action is ON.
The problem is that I'm not able to store the time that the time() function is counting. When I call the function 2 times the time starts on 0:00.
I know it's because I'm overwriting the variable every time I call the loop, but I can't find a good solution for it. It seems stupid, but I have this problem for a while.
PS: I would like to have the time information every loop.
Expected results:
Start
2s: press 1 - clock = 2s, time = 0s.
5s: press 2 - clock = 5s, time = 3s.
15s: press 1 - clock = 15s, time = 3s.
20s: press 2 - clock = 20s, time = 8s.
My code:
void clock() {
// ... function that returns date and time;
// ... using millis();
}
void time(){
if (first == 0){
sec_aux = 0;
min_aux = 0;
UtlTime = millis();
first = -1;
}
if(millis() - UtlTime < 0){
UtlTime = millis();
}
else{
sec_aux = int((millis() - UtlTime) / 1000);
}
if(sec_aux > 59){
sec_aux = 0;
min_aux++;
UtlTime = millis();
}
sec = sec_aux;
min = min_aux;
Serial.println("TIME");
Serial.print(min); Serial.print(":"); Serial.println(sec);
}
void loop() {
if (Serial.available()) {
inChar = Serial.read();
}
switch(inChar){
case '1':
time();
clock();
break;
case '2':
clock();
first = 0;
break;
default:
clock();
}
}
Ok, if I understood correctly you want a function that
1) you call once and it resets the counter
2) you call successively and tells you how much time passed
3) you can reset sometimes
If so, you have to ask yourself "how can I reset the timer?". IMHO the best solution is using a flag passed to the function.
And... avoid using the millis function twice ;)
And, BTW, I think you want to perform an action just once when you receive the serial data, so move the switch inside the test...
Here is a sample:
void time(bool reset){
unsigned long currMillis = millis();
if (reset){
sec_aux = 0;
min_aux = 0;
UtlTime = currMillis;
}
while ((currMillis - UtlTime) > 1000)
{
UtlTime += 1000;
sec_aux++;
}
while(sec_aux > 59){
sec_aux -= 60;
min_aux++;
}
// Why do you duplicate the data?
sec = sec_aux;
min = min_aux;
Serial.println("TIME");
Serial.print(min); Serial.print(":"); Serial.println(sec);
}
void loop() {
if (Serial.available()) {
inChar = Serial.read();
switch(inChar){
case '1':
// Show time measure
time(false);
clock();
break;
case '2':
clock();
// Start time measure
time(true);
break;
default:
clock();
}
}
}
EDIT:
Ok, then you want a "stoppable" stopwatch. What I suggest you is to detach the update from the serial interface, so you always have updated values. Or at least that's the way my head works :P
I modified some things. You should
init lastMillis to millis() in the setup
init timeIsRunning to the proper value
call resetTime() inside the setup
Here is the code:
void resetTime()
{
msec = 0;
sec = 0;
min = 0;
}
void updateTime()
{
unsigned long currStep = millis() - lastMillis;
lastMillis += currStep;
if (timeIsRunning)
{
msec += currStep;
while (msec > 1000)
{
msec -= 1000;
sec++;
}
while(sec > 59){
sec -= 60;
min++;
}
}
}
void printTime()
{
Serial.println("TIME");
Serial.print(min); Serial.print(":"); Serial.println(sec);
}
void loop()
{
updateTime();
if (Serial.available())
{
inChar = Serial.read();
switch(inChar)
{
case '1':
// Show time measure
timeIsRunning = false;
printTime();
clock();
break;
case '2':
clock();
// Start time measure
timeIsRunning = true;
break;
default:
clock();
}
}
}

Resources