PIC18F47K40的EUSART串口配置问题:Modbus RTU实现异常
PIC18F47K40 EUSART1看门狗触发与串口乱码问题排查方案
一、看门狗触发问题解决
- 调整喂狗时机:确保主循环、串口收发的阻塞等待循环中都加入
CLRWDT()喂狗操作,避免长时间无喂狗触发超时。比如在等待TXREG为空的死循环里,每次循环都喂狗,防止串口发送耗时超过看门狗周期。 - 优化看门狗配置:根据系统时钟调整看门狗预分频器(
WDTPS位),延长超时周期。比如系统时钟40MHz时,设置合适的预分频值让看门狗超时时间大于最长的单次操作耗时(比如串口发送一个字符串的时间)。 - 移除不必要的阻塞逻辑:尽量避免在主循环中使用死循环等待,改用中断驱动的缓冲区机制,让主循环能持续喂狗。
二、串口乱码问题解决
- 校验波特率精度:根据实际系统时钟重新计算波特率发生器参数(
SPBRG/SPBRGH),确保实际波特率与19200的误差≤5%(Modbus RTU要求)。注意区分高速(BRGH=1)和低速(BRGH=0)模式的分频系数:- 高速模式:
SPBRG_VAL = (FOSC/(16*BAUD)) - 1 - 低速模式:
SPBRG_VAL = (FOSC/(64*BAUD)) - 1
同时要开启BRG16位使用16位波特率发生器,提升精度。
- 高速模式:
- 检查中断配置:确认全局中断(
INTCONbits.GIE)、外围中断(INTCONbits.PEIE)、EUSART收发中断(PIE3bits.RCIE/PIE3bits.TXIE)均已正确启用,中断优先级配置与系统需求匹配。 - 修正中断服务程序(ISR):
- 接收ISR中需及时读取
RCREG寄存器,避免数据溢出;同时维护接收环形缓冲区的读写指针,确保数据正确存储。 - 发送ISR中仅负责加载下一个待发送字节,不要在ISR内执行耗时操作(如字符串处理),主循环负责填充发送缓冲区。
- ISR末尾需清除中断标志位(如
PIR3bits.RCIF/PIR3bits.TXIF),避免重复触发中断。
- 接收ISR中需及时读取
- 确认引脚配置:将RC6(TX)设为输出、RC7(RX)设为输入,同时禁用对应引脚的模拟功能(清零
ANSELC相关位),防止引脚功能冲突。 - 排查缓冲区逻辑:如果使用环形缓冲区,检查缓冲区大小是否足够,读写指针的更新是否原子化(避免中断中指针被篡改导致数据错乱),确保缓冲区不会溢出或读取无效数据。
波特率配置示例(40MHz时钟,19200波特率)
#define FOSC 40000000UL #define BAUD 19200UL void EUSART1_Init(void) { // 引脚配置 TRISCbits.TRISC6 = 0; // RC6为TX输出 TRISCbits.TRISC7 = 1; // RC7为RX输入 ANSELCbits.ANSELC6 = 0; // 禁用模拟功能 ANSELCbits.ANSELC7 = 0; // 波特率配置 TXSTAbits.BRGH = 1; // 高速模式 BAUDCONbits.BRG16 = 1; // 16位波特率发生器 unsigned int spbrg_val = (FOSC / (16 * BAUD)) - 1; SPBRG = spbrg_val & 0xFF; SPBRGH = (spbrg_val >> 8) & 0xFF; // 串口使能 TXSTAbits.TXEN = 1; RCSTAbits.SPEN = 1; RCSTAbits.CREN = 1; // 中断配置 PIE3bits.RCIE = 1; // 启用接收中断 INTCONbits.PEIE = 1; INTCONbits.GIE = 1; }
喂狗操作示例
void EUSART1_SendChar(uint8_t data) { while(!TXSTAbits.TRMT) { CLRWDT(); // 等待发送完成时喂狗 } TXREG = data; } void main(void) { // 看门狗配置(示例:超时约1秒,根据时钟调整) WDTCONbits.SWDTEN = 1; WDTPSbits.WDTPS = 0b1010; // 预分频值对应超时周期 EUSART1_Init(); while(1) { CLRWDT(); // 主循环定时喂狗 // 处理串口缓冲区数据 // ... } }
内容的提问来源于stack exchange,提问作者Hamza khalid
相关产品推荐
相关产品推荐

