How to delay switching off the relay (millis) - c

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);
}

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());
}
}

Struggling with the output of ADC on a PIC18F252

I've recently finished code for a PIC18F252 which uses the built in ADC to convert analogue inputs from 3 sensors into digital outputs that can be sent to motors. The code builds and uploads to the PIC perfectly fine, but unfortunately just doesn't work, and I'm struggling to see where the issue is.
After testing the output ports for the motors, I've found that they are all outputting the same signal, when they shouldn't be, and it doesn't change depending on the sensors.
My first thought is that there's something wrong between the output of the ADC (loading the result from ADRESH), and the if statements used to assign a digital value to these outputs.
I can't upload the entire code as this is coursework, but I've added the relevant parts. I've only included my function for AD conversion using one channel, but the functions for the other two channels are the same, just changing variables.
If anyone is able to spot an issue with this code (presumably around the if statements) I would be grateful!
#include <p18F252.h> // PIC specific definitions
#include <xc.h> // Xc8 compiler specifics
#include <stdio.h> // Standard C I/O library
#include <stdlib.h> // Standard C library
// Function declarations
void Config_ADC(void);
void delay(void);
void Motor_Output(unsigned char x, unsigned char y, unsigned char z);
void channel3(void);
unsigned char leftSens = 0b00000000; //Initialise left sensor variable
void Config_ADC(void){
// ADC Setup
TRISA = 0xFF; // configure port A as inputs
ADCON1bits.ADFM =0; // left justified
ADCON1bits.PCFG3=0;
ADCON1bits.PCFG2=1;
ADCON1bits.PCFG1=0;
ADCON1bits.PCFG0=0;
ADCON1bits.ADCS2=0;
ADCON0bits.ADCS1=1;
ADCON0bits.ADCS0=0;
ADCON0bits.ADON =1;
}
// Function for a delay of 1ms
void delay(void){
T2CON = 0x49; // start counting from 73
PR2 = 0x7C; // stop count at 124
T2CONbits.TMR2ON = 1; // activate timer 2
while(!PIR1bits.TMR2IF); // wait for timer flag
T2CONbits.TMR2ON = 0; // stop timer 2
PIR1bits.TMR2IF = 0; // clear flag
}
void channel3(void){
ADCON0bits.CHS2 = 0; //Channel selection
ADCON0bits.CHS1 = 1;
ADCON0bits.CHS0 = 1;
delay(); // Acquisition time to charge hold capacitor
ADCON0bits.GO_DONE = 1; // Start Conversion
while(ADCON0bits.GO_DONE); // Wait for A/D Conversion to complete
leftSens = ADRESH; // Return result
}
void main(void){
TRISB = 0x00; // configure Port B as output
Config_ADC(); // load ADC
while(1) { //loop forever/
channel3(); // Call channel 3 conversion
Motor_Output(leftSens, middleSens, rightSens);
}
}
// Function to send instructions to motors
void Motor_Output(unsigned char x, unsigned char y, unsigned char z){
int left, middle, right;
if(x >= 173){left = 1;} //173 chosen as threshold 8 bit value
else if(x < 173){left = 0;}
else if(y >= 173){middle = 1;}
else if(y < 173){middle = 0;}
else if(z >= 173){right = 1;}
else if(z < 173){right = 0;}
unsigned char output;
output = (left << 2) | (middle << 1) | right; //Bit shifted variables into one value
switch(output){
case 0x0:
PORTBbits.RB7 = 0; //Test for each output and activate motors accordingly
PORTBbits.RB6 = 1;
PORTBbits.RB5 = 0;
PORTBbits.RB4 = 1;
case 0x1:
PORTBbits.RB7 = 0;
PORTBbits.RB6 = 1;
PORTBbits.RB5 = 1;
PORTBbits.RB4 = 0;
case 0x2:
PORTBbits.RB7 = 0;
PORTBbits.RB6 = 1;
PORTBbits.RB5 = 0;
PORTBbits.RB4 = 1;
case 0x3:
PORTBbits.RB7 = 0;
PORTBbits.RB6 = 1;
PORTBbits.RB5 = 1;
PORTBbits.RB4 = 0;
case 0x4:
PORTBbits.RB7 = 1;
PORTBbits.RB6 = 0;
PORTBbits.RB5 = 0;
PORTBbits.RB4 = 1;
case 0x5:
PORTBbits.RB7 = 0;
PORTBbits.RB6 = 1;
PORTBbits.RB5 = 0;
PORTBbits.RB4 = 1;
case 0x6:
PORTBbits.RB7 = 1;
PORTBbits.RB6 = 0;
PORTBbits.RB5 = 0;
PORTBbits.RB4 = 1;
case 0x7:
PORTBbits.RB7 = 0;
PORTBbits.RB6 = 1;
PORTBbits.RB5 = 0;
PORTBbits.RB4 = 1;
}
return;
}
Without going any deeper in analysis there are two major problems:
The if-else if-chain will do just one assigment to left. To make that obvious I have indented your source this way without any other changes:
if (x >= 173) { // Either THIS...
left = 1;
} else
if (x < 173) { // Or THAT will be true.
left = 0;
} else // None of the following is executed therefore.
if (y >= 173) {
middle = 1;
} else
if (y < 173) {
middle = 0;
} else
if (z >= 173) {
right = 1;
} else
if (z < 173) {
right = 0;
}
So middle and right will have undefined values.
All your cases in the switch are missing a break. So only the last case or none at all will be executed. Why "none"? Because middle and right have undefined values, resulting in a random value in output.
Note: "Random" might be always the same value, depending on the bits set or reset at the locations of middle and right, respectively.
Quick question: Is it by design that you are falling through your switch-cases?
void Motor_Output(unsigned char x, unsigned char y, unsigned char z){
// ...
switch(output){
case 0x0:
... <-- no break, will continue to execute next case
case 0x1:
... <-- no break, will continue to execute next case
case 0x2:
... <-- no break, will continue to execute next case
case 0x3:
... <-- no break, will continue to execute next case
case 0x4:
... <-- no break, will continue to execute next case
case 0x5:
... <-- no break, will continue to execute next case
case 0x6:
... <-- no break, will continue to execute next case
case 0x7:
... <-- no break, will continue to execute next case
}
return;
}

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

