 |
 |
View previous topic :: View next topic |
Author |
Message |
Zeppo
Joined: 25 Sep 2025 Posts: 4
|
IOC Port A works fine, but Port B and C don't fire |
Posted: Thu Sep 25, 2025 11:10 pm |
|
|
In this code, interrupts from pins A work perfectly, but pins B and C do never fire an Interrupt. Any idea? We need many IOs which is why we use 16F15276. The input pushbuttons work fine; they can be polled for low/high. Compiler is 5.119.
Code: | #include <16F15276.h>
#use delay(internal=8MHz)
#use rs232(UART1,baud=115200,xmit=PIN_C7,rcv=PIN_C6,bits=8,stream=PORT1)
byte a_new;
byte a_old;
byte b_new;
byte b_old;
byte c_new;
byte c_old;
#INT_RA
void RA_isr(void) {
a_new=input_a();
putc('a');
}
#INT_RB
void RB_isr(void) {
b_new=input_b();
putc('b');
}
#INT_RC
void RC_isr(void) {
putc('c');
c_new=input_c();
}
void main() {
disable_interrupts(GLOBAL);
setup_uart(115200);
printf("\nStart\n");
port_a_pullups(0xFF);
port_b_pullups(0xFF);
port_c_pullups(0xFF);
// 8 pushbuttons at PIN_A0:PIN_A7
a_old=0xFF; // K_FF|K_REC|K_REW|K_MODE|K_PLAY|K3|VOL_A|K_SEL;
a_new=a_old;
set_tris_a(a_old);
// 4 pushbuttons at PIN_B2, PIN_B4, PIN_B5, PIN_B6
b_old=0x74; //SD_EXT_CD|K4|K5|ENC_C_ICLK;
b_new=b_old;
set_tris_b(b_old);
// 3 pushbuttons at PIN_C1, PIN_C4, PIN_C5
c_old=0x32; //VOL_B|K2|K1;
c_new=c_old;
set_tris_c(c_old);
clear_interrupt(INT_RA); // Clear IOC flag bit
clear_interrupt(INT_RB); // Clear IOC flag bit
clear_interrupt(INT_RC); // Clear IOC flag bit
enable_interrupts(INT_RA); // Enable IOC
enable_interrupts(INT_RB); // Enable IOC
enable_interrupts(INT_RC); // Enable IOC
enable_interrupts(GLOBAL); // Enable global interrupts
printf("Enter while\n");
while(TRUE){
// Check for key changes that were captured by interrupts:
if(a_new!=a_old) {
printf("go a ");
a_old=a_new;
}
if(b_new!=b_old) {
printf("go b ");
b_old=b_new;
}
if(c_new!=c_old) {
printf("go c ");
c_old=c_new;
}
}
}
|
|
|
 |
gaugeguy
Joined: 05 Apr 2011 Posts: 345
|
|
Posted: Fri Sep 26, 2025 6:28 am |
|
|
You should disable the analog inputs so the digital input buffers can work properly. |
|
 |
Zeppo
Joined: 25 Sep 2025 Posts: 4
|
|
Posted: Fri Sep 26, 2025 7:54 am |
|
|
How to disable the analog inputs? I added this:
set_adc_channel(NO_ANALOGS);
#byte ANSELA = 0x1F38
ANSELA=0;
#byte ANSELB = 0x1F43
ANSELB=0;
#byte ANSELC = 0x1F4e
ANSELC=0;
#byte ANSELD = 0x1F59
ANSELD=0;
#byte ANSELE = 0x1F64
ANSELE=0;
..but it did not change a thing. Still no IOC from Port B or Port C.
By the way, is there an "official" way in the CCS Compiler to disable the analog inputs? In the above code, I looked up the registers manually.
Last edited by Zeppo on Fri Sep 26, 2025 7:57 am; edited 1 time in total |
|
 |
Zeppo
Joined: 25 Sep 2025 Posts: 4
|
|
Posted: Fri Sep 26, 2025 7:56 am |
|
|
Also tried the according Peripheral Enable Interrupt pins, but no change:
#byte INTCON = 0x00B
#bit PEIE = INTCON.6
PEIE = 1;
#byte PIE0 = 0x716
#bit IOCIE = PIE0.4
IOCIE = 1; |
|
 |
Ttelmah
Joined: 11 Mar 2010 Posts: 19951
|
|
Posted: Fri Sep 26, 2025 10:44 am |
|
|
You are being misled by thinking there is a simple IOC. The IOC on these
later chips has individually programmable edges, and masks. Now you are
using the old syntax for your settings, which is designed to give the same
result as on older chips without the masks. on PortA, this defaults to setting
these for A0 to A5, but on portB, only B4 to B7 are enabled. Similarly on
Port C it is C4 to C7 that enable. Look at the manual entry for these.
You can override this by ORing together the edged and bit you want from
the table of IOC enables, or by directly setting the control registers for what
you want.
For the analogs, just use set_analog_pins(NO_ANALOGS); |
|
 |
