Arduino Loop and alarm - arduino

I'm working on my first physical computing project with an arduino, well actually a seeduino stalker 2.1. I'm building a device to record water collection rates over time.
Getting the project set up and running hasn't been all that hard, until today that is. Inside the main loop I have a call to the a method that handles the logging. I also now an alarm delay to handle a timer repeat I need in order to summarize data and send it via SMS to a recipient number.
The issue is that when the alarm.repeat() is active it preempts the logging of the data. The question is: why is the logging method inside the loop not working when the alarm.delay is there?
void setup() {
Serial.begin(9600);
Wire.begin();
setTime(1,17,0,1,1,13); // set time
Alarm.timerRepeat(60, Repeats); //set repeater
}
void loop(){
logging(); //call logging
Alarm.delay(1300); //for repeater
}
void Repeats(){
Serial.println("the repeater fired"); // just to see it working
}
void logging(){
val = digitalRead(Sensor_Pin); // read Sensor_Pin
if (val == HIGH) {
// If Sensor N.C. (no with magnet) -> HIGH : Switch is open / LOW : Switch is closed
// If Sensor N.0. (nc with magnet) -> HIGH : Switch is closed / LOW : Switch is open
digitalWrite(Led_Pin, LOW); //Set Led low
//Serial.print("status -->");
//Serial.println("low");
//delay(500);
} else {
digitalWrite(Led_Pin, HIGH); //Set Led high
logdata();
}
}
void logdata(){
// open the file. note that only one file can be open at a time,
// so you have to close this one before opening another.
File myFile = SD.open("datalog.txt", FILE_WRITE);
// if the file opened okay, write to it:
if (myFile) {
//DateTime now = RTC.now();
//String myString = readTimestamp(now);
time_t t = now();
String aDate = String(year(t))+"/"+String(month(t))+"/"+String(day(t))+" "+String(hour(t))+":"+String(minute(t))+":"+String(second(t));
myFile.println(aDate);
// close the file:
myFile.close();
Serial.println(aDate);
delay(500); } else {
// if the file didn't open, print an error:
// Serial.println("error opening DATALOG.TXT");
}
}

Q: Why must I use Alarm.delay() instead of delay()? A: Task scheduling
is handled in the Alarm.delay function. Tasks are monitored and
triggered from within the Alarm.delay call so Alarm.delay should be
called whenever a delay is required in your sketch. If your sketch
waits on an external event (for example, a sensor change), make sure
you repeatedly call Alarm.delay while checking the sensor.
From the FAQ of the Alarm library. So it looks like Alarm.Delay is just like the standard delay but can be interrupted by scheduled events. Your logging call isn't scheduled, it just happens at the start of the loop. ..is your logging not happening at all? It looks like it should be called at the start of each loop, then a 1300 delay with your repeater firing during the delay.

On your logdata() function you're calling delay(50) instead of Alarm.delay(50).
As caude pointed, you have to use Alarm.delay when a delay is needed, otherwise the delay will mess up with the alarms.

I think you could have done in other way using timer library. If you say the data has to be logged every second,it easier to done by timer.Example code
#include <SimpleTimer.h>
// the timer object
SimpleTimer timer;
// a function to be executed periodically
void repeatMe() {
Serial.print("Uptime (s): ");
Serial.println(millis() / 1000);
}
void setup() {
Serial.begin(9600);
timer.setInterval(1000, repeatMe);
}
void loop() {
timer.run();
}

Related

How to know if an Arduino restarted as a result of a WDT timeout?

