Arduino Multi-tasking - arduino

I'm trying to see if I can combine tasks that are currently being handled by two separate Arduino Unos onto a single Uno. I was shown the Adafruit guide to "multi-tasking" on the Arduino (Link) and thought I would give it a try.
I feel like I'm missing something really obvious, but my code is just not working...
I'm controlling a series of solenoids. They need to each act based on individual timing. I created a Solenoid class that handles telling the solenoid when to start and then monitor when to close it. For the life of me I can't see where my error is, but I never wind up satisfying my end condition.
class Solenoid {
//Class Variables
int solenoidPin;
long chargeTime;
long ventTime;
bool started = false;
unsigned long startMillis;
unsigned long endMillis;
unsigned long previousMillis;
int solenoidState;
//Constructor
public:
Solenoid(int pin, long charge, long vent) {
solenoidPin = pin;
pinMode(solenoidPin, OUTPUT);
chargeTime = charge;
ventTime = vent;
solenoidState = LOW;
previousMillis = 0;
}
void Start() {
Serial.println("Start called");
started = true;
}
void Update() {
//Check to see if it is time to change the state of the solenoid
unsigned long currentMillis = millis();
Serial.println("Update");
if((started == true) && (currentMillis-previousMillis <= chargeTime)) {
//Run
Serial.print("Run: Charge Time=");
Serial.print(chargeTime);
Serial.print(" current-previous=");
Serial.println(currentMillis-previousMillis);
previousMillis = currentMillis;
} else if ((started == true) && (currentMillis-previousMillis >= chargeTime)){
//Stop
Serial.println("Stop");
}
}
};
//Setup the solenoids
Solenoid solenoid1(13, 70, 70);
void setup() {
Serial.begin(115200);
Serial.println("Ready");
solenoid1.Start();
solenoid1.Update();
solenoid1.Update();
solenoid1.Update();
solenoid1.Update();
solenoid1.Update();
}
I'm just running everything in setup so I can see a few runs.
Can you help me with my clearer stupid mistake?

It's possible that the entire setup() void is executing faster than 70ms, meaning you never get to you end position before the 5 calls to solenoid1.Update() complete.
Try this:
class Solenoid {
//Class Variables
int solenoidPin;
long chargeTime;
long ventTime;
bool started = false;
unsigned long startMillis;
unsigned long endMillis;
unsigned long previousMillis;
int solenoidState;
//Constructor
public:
Solenoid(int pin, long charge, long vent) {
solenoidPin = pin;
pinMode(solenoidPin, OUTPUT);
chargeTime = charge;
ventTime = vent;
solenoidState = LOW;
previousMillis = 0;
}
void Start() {
Serial.println("Start called");
started = true;
}
void Update() {
//Check to see if it is time to change the state of the solenoid
unsigned long currentMillis = millis();
Serial.println("Update");
if((started == true) && (currentMillis-previousMillis <= chargeTime)) {
//Run
Serial.print("Run: Charge Time=");
Serial.print(chargeTime);
Serial.print(" current-previous=");
Serial.println(currentMillis-previousMillis);
previousMillis = currentMillis;
} else if ((started == true) && (currentMillis-previousMillis >= chargeTime)){
//Stop
Serial.println("Stop");
}
}
};
//Setup the solenoids
Solenoid solenoid1(13, 70, 70);
void setup() {
Serial.begin(115200);
Serial.println("Ready");
solenoid1.Start();
}
void loop(){
solenoid1.update()
}
The rest looks fine to me; if you still have issues try using explicit variable declarations instead of your constructor to troubleshoot if that's the issue.

Turns out I was erasing my own counter by setting previousMillis = currentMillis. Once I killed that, it started working. I added some other functionality since then, like a delayed start, but this is primarily the same code.
void Update() {
//Check to see if it is time to change the state of the solenoid
unsigned long currentMillis = millis();
if((started == true) && (currentMillis - startMillis <= startDelay)) {
//keep waiting
Serial.println("Waiting");
} else if((started == true) && (currentMillis - startMillis < (chargeTime + startDelay) )) {
//Run
Serial.print("Run ");
Serial.println(currentMillis - startMillis);
digitalWrite(solenoidPin, HIGH);
} else if ((started == true) && (currentMillis - startMillis >= (chargeTime + startDelay) )){
//Stop
Serial.print("Stop ");
Serial.println(currentMillis - startMillis);
digitalWrite(solenoidPin, LOW);
started = false;
}
}

