2

I am working on a project with PIC16F877 (using MPLABX). I use RB0 pin external interrupt and RB4 pin portb interrupt to detect zero cross detection. I did everything correct, in proteus simulation everything was okey. Then I set up the circuit on breadboard, the LCD wasnt displaying the numbers (just the white dots). I thought the problem is the RB0 and PORTB interrupt. I wrote a simple code just includeshe PORTB interrupt and LCD and simulated. Everything is okey until the interrupt occures, when interrupt comes the code stops. I am new to PIC, this is the code I wrote:


/*
 * File:   lcd_deneme_16f877a.c
 * Author: BATUHAN
 *
 * Created on 28 Aral?k 2022 Çar?amba, 13:52
 */


#include <xc.h>
#include <stdio.h>
#include <stdint.h>
#pragma config FOSC = XT        // Oscillator Selection bits (HS oscillator)
#pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = ON       // Power-up Timer Enable bit (PWRT enabled)
#pragma config BOREN = OFF      // Brown-out Reset Enable bit (BOR disabled)
#pragma config LVP = OFF        // Low-Voltage (Single-Supply) In-Circuit Serial Programming Enable bit (RB3 is digital I/O, HV on MCLR must be used for programming)
#pragma config CPD = ON         // Data EEPROM Memory Code Protection bit (Data EEPROM code-protected)
#pragma config WRT = OFF        // Flash Program Memory Write Enable bits (Write protection off; all program memory may be written to by EECON control)
#pragma config CP = ON          // Flash Program Memory Code Protection bit (All program memory code-protected)
#define _XTAL_FREQ 4000000


void __interrupt() interrpt()
{
    if(INTF)
    {
        uint8_t dummy = PORTB; // Read PORTB to end mismatch condition
        INTF=0;
        RD0=RD0^1;
    }
    
    if(RBIF==1 && RB4==1)
    {
        uint8_t dummy = PORTB; // Read PORTB to end mismatch condition
        RBIF=0;
        RD0=RD0^1;
    }
    

}

void main(void) 
{
    
    TRISD=0X00;
    PORTD=0X00;
    TRISB=0b00010001;
    PORTB=0X00;
    
    INTCON=0b11011000;   // GIE PEIE TMR0IE INTE RBIE TMR0IF INTF RBIF
    OPTION_REGbits.nRBPU = 1;
    INTEDG=1;  
    
    int V=0;
    
    while(1)
    {
        
        V++;
        __delay_ms(200);
        
       
    }
    
    
    return;
}


I tried the PORTB and RB0 interrupts separately and the problem still occurs. What could be the problem. Thanks in advance

David Jones
  • 2,879
  • 2
  • 18
  • 23
El_Canario
  • 41
  • 3

2 Answers2

3

This is because your program stucks in interrupt routine due to the lack of proper handling of interrupts. You don't seem to handle the INT interrupt at all. For RB interrupt-on-change (IOC), you have to handle it sort of a little different and end the mismatch condition before clearing the flag. According to the PIC16F877A Datasheet this how the IOC works and must be handled:

Four of the PORTB pins, RB7:RB4, have an interrupt-on-change feature. Only pins configured as inputs can cause this interrupt to occur (i.e., any RB7:RB4 pin configured as an output is excluded from the interrupt-on-change comparison). The input pins (of RB7:RB4)are compared with the old value latched on the last read of PORTB. The “mismatch” outputs of RB7:RB4 are OR’ed together to generate the RB port change interrupt with flag bit RBIF (INTCON<0>). This interrupt can wake the device from Sleep. The user, in the Interrupt Service Routine, can clear the interrupt in the following manner:
a) Any read or write of PORTB. This will end the mismatch condition.
b) Clear flag bit RBIF.
A mismatch condition will continue to set flag bit RBIF. Reading PORTB will end the mismatch condition and allow flag bit RBIF to be cleared.

So your interrupt service code should look like the following:

void __interrupt() interrpt()
{
    if(RBIF && RB4)
    {
        volatile uint8_t dummy = PORTB; // Read PORTB to end mismatch condition
        RBIF=0;
        RD1=RD1^1;
    }
    else if(INTIF) {
        INTIF = 0;
        RD0 = !RD0; // Toggle D0 for INT interrupt
    }
}

A friendly reminder
The proteus simulation is ok for some cases. However the simulation runs in ideal conditions. That's why you may not get the same expected behaviour in the real world conditions compared to proteus' ideal simulation conditions.

