|
|
View previous topic :: View next topic |
Author |
Message |
apakSeO
Joined: 07 Dec 2016 Posts: 60 Location: Northeast USA
|
Passing variables into ISR's |
Posted: Fri Jan 27, 2017 3:16 pm |
|
|
Using: CCS v5.065 / MPLAB X v3.40 / PIC18F46J50
Is it possible to pass variables ( global or otherwise ) into ISR's using the CCS framework?
An example: I've set up a low-frequency software PWM using CCP and interrupts. I define a static pin PWM_PIN = PIN_A5. The test code cyclically brightens an LED from min to max and then resets back to min.
Code: |
#include <18F46J50.h>
#fuses NOWDT,NOPROTECT,NODSBOR
#device PIC18F46J50 ICD=TRUE
#use delay(internal=8MHz, clock=48MHz) // Use internal 8MHz osc; setup CPU clock to 48MHz
#define PWM_PIN PIN_A5
#define PWM_PERIOD 5460L // 1/48e6 * 4 * 8 = 83.33ns per timer1 tick
// Timer1 divisor of 8 means 666.66ns per timer1 tick
// We want a pwm frequency of 275Hz or period of 3.64ms
// 3.64ms / 2 / 666.66ns = 2730 timer1 ticks
// Aiming for a PWM frequency of 275Hz
float duty = 50; // Default to 50% duty cycle
volatile float dutyDiv100;
volatile long high_time;
volatile float cMinusDuty;
volatile long low_time;
#int_ccp1
void ccp1_isr( void )
{
if(!input_state(PWM_PIN)){ // If the pin is low,
output_high(PWM_PIN); // Set the pin high ...
set_compare_time(1, high_time); // .. and change timer to time the low state
}
else{
output_low(PWM_PIN); // Set the pin low...
set_compare_time(1, low_time); // .. change timer to now time the high state
}
set_timer1(0); // Reset the timer1 to start counting from zero
}
long setSoftPwmDuty( float localDuty ){
dutyDiv100 = localDuty/100;
high_time = dutyDiv100 * PWM_PERIOD;
cMinusDuty = (100 - localDuty)/100;
low_time = cMinusDuty * PWM_PERIOD;
return high_time, low_time;
}
void main(void)
{
setup_timer_1(T1_INTERNAL|T1_DIV_BY_8); // Timer1 ticks every 1/48e-6 * 4 * 8 = 666.66ns
setup_ccp1(CCP_COMPARE_INT); // CCP1 setup to interrupt on compare
output_low(PWM_PIN); // Ensure pin starts in OFF state
clear_interrupt(INT_CCP1);
enable_interrupts(INT_CCP1);
enable_interrupts(GLOBAL);
set_timer1(0); // Ensure timer starts at zero
while(1)
{
for(int8 i = 1; i<20; i++){
setSoftPwmDuty(i*5);
delay_ms(100);
}//for
}//while(1)
return;
}//main())
|
Now the task is to implement a switch statement inside main() that will choose which pin is the PWM_PIN. Something akin to ...
Code: |
// #define PWM_PIN PIN_A6 // Comment this out from above code
int16 PWM_PIN; // Defined outside of main() as a global
//...within main, while(1) loop ... //
switch( toggleSwitch ){
case POSITION1:
PWM_PIN = PIN_A5;
break;
case POSITION2:
PWM_PIN = PIN_E0;
break;
case POSITION3:
PWM_PIN = PIN_E1;
break;
}
|
The error I am getting back from the compiler says:
\main.c:381:21: Error#27 Expression must evaluate to a constant ::
\main.c:385:5: Error#51 A numeric expression must appear here
flagged on the line input_state(PWM_PIN) within the ISR.
Either the ISR or the compiler doesn't like the fact that PWM_PIN is a variable. Is there a way to get around this error and be able to pass in a dynamic PWM_PIN for use in the ISR? |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9229 Location: Greensville,Ontario
|
|
Posted: Fri Jan 27, 2017 4:23 pm |
|
|
Yes, a globally declared variable can be acessed within an ISR.
According to the manual I have , the function "input_state(pin)", pin HAS to be a PIN not a variable.
That would explain the error you've got.
Jay |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri Jan 27, 2017 4:25 pm |
|
|
It appears that input_state() will not accept a variable for the parameter.
But output_low() and output_high() do. That looks like an oversight
by CCS and they probably should be told of it.
There is a work-around. You can substitute the read_bit_var() macro
as shown below. But keep in mind that if you use variables for the pin
functions, it generates a massive amount of ASM code in the .LST file.
It will be slow. It's better to have a global index, and set that in your
main(), then have a switch-case or if-else structure in the isr to select
the correct block of code to use. The pin functions with constant
parameters are quite compact.
Code: | #include <18F46J50.h>
#fuses HS, NOWDT
#use delay(clock=4M)
// This macro will read a Port pin. Give it a parameter
// such as PIN_A1, PIN_B0, PIN_C5, etc.
#define read_bit_var(x) bit_test(*(int8 *)(x >> 3), x & 7)
int16 PWM_PIN;
#int_ccp1
void ccp1_isr(void)
{
int8 temp;
temp = read_bit_var(PWM_PIN); // Use instead of input_state()
output_high(PWM_PIN);
output_low(PWM_PIN);
}
//========================================
void main(void)
{
PWM_PIN = PIN_A5;
while(TRUE);
}
|
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19520
|
|
Posted: Sat Jan 28, 2017 2:02 am |
|
|
However in fact the code will be much tidier just using a toggle.
So:
Code: |
#int_ccp1
void ccp1_isr( void )
{
static int1 toggle=FALSE;
if (toggle)
{
set_compare_time(1, high_time); // .. and change timer to time the low state
output_high(PWM_PIN); // Set the pin high ...
toggle=FALSE;
}
else
{
set_compare_time(1, low_time); // .. change timer to now time the high state
output_low(PWM_PIN); // Set the pin low...
toggle=TRUE;
}
//see comment below
//set_timer1(0); // Reset the timer1 to start counting from zero
}
|
As a comment, use the CCP in 'special event trigger' mode (CCP_COMPARE_RESET_TIMER). You can then get rid of the timer reset in the handler, and timings will be more accurate. This still triggers the CCPIF.
Since the pin I/O will be quite slow with a programmable pin, I've put it after the timer reset.
Use FAST_IO for the port with the PWM pin. This reduces the amount of code for a programmable pin very significantly.
At this point it depends on just how many pins you want to involve?. For perhaps four pins or less, it'll be smaller and faster to just branch in the ISR to routines for the required pins.
Remember if you change the pin number in the code, you should probably as the next instruction set the old pin 'low', otherwise if it was 'on' at the moment you make the change, it'll stay on.... |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|