PIC16F877的PORTB与INT外部中断触发后程序卡死求助
问题描述
- 基于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