write timer without delay()

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

Arduino boolean array; 1 true and the rest false

I have a question about arduino considering a setup with 8 leds and an potentiometer. I want to let 1 led light up, which is the led that matches the value returned by the potentiometer, and the rest of the leds should be turned off. Furthermore, when I change the position of the potentiometer, the leds should change accordingly. So far ive got this:
for(int i = 0; i)
{
if (i = draaiKnopStand)
{
status[i] = HIGH;
}
else
{
status[i] = LOW;
}
digitalWrite(draaiKnopStand, status[i]);
}
I'm considering this is Arduino Uno Front
I have no Arduino here in my job. I did this using a simulator. Please try it:
int _potentiometer = 9; // Potentiometer - Analog Pin
int _val = 0;
int _borderLineVal = 0;
int ledPins[] = { 2, 3, 4, 5, 6, 7 }; // an array of pin numbers to which LEDs are attached
int pinCount = 6; // the number of pins (i.e. the length of the array)
void setup() {
for (int thisPin = 0; thisPin < pinCount; thisPin++) {
pinMode(ledPins[thisPin], OUTPUT);
}
}
void loop() {
_val = analogRead(_potentiometer); //reading the Potentiometer value interval: 0 - 1023
_borderLineVal = (int)(1023 / pinCount);
Serial.println(_val);
// turn all leds off
for (int thisPin = 0; thisPin < pinCount; thisPin++) {
digitalWrite(ledPins[thisPin], LOW);
}
// turn the select led on
if(_val > 0){
_pinHigh = (int)(1023 / _borderLineVal);
digitalWrite(ledPins[_pinHigh], HIGH); // turn the pin on
}
}

Resources