I have Arduino code in which I have implemented an 8-second watchdog. To test I put a for loop and everything works correctly.
I want to know if it is possible to print a message when a watchdog timeout occurs in the Arduino, specifically what I want to do is send a message by XBee when a reset has occurred caused by the watch dog. I already have the XBee logic, how do I know when this reset occurs?
I already tried the solution raised here but it doesn't work for me:
link
My Code:
#include <avr/wdt.h>
void setup() {
Serial.begin(9600);
Serial.println("turning on");
delay(1000);
watchdogsetup();
}
void loop() {
for (int i = 0; i <= 9; i++) {
Serial.println();
delay(1000);
} //Test to activate watchdog
//My code ....
//....
wdt_reset(); // reset the watch dog to zero
}
Just an idea.
When the watchdog fires, it is uncertain if the time and resources you need to send a message via XBee are still available, so that message is probably best sent after the Arduino has reset and is running normally again.
I think the watchdog timer does set a flag that survives the reset itself, but it is cleared by the bootloader, so that information is lost if you use the bootloader.
So, you need to set your own flag, and read that flag back after the Arduino has reset. What you could try is writing an interrupt handler and add some other stuff to write a flag to EEPROM, something like this (untested):
#include <EEPROM.h>
int addr = 0; // Or whatever EEPROM address you like
setup() {
if (EEPROM.read(addr) == 1) { //If a WDT flag was set
// Send panicky message by XBee here
}
EEPROM.write(addr, 0); // Reset the WDT flag
// Rest of setup() goes here
}
ISR(WDT_vect) {
EEPROM.write(addr, 1); // Set the WDT flag
}
... and hope that the Arduino hasn't crashed beyond being able to write to the EEPROM when the watchdog fires.

AC Dimmer EpS32

I have an application on to control ESP32 Light Dimmer from the temperature read from a temperature sensor. The rule is very simple, when my sensor reads the temperature of more than 27ºC the lamp should be turned off by the Dimmer. However, this is not happening.
What the code does is, when the system is turned on the lamp turns on and the temperature is read from time to time, but when the temperature exceeds 27ºC the dimmer does not turn off the lamp. I think it might be something I'm doing wrong in the zero_crosss_int routine, because when the temperature reaches its limit the message "TRIAC OFF" is displayed.
Below the code used.
#define ZERO_CROSS 2
#define DIMMER_CONTROL 4
int dimming=64;
float programedTemp = 27.0;
int halfDimming=128;
int maxDimming=64;
void power(void *parameters){
tempSensor.requestTemperaturesByIndex(0);
temp=tempSensor.getTempCByIndex(0);
if(temp<programedTemp){
dimming=maxDimming;
if(temp<(programedTemp-1.0)){
dimming=maxDimming;
} else if(temp<programedTemp){
dimming++;
}
} else if(temp>programedTemp+0.9){
dimming=128;
}else{
dimming=halfDimming;
}
delay(4000);
}
void zero_crosss_int() {
if(dimming>=128){
delayMicroseconds(8.333);
digitalWrite(DIMMER_CONTROL, LOW); // triac Off
Serial.println((String) "=====>>> TRIAC OFF <<<=====");
}else{
int dimtime = (65*dimming);
delayMicroseconds(dimtime); // Off cycle
digitalWrite(DIMMER_CONTROL, HIGH); // triac firing
delayMicroseconds(8.333);
digitalWrite(DIMMER_CONTROL, LOW); // triac Off
}
}
void setup() {
pinMode(DIMMER_CONTROL, OUTPUT);
pinMode(ZERO_CROSS, INPUT);
attachInterrupt(ZERO_CROSS, zero_crosss_int, RISING);
Serial.begin(115200);
xTaskCreatePinnedToCore(power,"controlDimm",10000,NULL,0,&mainsPower,0);
}
void loop() {
}
You're doing way too much in your interrupt handler. It's amazing that it isn't just crashing constantly... the only reason that's not happening is likely because you don't do anything in loop().
It's not safe to call most of the functions you're calling in the interrupt handler. Interrupt handlers need to run for as little time as possible - other interrupts may be locked out and they may interfere with the network stack and other housekeeping functions. You absolutely should not be calling delayMicroseconds() or any Serial methods in an interrupt handler, or spending any more time there than is absolutely necessary. Almost all ESP-IDF or Arduino Core functions are not safe to call from inside an interrupt handler - the interrupt handler may interrupt another call to them while they're in an inconsistent state, or may change hardware settings while they're in the middle of using that hardware.
Your code would be much better if you structured it like this:
volatile bool zero_crossing_flag = false;
void IRAM_ATTR zero_cross_int() {
zero_crossing_flag = true;
}
void loop() {
if(zero_crossing_flag) {
zero_crossing_flag = false;
if(dimming>=128){
delayMicroseconds(8.333);
digitalWrite(DIMMER_CONTROL, LOW); // triac Off
Serial.println((String) "=====>>> TRIAC OFF <<<=====");
}else{
int dimtime = (65*dimming);
delayMicroseconds(dimtime); // Off cycle
digitalWrite(DIMMER_CONTROL, HIGH); // triac firing
delayMicroseconds(8.333);
digitalWrite(DIMMER_CONTROL, LOW); // triac Off
}
}
}
The IRAM_ATTR attribute on zero_cross_int() tells the compiler that this code must always be available. If you write an interrupt handler without IRAM_ATTR it's basically luck if it executes properly.
Restructuring your code this way will probably not solve the problem you're asking about, but it will allow it to run in a stable, reproducible way, which it's unlikely to the way it's written now.
Use your ZCD input to generate an interrupt. In the ISR start a Timer which generates another interrupt within 0ms(Full power) to 10ms(completely off) of the ZCD interrupt.
I don't understand to Switch off the lamp why are you using TRIAC instead of a Relay.

