AC Dimmer EpS32 - arduino

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.

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.

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 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?

Arduino External Interrupt Not Fast Enough

I've been trying to measure the time that the line is high on the Arduino. It goes high, then stays high for a couple of milliseconds. Then it gets pulled low for 1us and then floats back to high. My code doesn't seem to recognise the line getting pulled low. Is 1us too fast for the interrupt? How can I slow it down?
Thank you
EDIT
My thoughts are to use an RC filter in conjunction with a diode to slow the rise time enough for the Arduino to recognise the change, but only when the change occurs from the receiving line. Is this viable? Or can I use a pulse extender chip with a diode in the same way?
#define ESC 2 //the digital pin the esc signal line is attached to
int throttlePos = 0;
volatile unsigned long timer_start;
volatile int last_interrupt_time;
volatile int pulse_time;
void setup() {
// put your setup code here, to run once:
pinMode(ESC, OUTPUT); //originally set the ESC's line to output to keep line high ready for throttle armature
digitalWrite(ESC, HIGH); //keep the pulse high due to inverted throttle pulse
Serial.begin(115200); //opens the serial port for use when testing
timer_start = 0;
attachInterrupt(digitalPinToInterrupt(ESC), calcSignal, CHANGE);
for(throttlePos = 0; throttlePos <= 1000; throttlePos += 1) //these for loops arm the ESC by emulating an inverted PWM pulse, process takes two seconds
{
digitalWrite(ESC, LOW);
delayMicroseconds(1500);
digitalWrite(ESC, HIGH);
delayMicroseconds(100);
}
for(throttlePos = 1000; throttlePos <= 2000; throttlePos += 1)
{
digitalWrite(ESC, LOW);
delayMicroseconds(1000);
digitalWrite(ESC, HIGH);
delayMicroseconds(100);
}
}
void loop() {
digitalWrite(ESC, LOW);
delayMicroseconds(1200);
digitalWrite(ESC, HIGH);
delayMicroseconds(100);
delay(19);
Serial.println(pulse_time);
}
void calcSignal()
{
//record the interrupt time so that we can tell if the receiver has a signal from the transmitter
last_interrupt_time = micros();
//if the pin has gone HIGH, record the microseconds since the Arduino started up
if(digitalRead(ESC) == HIGH)
{
timer_start = micros();
}
//otherwise, the pin has gone LOW
else
{
//only worry about this if the timer has actually started
if(timer_start != 0)
{
//record the pulse time
pulse_time = ((volatile int)micros() - timer_start);
//restart the timer
timer_start = 0;
}
}
}
1/1us is 1MHz. Given that your Arduino executes instructions at 16MHz (at best, some instructions take longer), your interrupt handler could easily be missing things. However, the interrupt should still execute, even if the interrupt condition is cleared before the interrupt finishes.
Are you using the Arduino libraries for interrupts or configuring pin change interrupts directly at the register level?
Have you verified that the pulse into the Arduino is electrically sound? Without knowing more about your circuit, it's difficult to suggest a fix.

Arduino - Using interrupts freezes processing and serial output?

So, the interrupts seem to work insofar as "interrupting" when an event happens. My only problem is that I the interrupts will occur 2-3 times and everything essentially stops (Serial out, everything).
I was programming the board to output serially a calculated distance based on the output of the HC-SR04 distance IC. The distances are calculated accurately but, like I said earlier, everything seems to freeze. Below is both the code and an image of the serial monitor.
#define TRIGPIN 4
#define ECHOPIN 3
#define RED 2
#define GREEN 13
#define INTNUM 1 //interrupt pin 1 is digital pin 3 on the duemilanove
#define PULSE 10 //microseconds
#define CYCLETIME 50 //milliseconds
void ledWrite(int), trigPulse(), getTime();
int millisNow, millisPrev = 0;
int microsPrev;
boolean isHigh = false;
void setup() {
Serial.begin (9600);
pinMode(TRIGPIN, OUTPUT);
pinMode(ECHOPIN, INPUT);
pinMode(RED, OUTPUT);
pinMode(GREEN, OUTPUT);
attachInterrupt(INTNUM, getTime, CHANGE);
}
void loop() {
trigPulse();
// some other code while waiting on HC-SR04 to interrupt us when echo goes HIGH
}
void trigPulse(){
if( (millisNow = millis()) - millisPrev >= CYCLETIME){ //sufficient cycle time
digitalWrite(TRIGPIN, HIGH);
delayMicroseconds(PULSE);
digitalWrite(TRIGPIN, LOW);
millisPrev = millisNow; //reset clock
}
return;
}
void ledWrite(int dTime){
int distance = dTime/58.2;
if (distance < 4) {
digitalWrite(RED,HIGH);
digitalWrite(GREEN,LOW);
}
else {
digitalWrite(RED,LOW);
digitalWrite(GREEN,HIGH);
}
if (distance >= 200 || distance <= 0){
Serial.println("Out of range");
}
else {
Serial.print(distance);
Serial.println(" cm");
}
}
void getTime(){
int timeNow = micros();
Serial.println("Interrupted");
if(isHigh == false){
microsPrev = timeNow; //get time now, pin LOW->HIGH
isHigh = true;
Serial.println("Returning ..");
return;
}
else { //pin HIGH->lOW
ledWrite(timeNow - microsPrev);
isHigh = false;
microsPrev = micros();
Serial.println("Returning ..");
return;
}
return;
}
I know this is an old thread, but I just came by it having my own problems. The problem here is that you cannot use:
Serial.Print()
Within an interrupt service routine. The reason that the Serial.Print() doesn't work within an ISR is that it uses interrupts to pull the characters out of the serial buffer, but interrupts of a certain level are masked within the ISR. What basically happens is that the arduino throws out all other interrupts that are of a lower priority, which Serial.Read() falls into.
It is documented in a number of places: link1, link2, link3
I think you are getting interrupt while you are already processing interrupt. You should try disabling the interrupt as soon as you are in interrupt function and re-enable it again when you are done processing just before return. Hence I would advice to have just one return so that you don't have to repeat code of enabling interrupt. Also make sure the function which you are calling inside your interrupt code do not re-enable the interrupt. It may happen that the function micros() or any of the Serial function are re-enabling the interrupt.
I would suggest instead of calling function directly in you interrupt code try using some flags and set/reset in interrupt and use these flags in main loop to call your regular function.

Resources