Kozmotronik
  • 2,080
  • 3
  • 10
  • 25
  • Thanks for your reply. I rewrote the code including the portb reading in interrupt. The interrupt condition is if(RBIF==1 && RB4==1), the simulation works untill the interrupt occurs then stops, and it works only if I keep pushing the button (the button is connected pull up). When the interrupt condition is if(RBIF==1 && RB4==0) and the button is pull-up, the simulation works correct. But the button is pull-down connected, simulation is not working untill I push the button, then works if I keep pushing button. I couldn't make it work on board as well. – El_Canario Dec 30 '22 at 09:54
  • I also tried INTF(RB0) interrupt (including the portb read code) it works correct on simulation. But on board the code stucks whatever I do. I tried leaving the RB0 pin disconnected but nothing changes. How could I solve this problem. Could the connections on the breadboard be causing problems? – El_Canario Dec 30 '22 at 10:00
  • Can you please add a photo that shows your actual schematic? If you use INT interrupt for the button, what is the purpose of RBIF IOC interrupt? – Kozmotronik Dec 30 '22 at 10:45
  • < https://img.onl/bNCpti > My project is about power factor improvement. The goal is to measure phase shift between voltage and current on RB0 and RB4 pins using 2 different ext interrupt. On breadboard I realized the error then I tried buttons for external interrupts. – El_Canario Dec 30 '22 at 11:09
  • And how does the RBPU bit of OPTION_REG register is related to PORTB interrupts. Thanks for your interest – El_Canario Dec 30 '22 at 11:18
  • Humm I see, it seems that you use the internal pullups for PORTB inputs. `RBPU` bit is for enabling or disabling the PORTB pullups. If you wanna use external pulling resistors then you have to set it to 1 to disable the internal pullups. Well if you wanna use the internal pullups then you have to set it to 0 to enable, it is kinda negative logic. But also you should take into account that the idle states of both inputs will be logic high and handle them considering this state. Although for phase shift detection you could have use the CAPTURE module, but 877A has only 1. – Kozmotronik Dec 30 '22 at 11:37
  • BTW, have you modified your interrupt code in order to handle the `INT` interrupt? Can you add only the updated interrupt part of the latest code without changing the original code in your question? – Kozmotronik Dec 30 '22 at 11:44
  • void __interrupt() interrpt() { if(INTF) { uint8_t dummy = PORTB; // Read PORTB to end mismatch condition INTF=0; RD1=RD1^1; } } I still dont get it why the code stucks on breadboard. – El_Canario Dec 30 '22 at 11:56
  • Let's keep things simple @batuhan. Disable the internal pullups as I mentioned before and put 2 external pull-down resistors instead. This may keep things simpler and more suitable for this application since it is used positive logic. I meant you add code in your question not in comments. Do you know how to update your question? But I should say that your latest code still has problems. Remember that there are 2 interrupts enabled: `INT` and `IOC` you must handle the both in the interrupt service routine, but you still handle only 1 of them, that's why your program keeps getting stuck. – Kozmotronik Dec 30 '22 at 12:12
  • I updated the question. I disabled internal pullups. Now it is working on board. The IOC interrupt works fine when the button is connected pull-down. when connected to pull up the code stucks when interrupt occurs. INT interrupt is working correct in both cases. Where do I do wrong in code, I check flags and mismatch case. – El_Canario Dec 30 '22 at 12:57
  • @batuhan have a look at my updated code, just copy and paste it as is to replace only the interrupt code. Don't change anything on it. Then try it with pullups again. – Kozmotronik Dec 30 '22 at 13:09
  • I tried your code. RB0 interrupt is correct. but RB4 interrupt stucks the code. And I have a question: in the actual circuit that includes sinusoidal voltage and current source as RB0 and RB4 inputs, do I still have to disable internal pullups. – El_Canario Dec 30 '22 at 14:02
  • *RB4 interrupt stucks the code.* I think the problem here is the floating unused pins of PORTB. When you use IOC on RB<7:4> pins you set all those pins as input while you only need the RB0 and RB4. Other unused pins of IOC will have unstable input logic levels due to the floating state, resulting in false IOC interrupt triggering. To eliminate this condition you should either pullup or pulldown the floating inputs or set the unused IOC pins as output which are RB5, RB6 and RB7 in this case. Then let me know the results. – Kozmotronik Dec 30 '22 at 14:41
  • The pulling resistors are actually used to provide a stable logic current levels in the inputs to prevent false triggering in case of the pin connections are left floating. However if you can guarantee that the input source will never be unstable or floating, you wouldn't have to use pulling resistors at all. – Kozmotronik Dec 30 '22 at 14:52
  • I already thought it might cause the error and only set the relevant pins as inputs. TRISB= 0b00010001;. :( – El_Canario Dec 30 '22 at 14:53
1
void __interrupt() interrpt()
{
    if(RBIF)
    {
        PORTB; // Read PORTB to end the mismatch condition
        RBIF=0;
        if(RB4)
            RD1=RD1^1;
        
    }
    else if(INTF) {
        INTF = 0;
        RD0 = !RD0; // Toggle D0 for INT interrupt
        
    }
}
Kozmotronik
  • 2,080
  • 3
  • 10
  • 25
El_Canario
  • 41
  • 3
  • please explain your code! – Mike Jan 02 '23 at 12:00
  • 1
    Congratulations @El_Canario! Moving the `RB4` inside of the `RBIF` interrupt service was the another piece of the solution and you have completed it. Finding some bugs are very tricky just like yours. It would be very useful for the others who struggle with similar problems if you would've add some explanations about the solution. This how this community grows its knowledge. – Kozmotronik Jan 05 '23 at 11:11