Arduino Interrupt won't ignore falling edge

I'm having some trouble completely debouncing a button attached to to an interrupt. The goal is to have the statement in the void loop() run exactly once when the button is pressed/released.
What usually ends up happening is one of two things
The ISR flag is set once when the button is pressed. Releasing the button does nothing, as intended.
The ISR flag is set once when the button is pressed, and once more when the button is released.
Here is the exact code I have:
#define interruptPin 2
#define DBOUNCE 100
volatile byte state = LOW; //ISR flag, triggers code in main loop
volatile unsigned long difference;
void setup() {
pinMode(interruptPin, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(interruptPin), ISR_0, CHANGE);
Serial.begin(115200);
}
void loop() {
if(state){ //If we have a valid interrupt
Serial.println(difference); //Print the time since the last ISR call
state = LOW; //Reset the flag
}
}
void ISR_0() {
static unsigned long last_interrupt = 0;
if(millis()-last_interrupt > DBOUNCE && digitalRead(interruptPin)){
difference=millis()-last_interrupt;
state = HIGH;
}
last_interrupt = millis(); //note the last time the ISR was called
}
This seems to be a popular way to debounce an interrupt, but for whatever reason it isn't working for me.
I was hoping on the first falling edge of the button release that digitalRead(interruptPin) would read low, so the state flag would not be set.
Since the ISR updates the last_interrupt time, the successive bounces after the first falling edge still seem to be successfully ignored. This leads me to believe the debouncing is not the issue, but the digitalRead(interruptPin) is.
The debouncing seems to take care of all but one state. When the button is released, the code still occasionally sets the state flag to HIGH.
Here's some sample output:
3643 (after waiting ~3.6 seconds from boot, I press the button, releasing it ~1 second later)
In the same scenario as above, the output occasionally looks like this:
3643
1018
This shows me pressing the button, but also releasing the button.
I'm using an UNO R3 and a momentary tactile push button with a 1k pull-down resistor.
I'm not sure what's going wrong at this point. I hope this is simple enough that anyone can easily test this on their arduino if they feel so inclined.
You can always do debouncing in the hardware
I've encountered bounce several times with buttons and encoders, and doing debouncing in the software can get messy and lead to unreadable code or logic errors.
The easiest thing you can do is add a 0.1 uF capacitor, as illustrated:
The Arduino has hysteresis inputs, and if you use 10K as your pullup then this works for bounce that is under 1ms. This is my favorite approach.
If you wanna get more serious, a wonderful pdf exists on the internet with lots of examples and explanations: A Guide to Debouncing
You use the internal pullup resistor of the Uno, but also a pulldown resistor on the button itself. That's not correct, you can only use one of of them.
Inside the if, you want the input to be high, so use the pulldown resistor and change INPUT_PULLUP into INPUT.
(to make things clear: the resistor is connected between input pin and ground, the button between input pin and +5V)
[edit]
I think when the ISR is called, the status of interruptPin might be changed again.
Due to the slowness of digitalRead, compared to the (possible) spike.
I'm not sure if this is what you want, but the example below is working.
(I've enabled the LED for testing purposes).
One thing: keep the button pressed at least the debounce time (100msec), otherwise it won't work.
Not ideal, but that's the price you have to pay if you want instantly response on a switch.
#define interruptPin 2
#define DBOUNCE 100
volatile byte state = LOW; //ISR flag, triggers code in main loop
volatile unsigned long difference;
bool hasPrinted = false;
void setup() {
pinMode(interruptPin, INPUT);
pinMode (13, OUTPUT);
attachInterrupt(digitalPinToInterrupt(interruptPin), ISR_0, CHANGE);
Serial.begin(115200);
}
void loop() {
digitalWrite(13, state);
if (!hasPrinted) {
Serial.println(difference);
hasPrinted = true;
}
}
void ISR_0() {
static unsigned long last_interrupt = 0;
if(millis()-last_interrupt > DBOUNCE){
state = !state;
hasPrinted = false;
difference = millis()-last_interrupt;
}
last_interrupt = millis(); //note the last time the ISR was called
}
Debouncing buttons/switches in interrupts is a hassle.
I faced a (sort of) similar situation with limit switches.
The moment a limit switch is hit, something has to occur - so interrupt.
However the interrupt would fire when the limit switch was released as well which was a problem. I had my interrupt set to fire on a FALLING edge.
Anyhow, I wound up debouncing outside of the interrupt, using flags.
The code explains it but:
Switch is hit, ISR runs (does what it needs to) and sets an ISR flag.
The ISR flag stops the ISR from actually doing anything until it's cleared.
In the main loop, call a debounce function if the ISR flag is set.
the debounce function will wait until a pin/switch is stable at the required state (HIGH/LOW) for a predefined time, then clear ISR flag, allowing the ISR to do something again.
#define interruptPin 2
#define DEBOUNCE_TIME 100L
volatile bool ISR_ACTIVATED = false;
volatile bool display_int_time = false;
bool debounce_started = false;
unsigned long Isr_debounce_pin_timer;
volatile unsigned long difference;
void setup() {
pinMode(interruptPin, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(interruptPin), ISR_0, CHANGE);
Serial.begin(112500);
}
void loop() {
if (display_int_time) {
Serial.println(difference); //Print the time since the last ISR call
// Right, done with interrupt stuff. clear the interrupt flag
display_int_time = false;
}
// Call debounce ISR routine in main loop
if (ISR_ACTIVATED)
ISR_ACTIVATED = !debounce(interruptPin, HIGH, Isr_debounce_pin_timer);
}
bool debounce(int debounce_pin, bool state, unsigned long &state_latch_start) {
// debounce_pin - what pin are we debouncing?
// state - should the stable state be HIGH or LOW
// state_latch_start - when we 'latched' on to a (possibly) stable state
static bool current_state;
// Read the required pin
current_state = digitalRead(debounce_pin);
// Is the pin at the required state, and we have not yet 'latched' it?
if ((!debounce_started) && (current_state == state)) {
// 'latch' this state (ie take note of when the pin went to the required level)
state_latch_start = millis();
debounce_started = true;
}
// Have we 'latched', but the pin has bounced
if (debounce_started && (current_state != state))
// unlatch
debounce_started = false;
// Have we latched, the pin is at the required level and enough time has passed (ie pin is stable)
if (debounce_started && (current_state == state) && (((unsigned long)(millis() - state_latch_start)) >= DEBOUNCE_TIME)) {
// cool. unlatch
debounce_started = false;
// report back that all is goood.
return(true);
}
// Blast. Either the pin is at the wrong level, or is still bouncing. Tell the boss to try again later!
return(false);
}
void ISR_0() {
static unsigned long last_interrupt = 0;
if((millis()-last_interrupt > DEBOUNCE_TIME) && digitalRead(interruptPin) && !ISR_ACTIVATED){
difference=millis()-last_interrupt;
//state = HIGH;
ISR_ACTIVATED = true;
display_int_time = true;
}
last_interrupt = millis(); //note the last time the ISR was called
}
*** Just a note, edited my code to incorporate the debounce time in your original ISR to ensure that the interrupt is valid. I had not read the comment regarding your noisy environment
I suppose the main issue, as was said in the comments, is because you have no actual debounce.
So, after the button is released, it continues to bounce, causing logic level on the input pin to change. If at the moment, when the pin state is latched for the digitalRead(), the state was read as high, then the whole condition will be met and state = HIGH; will be performed.
I'm not an artist, but I did my best to draw this timing diagram:
So, to avoid this, you can utilize any simple approach to debounce. Most simple one is to read again the pin state after a little timeout, greater than the maximal expected bounce time.
For example, if you're waiting for the button to be pressed and got high logical level (or low if the button is connected to GND), just wait about 5ms and read the level again. Process the button press only if the level still high (low).
And as was said in the other answers, hardware debounce also will help. You can use a higher resistor (actually you need not use external resistor: connect the button to GND and enable the internal pull-up, which is about 35kOhm). And add a capacitor about 1nF, parallel to the button.
My final solution, thanks to #darrob
#define interruptPin 2
#define DEBOUNCE_TIME 50L
//ISR Flags
volatile bool ISR_DEACTIVATED = false;
volatile bool display_int_time = false;
bool debounce_started = false;
unsigned long Isr_debounce_pin_timer;
int x = 0;
void setup() {
pinMode(interruptPin, INPUT);
attachInterrupt(digitalPinToInterrupt(interruptPin), ISR_0, CHANGE);
Serial.begin(112500);
}
void loop() {
//This runs every time we press the button
if (display_int_time) {
Serial.print("X "); //Print the time since the last ISR call
x++;
(x%10==0)?Serial.println(x):Serial.println();
display_int_time = false; //Done with interrupt stuff. Clear the interrupt flag
}
//Debounce for the ISR routine in main loop
if (ISR_DEACTIVATED)
//Wait until the pin settles LOW to reactivate the ISR
ISR_DEACTIVATED = !debounce(interruptPin, LOW, Isr_debounce_pin_timer);
}
//Returns TRUE if pin is stable at desired state, FALSE if bouncing or other state
bool debounce(const int debounce_pin, const bool state, unsigned long &state_latch_start) {
// debounce_pin - what pin are we debouncing?
// state - should the stable state be HIGH or LOW
// state_latch_start - when we 'latched' on to a (possibly) stable state
//If you are calling this routine to debounce multiple pins in the same loop,
// this needs to be defined outside of the function, and passed in as a separate
// parameter for each debounce item (like unsigned long &state_latch_start)
static bool current_state;
// Read the required pin
current_state = digitalRead(debounce_pin);
// Is the pin at the required state, and we have not yet 'latched' it?
if ((!debounce_started) && (current_state == state)) {
// 'latch' this state (ie take note of when the pin went to the required level)
state_latch_start = millis();
debounce_started = true;
}
// Have we 'latched', but the pin has bounced
if (debounce_started && (current_state != state))
// unlatch
debounce_started = false;
// Have we latched, the pin is at the required level and enough time has passed (ie pin is stable)
if (debounce_started && (current_state == state) && (((unsigned long)(millis() - state_latch_start)) >= DEBOUNCE_TIME)) {
// cool. unlatch
debounce_started = false;
// report back that all is goood.
return(true);
}
//Either the pin is at the wrong level, or is still bouncing. Try again later!
return(false);
}
void ISR_0() {
if(!ISR_DEACTIVATED){
ISR_DEACTIVATED = true;
display_int_time = true;
}
}

Arduino Micro keyboard

I'm trying to make a keyboard with my Arduino Micro. Circuit is OK but I having some issues with the code and hope you can gimme a hand here. For now I'm just trying with one key in pin 8 that should open a new tab in the web browser when you press the button. Just one key for now to see if it works.
I have this code:
#include <Keyboard.h>
void setup() {
// put your setup code here, to run once:
pinMode(8, INPUT);
Keyboard.begin(); // setup keyboard
}
void loop() {
// check buttons
if (readButton(8)) {
doAction(8);
}
}
boolean readButton(int pin) {
// check and debounce buttons
if (digitalRead(pin) == HIGH) {
delay(10000);
if (digitalRead(pin) == HIGH) {
return true;
}
}
return false;
}
void doAction(int pin) {
// perform tasks
switch (pin) {
case 8:
// CMD + T (new tab, Chrome)
Keyboard.press(KEY_LEFT_GUI);
Keyboard.press('t');
delay(10000);
Keyboard.releaseAll();
break;
}
}
But once I upload the code it starts opening new tabs automatically for 10 seconds and then stops for another 10 seconds and starts again. All this without pressing the button, it does it automatically. Any idea what I have wrong?
You're using Keyboard.press() which according to the documentation
When called, Keyboard.press()functions as if a key were pressed and held on your keyboard.
That is, you're pressing and holding the key. And so the Arduino keeps sending the key sequence CMD + T (new tab, Chrome) to your PC and thus Chrome will keep opening new tabs.
You need to release after giving enough delay so that you send only one key press to the application.
To end the key press, use Keyboard.release() or Keyboard.releaseAll().
The 10 second is evident from the delay(10000) you've used.

arduino keyboard does not release cause freeze

When I upload this script, my normal keyboard is not usable anymore and I think the right alt key is stuck in, even if I unplug the arduino the problem is still there.
The goal of this is to have a push to talk pedal for teamspeak. I was able to get around the problem using another script that passes itself as a controller but this causes other issues with games since they think I am using a controller all of a sudden.
From what I understand, this code should loop, while the pin is active, it should simulate the right alt key being pressed. When it is done it should release all key pressed by the script. It is hard to debug this since whenever I upload it I have to spend 10 minutes to be able to use my keyboard again.
Any help would be appreciated. Extra info, I am using the arduino leonardo.
#include <Keyboard.h>
void setup() {
// Initialize Button Pins
Keyboard.begin();
pinMode(9, INPUT_PULLUP);
}
void loop() {
Keyboard.releaseAll();
while (digitalRead(9) == HIGH) {
Keyboard.press(KEY_RIGHT_ALT);
delay(500);
}
delay(500);
Keyboard.releaseAll();
// wait for new window to open:
}
Note: without the actual hardware at my disposal for some tests, it is hard to know what is going wrong, so I'll try to review your code looking for possible point of failures.
According to the docs, press() functions as if a key were pressed and held down on the keyboard.
According to these other docs, INPUT_PULLUP effectively inverts the behavior of the INPUT mode, where HIGH means the sensor is off, and LOW means the sensor is on.
Therefore, a simple modification would be:
#include <Keyboard.h>
void setup() {
// Initialize Button Pins
Keyboard.begin();
pinMode(9, INPUT_PULLUP);
}
void loop() {
static bool pressed = false;
// does the pedal close the circuit with GND?
if (digitalRead(9) == HIGH) { // no
if (pressed) {
Keyboard.release(KEY_RIGHT_ALT);
pressed = false;
}
} else { // yes
if (!pressed) {
Keyboard.press(KEY_RIGHT_ALT);
pressed = true;
}
}
delay(500); // waste time
}
Does this code display the same issues?

Resources