Help with writing to registers for 1Hz pwm and timer interrupt

Hello all, this is the first time I am doing something writing to registers so I don't even know if what I want is possible.

I made abit of a mix with two codes I found. One is to measure mains grid frequency using a optocoupler and an external interrupt. The second code is to create a PWM on pin 9 with a frequency of 1Hz.

I am interested in doing a code that can read the grid frequency and change the duty cycle of the 1Hz PWM that is controlling a SSR so I can control power going to a heating element. Duty cycle should be 0% at 50.5Hz and 100% at 51Hz

Each part of the code works ok. If I measure frequency it will measure ok. And changing duty cycle of 1Hz pwm works ok too. But when I try to do both together arduino will stop generating PWM signal on pin 9. I think this might be due to the external interrupt on pin 2

This is my code

unsigned int outputvalue;
void setup() { 
  pinMode(9, OUTPUT);                               // Set digital pin 9 (D9) to an output
  TCCR1A = _BV(COM1A1) | _BV(WGM11);                // Enable the PWM output OC1A on digital pins 9
  TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS12);     // Set fast PWM and prescaler of 256 on timer 1
  ICR1 = 62499;                                     // Set the PWM frequency to 1Hz: 16MHz/(256 * 1Hz) - 1 = 62499
  OCR1A = 6249;                                     // Set the duty-cycle to 10%: 62499 / 10 = 6249
  TCNT1  = 0;   // Set Timer1 preload value to 0 (reset)
  TIMSK1 = 1;   // enable Timer1 overflow interrupt

  EIFR |= 1;  // clear INT0 flag
  attachInterrupt(0, timer1_get, FALLING);  // enable external interrupt (INT0)
  Serial.begin(9600);
}

uint16_t tmr1 = 0;
float period, frequency;
 
void timer1_get() {
  tmr1 = TCNT1;
  TCNT1  = 0;   // reset Timer1
}
 
ISR(TIMER1_OVF_vect) {  // Timer1 interrupt service routine (ISR)
  tmr1 = 0;
}

void loop(){
  
  // save current Timer1 value
  uint16_t value = tmr1;
  // calculate signal frequency which is = 1/period ; or = MCU_CLK/(Prescaler * Timer_Value)
  // since using full bridge rectifier we measure half period, so f=1/2*p
  if(value == 0)
    frequency = 0;   // aviod division by zero
  else
    frequency = 16000000.0/(2*(256UL*value));
  
  if (frequency>50.49 && frequency<51){
    outputvalue= 2*62499*(frequency-50.5);
  }
  if (frequency>51){
    outputvalue=62499;
  }
  if (frequency<50.5){
    outputvalue=0;
  }
  OCR1A = outputvalue;
  Serial.println(frequency);

}

I am just starting with using external interrupts and also writing to registers. But I think it might be that I am setting TCNT1 to cero after each cero crossing of ac, so this "resets" the counter for PWM?

Any recomendation in how I could to this?

Thank you in advanced

I think I might have found a solution by changing this part of the code

void timer1_get() {
  tmr1 = TCNT1 - previous;
  previous = TCNT1;
  //TCNT1  = 0;   // reset Timer1
  
}
 
ISR(TIMER1_OVF_vect) {  // Timer1 interrupt service routine (ISR)
  tmr1 = 0;
  previous = 0;
}

So instead of reseting the timer after each cero crossing I save the previous value and later reset when timer1 overflows.

The correct way to clear a flag is to write just that flag...
EIFR = 1; // clear INT0 flag

...needs to be protected with a critical section.

...will nearly always overflow outputvalue. And, is useless because you overwrite the value before using it.

In microcontroller terms that is glacial. Blink-without-delay gets you the same result without the complexity.

If yours is a typical residential mains circuit in an advanced country, it is highly unlikely that the frequency will vary by that much.

Don't forget volatile :grinning:

You are not calculating outputvalue if frequency is 51 or 50.5.

Simplify this to:

  if (frequency > 51) {
    outputvalue = 62499u;
  } else if (frequency < 50.5) {
    outputvalue = 0;
  } else {
    outputvalue = 2 * 62499ul * (frequency - 50.5);
  }

This is for a remote place where we have a microgrid powered by PV energy. We use grid tie inverters ac coupled to battery inverter. Battery inverter will regulate PV production through Frequency Shifting Power Control, so when there is excess of PV production it will gradualy increase frequency and PV inverters will start to throttle production once reached 51Hz. So the idea is to activate some heating elements that will act as dump loads to heat water before PV production is throttled and this way maximising PV production

Thanks, totally forgot about that

Thank you, this looks like a better way to do it!

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.