View previous topic :: View next topic |
Author |
Message |
younder
Joined: 24 Jan 2013 Posts: 53 Location: Brazil
|
Help on 3 external interrupts at the same time PIC18F4550... |
Posted: Sat Aug 17, 2013 8:21 pm |
|
|
Hi All,
I need to read 3 external pulses at the same time and I'm planning to use external interrupts 0, 1 and 2 for that... however I'm trying to figure it out if that is going to work considering 2 or 3 pulses at the same time...
INT0 will be a car RPM, worse case 5000 RPM ~167Hz pulse frequency
INT1 will be a fuel flow measuring sensor, worse case 42LPH (Liters per Hour) ~45,5Hz pulse frequency
INT2 will be speed, worse case 140Km/h ~20Hz pulse frequency
How would be the best way to do it?
I'm using a PIC18F4550 (clock=48000000)
Any comments/suggestions would be appreciated!
Thanks
Hugo _________________ Hugo Silva |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19513
|
|
Posted: Sun Aug 18, 2013 4:19 am |
|
|
No problem at all, provided you follow the old 'adage', and keep the handlers quick.
Basically in a handler only either count, record a time, etc.. Don't do any arithmetic in the handlers. don't delay in the handlers etc.. Just record what needs to be recorded, nothing else.
The only time you'd get a problem, is if a combination of two handlers takes longer to process than the time between events on the third channel.
Best Wishes |
|
|
younder
Joined: 24 Jan 2013 Posts: 53 Location: Brazil
|
code |
Posted: Sun Aug 18, 2013 11:25 am |
|
|
Thanks for the reply,
I just did the code below and was wondering if it can be optimized...
Tmr1 is being used as a timebase in my application...
what does the PIC do when got 2 or 3 external pulse coming at the same time? it process INT0 then INT1 and so on according #priority INT_EXT, INT_EXT1, INT_EXT2, INT_TIMER0?
Any help would be appreciated!
Hugo
Code: |
Float Time_Count_INT0=0.0,Time_Count_INT0_Mem[2]={0.0,0.0};
Float Time_Count_INT1=0.0,Time_Count_INT1_Mem[2]={0.0,0.0};
Float Time_Count_INT2=0.0,Time_Count_INT2_Mem[2]={0.0,0.0};
#INT_TIMER0 // Definition that next line will be associated to Timer0 interrupt
void timer0() // Function called automaticaly
{
//Timer0 will not be reseted or restarted, it will continuously count till its overflow
if (Time_Count_INT0_Mem[0]==0) { //if no external interrupt has been called
Time_Count_INT0=Time_Count_INT0+1.39810133333333; //Then add time counter by total tmr0 overflow -> 1.39810133333333= Total time for tmr0 overflow
}
else { //Time count must start from last tmr0 reset value
Time_Count_INT0=Time_Count_INT0+((65536-Time_Count_INT0_Mem[0])*0.0000213333333333333); //1.39810133333333= Total time for tmr0 overflow
Time_Count_INT0_Mem[0]=0; //clear time count mem 0
Time_Count_INT0_Mem[1]=0; //clear time count mem 1
}
if (Time_Count_INT1_Mem[0]==0) { //if no external interrupt has been called
Time_Count_INT1=Time_Count_INT1+1.39810133333333; //Then add time counter by total tmr0 overflow -> 1.39810133333333= Total time for tmr0 overflow
}
else { //Time count must start from last tmr0 reset value
Time_Count_INT1=Time_Count_INT1+((65536-Time_Count_INT1_Mem[0])*0.0000213333333333333); //1.39810133333333= Total time for tmr0 overflow
Time_Count_INT1_Mem[0]=0; //clear time count mem 0
Time_Count_INT1_Mem[1]=0; //clear time count mem 1
}
if (Time_Count_INT2_Mem[0]==0) { //if no external interrupt has been called
Time_Count_INT2=Time_Count_INT2+1.39810133333333; //Then add time counter by total tmr0 overflow -> 1.39810133333333= Total time for tmr0 overflow
}
else { //Time count must start from last tmr0 reset value
Time_Count_INT2=Time_Count_INT2+((65536-Time_Count_INT2_Mem[0])*0.0000213333333333333); //1.39810133333333= Total time for tmr0 overflow
Time_Count_INT2_Mem[0]=0; //clear time count mem 0
Time_Count_INT2_Mem[1]=0; //clear time count mem 1
}
}
Float TimeCount_Total_INT0=0.0;
#INT_EXT // Definition that next line will be associated to External interrupt
void ext_isr(void) // Function called automaticaly @ Pin_B0 rise edge detection
{
Time_Count_INT0_Mem[0]=get_timer0(); //get actual tmr0 value
FTemp0=Time_Count_INT0_Mem[0]-Time_Count_INT0_Mem[1]; //how many tmr0 counts since last interrupt?
TimeCount_Total_INT0=Time_Count_INT0+(FTemp0*0.0000213333333333333); //Calculates total pulse time lenght -> Period = 1/((F.Osc/4) / Prescaler)
Time_Count_INT0_Mem[1]=Time_Count_INT0_Mem[0]; //memorizes current tmr0 value in case a new interrupt happens before tmr0 overflows
Time_Count_INT0=0; //Reset Actual "Time counter" for external interrupt INT0
clear_interrupt(INT_EXT);
}
Float TimeCount_Total_INT1=0.0;
#INT_EXT1 // Definition that next line will be associated to External interrupt
void ext_isr1(void) // Function called automaticaly @ Pin_B1 rise edge detection
{
Time_Count_INT1_Mem[0]=get_timer0(); //get actual tmr0 value
FTemp0=Time_Count_INT1_Mem[0]-Time_Count_INT1_Mem[1]; //how many tmr0 counts since last interrupt?
TimeCount_Total_INT1=Time_Count_INT1+(FTemp0*0.0000213333333333333); //Calculates total pulse time lenght -> Period = 1/((F.Osc/4) / Prescaler)
Time_Count_INT1_Mem[1]=Time_Count_INT1_Mem[0]; //memorizes current tmr0 value in case a new interrupt happens before tmr0 overflows
Time_Count_INT1=0; //Reset Actual "Time counter" for external interrupt INT1
clear_interrupt(INT_EXT1);
}
Float TimeCount_Total_INT2=0.0;
#INT_EXT2 // Definition that next line will be associated to External interrupt
void ext_isr2(void) // Function called automaticaly @ Pin_B2 rise edge detection
{
Time_Count_INT2_Mem[0]=get_timer0(); //get actual tmr0 value
FTemp0=Time_Count_INT2_Mem[0]-Time_Count_INT2_Mem[1]; //how many tmr0 counts since last interrupt?
TimeCount_Total_INT2=Time_Count_INT2+(FTemp0*0.0000213333333333333); //Calculates total pulse time lenght -> Period = 1/((F.Osc/4) / Prescaler)
Time_Count_INT2_Mem[1]=Time_Count_INT2_Mem[0]; //memorizes current tmr0 value in case a new interrupt happens before tmr0 overflows
Time_Count_INT2=0; //Reset Actual "Time counter" for external interrupt INT2
clear_interrupt(INT_EXT2);
}
|
_________________ Hugo Silva |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19513
|
|
Posted: Sun Aug 18, 2013 12:23 pm |
|
|
The only time 'priority' come into things, is if two interrupt flags are both set when the handler is called. Then the one that is defined first _or_ has the higher 'priority' is processed first.
Generally with a 48MHz clock (12MHIPS), both signals have to be set within a uSec of one another for this ever to apply.
Screaming thing in your posted code - float. Never use floats unless you have to. Even simple things like addition take vastly longer with floats, than with integers. Just set a flag in the timer, and do the FP maths in the main code. Performing FP maths in an interrupt handler, not only takes an age, but also means that interrupts will be disabled in similar maths in the main code.
As a further comment, the PIC 'float' only supports a maximum of 7 digits of resolution. You have a lot of wasted digits in your entries.... |
|
|
younder
Joined: 24 Jan 2013 Posts: 53 Location: Brazil
|
|
Posted: Wed Aug 21, 2013 4:41 pm |
|
|
I've just eliminated all float variables in my code... I have also tried a flag in the handle with all the math in the main loop, but it gets worse then everything inside the handle... my longest cycle time in the main loop is 66ms... average is 1ms... any help on how to get a better performance by having all math in the main loop?
Code: |
Unsigned int32 Cycle_Time=0,Time_Count_INT0=0,Time_Count_INT1=0,Time_Count_INT2=0; // Global variable that contains tmr0 accumulated timer for INT0 - variável global com contador de tempo acumulado (INT0) do Timer 0
Unsigned int16 Cycle_Time_Mem[2]={0,0},Time_Count_INT0_Mem[2]={0,0},Time_Count_INT1_Mem[2]={0,0},Time_Count_INT2_Mem[2]={0,0};
#INT_TIMER0 // Definition that next line will be associated to Timer0 interrupt - linha que define que a próxima função será associada à interrupção do TIMER0
void timer0() // Function called automaticaly - esta função não precisará ser chamada. Será executada automaticamente.
{
//Pulse time counting for External Interrupt 0
if (Time_Count_INT0_Mem[0]==0) { //if no external interrupt has been called
Time_Count_INT0=Time_Count_INT0+13981013; //Then add time counter by total tmr0 overflow -> 1.3981013=Tempo Total para overflow to contator (TMR0 16bits) = (Tempo de cada incremento * 65536)
}
else { //Time count must start from last tmr0 reset value
Time_Count_INT0=Time_Count_INT0+((int32)(65536-Time_Count_INT0_Mem[0])*213); //0.0000213=Tempo de "cada" Incremento do contador Timer0 (Período) = 1/((F.Oscilador/4) / Prescaler)
Time_Count_INT0_Mem[0]=0; //clear time count mem 0
Time_Count_INT0_Mem[1]=0; //clear time count mem 1
}
//Pulse time counting for External Interrupt 1
if (Time_Count_INT1_Mem[0]==0) { //if no external interrupt has been called
Time_Count_INT1=Time_Count_INT1+13981013; //Then add time counter by total tmr0 overflow -> 1.3981013=Tempo Total para overflow to contator (TMR0 16bits) = (Tempo de cada incremento * 65536)
}
else { //Time count must start from last tmr0 reset value
Time_Count_INT1=Time_Count_INT1+((int32)(65536-Time_Count_INT1_Mem[0])*213); //0.0000213=Tempo de "cada" Incremento do contador Timer0 (Período) = 1/((F.Oscilador/4) / Prescaler)
Time_Count_INT1_Mem[0]=0; //clear time count mem 0
Time_Count_INT1_Mem[1]=0; //clear time count mem 1
}
//Pulse time counting for External Interrupt 2
if (Time_Count_INT2_Mem[0]==0) { //if no external interrupt has been called
Time_Count_INT2=Time_Count_INT2+13981013; //Then add time counter by total tmr0 overflow -> 1.3981013=Tempo Total para overflow to contator (TMR0 16bits) = (Tempo de cada incremento * 65536)
}
else { //Time count must start from last tmr0 reset value
Time_Count_INT2=Time_Count_INT2+((int32)(65536-Time_Count_INT2_Mem[0])*213); //0.0000213=Tempo de "cada" Incremento do contador Timer0 (Período) = 1/((F.Oscilador/4) / Prescaler)
Time_Count_INT2_Mem[0]=0; //clear time count mem 0
Time_Count_INT2_Mem[1]=0; //clear time count mem 1
}
//Cycle Time counting for Main Loop
Cycle_Time=Cycle_Time+((int32)(65536-Cycle_Time_Mem[0])*213); //0.0000213=Tempo de "cada" Incremento do contador Timer0 (Período) = 1/((F.Oscilador/4) / Prescaler)
Cycle_Time_Mem[0]=0; //clear time count mem 0
Cycle_Time_Mem[1]=0; //clear time count mem 1
}
unsigned int32 TimeCount_Total_INT0=0;
#INT_EXT // Definition that next line will be associated to External interrupt - linha que define que a próxima função será associada à interrupção externa
void ext_isr(void) // Function called automaticaly @ Pin_B0 rise edge detection - função executada automaticamente a cada detecção de borda de subida no pino B0.
{
Time_Count_INT0_Mem[0]=get_timer0(); //get actual tmr0 value
Temp0=Time_Count_INT0_Mem[0]-Time_Count_INT0_Mem[1]; //how many tmr0 counts since last interrupt?
TimeCount_Total_INT0=Time_Count_INT0+((int32)Temp0*213); //Calculates total pulse time lenght -> 0.0000213=Tempo de "cada" Incremento do contador Timer0 (Período) = 1/((F.Oscilador/4) / Prescaler)
Time_Count_INT0_Mem[1]=Time_Count_INT0_Mem[0]; //memorizes current tmr0 value in case a new interrupt happens before tmr0 overflows
Time_Count_INT0=0; //Reset Actual "Time counter" for external interrupt INT0
clear_interrupt(INT_EXT);
}
unsigned int32 TimeCount_Total_INT1=0;
#INT_EXT1 // Definition that next line will be associated to External interrupt
void ext_isr1(void) // Function called automaticaly @ Pin_B1 rise edge detection
{
Time_Count_INT1_Mem[0]=get_timer0(); //get actual tmr0 value
Temp0=Time_Count_INT1_Mem[0]-Time_Count_INT1_Mem[1]; //how many tmr0 counts since last interrupt?
TimeCount_Total_INT1=Time_Count_INT1+((int32)Temp0*213); //Calculates total pulse time lenght -> 0.0000213=Tempo de "cada" Incremento do contador Timer0 (Período) = 1/((F.Oscilador/4) / Prescaler)
Time_Count_INT1_Mem[1]=Time_Count_INT1_Mem[0]; //memorizes current tmr0 value in case a new interrupt happens before tmr0 overflows
Time_Count_INT1=0; //Reset Actual "Time counter" for external interrupt INT1
clear_interrupt(INT_EXT1);
}
unsigned int32 TimeCount_Total_INT2=0;
#INT_EXT2 // Definition that next line will be associated to External interrupt
void ext_isr2(void) // Function called automaticaly @ Pin_B2 rise edge detection
{
Time_Count_INT2_Mem[0]=get_timer0(); //get actual tmr0 value
Temp0=Time_Count_INT2_Mem[0]-Time_Count_INT2_Mem[1]; //how many tmr0 counts since last interrupt?
TimeCount_Total_INT2=Time_Count_INT2+((int32)Temp0*213); //Calculates total pulse time lenght -> 0.0000213=Tempo de "cada" Incremento do contador Timer0 (Período) = 1/((F.Oscilador/4) / Prescaler)
Time_Count_INT2_Mem[1]=Time_Count_INT2_Mem[0]; //memorizes current tmr0 value in case a new interrupt happens before tmr0 overflows
Time_Count_INT2=0; //Reset Actual "Time counter" for external interrupt INT2
clear_interrupt(INT_EXT2);
}
|
_________________ Hugo Silva |
|
|
asmboy
Joined: 20 Nov 2007 Posts: 2128 Location: albany ny
|
|
Posted: Wed Aug 21, 2013 5:01 pm |
|
|
whats your #use delay statement ?
whats your TIMER setup statement ?
prescalar of interest as you say 16 bits.....
and whats this about ?
|
|
|
younder
Joined: 24 Jan 2013 Posts: 53 Location: Brazil
|
|
Posted: Wed Aug 21, 2013 8:06 pm |
|
|
[quote="asmboy"]whats your #use delay statement ?
Code: | #use delay (clock=48000000) |
whats your TIMER setup statement ?
prescalar of interest as you say 16 bits.....
Code: |
setup_timer_0 (T0_INTERNAL | T0_DIV_256 );
enable_interrupts(INT_TIMER0);
setup_timer_1 (T1_INTERNAL | T1_DIV_BY_8);
enable_interrupts(INT_TIMER1)
|
and whats this about ?
1.3981013 seconds is the total time for Timer0 overflows (65536*0.0000213 sec.) -> 0.0000213=time of each increment _________________ Hugo Silva |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9226 Location: Greensville,Ontario
|
|
Posted: Thu Aug 22, 2013 9:19 am |
|
|
hmm...
You might consider simplfying your code by getting one sensor working right,say the RPM one, as it has the highest frequency.
If you 'sync' the others to be read at the same time,then you only need ONE ISR( RPM in this case).
Then use fast integer math to do all the required calculation in 'main' to display the results.
just another way to do it...
hth
jay |
|
|
|