View previous topic :: View next topic |
Author |
Message |
bschriek
Joined: 18 Dec 2007 Posts: 80
|
12F1822 Simple Interrupt_On_change does not work |
Posted: Mon Nov 21, 2011 7:11 am |
|
|
Simple program to test/simulate an Interrupt on change at RA3.
IOCAP & IOCAN registers work fine, IOCAF is always zero.
IDE, PCB and PCM version 4.127 (latest).
Remark, this is just a stupid test-program and does nothing.
How do I manage to increase the counter variable by PortA?
Code: |
#include <12F1822.H>
#Device ADC=10
#FUSES INTRC_IO, NOMCLR, CPD,PROTECT, NOWDT, BROWNOUT, PUT
#use delay(clock=16000000)
#use fast_io(A)
#bit RXDTSEL = 0x11D.7
#bit SDOSEL = 0x11D.6
#bit SSSEL = 0x11D.5
#bit T1GSEL = 0x11D.3
#bit TXCKSEL = 0x11D.2
#bit P1BSEL = 0x11D.1
#bit CCP1SEL = 0x11D.0
//#define POTM PIN_A0 //pin7 analoog input
#define LED PIN_A1 //pin6 digital output
#define PWM PIN_A2 //pin5 PWM output
#define PPM PIN_A3 //pin4 digital input 1K pull-up external
//#define LDR PIN_A4 //pin3 analoog input
#define PIR PIN_A5 //pin2 digital input 10K pull-up external
int counter=0;
long loop_counter=0;
#INT_RA
void ra_isr()
{
counter = counter+1;
}
//====================================
void main()
{
setup_oscillator(OSC_16MHZ);
setup_comparator(NC_NC);
setup_adc_ports(sAN0|sAN3||VSS_VDD);
setup_adc(ADC_CLOCK_DIV_8); // Built-in A/D setup function TAD
setup_timer_0 (RTCC_INTERNAL|RTCC_DIV_256); //
set_timer0 (0);
setup_timer_1(T1_INTERNAL|T1_DIV_BY_1); //
setup_timer_2(T2_DIV_BY_1, 127, 1); // 31.2kHz
setup_ccp1(CCP_PWM); // Configure CCP1 as a PWM
set_tris_a (0x39); // 111001 (0=output) 5 4 3 2 1 0
PORT_a_PULLUPS(0x00); // 000000 (1=enabled) 5 4 3 2 1 0
enable_interrupts (INT_RA3);
enable_interrupts (GLOBAL);
RXDTSEL = 0;
SDOSEL = 0;
SSSEL = 0;
T1GSEL = 1;
TXCKSEL = 0;
P1BSEL = 0;
CCP1SEL = 0;
while (1)
{
////////////////////////////////////////////////////////////////////////////////
output_low (LED);
loop_counter=0;
while (loop_counter<=7600)
{
loop_counter=loop_counter+1; //Vertraging van 25mSec
}
//////
output_high (LED);
loop_counter=0;
while (loop_counter<=7600)
{
loop_counter=loop_counter+1; //Vertraging van 25mSec
}
set_pwm1_duty (64);
}
} |
|
|
|
RF_Developer
Joined: 07 Feb 2011 Posts: 839
|
|
Posted: Mon Nov 21, 2011 7:57 am |
|
|
In all interrupt service routines (isr) you must clear the source of the interrupt. In this case you must read port a in ra_isr().
RF Developer |
|
|
bschriek
Joined: 18 Dec 2007 Posts: 80
|
|
Posted: Mon Nov 21, 2011 8:41 am |
|
|
I know, to reset the isr I must read the port but the reset of the interrupt is not the problem.
The real problem is the IOCAF register is always zero, so the program does NEVER reach the interrupt. So again the problem is not to leave the interrupt but to GO TO the interrupt.
I only simulated this program with MPlab and the Asynchronous PIN simulus but for hours. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Nov 21, 2011 5:35 pm |
|
|
I was able to make it work in hardware. I used compiler vs. 4.127 with a
Microchip "low pin count" board. I have Pin A1 jumpered over to one of
the LEDs on the board. When I press the push-button switch, the LED
toggles. I supply +5v power to the board from a bench power supply.
The ICD3 doesn't power the board.
Code: |
#include <12F1822.H>
#fuses INTRC_IO, NOWDT, BROWNOUT, PUT, NOMCLR
#use delay(clock=4M)
#define LED_PIN PIN_A1
#byte IOCAF = getenv("SFR:IOCAF")
#define clear_IOCA_flags() IOCAF = 0
#int_ra
void ra_isr(void)
{
output_toggle(LED_PIN);
delay_ms(10); // Debounce delay for testing purposes
clear_IOCA_flags(); // Clear flags after the debounce delay
}
//==========================================
void main()
{
output_low(LED_PIN); // Initialize LED to "Off".
port_a_pullups(0x08); // Enable pull-up on pin A3
clear_interrupt(INT_RA); // Clear any existing interrupt condition
clear_IOCA_flags(); // Clear any existing "change" condition
enable_interrupts(INT_RA3_L2H); // Interrupt when button is released
enable_interrupts(GLOBAL);
while(1);
} |
|
|
|
bschriek
Joined: 18 Dec 2007 Posts: 80
|
Hardware OK, simulation fails |
Posted: Tue Nov 22, 2011 3:46 am |
|
|
Thank you pcm programmer.
The hardware works but the simulation with MPlab does NOT work.
We learned from the past to simulate first with MPlab because the registers of the WATCH window will inform you in an early stage about possible bugs of the CCS compiler. Due to manual bit settings most of the time we were able to make the program working until now.
I only got 1 warning left nr: 225 and it informs about a Duplicate define.
Best regards,
Bas |
|
|
norman_tan
Joined: 30 Jan 2008 Posts: 27
|
INT_TIMER1 will disable INT_RA function in PIC12F1822? |
Posted: Sat Oct 19, 2019 1:47 am |
|
|
Dear PCM programmer,
I read your codes here and change pin_RA3 to pin_RA2, it also works well, very good.
And I add codes of INT_TIMER1(it also works well without enable INT_RA), then I find INT_RA does not work at all now!
Codes as below:
Code: |
#include <12F1822.H>
#fuses INTRC_IO, NOWDT, BROWNOUT, PUT, NOMCLR
#use delay(clock=8M)
#define LED_PIN PIN_A1
#define Launch_ON output_high(PIN_A5) // For Laser tube control
#define Launch_OFF output_low(PIN_A5) // For Laser tube control
#byte IOCAF = getenv("SFR:IOCAF")
#define clear_IOCA_flags() IOCAF = 0
unsigned char pulse_counter = 0; // record counting for LS led control in Timer1 interrupt
#int_ra
void ra_isr(void)
{
output_high(LED_PIN);
delay_ms(10); // Debounce delay for testing purposes
clear_IOCA_flags(); // Clear flags after the debounce delay
output_low(LED_PIN);
}
[color=red]
#INT_TIMER1
void clock1_isr()
{
pulse_counter++;
// codes below will generate pulse with period 115uS(_||______) as:
// 31us high and 84us low with setup_oscillator(OSC_8MHZ);
if(pulse_counter == 1) Launch_ON;
else if(pulse_counter == 2) Launch_OFF;
else if(pulse_counter >= 4) pulse_counter = 0;
set_timer1(0xFFFE); // 31uS/115uS
}[/color]
//==========================================
void main()
{
output_low(LED_PIN); // Initialize LED to "Off".
port_a_pullups(0x04); // Enable pull-up on pin A2
clear_interrupt(INT_RA); // Clear any existing interrupt condition
clear_IOCA_flags(); // Clear any existing "change" condition
enable_interrupts(INT_RA2_L2H); // Interrupt when button is released
[color=red]set_timer1(0xFFFE); //
setup_timer_1(T1_INTERNAL|T1_DIV_BY_1);
enable_interrupts(INT_TIMER1); // used for pulse generation[/color]
enable_interrupts(GLOBAL);
while(1);
}
|
And I also found I/O function input(PIN_A2) fails too if INT_TIMER1 used.
Would you please teach me how to solve this problem? |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
Re: INT_TIMER1 will disable INT_RA function in PIC12F1822? |
Posted: Sat Oct 19, 2019 2:48 am |
|
|
norman_tan wrote: |
And I add codes of INT_TIMER1 (it also works well without enable
INT_RA), then I find INT_RA does not work at all now!
#INT_TIMER1
void clock1_isr()
{
pulse_counter++;
// codes below will generate pulse with period 115uS(_||______) as:
// 31us high and 84us low with setup_oscillator(OSC_8MHZ);
if(pulse_counter == 1) Launch_ON;
else if(pulse_counter == 2) Launch_OFF;
else if(pulse_counter >= 4) pulse_counter = 0;
set_timer1(0xFFFE); // 31uS/115uS
}
//==========================================
void main()
{
output_low(LED_PIN); // Initialize LED to "Off".
port_a_pullups(0x04); // Enable pull-up on pin A2
clear_interrupt(INT_RA); // Clear any existing interrupt condition
clear_IOCA_flags(); // Clear any existing "change" condition
enable_interrupts(INT_RA2_L2H); // Interrupt when button is released
set_timer1(0xFFFE);
setup_timer_1(T1_INTERNAL|T1_DIV_BY_1);
enable_interrupts(INT_TIMER1); // used for pulse generation[/color]
enable_interrupts(GLOBAL);
while(1);
}
|
Your Timer1 reload value of 0xFFFE is way too small, in terms of time.
It's only two instruction cycles before it rolls over to 0x0000 and causes
an interrupt. With Fosc = 8 MHz, the instruction clock is 2 MHz. Each
instruction clock is 1/2 usec. So two clocks is 1 usec. That's your
interrupt rate.
By counting instructions in the .LST file, I calculate that the shortest
path through your Timer1 isr and through the compiler's interrupt handler
code will take about 27 usec. You can't interrupt every 1 usec, and then
take 27 usec (minimum) to process it. Your program will continuously
process the interrupt and them immediately jump right back into it.
There will be no processor time left to run the main program or anything
else. The net effect is that your program will appear to be locked up.
You need to substantially increase the time between Timer1 interrupts. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19518
|
|
Posted: Sat Oct 19, 2019 4:41 am |
|
|
As a comment, if you want to toggle a pin at that sort of speed, this can be
done using the PWM on pin A2 or A5. |
|
|
norman_tan
Joined: 30 Jan 2008 Posts: 27
|
|
Posted: Sat Oct 19, 2019 8:11 pm |
|
|
Dear PCM Programmer and Ttelmah,
Thanks for your kindly reply!
According to advice from email of CCS support, I added command line "if(bit_test(input_a(),2))" in codes, it works well now.
but I will try to change the value in set_timer1(0xFFFE) to get a better pulse too. As said by PCM Programmer, "0xFFFE" will cause interrupt too frequently, hehe.
I also want to try the PWM from RA5, it is the first time I use this small chip, I am not familiar to some functions of it , I will try them.
Thanks again! |
|
|
norman_tan
Joined: 30 Jan 2008 Posts: 27
|
|
|
norman_tan
Joined: 30 Jan 2008 Posts: 27
|
|
Posted: Sat Oct 19, 2019 9:09 pm |
|
|
Dear PCM Programmer and Ttelmah,
Additional remarks as below:
When I changed "setup_ccp1(CCP_PWM); " to "setup_ccp1(CCP_PWM|CCP1_A5); ", PWM generated on RA5 now, it works!
Thanks! |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19518
|
|
Posted: Sat Oct 19, 2019 10:52 pm |
|
|
Well done. This is where reading what the .h file actually says helps.
Some things are 'single' values, while others need to be ored together
like this. |
|
|
norman_tan
Joined: 30 Jan 2008 Posts: 27
|
|
Posted: Sun Dec 01, 2019 7:34 pm |
|
|
Dear PCM Programmer and Ttelmah,
I am very regret that I met an issue as below,
pulse width on PA5 changed to unnormal 19us(interrupt happens on PA2) form normal 9us(no interrupt on PA2)!!!!
and I don't know how to solve it
All codes I attach here:
Code: | #define Launch_ON output_high(PIN_A5) // For Laser tube control
#define Launch_OFF output_low(PIN_A5) // For Laser tube control
#bit IOCAF_2 = getenv("SFR:IOCAF").2
#define clear_IOCA_2_flags() IOCAF_2 = 0
#int_ra
void ra_isr(void)
{
clear_IOCA_2_flags(); // Clear flag of PA2
}
void main()
{
Initialization();
while(TRUE)
{
// pulse width on PA5 is 9.2us
Launch_ON;
delay_us(8);
Launch_OFF;
delay_us(450);
}
}
void Initialization(void)
{
setup_oscillator(OSC_16MHZ); // Set the internal oscillator to 16MHz
SET_TRIS_A(0x0C); // 00 1100: Set A5, A4, A1, A0 as output, A3, A2 as input
port_a_pullups(0x0C); // Enable pull-up on pin A2
SETUP_ADC_PORTS(NO_ANALOGS);
// set INT-RA interrupt
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
clear_interrupt(INT_RA2); // Clear any existing interrupt condition
clear_IOCA_2_flags(); // Clear any existing "change" condition
enable_interrupts(INT_RA2_L2H); // Interrupt when button is released
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
enable_interrupts(global); // Enabled all interruptions.
} |
|
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sun Dec 01, 2019 8:41 pm |
|
|
If you don't want the 9us pulse to be lengthened by an interrupt occurring
during the pulse, then disable interrupts during the pulse. Example:
Quote: | while(TRUE)
{
disable_interrupts(GLOBAL);
Launch_ON;
delay_us(8);
Launch_OFF;
enable_interrupts(GLOBAL);
delay_us(450);
}
|
If you do it as shown above, then the 450us pulse low time could become 459us
if the interrupt occurs. |
|
|
norman_tan
Joined: 30 Jan 2008 Posts: 27
|
|
Posted: Sun Dec 01, 2019 9:05 pm |
|
|
but, I shoud give a fixed period pulse with on PA5, and interrput happens only in the period of PA5 is high
Launch_ON;
delay_us(8);
Launch_OFF; |
|
|
|