Firing triac using frequency condition

This is a program of dimmer circuit where i should control dimming through freq of zero crossing output.

// Input: Pin D2
const uint8_t AC_LOAD = 3;
volatile uint8_t dimming = 128;
volatile boolean first;
volatile boolean triggered;
volatile unsigned long overflowCount;
volatile unsigned long startTime;
volatile unsigned long finishTime;

// here on rising edge
void isr ()
{
  unsigned int counter = TCNT1;  // quickly save it
  //firing();
  // wait until we noticed last one
  if (triggered)
    return;

  if (first)
  {
    startTime = (overflowCount << 16) + counter;
    first = false;
    return;
  }


  finishTime = (overflowCount << 16) + counter;
  triggered = true;
  detachInterrupt(0);
}  // end of isr

// timer overflows (every 65536 counts)
ISR (TIMER1_OVF_vect)
{
  overflowCount++;
}  // end of TIMER1_OVF_vect


void prepareForInterrupts ()
{
  // get ready for next time
  EIFR = bit (INTF0);  // clear flag for interrupt 0
  first = true;
  triggered = false;  // re-arm for next time
  attachInterrupt(0, isr, RISING);
  firing();
} // end of prepareForInterrupts

void firing()
{
  volatile int dimtime = (75 * dimming);
  delayMicroseconds(dimtime);
  digitalWrite(AC_LOAD, HIGH);
  delayMicroseconds(10);
  digitalWrite(AC_LOAD, LOW);
}

void setup ()
{
  Serial.begin(9600);
  Serial.println("Frequency Counter");
  pinMode(AC_LOAD, OUTPUT); // Added
  // reset Timer 1
  TCCR1A = 0;
  TCCR1B = 0;
  // Timer 1 - interrupt on overflow
  TIMSK1 = bit (TOIE1);   // enable Timer1 Interrupt
  // zero it
  TCNT1 = 0;
  overflowCount = 0;
  // start Timer 1
  TCCR1B =  bit (CS10);  //  no prescaling

  // set up for interrupts
  prepareForInterrupts ();

} // end of setup

void loop ()
{
  if (!triggered)
    return;

  unsigned long elapsedTime = finishTime - startTime;
  float freq = F_CPU / float (elapsedTime);  // each tick is 62.5 ns at 16 MHz
  noInterrupts();              //Added
  float f  = freq;
  freq = 0;
  interrupts();                 //Added
  //Serial.print ("Took: ");
  // Serial.print (elapsedTime);
  // Serial.print (" counts. ");

  Serial.print ("Frequency: ");
  Serial.print (f);
  Serial.println (" Hz. ");

  // so we can read it
  delay (500);            //no problem if removed (only reading is fast)
  prepareForInterrupts ();

  if (f <= 100) //Added
  {
    dimming = 64; //dim light to 50 % if freq is less than or equal to 100
  }
  else if (f > 100)
  {
    dimming = 0; //Dim light to only 25% if freq is greater than 100
  }
}//Added

I have made firing(); —> //firing(); inside ISR because it changed my freq reading.What changes should i make in this program so that it will not hamper my freq reading.
Note: I will not achieve anything by dimming light as in this program since i have no control over line freq but i want to know how i can remove the effect of using firing() on freq reading if i call it inside ISR. Thank you.

And what is wrong with the answers in your other thread on this topic.

Maybe you should find out what frequency is!

Mark

holmes4:
And what is wrong with the answers in your other thread on this topic.

Maybe you should find out what frequency is!

Mark

They were useful. Helped me a lot in understanding my core mistake. The program of my previous question was based on calculating freq by waiting 1 sec which was creating problem and now i am using different program that no longer need to wait 1 sec.

Yes, i am trying to use freq to control brightness but when i do so it changed the freq value which is problem. Can you help me with this.

Your indenting is horrible. It hurts my eyes. Hit ctrl-t in the IDE and re-post the code.

gfvalvo:
Your indenting is horrible. It hurts my eyes. Hit ctrl-t in the IDE and re-post the code.

Sorry for that. I reposted it. Thank you.

Is this really impossible to control firing without affecting the reading of freq? . or is it possible to do so using different interrupt pin (pin 3) (i am using arduino UNO, ATmega328p) or can i do this using two arduino? I got lot of helpful answers in this topic from various source but not exactly what i asked. I hope atleast arduino forum have that solution.

