Keil C51声明数组后UART首字符重复发送异常求助
89C52 UART首字符重复发送(数组声明触发)
问题现象
使用Keil C51 uVision4开发89C52单片机程序,Proteus仿真时出现UART传输异常:
- 代码中存在任意类型数组声明时,UART发送字符串的首字符会被重复发送,例如发送
"xyz"会收到"xxyz" - 移除数组声明后,传输恢复正常;仅发送单个字节时,该问题依然复现
复现代码
#include <reg52.h> #include <intrins.h> // 数组声明触发问题 unsigned long myArrayDeclaration[4] = { 0x00FFF789, }; sbit UART_RXD = P3^0; // RXD引脚 sbit UART_TXD = P3^1; // TXD引脚 void UART_Init() { TMOD |= 0x20; // 定时器1设为模式2(8位自动重装) TH1 = 0xFA; // 22.1184MHz晶振下配置9600波特率 TL1 = TH1; TR1 = 1; // 启动定时器1 SCON = 0x50; // 串口模式1(8位UART) EA = 1; // 开启全局中断 ES = 1; // 开启串口中断 } void UART_TxString(const char *string) { while (*string != '\0') { SBUF = *string; // 加载待发送字符 while (!TI); // 等待发送完成 TI = 0; // 清除发送中断标志位 string++; // 指针移至下一个字符 } } void main() { UART_Init(); // 初始化串口 UART_TxString("xyz"); // 发送字符串 while (1) { } }
已尝试的无效操作
- 在
UART_Init()后添加延时或_nop_()无改善 - 调整Keil uVision4的优化参数未解决问题
解决思路
1. 强制清除串口标志位
数组声明可能改变单片机上电后的内存初始化状态,导致TI(发送中断标志)在初始化前被意外置位。建议在UART_Init()末尾强制清除标志位:
void UART_Init() { // 原有初始化代码... SCON = 0x50; // 串口模式1(8位UART) EA = 1; // 开启全局中断 ES = 1; // 开启串口中断 TI = 0; // 强制清除发送标志 RI = 0; // 强制清除接收标志 }
2. 禁用未使用的串口中断
当前代码仅用到串口发送功能,未实现串口中断服务函数,开启ES可能引入未知干扰。尝试关闭串口中断:
void UART_Init() { // 原有初始化代码... SCON = 0x50; // 串口模式1(8位UART) EA = 1; // 开启全局中断 // ES = 1; // 注释该行,关闭串口中断 TI = 0; RI = 0; }
3. 调整数组存储位置
数组声明占用RAM空间可能影响寄存器初始化流程,尝试将数组存放到ROM:
unsigned long code myArrayDeclaration[4] = { 0x00FFF789, };
同时检查Keil工程Target选项中的内存分配,确保Data Memory和Code Memory地址配置正确。
4. 验证仿真与实际硬件差异
Proteus仿真可能存在时序或初始化bug,可尝试:
- 更换Proteus版本测试
- 将代码烧录到实际89C52芯片,用串口助手验证是否存在同样问题
内容的提问来源于stack exchange,提问作者Iorp
相关产品推荐
相关产品推荐

