Hello Everyone,
I am making a little program that measures the time between pulses. First pulse starts the timer the middle pulses are snapshots of the timer and the last pulse stops the timer.
The idea being i want to the order of the pulses as the come in and the time between each. The number of pulses are always the same. In this example i am only using three pulses on three different pins.
The code works but i am getting significant time variation in the output based on order of input pulses (in this case A2,A1,A0 compared to A0,A1,A2). I was expecting slight changes in time due to code operations (and the variation on that) as well as clock instability but not in the order of uS?!?! Is this correct?
I tested a few if statements etc and they only take 2 clock cycles to process each the big time sucker is copying over the timer1 values which takes around 60 clock pulses. (based on my own testing)
I averaged some results out and came up with the following results
Order - A2,A1,A0 with the Max Min times below
Max Snap_shot =125.19
Min Snap_shot = 116.19
Max Final = 325.94
Min Final = 317
Order - A0,A1,A2 with the Max Min times below
Max Snap_shot =274
Min Snap_shot = 260
Max Final = 407.63
Min Final = 401.13
Is the code actually working?
Test Setup. I have two nano's,
A - is the main nano that i plan on using Inputs are A0,A1,A2
B - Test nano that sends pulses to A on pins 7,8,12 to 'A' on pins.
Code for 'A'
volatile boolean TimedOut = false;
volatile boolean Success = false;
volatile boolean Listening = true;
volatile boolean First_Trigger = true;
volatile boolean Second_Trigger = true;
volatile long Snap_shot = 0;
volatile int Pin_A0_Place = 0;
volatile int Pin_A1_Place = 0;
volatile int Pin_A2_Place = 0;
volatile char PBNOW;
volatile char PBLAST;
ISR (PCINT1_vect)// handle pin change interrupt for A0 to A5 here
{
PBNOW = PINC ^ PBLAST; // Find changed pins by doing a XOR with last state. any bits that changed will be 1 all else 0. e.g. 1000 ^ 0010 = 1010 - Thanks ARWARE
PBLAST = PINC;
switch (PBNOW) { // only one of these could have changed, first come first served
//************************************************************************************************************A0
case (1 << PINC0):
//A0 Triggered the Interrupt
if (Pin_A0_Place == 0) // checks if we have placed the interrupts
{
if (First_Trigger)
{
TCCR1B = 0x01; // Timer 1 precaller '1' starts timer 1
First_Trigger = false;
Pin_A0_Place = 1;
}
else if (Second_Trigger)
{
Snap_shot = TCNT1; // grabs the current time for our snap shot
Second_Trigger = false;
Pin_A0_Place = 2;
}
else
{
TCCR1B = 0x00; // Timer 1 precaller '0' Stops timer 1
Pin_A0_Place = 3;
Success = true;
PORTD &= 0b01111111;
}
PCMSK1 &= 0b11111110; // Disable PCINT8 = A0 but leave others alone (A2,A1)
}
break;
//************************************************************************************************************A1
case (1 << PINC1):
////A1 Triggered the Interrupt
if (Pin_A1_Place == 0) // checks if we have placed the interrupts
{
if (First_Trigger)
{
TCCR1B = 0x01; // Timer 1 precaller '1' starts timer 1
First_Trigger = false;
Pin_A1_Place = 1;
}
else if (Second_Trigger)
{
Snap_shot = TCNT1;
Second_Trigger = false;
Pin_A1_Place = 2;
}
else
{
TCCR1B = 0x00; // Timer 1 precaller '0' Stops timer 1
Pin_A1_Place = 3;
Success = true;
}
PCMSK1 &= 0b11111101; // Disable PCINT9 = A1 but leave others alone (A2,A0)
}
break;
//************************************************************************************************************A2
case (1 << PINC2):
////A2 Triggered the Interrupt
if (Pin_A2_Place == 0) // checks if we have placed the interrupts
{
if (First_Trigger)
{
TCCR1B = 0x01; // Timer 1 precaller '1' starts timer 1
First_Trigger = false;
Pin_A2_Place = 1;
}
else if (Second_Trigger)
{
Snap_shot = TCNT1;
Second_Trigger = false;
Pin_A2_Place = 2;
}
else
{
TCCR1B = 0x00; // Timer 1 precaller '0' Stops timer 1
Pin_A2_Place = 3;
Success = true;
}
PCMSK1 &= 0b11111011; // Disable PCINT10 = A2 but leave others alone (A1,A0)
}
break;
default:
break;
}
}
void prepTiming ()
{
// reset Timer 1
TCCR1A = 0; // Houses compare settings plus how it counts, here we want to count 0 - max (normal mode is WGMxx bits set to 0 - WGM10, WGM11 are in TCCR1A, WGM12, WGM13 are in TCCR1B
TCCR1B = 0; // prescalers = 0 = means timer 1 is off/stopped
TIMSK1 = 0x01; // Turn On Overflow interrupt on Timer 1 so i know if i missed my pulse
TCNT1 = 0; // sets Timer1 Counter to zero
// We are stopping interrupts on timers 0 and 2 so other timing functions will not work but they will not interrupt us (millis etc)
TIMSK0 = 0x00; // Turn off all interrupts on Timer 0
TIMSK2 = 0x00; // Turn off all interrupts on Timer 2
// Reset prescalers
GTCCR = bit (PSRASY); // reset prescaler - seen other people doing it not sure why? data sheets has it greyed out???
} // end of startTiming
//******************************************************************
// Timer1 Overflow service routine will trigger 16Mhz with no prescaler, overflow would cause it to trigger every 4.096ms
ISR (TIMER1_OVF_vect)
{
TCCR1B = 0x00; // sets prescaler to 0 stoping timer1
TCNT1 = 0; // sets Timer1 Counter to zero
TimedOut = true;
}
void setup ()
{
//pinMode(11, OUTPUT); // used to manually test / debug
pinMode(13, OUTPUT); // used to assert so that we can 'add a delay' debug
//don't think this is needed - PCINT's for those have been turned off
pinMode(A3, OUTPUT);// going to write these high so no noise input
pinMode(A4, OUTPUT);
pinMode(A5, OUTPUT);
digitalWrite(A3, INPUT_PULLUP);// so the is no possibility of noise on these pins that can float high and create pin change interrupts...
digitalWrite(A4, INPUT_PULLUP);
digitalWrite(A5, INPUT_PULLUP);
// Setting up Pin Change Interrupts
PCMSK1 = 0b00000111; // want PCINT's on pins A2,A1,A0
PCIFR |= bit (PCIF1); // clear any outstanding interrupts
PCICR |= 0b00000010; // bit PCIE1 to 1 all others zero --- enable pin change interrupts for A0 to A5
Serial.begin(115200);
}
void loop ()
{
PBLAST = PINC; // sets the state of Pin C in terms of which pins are high and which are low
prepTiming();
while (!TimedOut && !Success) // Wait here until we either time out or we have a successful timed event
{}
// displaying the results
if (TimedOut)
{
TIFR1 &= 0b11111110; // clears the TOV1 (Timer 1 Overflow Flag)
Serial.println ("Overflow");
}
if (Success)
{
Serial.println(String(((Snap_shot) * 62.5) / 1000)+":"+String(((TCNT1) * 62.5) / 1000));
//Serial.println (" ");
}
//delay(500);
//variables that i need to reset in order to loop around
TimedOut = false;
Success = false;
First_Trigger = true;
Second_Trigger = true;
Pin_A0_Place = 0;
Pin_A1_Place = 0;
Pin_A2_Place = 0;
Snap_shot = 0;
PCMSK1 = 0b00000111; // want PCINT's on pins A2,A1,A0
PCICR |= 0b00000010; // last thing re enable all PCINT's on
}
Code for 'B'
void setup() {
// put your setup code here, to run once:
pinMode(7,OUTPUT);
pinMode(8,OUTPUT);
pinMode(12,OUTPUT);
pinMode(13,OUTPUT);
PORTD &= 0b01111111; // sets PortD LOW (D0-7) - only want D7 LOW ( PD7)
PORTB &= 0b00000000; // sets PortB LOW (D8-13) - all
}
void loop() {
PORTD |= 0b10000000; // asserts pin 7 = A0
delayMicroseconds(202);
PORTB |= 0b00000001; // asserts pin 8 = A1
delayMicroseconds(202);
PORTB |= 0b00010000; // asserts pin 12 = A2
delayMicroseconds(202);
PORTD &= 0b01111111; // sets PortD LOW (D0-7) - only want D7 LOW ( PD7)
PORTB &= 0b00100000; // sets PortB LOW (D8-13) - all except LED Pin 13
delayMicroseconds(202);
}
Any help would be greatly appreciated!!!
Cheers
Chris