There are (IMO) several things that you can do to make this better. The following suggestions are based on my personal preference. I make no claim that my method is either the best or only way to do it.

  1. Google “arduino direct port manipulaton” to learn how to set outputs faster than digitialWrite()

  2. There is no need to do the “(75 * dimming)” multiplication EVERY TIME the isr fires!!! Do that multiplication in loop() and ONLY when the value of ‘dimming’ changes.

  3. Sum the AC period information over several cycles (say 50, that gives a new reading every second) and then average in loop(). Set a flag in the isr when a new sum is ready for loop() to pick up. Use a ping-pong technique so loop() has a whole second to process and display the information before the next sum is available.

  4. I really don’t like the use of delays in the ISR. I’d look for a hardware solution. I’m not really familiar with the Counter / Timer capabilities in the ATmega family as I do almost all of my projects with Teensy or ESP8266 boards. So, the following algorithm (and my code below) will be generic / pseudo code.

Let’s assume you have two counters available with the following characteristics:

upCounter -- counts up microseconds since the last zero crossing. So, it must be able to count past 20000 without overflowing (for 50 Hz). It does not need to generate an interrupt.

downCounter -- counts down microseconds from a set value. Generates an interrupt when it reaches 0. Used to time both the triac turn-on phase delay and triac turn-off time. If ATmega only provides an up count capability, then you’ll need to adjust the initial setting accordingly and interrupt on overflow.

So, given all that, the idea is: that every time the zero crossing isr fires, it will get the time since the last zero crossing from upCounter and add it to the running sum. It then resets and restarts upCounter for the next cycle. If 50 samples have been received, it will set the flag for loop() and ping-pong the summing variable. Finally, it will set the downCounter to interrupt at the appropriate triac turn-on phase.

When the downCounter interrupt fires, its isr will turn on the triac and reset the downCounter for the gate-on period. When the interrupt fires again, it will turn off the triac gate. It then does nothing until the next zero crossing event.

Here’s the pseudo code. It (of course) is not compile-able and is untested. But, it should give you the idea.

const uint8_t countDownNop = 0;
const uint8_t countDownTriggerTriac = 1;
const uint8_t countDownResetTriac = 2;
const uint8_t numPeriods = 50;
const uint32_t triacTriggerTime = 10;

volatile bool periodInfoReady = false;
volatile uint8_t countDownFunction = countDownNop;
volatile uint8_t sumIndex;
volatile uint32_t triacPhaseDelay;
volatile uint32_t periodSum[] = {0, 0};

void setup() {
  triacPhaseDelay = dimming * 75;
  upCounter = 0;
  // start upCounter
  attachInterrupt(0, zeroCrossingIsr, RISING);
}

void loop() {
  uint32_t localPeriodSum;
  float averagePeriod;

  if (periodInfoReady) {
    noInterrupts();
    periodInfoReady = false;
    localPeriodSum = periodSum[sumIndex];
    interrupts();
    averagePeriod = localPeriodSum / (float) numPeriods;
    // Display averagePeriod as desired
  }

  if (you want to change the dimming) {
    noInterrupts();
    triacPhaseDelay = newDimmingValue * 75;
    interrupts();
  }
}

void zeroCrossingIsr() {
  static uint8_t periodCount = 0;
  static uint8_t currentIndex = 0;
  uint32_t period;

  period = upCounter;
  upCounter = 0;
  // re-start upCounter
  periodSum[currentIndex] += period;
  periodCount++;
  if (periodCount >= numPeriods) {
    periodCount = 0;
    sumIndex = currentIndex++;
    currentIndex &= 0x1;
    periodSum[currentIndex] = 0;
    periodInfoReady = true;
  }
  countDownFunction = countDownTriggerTriac;
  downCounter = triacPhaseDelay;
  // start downCounter
}

void downCounterIsr() {
  switch (countDownFunction) {
    case countDownTriggerTriac:
      // User direct port manipulation to trigger triac
      countDownFunction = countDownResetTriac;
      downCounter = triacTriggerTime;
      // re-start downCounter
      break;

    case countDownResetTriac:
      // User direct port manipulation to reset triac
      countDownFunction = countDownNop;
      break;

    default:
      break;
  }
}

Thank you so much. The best answer i have ever got.

gfvalvo:
Here’s the pseudo code. It (of course) is not compile-able and is untested.

Thanks a lot for this help. I tried to make it compileable but cant make it. Can you further help me to make it happen.

Sorry, that’s as far as I’m going. As I said, you need to research and understand the capabilities of the actual hardware you’re using with regard to timers, counters, interrupts etc. Time to cut you loose and let you do your own work, Grasshopper.

EDIT:
PS - For additional forum help, post your updated code with what you've tried so far.