Related

Arduino: LCD won't turn off

a few days ago I started working with the Arduino. I've set up a small project with a DHT22 to read the temperature and humidity and write it to an LCD. That works without a problem. Now I want to only turn on the backlight of the LCD when I press a button. That mostly works too:
void loop() {
buttonState = digitalRead(BUTTONPIN);
currentMillisScreen = millis();
if (buttonState == HIGH) {
screenOn = true;
lcd.backlight();
}
// DHT22 related code in here
if (currentMillisScreen - previousMillisScreen >= SCREEN_ON_TIME) {
previousMillisScreen = currentMillisScreen;
screenOn = false;
lcd.noBacklight();
}
}
The problem is that with this code is that the Backlight won't always stay on for exactly 5 seconds. I thought putting the currentMillisScreen = millis() in the following if-Statement would fix it:
if (buttonState == HIGH) {
currentMillisScreen = millis();
screenOn = true;
lcd.backlight();
}
But if I do that, the Backlight won't turn off again and I don't understand why.
You are not updating currentMillisScreen in the loop and that is your problem. You just need to find different between currentTime (equal to millis()) and previous time that light turned on and if it reaches above the threshold then turn it off. Something like this:
#define SCREEN_ON_TIME 5000
bool screenOn = false;
void setup()
{
//setup
}
void loop()
{
buttonState = digitalRead(BUTTONPIN);
if (buttonState == HIGH)
{
previousMillisScreen = millis();
lcd.backlight();
screenOn = true;
}
// DHT22 related code in here
// if time passed above SCREEN_ON_TIME after we turned on light
if ((screenOn) && (millis() - previousMillisScreen >= SCREEN_ON_TIME))
{
lcd.noBacklight();
screenOn = false;
}
}

Problem with interruptions in Arduino Uno

I work with interruptions in Arduino UNO. In this project, I want to when the Door is opened the LED blink 10 times, and when the door is closed again, stop blinking the LED and exit the function. But in this code the LED only turn on and off once and it does not flash again.
My other problem is that, when the door is opened or closed, sometimes the opened or closed word appears several times in the Series monitor.
const byte LED_Red = 13;
const byte DOOR_SENSOR = 2; // magnetic door sensor pin
volatile int SensorState = LOW; // 0 close - 1 open wwitch
void setup()
{
Serial.begin(9600);
pinMode(LED_Red, OUTPUT);
pinMode(DOOR_SENSOR, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(DOOR_SENSOR), DoAction, CHANGE);
}
void DoAction()
{
SensorState = digitalRead(DOOR_SENSOR);
if (SensorState == HIGH) {
Serial.println("Opened");
blinkLED(10, 500);
}
else {
Serial.println("Closed");
}
}
void blinkLED(int repeats, int time)
{
for (int i = 0; i < repeats; i++) {
if (SensorState == HIGH) {
digitalWrite(LED_Red, HIGH);
delay(time);
digitalWrite(LED_Red, LOW);
delay(time);
}
else
return;
}
}
void loop()
{
}
You can't simply put a delay() on an interrupt's function. You need to just set a flag when the door is opened and based on that start blinkLED inside the main loop.
I also recommend you to use millis() function for an unblocking delay inside blinkLED function (e.g when you want to stop blinking while the door is closed).
const byte LED_Red = 13;
const byte DOOR_SENSOR = 2; // magnetic door sensor pin
// flag to check door is opened
volatile bool isOpened = false;
//flag to check already blinked
volatile bool isBlinked = false;
void setup()
{
Serial.begin(9600);
pinMode(LED_Red, OUTPUT);
pinMode(DOOR_SENSOR, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(DOOR_SENSOR), DoAction, CHANGE);
}
void DoAction()
{
if (digitalRead(DOOR_SENSOR) == HIGH)
{
//Serial.println("Opened");
isOpened = true;
}
else
{
isOpened = false;
isBlinked = false;
//Serial.println("Closed");
}
}
void blinkLED(int repeats, int time)
{
byte LEDState = LOW;
unsigned long delay_start = millis();
for (int i = 0; i < 2 * repeats; i++)
{
//Toggle LED state
if (LEDState == HIGH)
LEDState = LOW;
else
LEDState = HIGH;
// set value
digitalWrite(LED_Red, LEDState);
// some unblocking delay
while (millis() - delay_start < time)
{
// return if door is closed
if (!isOpened)
{
// turn off LED
digitalWrite(LED_Red, LOW);
return;
}
}
delay_start = millis();
}
isBlinked = true;
}
void loop()
{
// Check isBlinked beacue don't want to blink again until door is closed
if (isOpened && !isBlinked)
{
blinkLED(10, 500);
}
}

