You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PIC16F877的PORTB与INT外部中断触发后程序卡死求助

PIC16F877中断问题排查(仿真正常,实物/简化代码触发中断后卡死)

问题描述

  • 基于PIC16F877开发项目,采用RB0外部中断+RB4的PORTB中断实现过零检测
  • Proteus仿真中功能正常,但面包板搭建实物电路后,LCD仅显示白点
  • 编写仅包含PORTB中断的简化测试代码,仿真中触发中断后程序直接卡死;单独使用两个中断时问题仍存在

简化测试代码

/*
 * 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 (XT 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;
}

可能的原因分析

  • PORTB中断状态判断逻辑错误:RBIF触发时,直接读取RB4的当前电平可能不准确——中断触发是因为电平变化,触发后RB4的电平可能已经改变,导致判断条件不成立,或者反复触发中断。正确做法是先读取PORTB保存触发时的状态,再基于保存的状态判断:

    uint8_t portb_state = PORTB;
    if(RBIF && (portb_state & 0x10)) {
        RBIF = 0;
        RD0 ^= 1;
    }
    
  • RB端口无有效电平拉持:OPTION_REGbits.nRBPU = 1会禁用PORTB内部上拉电阻,若RB0、RB4引脚未外接上拉/下拉电阻,引脚会处于浮空状态,极易受干扰产生误中断,甚至导致程序跑飞。实物电路需给输入引脚添加外部拉阻,或改为nRBPU = 0启用内部上拉(需匹配电路需求)。

  • 中断标志位清除不彻底:虽然代码中读取了PORTB,但如果RBIF清除时机不对,或电平变化持续存在,会导致标志位立即再次置位,程序反复进入中断无法回到主循环,表现为“卡死”。需确保清除RBIF前,PORTB的电平不匹配状态已消除。

  • 时钟电路异常:实物电路中XT模式的4MHz晶振需搭配合适的负载电容(通常22pF左右),若晶振不起振或时钟偏差过大,程序无法正常初始化或执行,原项目中LCD显示白点可能与此有关。

  • 过零检测信号抖动:若硬件电路输出的过零信号存在毛刺或抖动,会频繁触发PORTB中断,导致程序一直停留在中断函数中,无法执行主循环。可在硬件上加RC滤波,或在中断函数中添加软件防抖逻辑。

  • 中断函数寄存器冲突:PIC16F877的中断函数中,编译器自动保护部分寄存器,但如果局部变量使用不当,可能导致栈溢出或寄存器值被破坏,进而引发程序异常。可尝试将中断内的局部变量改为全局变量,简化中断操作。

内容的提问来源于stack exchange,提问作者El_Canario

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 18:05:19