1

I am trying to measure AC power using an Arduino with an Atmega328p. In summary, I want to use timer1 to make an interrupt every 400us where I measure two ADC channels (A0 and A1) and put them into an array. The problem is that instead of measuring five mains periods (mains frequency = 50Hz so 20ms * 5), I get instead 13 of these periods (260ms). What am I doing wrong?

volatile int sample_incremental = 0;

void setup() {
      Serial.begin(115200);
      pinMode(voltagePin, INPUT);
      pinMode(currentPin, INPUT);
      set_sample_interrupt();
      sei();
    }

void set_sample_interrupt() {
  //Count to 400us
  OCR1A = 99;
  //Mode 4, CTC
  TCCR1B |= (1 << WGM12);
  //Enable interrupt
  TIMSK1 |= (1 << OCIE1A);
  //Prescaler 64
  TCCR1B |= (1 << CS11) | (1 << CS10);
}

ISR (TIMER1_COMPA_vect) {
  // action to be done every 400 usec
  current_sample[sample_incremental] = analogRead(currentPin) - 504;
  voltage_sample[sample_incremental] = analogRead(voltagePin) - 512;
  if (sample_incremental < (SAMPLES * PERIODREADS))
    sample_incremental++;
  else {
    //Disable interrupt
    TIMSK1 &= ~(1 << OCIE1A);
    sample_incremental = 0;
    finishedReading = true;
  }
}

Where after I do one reading, I stop the interrupt, and SAMPLES * PERIODREADS = 250.

3
  • Since you've omitted extremely much of your code, I'll guess that you have not declared the variable "sample_incremental" as volatile.
    – Harry Svensson
    Jan 1, 2018 at 12:39
  • Sorry about that, is has a large portion for computing RMS and real power that is not relevant to the question. Unfortunately that is not the problem as I have declared sample_incremental as volatile.
    – Cezar Chirila
    Jan 1, 2018 at 12:40
  • please post a graph of what you expect and what you actually get
    – jsotola
    Jan 1, 2018 at 23:34

1 Answer 1

1

The Arduino core library configures the Timer 1 for phase-correct PWM at about 490 Hz. Then you are setting some configuration bits in the timer's control registers without clearing the bits that had previously been set by the Arduino core. If you want to use the timer for your own purposes, and configure it by yourself, you should completely overwrite the core's configuration with your own. For that, use the = operator rather than |=, as in:

OCR1A  = 99;                         //Count to 400us
TIMSK1 = (1 << OCIE1A);              //Enable interrupt
TCCR1A = 0;
TCCR1B = (1 << WGM12)                //Mode 4, CTC
       | (1 << CS11) | (1 << CS10);  //Prescaler 64
1
  • This is the right answer, I fixed it using " TCCR1A = 0; TCCR1B = 0; TCNT1 = 0;" as a "hack" but your reply goes to the problem. Thank you! Jan 2, 2018 at 11:16

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.