Simulating it, it was in an endless interrupt loop because of this:
INTCONbits.INTE = 1;
OPTION_REGbits.INTEDG = 0;
INTCONbits.RBIE = 1;
Either INT or RBIE interrupts were firing, but flags not cleared.
You shouldn't enable interrupts you're not managing!
When initializing follow this order:
- Init peripherals, pins
- Enable peripheral interrupts, clear flags
- Enable GIE/ PEIE.
Not at the beginning like you're doing! This can cause unexpected behaviour, interrupts firing while writing to the registers, etc.
Adding decimals is a bad idea! Might get you into trouble, rounded to 0 by the compiler, or adding heavy float libraries into the system.
The formula is also wrong.
unsigned int PR1 = (0.001 * 8000000) / (4 * 8);
Timer1 doesn't auto-reload. It just counts up, lacking compare match.
So you must always reload the counter value within the ISR, stopping the timer first as this is not an atomic operation.
Then it'll keep counting up until 0xFFFF, overflowing to 0 and triggering next ISR.
So for calculating the period, the correct formula is:
0xFFFF - (8000000/(4*8*1000))
But as it adds the delay from the interrupt until the manual reload, the final timebase becomes larger, about 1.02ms.
We can compensate for this by slighly increasing the default preload, so the timer overflows earlier:
#define PR1 ((unsigned int)0xFFFF - (unsigned int)(8000000/(4*8*1000)) + 5) /* +5 for calibrating reload delay, etc */
This gives between 1.000ms and 0.9995ms (500ns variation = 1 cpu clock). This can be tweaker further by adding few NOP().
This was wrong too:.
You're ANDing with pb_last, while you should do it with pb_now to detect which button was just pressed.
unsigned char pb_changed = (pb_last ^ pb_now) & pb_last;
Fix:
unsigned char pb_changed = (pb_last ^ pb_now) & pb_now;
Also: Learn to properly make interrupts. You shouldn't call any slow process inside them, and LCD commands are very slow!
Instead, use flags. Set them in the interrupt, process them in the main program.
Try this:
#define PR1 ((unsigned int)0xFFFF - (unsigned int)(8000000/(4*8*1000)) + 5) /* +5 for calibrating reload delay, etc */
volatile unsigned char press_RB1, press_RB2, long_press_RB1, long_press_RB2;
void main(void)
{
OSCCON = 0x70;
ANSEL = 0b0000000;
ANSELH = 0b0000000;
TRISA = 0x0;
TRISC = 0x0;
PORTA = 0x0;
PORTC = 0x0;
TRISBbits.TRISB0 = 1;
TRISBbits.TRISB1 = 1;
TRISBbits.TRISB2 = 1;
TRISCbits.TRISC0 = 0;
TMR1H = PR1 >> 8;
TMR1L = PR1 & 0xFF;
T1CONbits.TMR1CS = 0;
T1CONbits.T1CKPS = 0b11;
T1CONbits.TMR1ON = 1;
PIE1bits.TMR1IE = 1;
INTCONbits.GIE = 1;
INTCONbits.PEIE = 1;
while(1)
{
if(press_RB1)
{
press_RB1 = 0;
Lcd_Goto(1,1);
Lcd_Print("Button RB1 pressed");
}
if(press_RB2)
{
press_RB2 = 0;
Lcd_Goto(1,1);
Lcd_Print("Button RB2 pressed");
}
if(long_press_RB1)
{
long_press_RB1 = 0;
Lcd_Goto(1,1);
Lcd_Print("Button RB1 L_pressed");
}
if(long_press_RB2)
{
long_press_RB2 = 0;
Lcd_Goto(1,1);
Lcd_Print("Button RB2 L_pressed");
}
// displaying menu, etc. code here
}
}
void __interrupt() isr(void) {
if(PIR1bits.TMR1IF)
{
static unsigned int RB1_count, RB2_count;
static unsigned char pb_last;
unsigned char pb_now = PORTB;
unsigned char pb_changed = (pb_last ^ pb_now) & pb_now;
pb_last = pb_now;
T1CONbits.TMR1ON = 0;
TMR1H = PR1 >> 8; /* Preload timer */
TMR1L = PR1 & 0xFF;
NOP(); /* For best calibration of 1ms */
T1CONbits.TMR1ON = 1;
PIR1bits.TMR1IF = 0; /* Reset flag */
/********************************************************************************************/
/* Instant press actions */
/********************************************************************************************/
if (pb_changed & 0b10) /* RB1 pressed */
{
RB1_count = 1; /* Start RB1 counter */
press_RB1 = 1;
}
else if(!(pb_last & 0b10)) /* Not pressed */
{
RB1_count = 0; /* Disable RB1 counter */
}
if (pb_changed & 0b100) /* RB2 pressed */
{
RB2_count = 1; /* Start RB2 counter */
press_RB2 = 1;
}
else if(!(pb_last & 0b100)) /* Not pressed */
{
RB2_count = 0; /* Disable RB2 counter */
}
/********************************************************************************************/
/* Long press actions */
/********************************************************************************************/
if (RB1_count && ++RB1_count>1000) /* RB1 counter enabled, increase, if higher than 1000ms */
{
RB1_count = 0; /* Disable counter */
long_press_RB1 = 1;
}
if (RB2_count && ++RB2_count>1000) /* RB2 counter enabled, increase, if higher than 1000ms */
{
RB2_count = 0; /* Disable counter */
long_press_RB2 = 1;
}
}
}