A timer in Arduino seems to run faster when using classes. But in a C version (with the same values), it works as expected.
I coded a quick and dirty version for a NEC infrared protocol decoder on Arduino UNO (kind of plain C, no classes). It worked.
I coded a class in C++ (encapsulating data) for the same problem, but Timer1 seems to run a lot faster. In the C version I got 13500 microseconds for a run, which is Ok and expected. In the C++ version I got 5 microseconds. It makes no sense.
I rewrite the C version in a module (*.cpp and *.h; though it's cpp I'm not using classes) and it still worked.
The ISRs runs in both C and C++, but for a unknown reason the Timer1 runs faster, or it's not running whatsoever.
// C version of the initializer function:
void ir_init( IR_Nek* self, uint8_t pin, uint8_t address )
{
self->pin = pin;
self->address = address;
self->bits = 0;
self->error = false;
self->done = false;
TCCR1A = 0;
TCCR1B = 0;
TCNT1 = 0;
TIMSK1 = 1;
pinMode( self->pin, INPUT );
}
// C version of the NEC core decoder:
void ir_decode_isr( IR_Nek* self )
{
static uint8_t state = 0;
static uint8_t bit_counter = 0;
uint16_t period = 0;
digitalWrite( 13, HIGH );
switch( state ){
case 0:
self->error = false;
TCNT1 = 0;
TCCR1B = 2;
state = 1;
break;
case 1:
period = TCNT1 >> 1;
TCNT1 = 0;
if( 13000 < period and period < 14000 ){
state = 2;
self->done = false;
bit_counter = 32;
self->bits = 0L;
} else{
state = 0;
self->error = true;
TCCR1B = 0;
}
break;
case 2:
{
period = TCNT1 >> 1;
TCNT1 = 0;
uint8_t bit_val;
if( 1000 < period and period < 1300 ){
bit_val = 0;
} else if( 2100 < period and period < 2400 ){
bit_val = 1;
} else{
state = 0;
self->error = true;
TCCR1B = 0;
}
self->bits |= bit_val ? 0x00000001 : 0x00000000;
if( bit_counter > 1 ) self->bits <<= 1;
--bit_counter;
if( bit_counter == 0 ){
TCCR1B = 0;
state = 0;
self->error = false;
self->done = true;
}
break;
}
default:
TCCR1B = 0;
state = 0;
self->done = false;
self->error = true;
break;
} // switch
digitalWrite( 13, LOW );
}
// C++ constructor:
IR_Nek::IR_Nek( uint8_t pin, uint8_t address ) :
pin{pin}, address{address}
{
this->bits = 0;
this->error = false;
this->done = false;
TCCR1A = 0;
TCCR1B = 0;
TCNT1 = 0;
TIMSK1 = 1;
pinMode( this->pin, INPUT );
}
// C++ version of the NEC core decoder
void IR_Nek::decode_isr()
{
static uint8_t state = 0;
static uint8_t bit_counter = 0;
uint16_t period = 0;
switch( state ){
case 0:
this->error = false;
TCNT1 = 0;
TCCR1B = 2;
state = 1;
break;
case 1:
period = TCNT1 >> 1;
TCNT1 = 0;
if( 13000 < period and period < 14000 ){
state = 2;
this->done = false;
bit_counter = 32;
this->bits = 0L;
} else{
state = 0;
this->error = true;
TCCR1B = 0;
}
break;
case 2:
{
period = TCNT1 >> 1;
TCNT1 = 0;
uint8_t bit_val;
if( 1000 < period and period < 1300 ){
bit_val = 0;
} else if( 2100 < period and period < 2400 ){
bit_val = 1;
} else{
state = 0;
this->error = true;
TCCR1B = 0;
}
this->bits |= bit_val ? 0x00000001 : 0x00000000;
if( bit_counter > 1 ) this->bits <<= 1;
--bit_counter;
if( bit_counter == 0 ){
TCCR1B = 0;
state = 0;
this->error = false;
this->done = true;
}
break;
}
default:
TCCR1B = 0;
state = 0;
this->done = false;
this->error = true;
break;
} // switch
}
I expect something between 13000 and 14000 microseconds, but I get 5.
I don't know anything about Arduino, but I'm going to guess the difference is because you call digitalWrite( 13, HIGH );
at the top of ir_decode_dsr()
, but neglect to do so at the top of IR_Nek::decode_isr()
.
User contributions licensed under CC BY-SA 3.0