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.
-
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– Harry Svensson2018年01月01日 12:39:46 +00:00Commented 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– Cezar Chirila2018年01月01日 12:40:52 +00:00Commented Jan 1, 2018 at 12:40
-
please post a graph of what you expect and what you actually getjsotola– jsotola2018年01月01日 23:34:35 +00:00Commented Jan 1, 2018 at 23:34
1 Answer 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
-
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!Cezar Chirila– Cezar Chirila2018年01月02日 11:16:33 +00:00Commented Jan 2, 2018 at 11:16