I was working on a program to measure the pulse width , for that I thought of using Timer 2 in Arduino mega along with pin change interrupt,
The program I have written is as follows
volatile float ovfCount = 0;
typedef struct{
float curr_ovfCount,prev_ovfCount;
uint8_t curr_tcnt2, prev_tcnt2;
uint16_t width;
bool stateHigh = true;
}Pulse;
Pulse ch1, ch2, ch3, ch4, ch5, ch6;
void setup() {
Serial.begin(115200);
/*
* Pin Change Interupt for
* measuring the pulse width
* from the receiver
*
*/
DDRK = 0; // A8:A15 -> direction as Input
PORTK = B00111111; // A8:A15 -> pullupResistor
PCICR = B00000100; // activating 2 nd PCINT
PCIFR = 0; // resetting the flags
PCMSK2 = B00111111; // activating from A8:21 :: 6
/*
* 8 bit timer setup for counting
* timer 2 is used
*/
TCCR2B=0x00;
TCCR2A = 0x00; // wave generation is normal:: all zeros
TCNT2 = 0x00;
TIFR2 = 0x00; // resetting all flags
TIMSK2 = 0x01; //timer overflow enable
TCCR2B = 0x01; // no prescaling
}
ISR(TIMER2_OVF_vect){
ovfCount++;
}
ISR(PCINT2_vect){
float ovf_count = ovfCount;
uint8_t tcnt2 = TCNT2;
if( (PINK & 1 << PINK0) & ch1.stateHigh ){
//Low-High
ch1.prev_ovfCount = ovf_count;
ch1.prev_tcnt2 = tcnt2;
ch1.stateHigh = false;
} else if( ! ((PINK & 1 << PINK0) & ch1.stateHigh)){
// High-Low
ch1.curr_ovfCount = ovf_count;
ch1.curr_tcnt2 = tcnt2;
ch1.width = (256.0*(ch1.curr_ovfCount - ch1.prev_ovfCount) + (ch1.curr_tcnt2 - ch1.prev_tcnt2) ) * 1000 / 16e6;
ch1.stateHigh = true;
}
}
void loop() {
Serial.println(ch1.width);
pinMode(13, OUTPUT);
digitalWrite(13,!digitalRead(13));
delay(1000);
}
and the output I am getting is ,
16:22:05.667 -> 0
16:22:05.847 -> 927
16:22:06.826 -> 927
16:22:07.820 -> 1001
16:22:08.847 -> 1001
16:22:09.837 -> 1001
16:22:10.843 -> 1001
16:22:11.835 -> 1002
16:22:12.863 -> 1002
16:22:13.871 -> 1002
16:22:14.854 -> 1002
16:22:15.873 -> 1003
16:22:16.875 -> 1003
16:22:17.887 -> 1003
16:22:18.860 -> 1003
16:22:19.875 -> 1003
16:22:20.867 -> 1003
16:22:21.907 -> 1003
16:22:22.895 -> 1003
16:22:23.922 -> 1008
16:22:24.921 -> 1008
16:22:25.938 -> 1008
16:22:26.922 -> 1008
16:22:27.939 -> 1008
16:22:28.961 -> 1008
16:22:29.946 -> 1008
16:22:30.971 -> 1008
16:22:31.993 -> 1008
16:22:32.974 -> 1008
16:22:34.011 -> 1008
16:22:35.016 -> 1008
16:22:36.026 -> 1008
16:22:37.012 -> 1008
16:22:38.024 -> 1008
16:22:38.939 -> 1008
16:22:39.802 -> 906
16:22:40.638 -> 906
16:22:41.508 -> 844
16:22:42.345 -> 844
16:22:43.189 -> 842
16:22:44.059 -> 842
16:22:44.905 -> 843
16:22:45.750 -> 843
16:22:46.593 -> 842
16:22:47.428 -> 842
16:22:48.305 -> 842
16:22:49.139 -> 842
16:22:50.011 -> 845
16:22:50.839 -> 845
16:22:51.707 -> 842
16:22:52.539 -> 842
16:22:53.419 -> 842
16:22:54.260 -> 842
16:22:55.111 -> 842
16:22:55.975 -> 842
16:22:56.791 -> 842
16:22:57.642 -> 842
16:22:58.492 -> 842
16:22:59.372 -> 842
16:23:00.212 -> 842
16:23:01.046 -> 842
16:23:01.918 -> 842
16:23:02.775 -> 842
16:23:03.600 -> 849
16:23:04.473 -> 849
16:23:05.329 -> 842
16:23:06.159 -> 842
16:23:07.022 -> 842
16:23:07.862 -> 842
16:23:08.709 -> 842
16:23:09.574 -> 842
16:23:10.412 -> 843
16:23:11.292 -> 843
16:23:12.116 -> 848
16:23:12.996 -> 848
16:23:13.899 -> 848
16:23:14.779 -> 848
The output I am expecting is 1000 as the connection to the PCINT is directly form the digital pin13 of the Arduino and it is made to blink at that interval
I want to know
- What mistake I am making here in measuring the counts
- How can I generalise this method for measuring width of 6 channels simultaneously.
===== Edit after input from Edgar Bonet ===========
I have written a program , can you please tell me is this a good way to accomplish my requirement
volatile uint32_t ovfCount = 0;
struct Pulse {
uint32_t last_toggle;
uint32_t width;
bool stateHigh;
bool input_is_high;
uint32_t get_width() {
noInterrupts();
uint32_t width_copy = width;
interrupts();
return width_copy;
}
};
Pulse ch1, ch2, ch3, ch4, ch5, ch6;
void setup() {
Serial.begin(115200);
/*
Pin Change Interupt for
measuring the pulse width
from the receiver
*/
DDRK = 0; // A8:A15 -> direction as Input
PORTK = B00111111; // A8:A15 -> pullupResistor
PCIFR = 0; // resetting the flags
PCMSK2 = B00111111; // activating from A8:21 :: 6
PCICR = B00000100; // activating 2 nd PCINT
/*
8 bit timer setup for counting
timer 2 is used
*/
TCCR2B = 0x00;
TCCR2A = 0x00; // wave generation is normal:: all zeros
TCNT2 = 0x00;
TIFR2 = 0x00; // resetting all flags
TIMSK2 = 0x01; //timer overflow enable
TCCR2B = 0x01; // no prescaling
DDRH = B00111000;
fastPWM_init();
}
void fastPWM_init() {
// clearing
TCCR4A = 0; TCCR4B = 0; TCCR4C = 0;
// Initializing
TCCR4A = B10101010; // OC4A, OC4B, OC4C : ICR-WGM
TCCR4B = B00011010; // ICR-WGM prescalar : 8
// Setting frequency
ICR4 = 39999;
// Setting PWM
OCR4A = 2000; OCR4B = 2000; OCR4C = 2000;
}
ISR(TIMER2_OVF_vect) {
ovfCount++;
}
ISR(PCINT2_vect) {
uint8_t tcnt2 = TCNT2;
uint32_t ovf_count = ovfCount;
if ( bit_is_set(TIFR2, TOV2) && tcnt2 < 128 ) {
ovf_count ++;
}
uint32_t time = ovf_count << 8 | tcnt2;
pinChangeFunction(&ch1, time, PK0);
pinChangeFunction(&ch2, time, PK1);
pinChangeFunction(&ch3, time, PK2);
pinChangeFunction(&ch4, time, PK3);
pinChangeFunction(&ch5, time, PK4);
pinChangeFunction(&ch6, time, PK5);
}
void pinChangeFunction(Pulse *channel, uint32_t time, uint8_t pin){
channel->input_is_high = bit_is_set(PINK, pin);
if (channel->input_is_high && !channel->stateHigh) {
channel->stateHigh = true;
} else if (! channel->input_is_high && channel->stateHigh) {
channel->width = time - channel->last_toggle;
channel->stateHigh = false;
}
channel->last_toggle = time;
}
void loop() {
if(Serial.available() > 0){
OCR4A = Serial.parseInt();
}
Serial.print(ch1.get_width() / 16e3);Serial.print("\t");
Serial.println(ch6.get_width() / 16e3);
}
The PWM is only used for testing.
millis()ormicros()to get the current timestamp instead of messing with timers.