How to convert delay to millis

I have a simple code with delays.
I'd like to know how to convert this code to millis? Is there a function to do so?
long revers = 1000;
void setup() {
pinMode(D1, OUTPUT);
pinMode(D2, OUTPUT);
}
void loop() {
digitalWrite(D1, LOW);
delay(revers);
digitalWrite(D2, HIGH);
delay(revers);
digitalWrite(D2, LOW);
delay(revers);
digitalWrite(D1, HIGH);
delay(revers);
}
The basic concept is this: record the millis() at a given moment in a variable - say 'starttime'. Now, during every loop(), check the time that has elapsed by subtracting millis() from 'starttime'. If the elapsed time is greater than the delaytime you set, execute code. Reset the starttime to create a repeating pattern.
That may be too short of an explanation for you, so before you dive into the code, I highly advise you to read this introduction about using millis() for timing. It's lengthy, but it explains the principle extensively. This will help you understand the code below.
Lastly, there are several libraries written to make the use of timing easier. For instance the SimpleTimer-library, but you can google "arduino timer library" for others. I've included an example below.
1 second on, 3 seconds off:
unsigned long startMillis; //some global variables available anywhere in the program
unsigned long currentMillis;
const unsigned long period = 1000; //the value is a number of milliseconds
int fase; //value used to determine what action to perform
void setup() {
pinMode(7, OUTPUT);
pinMode(8, OUTPUT);
startMillis = millis(); //initial start time
fase = 0;
}
void loop() {
currentMillis = millis(); //get the current "time" (actually the number of milliseconds since the program started)
if (currentMillis - startMillis >= period) //test whether the period has elapsed
{
if (fase == 0)
{
digitalWrite(8, LOW);
startMillis = currentMillis; //IMPORTANT to save the start time of the current LED state.
fase = 1; //increment fase, so next action will be different
}
else if (fase == 1)
{
digitalWrite(7, HIGH);
startMillis = currentMillis;
fase = 2;
}
else if (fase == 2)
{
digitalWrite(7, LOW);
startMillis = currentMillis;
fase = 3;
}
else if (fase == 3)
{
digitalWrite(8, HIGH);
fase = 0;
startMillis = currentMillis;
}
}
}
Example of a flashing led using the SimpleTimer library
#include <SimpleTimer.h>
// the timer object
SimpleTimer timer;
int ledPin = 13;
// a function to be executed periodically
void repeatMe() {
digitalWrite(ledPin, !digitalRead(ledPin));
}
void setup() {
pinMode(ledPin, OUTPUT);
timer.setInterval(1000, repeatMe);
}
void loop() {
timer.run();
}

Arduino timing programming for NEC signal output on wire

