Skip to content

Instantly share code, notes, and snippets.

@me-no-dev
Created February 22, 2016 14:48
Show Gist options
  • Save me-no-dev/2e185a909000f6ac9605 to your computer and use it in GitHub Desktop.
Save me-no-dev/2e185a909000f6ac9605 to your computer and use it in GitHub Desktop.
#define TRIAC_PIN 5
#define ZERO_CROSS_PIN 4
#define DEBOUNCE_TIME 9000 //9ms - 10ms is the pulse period
static uint32_t lastPulse = 0;
static uint16_t period = 5000; //5ms - 50% for each half wave
void ICACHE_RAM_ATTR onTimerISR(){
if(GPIP(TRIAC_PIN)){//OUTPUT is HIGH
GPOC = (1 << TRIAC_PIN);//low
timer1_write(60);//12us
} else GPOS = (1 << TRIAC_PIN);//high
}
void ICACHE_RAM_ATTR onPinISR(){
uint32_t now = micros();
if(now - lastPulse < DEBOUNCE_TIME) return;
lastPulse = now;
GPOS = (1 << TRIAC_PIN);//high
timer1_write(period * 5);
}
void setup(){
pinMode(TRIAC_PIN, OUTPUT);
pinMode(ZERO_CROSS_PIN, INPUT);
GPOS = (1 << TRIAC_PIN);//high
timer1_attachInterrupt(onTimerISR);
timer1_enable(TIM_DIV16, TIM_EDGE, TIM_SINGLE);
attachInterrupt(ZERO_CROSS_PIN, onPinISR, RISING);
}
@larsenglund
Copy link

Input without hysteresis

CH2 is the input signal (to gpio4 from the zero cross detection ac opto coupler) and CH3 is gpio14 controlled in interrupt_handler in core_esp8266_wiring_digital.c:

void ICACHE_RAM_ATTR interrupt_handler(void *arg) {
  uint32_t status = GPIE;
  uint32_t levels = GPI;
  GPIEC = status;//clear them interrupts
  if(GPIP(14)) GPOC = 0x4000; else GPOS = 0x4000; // ADDED TO DEBUG INTERRUPTS
  if(status == 0 || interrupt_reg == 0) return;
  ETS_GPIO_INTR_DISABLE();
  int i = 0;
  uint32_t changedbits = status & interrupt_reg;
  while(changedbits){
    while(!(changedbits & (1 << i))) i++;
    changedbits &= ~(1 << i);
    interrupt_handler_t *handler = &interrupt_handlers[i];
    if (handler->fn && 
        (handler->mode == CHANGE || 
         (handler->mode & 1) == !!(levels & (1 << i)))) {
      // to make ISR compatible to Arduino AVR model where interrupts are disabled
      // we disable them before we call the client ISR
      uint32_t savedPS = xt_rsil(15); // stop other interrupts 
      handler->fn();
      xt_wsr_ps(savedPS);
    }
  }
  ETS_GPIO_INTR_ENABLE();
}

Some randomness as to when RISING and CHANGE ISR:s are called for signals without hysteresis are introduced with the GPIO sampling in interrupt_handler in core_esp8266_wiring_digital.c. Either don't use attachInterrupt and instead register you interrupt directly to get interrupts on all edges (even from very short pulses as in the image above) or add "debouncing" as shown in the code above. Or just use FALLING interrupts :)

@josep112
Copy link

josep112 commented Sep 7, 2017

How do I use this code with 2 lamps?

@devyte
Copy link

devyte commented Sep 7, 2017

@josep112 For two lamps you would need 2 different timers to trigger the 2 triacs. But the the ESP only has 2 hardware timers, and one is in use by the wifi stack (I think), which his why the gist uses the other. I would use this same code on two different ESPs, one per lamp. A wemos d1 mini v2 goes for under USD3 these days, they're cheap enough.
Having said that, and in view of the current cleanup effort, this is not the right place for "how do I..." questions. This is an issue tracker for tracking issues in the core. Please ask such questions at esp8266.com or stackoverflow.

@josep112
Copy link

josep112 commented Sep 8, 2017

Thanks devyte!

@ayushsharma82
Copy link

ayushsharma82 commented Mar 28, 2018

@devyte , I think we can use the same onTimerISR() function to control 2 triacs as both lamps would be having the same zero crossing?

@Prathamarora29
Copy link

can i use interrupts instead of timers

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment