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

PIC16F690 UART中RCREG寄存器清除及长数据包处理问题

UART接收21字节后停止并清除RCREG的解决方案

问题背景

基于PIC16F690、MPLAB IDE v8.84(非X IDE)及HiTech-C开发UART收发程序,接收长度≤21字节的数据包时工作正常,但接收超过21字节的数据包时,RCREG寄存器会残留未处理数据,导致程序阻塞直至读完所有残留数据。需求为:接收满21字节后停止接收,并彻底清除RCREG寄存器内的残留数据。

问题分析

当前代码中CREN位始终处于开启状态,UART会持续接收数据并填充RCREG;同时代码缺乏主动停止接收或清空残留数据的逻辑,后续调用uart_getch()时会一直等待RCIF置位,最终造成程序阻塞。

修改方案

  1. 接收满21字节后,关闭CREN位以停止UART接收
  2. 新增缓存清空函数,主动读取RCREG直至所有残留数据被处理
  3. 优化主循环逻辑,避免状态变量混乱导致的异常

修改后的完整代码

__CONFIG(FOSC_INTRCIO & WDTE_OFF & PWRTE_OFF & MCLRE_ON & BOREN_OFF & CP_ON & CPD_ON);
#define _XTAL_FREQ 8000000  // 8MHz晶振频率
#define Fcyc _XTAL_FREQ / 4 // 2MHz
#define Tcyc 1 / Fcyc       // 500ns = 0.5ms

#define BAUD_RATE 9600
#define BRG_VALUE (_XTAL_FREQ/(16*BAUD_RATE)) -1 // (8MHZ/(16*9600))-1 = 51.083333->51

unsigned int count = 0;
unsigned int header = 0;
unsigned int tail  = 20;

unsigned char received_data[21] = {0};

void init_ports(void){
    OSCCON = 0b01110000; //8MHz
    CM1CON0 = 0x00;
    CM2CON0 = 0x00;
    ADCON0 = 0x00;
    ANSEL = 0x00;
    ANSELH = 0x00;
    
    TRISA = 0b00000000;
    TRISB = 0b00100000; //  TRISB5 : RX | TRISB7 : TX
    TRISC = 0b00000011; // 1 : input / 0 : output
}

void init_uart(void){
    SPBRG = 51; TX9 = 0;    TXEN = 1;   SYNC = 0;   BRGH = 1;
    SPEN = 1;   RX9 = 0;    CREN = 1;
    RCIF = 0;   RCIE = 0;   TXIF = 0;   TXIE = 0;
}

void init_timer2(void){
    GIE = 1;
    PEIE = 1;
    TMR2IE = 1;
    TMR2IF = 0;
    T2CON = 0b00001000;             // 1:2 postscaler, TIMER2 OFF, 1:1 prescaler
    TMR2 = 0;
    PR2 = 99;       // Tcyc X pre X post X PR2 = 500ns X 2 X 1 X 100(0~99) = 100us
    TMR2ON = 1;
}

unsigned char uart_getch(void)
{
    while(!RCIF);
    RCIF = 0;
    return RCREG;
}

void uart_putch(unsigned char data)
{
    TXREG = data;
    while(!TRMT);
}

// 新增:清空RCREG残留数据
void uart_flush_rcbuf(void)
{
    unsigned char dummy;
    // 循环读取RCREG直到RCIF位清零,彻底清空缓存
    while(RCIF)
    {
        dummy = RCREG;
        RCIF = 0;
    }
}

void main(void){
    init_ports();
    init_uart();
    init_timer2();
    
    while(1){
        if(RCIF){
            int i;
            header = 0;
            // 接收21字节数据
            for(i=0; i<21; i++){
                count = 0;
                while(!RCIF){
                    if(count >= 10){
                        break;
                    }
                    count ++;
                    __delay_ms(1);
                }
                if(count >= 10){ 
                    break;
                }
                received_data[i] = uart_getch();
                header = i;
            }
            
            // 停止接收并清空残留数据
            CREN = 0;
            uart_flush_rcbuf();
            
            // 收到完整21字节则回发
            if(header == tail){
                for(int i = 0; i<21; i++){
                    RB4=1; 
                    uart_putch(received_data[i]); 
                    RB4=0;
                }
            }
            
            // 重新开启接收,准备下一次数据包
            CREN = 1;
        }
    }
}

关键修改说明

  • 新增uart_flush_rcbuf()函数:通过循环读取RCREG寄存器,确保所有残留数据被处理,RCIF位清零,从根源避免阻塞
  • 接收满21字节后先关闭CREN位停止接收,再清空缓存,防止新数据持续写入
  • 移除冗余的flag和overflow_bit变量,简化状态逻辑,避免异常触发
  • 处理完当前数据包后重新开启CREN位,保证后续接收正常

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 13:32:01