For a project containing a led-strip controller I want to replace the IR remote with an Arduino nano. Now after doing some research (http://blog.allgaiershops.com/2012/05/10/reversing-an-rgb-led-remote/) and measurements I found that the led-strip controller uses the NEC protocol.
Now I have tried to create a program that will emulate one of the button press events as measured on the IR_receiver. However, when the output on the digital pin 2 (which is PWM supported) is measured, the timing isn't anywhere near desired.
However, if I use the for loop as written in the functions (high/low output) in the main loop it is possible to create a high output for 500us.
I was wondering if you could give me some support in order to get the code functioning, or could you give me some tips as how to handle timing on the Arduino in an efficient way.
/*
Timer2_Counter_display_time_elapsed.ino
Timer2 Counter Basic Example - Demonstrates use of my Timer2_Counter, which is a timer function with 0.5us precision,
rather than 4us precision like the built-in Arduino micros() function has.
By Gabriel Staples
Visit my blog at http://electricrcaircraftguy.blogspot.com/
-My contact info is available by clicking the "Contact Me" tab at the top of my blog.
-Please support my work & contributions by buying something here: https://sites.google.com/site/ercaguystore1/
My original post containing this code can be found here: http://electricrcaircraftguy.blogspot.com/2014/02/Timer2Counter-more-precise-Arduino-micros-function.html
Written: 17 May 2014
Updated: 30 May 2014
*/
//CODE DESCRIPTION:
//This code demonstrates the use of my Timer2, which provides a more precise timer than micros().
//micros() has a precision of only 4us. However, Timer2 keeps track of time to a precision of 0.5us.
//This is especially important in my code which reads an RC receiver PWM signal, which varies from 900~2100us.
//Though this code demonstrates the use of the Timer_2 functions I have written, it does not adequately demonstrate the
//real utility of the code, so I will state the following:
//By using my Timer2 timer to measure the PWM high time interval on an RC receiver, in place of using micros(), I can get repeatable
//pulse width reads with a fluctuation of ~1us, rather than having a read-in range fluctuating by as much as +/- 4~8 us when I use micros().
//This is an increase in precision of ~8x.
//include the library
#include <eRCaGuy_Timer2_Counter.h>
#define pin_output 2
#include <time.h>
//Note: an object of this class was already pre-instantiated in the .cpp file of this library, so you can simply access its methods (functions)
// directly now through the object name "timer2"
//eRCaGuy_Timer2_Counter timer2; //this is what the pre-instantiation line from the .cpp file looks like
boolean on=false;
int values[24][32]={0};
int one_output =1680;
int zero_output= 560;
void low_output(int );
void high_output(int );
void start_protocol(int);
void end_protocol(int);
void setup() {
//configure Timer2
timer2.setup(); //this MUST be done before the other Timer2_Counter functions work; Note: since this messes up PWM outputs on pins 3 & 11, as well as
//interferes with the tone() library (http://arduino.cc/en/reference/tone), you can always revert Timer2 back to normal by calling
//timer2.unsetup()
//values[0]={8,4,1,5,8,6};
//prepare serial
Serial.begin(115200);
pinMode(pin_output, OUTPUT);
digitalWrite(pin_output, HIGH);
//Output a header of info:
/*Serial.println(F("Notes:"));
Serial.println(F("micros() has a precision of 4us"));
Serial.println(F("get_count() with unsigned long final data type has a final precision of 1us, and is fast"));
Serial.println(F("get_count() with float final data type has a final precision of 0.5us, and is not quite as fast"));
Serial.println(F("get_micros() has a precision of 0.5us, and is slower than the above 2 methods, so one of the above 2 methods is preferred"));
Serial.println(F("=============================================="));*/
}
void loop() {
//declare local variables
delay(2000);
start_protocol();
low_output(8);
high_output(4);
low_output(1);
high_output(5);
low_output(8);
high_output(6);
end_protocol();
static unsigned long t_start = timer2.get_count();
// unsigned long t_micros = micros();
unsigned long t_T2_count = timer2.get_count();
//float t_T2_micros = timer2.get_micros();
if ((t_T2_count - t_start)/2 >= 2000003)
{
digitalWrite(pin_output, HIGH);
}
} //end of loop()
void low_output(int xtimes)
{
for (int i =0 ; i<xtimes ; i++){
static unsigned long t_start = timer2.get_count(); //units of 0.5us; the count accumulated by Timer2_Counter
//acquire time stamps
unsigned long t_T2_count = timer2.get_count(); //units of 0.5us; the count accumulated by Timer2_Counter
//See if 1.000003 seconds has elapsed. If so, print out the time stamps. Note: I am using this elapsed time because I want it to NOT be divisible by 4, so that
//you can hopefully see the extra precision provided by the Timer2_Counter library, which the default Arduino micros() function does not have
if ((t_T2_count - t_start)/2 >= zero_output)//1000003) //if 1.000003 seconds has elapsed
{
t_start = t_T2_count; //update start time
if(on==false) {
digitalWrite(pin_output, LOW);
on=true;
}else {
digitalWrite(pin_output, HIGH);
on=false;
}
}
}
return;
}
void high_output(int xtimes)
{
for (int i =0 ; i<xtimes ; i++){
static unsigned long t_start = timer2.get_count();
//acquire time stamps
unsigned long t_T2_count = timer2.get_count();
if ((t_T2_count - t_start)/2 >= one_output)
{
t_start = t_T2_count; //update start time
if(on==false) {
digitalWrite(pin_output, LOW);
on=true;
}else {
digitalWrite(pin_output, HIGH);
on=false;
}
}
}
return;
}
void start_protocol(){
static unsigned long t_start = timer2.get_count();
unsigned long t_T2_count = timer2.get_count();
digitalWrite(pin_output, LOW);
t_start = timer2.get_count();
t_T2_count = timer2.get_count();
if ((t_T2_count - t_start)/2 >= 9000)
{
digitalWrite(pin_output, HIGH);
}
}
void end_protocol(){
static unsigned long t_start = timer2.get_count();
unsigned long t_T2_count = timer2.get_count();
if ((t_T2_count - t_start)/2 >= zero_output)
{
digitalWrite(pin_output, LOW);
}
t_start = timer2.get_count();
t_T2_count = timer2.get_count();
if ((t_T2_count - t_start)/2 >= 40000)
digitalWrite(pin_output, HIGH);
t_start = timer2.get_count();
t_T2_count = timer2.get_count();
if ((t_T2_count - t_start)/2 >= 9000)
{
digitalWrite(pin_output, LOW);
}
t_start = timer2.get_count();
t_T2_count = timer2.get_count();
if ((t_T2_count - t_start)/2 >= 2100)
{
digitalWrite(pin_output, HIGH);
}
t_start = timer2.get_count();
t_T2_count = timer2.get_count();
if ((t_T2_count - t_start)/2 >= zero_output)
{
digitalWrite(pin_output, LOW);
}
digitalWrite(pin_output, HIGH);
}
For this this code, I used a timing library made by Gabriel Staples.
[update]
After following the tips of #Gmodjackass the following code got the NEC signal on the output of pin 2. note: code can be optimized by adding support for direct pin port manipulation.
#define pin_output 2
#include <time.h>
boolean on=false;
int values[24][32]={0};
int one_output =1680;
int zero_output= 560;
int sb=-1;
void low_output(int );
void high_output(int );
void start_protocol();
void end_protocol();
void selection_protocol(String);
void setup() {
Serial.begin(115200);
pinMode(pin_output, OUTPUT);
digitalWrite(pin_output, HIGH);
Serial.print("user_inpu: on(1) / off(0)");
delayMicroseconds(400);
}
void loop() {
//declare local variables
if (Serial.available())
{
char sb = Serial.read();
Serial.print(sb);
switch (sb){
case '0':
selection_protocol("off");
break;
case '1':
selection_protocol("on");
break;
}
sb=-1;
}
} //end of loop()
void low_output(int xtimes)
{
for (int i =0 ; i<xtimes*2 ; i++){
if(on==false) {
digitalWrite(pin_output, LOW);
on=true;
}else {
digitalWrite(pin_output, HIGH);
on=false;
}
delayMicroseconds(zero_output);
//}
}
return;
}
void high_output(int xtimes)
{
for (int i =0 ; i<xtimes*2 ; i++){
if(on==false) {
digitalWrite(pin_output, LOW);
on=true;
delayMicroseconds(zero_output);
}else {
digitalWrite(pin_output, HIGH);
on=false;
delayMicroseconds(one_output);
}
//}
}
return;
}
void start_protocol(){
digitalWrite(pin_output, LOW);
delayMicroseconds(9000);
digitalWrite(pin_output, HIGH);
delayMicroseconds(4400);
return;
}
void end_protocol(){
digitalWrite(pin_output, LOW);
delayMicroseconds(zero_output);
digitalWrite(pin_output, HIGH);
delay(40);
digitalWrite(pin_output, LOW);
delayMicroseconds(9000);
digitalWrite(pin_output, HIGH);
delayMicroseconds(2100);
digitalWrite(pin_output, LOW);
delayMicroseconds(zero_output);
digitalWrite(pin_output, HIGH);
return;
}
void selection_protocol(String user_input){
if(user_input == "on"){
Serial.print("on selected");
start_protocol();
low_output(8);
high_output(4);
low_output(1);
high_output(5);
low_output(8);
high_output(6);
end_protocol();
}
if(user_input == "off"){
Serial.print("off selected");
start_protocol();
low_output(8);
high_output(4);
low_output(1);
high_output(3);
low_output(1);
high_output(1);
low_output(6);
high_output(1);
low_output(1);
high_output(6);
end_protocol();
}
return;
}
Some of your timing discrepancies may be caused by the very slow nature of arduino's digitalWrite, maybe look into using direct port manipulation. Also consider using this delay function instead since it may cause some more of your timing issues.
(edited for spelling errors)

Arduino Communicate with android through bluetooth

Currently i success to build the communication between the android device and arduino through bluetooth. As arduino will send string "ON" or "OFF" depend on the LED condition to Android through bluetooth and my android able to receive the string "LED:ARE:OFF" and "LED:ARE:ON" through the read() function. But currently i want to read a data by split the string into 3 from the LED, for example: "LED:ARE:OFF" into "LED" , "Are", "OFF" , but i failed to received the data. I had tried the String.split(":") to split out the aaa:bbb:ccc into 3 part, and it unable to read the data as well. Please help
Arduino Code:
#include <SoftwareSerial.h>// import the serial library
SoftwareSerial Genotronex(10, 11); // RX, TX
int ledpin=8; // led on D13 will show blink on / off
long previousMillis = 0; // will store last time LED was updated
long interval = 1000; // interval at which to blink (milliseconds)
int ledState = LOW; // ledState used to set the LED
long Counter=0; // counter will increase every 1 second
void setup() {
// put your setup code here, to run once:
Genotronex.begin(9600);
Genotronex.println("Bluetooth On please wait....");
pinMode(ledpin,OUTPUT);
}
void loop() {
// put your main code here, to run repeatedly:
unsigned long currentMillis = millis();
if(currentMillis - previousMillis > interval) {
// save the last time you blinked the LED
previousMillis = currentMillis;
Counter+=1;
delay(4000);
// if the LED is off turn it on and vice-versa:
if (ledState == LOW){
ledState = HIGH;
Genotronex.print("LED:ARE:ON");
digitalWrite(ledpin, ledState);
}
else{
ledState = LOW;
Genotronex.print("LED:ARE:OFF");
digitalWrite(ledpin, ledState);
}
// set the LED with the ledState of the variable:
}
}
Android Code:
btnSend.setOnClickListener(this);
int delay = 1000; // delay in ms
int period = 100; // repeat in ms
timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask()
{
public void run()
{
if (flag)
{
final byte data = read();
readMessageHandler.post(new Runnable()
{
public void run()
{
if (data != 1){
message = txtReceived.getText().toString() + (char)data;}
else{
message = "";
}
String message;
//New Code for split the data
String[] parts = message.split(":"); // escape .
String part0 = parts[0];
String part1 = parts[1];
String part2 = parts[2];
txtReceived.setText(part0);
//End of Split
// txtReceived.setText(Message);
}
});
}
}
}, delay, period);
private byte read()
{
byte dataRead = 0;
try
{
dataRead = (byte) inputStream.read();
}
catch(IOException readException)
{
toastText = "Failed to read from input stream: " + readException.getMessage();
Toast.makeText(Blood_Pressure.this, toastText, Toast.LENGTH_SHORT).show();
}
return dataRead;
}

Resources