Zeppo
Joined: 25 Sep 2025 Posts: 4
|
|
Posted: Mon Sep 29, 2025 4:17 am |
|
|
Thanks everyone - I got it working. The full code is copied below.
Important is to NOT use the #INT_RA directives (or #INT_RB, etcetera), but the #INT_IOC. It is a bit unfortunate that the #INT_RA directives are inserted by the CCS environment without further notice or warning. I became suspicious about them when looking at the assembler listing, when it becomes clear that the system does not differentiate between INT_RA, INT_RB or INT_RC at all: Code: | .................... enable_interrupts(INT_RA); // Enable IOC
0168: BSF 16.4
0169: MOVLW FF
016A: MOVLB 3E
016B: IORWF 3D,F
016C: IORWF 3E,F
.................... enable_interrupts(INT_RB); // Enable IOC
016D: MOVLB 0E
016E: BSF 16.4
016F: MOVLB 3E
0170: IORWF 3D,F
0171: IORWF 3E,F
.................... enable_interrupts(INT_RC); // Enable IOC
0172: MOVLB 0E
0173: BSF 16.4
0174: MOVLB 3E
0175: IORWF 3D,F
0176: IORWF 3E,F | A clear hint is given in the included 16F15276.h file of the chip: Code: | // Constants used in ENABLE/DISABLE_INTERRUPTS() are:
#define GLOBAL 0x0BC0
#define PERIPH 0x0B40
#define INT_EXT_L2H 0x50001601
#define INT_EXT_H2L 0x60001601
#define INT_EXT 0x301601
#define INT_TIMER0 0x301620
#define INT_AD 0x301701
#define INT_SSP 0x301702
#define INT_BUSCOL 0x301704
#define INT_TBE 0x301708
#define INT_RDA 0x301710
#define INT_TIMER1 0x301720
#define INT_TIMER2 0x301740
#define INT_CCP1 0x301780
#define INT_TIMER1_GATE 0x301820
#define INT_NVM 0x301840
#define INT_CCP2 0x301880
#define INT_IOC 0x3FFF1610
#define INT_IOC_A0 0x30011610
#define INT_IOC_A0_L2H 0x10011610
#define INT_IOC_A0_H2L 0x20011610
#define INT_IOC_A1 0x30021610
#define INT_IOC_A1_L2H 0x10021610
| ...and so on. And further below: Code: | //The following defines are provided for compatibility with older compiler versions
//INT_IOC define should be used to create Interrupt on Change ISR, and the INT_IOC_xx,
//INT_IOC_xx_L2H and INT_IOC_xx_H2L defines should be used in the ENABLE_INTERRUPTS(),
//DISABLE_INTERRUPTS(), CLEAR_INTERRUPT(), INTERRUPT_ACTIVE() and INTERRUPT_ACTIVE()
//function calls.
#define INT_RA 0x30FF1610
#define INT_RA0 0x30011610
#define INT_RA0_L2H 0x10011610
#define INT_RA0_H2L 0x20011610
#define INT_RA1 0x30021610
#define INT_RA1_L2H 0x10021610
#define INT_RA1_H2L 0x20021610
#define INT_RA2 | ...and so on.
Ttelmah wrote: | For the analogs, just use set_analog_pins(NO_ANALOGS); | Thank you, this one worked just fine.
Full working code: Code: | #include <16F15276.h>
#use delay(internal=8MHz)
#use rs232(UART1,baud=115200,xmit=PIN_C7,rcv=PIN_C6,bits=8,stream=PORT1)
byte a_new;
byte a_old;
byte b_new;
byte b_old;
byte c_new;
byte c_old;
#INT_IOC
void ioc_isr(void) {
a_new=input_a();
b_new=input_b();
c_new=input_c();
}
void main() {
disable_interrupts(GLOBAL);
setup_uart(115200);
printf("\nStart\n");
port_a_pullups(0xFF);
port_b_pullups(0xFF);
port_c_pullups(0xFF);
set_adc_channel(NO_ANALOGS);
// 8 pushbuttons at PIN_A0:PIN_A7
a_old=0xFF; // K_FF|K_REC|K_REW|K_MODE|K_PLAY|K3|VOL_A|K_SEL;
a_new=a_old;
set_tris_a(a_old);
// 4 pushbuttons at PIN_B2, PIN_B4, PIN_B5, PIN_B6
b_old=0x74; //SD_EXT_CD|K4|K5|ENC_C_ICLK;
b_new=b_old;
set_tris_b(b_old);
// 3 pushbuttons at PIN_C1, PIN_C4, PIN_C5
c_old=0x32; //VOL_B|K2|K1;
c_new=c_old;
set_tris_c(c_old);
clear_interrupt(INT_IOC); // Clear IOC flag bit
enable_interrupts(INT_IOC); // Enable IOC
enable_interrupts(GLOBAL); // Enable global interrupts
printf("Enter while\n");
long int q=0;
while(TRUE){
q++;
// Show heart beat to indicate the thing is still alive:
if(q%3000==0) {
putc('.');
}
// Check for key changes that were captured by interrupts:
if(a_new!=a_old) {
printf("go a ");
a_old=a_new;
}
if(b_new!=b_old) {
printf("go b ");
b_old=b_new;
}
if(c_new!=c_old) {
printf("go c ");
c_old=c_new;
}
}
}
|
|
|
 |
|
|
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
|