View previous topic :: View next topic |
Author |
Message |
ChicoCyber
Joined: 09 May 2020 Posts: 7
|
Port change interrupt mask (12F675) |
Posted: Sat May 09, 2020 6:11 pm |
|
|
Hello.
I'm trying to read 2 buttons with the port change interrupt with the PIC 12F675, but it is triggering with any pin change (INT_RA), which is expected. I have checked the datasheet, it says about REGISTER 3-4: IOC, which looks like is what I need, but how can I access it with the CCS?
Also I have found in the CCS the INT_RAx, which the x is the pin number, which triggers the interrupt also, but just one pin, I need two.
I believe this is simple to solve, it just lack of my knowledge.
Thank you very much. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sat May 09, 2020 6:47 pm |
|
|
The program below shows how to enable the IOC interrupts. You will have
to add your user code in the interrupt routine:
Code: |
#include <12F675.h>
#use delay(clock=4M)
#byte PORTA = getenv("SFR:PORTA")
#INT_RA
void int_ra_isr(void)
{
int8 temp;
// Read port pins to clear mismatch condition.
temp = PORTA;
}
//======================
void main()
{
port_a_pullups(0b00011000); // Enable weak pullups on RA3, RA4
delay_us(10); // Allow time for them to pull up
enable_interrupts(INT_RA3); // Set IOC register, bit 3 = 1
enable_interrupts(INT_RA4); // Set IOC register, bit 4 = 1
clear_interrupt(INT_RA); // Clear any existing IOC interrupts
enable_interrupts(GLOBAL);
while(TRUE);
}
|
Look at this CCS example file, which shows how to detect a specific edge
on a specific pin, inside the interrupt routine code:
Quote: | c:\...\picc\examples\ex_pbutt.c |
|
|
|
ChicoCyber
Joined: 09 May 2020 Posts: 7
|
|
Posted: Sat May 09, 2020 7:27 pm |
|
|
NICE! Thank you very much!
I was trying like this, but not worked, I would like very much to understand why.
Code: |
#include <main.h>
#USE FAST_IO (A)
#byte WPU = 0x95 //Pullups 1=ativado
#bit GPPU = 0x81.7 //Pullups global 0=seleção individual
#byte IOC = 0x96 //Port on change mask (1=Enabled)
#INT_RA
void RA_isr(void)
{
clear_interrupt(INT_RA);
output_toggle(PIN_A5);
delay_ms(100);
}
void main()
{
set_tris_a(0b11011111); //0=saída 1=entrada
WPU = 0b00000000; //Pullups 0=ativado 1=desativado
GPPU = 0; //Global Pullups 0=seleção individual pelo WPU
IOC = 0b00010100; //Port on change mask (1=Enabled)
enable_interrupts(INT_RA);
enable_interrupts(GLOBAL);
while(TRUE) {}
}
|
|
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sat May 09, 2020 7:56 pm |
|
|
Your code doesn't read PortA inside the isr.
You have to read PortA to clear the mismatch condition latch.
The 12F675 datasheet says:
Quote: | The user, in the Interrupt Service Routine, can clear
the interrupt in the following manner:
a) Any read or write of GPIO. This will end the mismatch condition.
b) Clear the flag bit GPIF.
A mismatch condition will continue to set flag bit GPIF.
Reading GPIO will end the mismatch condition and
allow flag bit GPIF to be cleared.
|
Both (a) and (b) have to be done. The compiler handles item (b).
You have to do item (a) in the interrupt routine. I show how to read
PortA without affecting the TRIS bits in my sample code.
If you don't read the port, the mismatch latch will continue to cause
an interrupt. You'll get re-interrupted again, as soon as the code exits
the interrupt routine. The program will appear to be locked up.
So it's essential to read the port in the interrupt routine.
Note that my code also reads the port before enabling interrupts in main().
That way, you won't get an interrupt immediately upon enabling global
interrupts. A new change condition must occur to get your first IOC interrupt. |
|
|
ChicoCyber
Joined: 09 May 2020 Posts: 7
|
|
Posted: Sat May 09, 2020 8:30 pm |
|
|
Nice! I got it!
But here is what is happening:
Cant make it work with the IOC register, it is triggered constantly (it is just curiosity):
Code: |
#include <main.h>
#USE FAST_IO (A)
#byte WPU = 0x95 //Pullups 1=ativado
#bit GPPU = 0x81.7 //Pullups global 0=seleção individual
#byte IOC = 0x96 //Port on change mask (1=Enabled)
int8 Temp;
#INT_RA
void RA_isr(void)
{
Temp = input_a();
clear_interrupt(INT_RA);
output_toggle(PIN_A5);
delay_ms(100);
}
void main()
{
set_tris_a(0b11011111); //0=saída 1=entrada
WPU = 0b00000000; //Pullups 0=ativado 1=desativado
GPPU = 0; //Global Pullups 0=seleção individual pelo WPU
IOC = 0b00010100; //Port on change mask (1=Enabled)
Temp = input_a();
enable_interrupts(INT_RA);
enable_interrupts(GLOBAL);
while(TRUE)
{
//TODO: User Code
}
}
|
This works ok even without the 2 port reads:
Code: |
#include <main.h>
#USE FAST_IO (A)
#byte WPU = 0x95 //Pullups 1=ativado
#bit GPPU = 0x81.7 //Pullups global 0=seleção individual
int8 Temp;
#INT_RA
void RA_isr(void)
{
Temp = input_a();
clear_interrupt(INT_RA);
output_toggle(PIN_A5);
delay_ms(100);
}
void main()
{
set_tris_a(0b11011111); //0=saída 1=entrada
WPU = 0b00000000; //Pullups 0=ativado 1=desativado
GPPU = 0; //Global Pullups 0=seleção individual pelo WPU
Temp = input_a();
enable_interrupts(INT_RA2);
enable_interrupts(INT_RA4);
enable_interrupts(GLOBAL);
while(TRUE)
{
//TODO: User Code
}
}
|
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19504
|
|
Posted: Sun May 10, 2020 1:46 am |
|
|
Enabling INT_RA, without specifying any pin, automatically sets
all the bits in the IOC register 'on'. Overrides what you have already
written to this register....
In fact you can 'OR' combine multiple pins in one enable:
enable_interrupts(INT_RA2 | INT_RA4);
Potentially tidier. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sun May 10, 2020 2:33 am |
|
|
Your code is disabling the pull-up resistors.
The WPU comments below are wrong. You have it backwards.
ChicoCyber wrote: |
void main()
{
set_tris_a(0b11011111); //0=saída 1=entrada
WPU = 0b00000000; //Pullups 0=ativado 1=desativado
GPPU = 0; //Global Pullups 0=seleção individual pelo WPU
IOC = 0b00010100; //Port on change mask (1=Enabled)
Temp = input_a();
|
A logic '1' turns on each pull-up. The 12F675 datasheet says:
Quote: | REGISTER 3-3: WPU: WEAK PULL-UP REGISTER (ADDRESS: 95h)
bit 7-6 Unimplemented: Read as ‘0’
bit 5-4 WPU<5:4>: Weak Pull-up Register bit
1 = Pull-up enabled
0 = Pull-up disabled
bit 3 Unimplemented: Read as ‘0’
bit 2-0 WPU<2:0>: Weak Pull-up Register bit
1 = Pull-up enabled
0 = Pull-up disabled
|
|
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9225 Location: Greensville,Ontario
|
|
Posted: Sun May 10, 2020 4:45 am |
|
|
also...
CCS will(should) add the 'clear_interupt' automatically,so you don't need to ....
having delay_ms(100); inside the ISR is 'bad' programming.
ISRs are supposed to be short and fast. Set a few bits or bytes( flags) then exit. delays, prints and 'math' should be avoided within ISRs. |
|
|
ChicoCyber
Joined: 09 May 2020 Posts: 7
|
|
Posted: Sun May 10, 2020 4:42 pm |
|
|
Ttelmah wrote: | Enabling INT_RA, without specifying any pin, automatically sets
all the bits in the IOC register 'on'. Overrides what you have already
written to this register....
In fact you can 'OR' combine multiple pins in one enable:
enable_interrupts(INT_RA2 | INT_RA4);
Potentially tidier. |
This explains a lot! Thank you! |
|
|
ChicoCyber
Joined: 09 May 2020 Posts: 7
|
|
Posted: Sun May 10, 2020 4:44 pm |
|
|
PCM programmer wrote: | Your code is disabling the pull-up resistors.
The WPU comments below are wrong. You have it backwards.
ChicoCyber wrote: |
void main()
{
set_tris_a(0b11011111); //0=saída 1=entrada
WPU = 0b00000000; //Pullups 0=ativado 1=desativado
GPPU = 0; //Global Pullups 0=seleção individual pelo WPU
IOC = 0b00010100; //Port on change mask (1=Enabled)
Temp = input_a();
|
A logic '1' turns on each pull-up. The 12F675 datasheet says:
Quote: | REGISTER 3-3: WPU: WEAK PULL-UP REGISTER (ADDRESS: 95h)
bit 7-6 Unimplemented: Read as ‘0’
bit 5-4 WPU<5:4>: Weak Pull-up Register bit
1 = Pull-up enabled
0 = Pull-up disabled
bit 3 Unimplemented: Read as ‘0’
bit 2-0 WPU<2:0>: Weak Pull-up Register bit
1 = Pull-up enabled
0 = Pull-up disabled
|
|
I have noticed that soon as posted here, just writed the comment wrong.
Thank you for the advice :D |
|
|
ChicoCyber
Joined: 09 May 2020 Posts: 7
|
|
Posted: Sun May 10, 2020 4:48 pm |
|
|
temtronic wrote: | also...
CCS will(should) add the 'clear_interupt' automatically,so you don't need to ....
having delay_ms(100); inside the ISR is 'bad' programming.
ISRs are supposed to be short and fast. Set a few bits or bytes( flags) then exit. delays, prints and 'math' should be avoided within ISRs. |
Got it, thank you.
Actually what I need is very simple but as I'm not so used to program this it is getting very hard, I dont know very well how to join the interrupt things with the main code, or what to put each thing.
I just want to solve it quickly, even it is a little dirty.
I want to make a timer, one button starts and stops, another one sums +5 minutes.
After the time it beeps and turns off the device. |
|
|
|