第一次接触51单片机串口通信时,最让我困惑的就是那几根交叉连接的线。为什么电脑的TXD要接单片机的RXD?这就像两个人打电话,你的听筒必须连着我的话筒,我的听筒连着你的话筒才能正常对话。具体连接时,除了TXD-RXD的交叉连接,千万别忘了共地线(GND),这是保证信号电平基准一致的关键。我早期调试时就因为漏接GND,导致数据乱码折腾了一整天。
串口通信的本质是电平转换。51单片机用的是TTL电平(0-5V),而电脑串口是RS232电平(±12V),所以通常需要CH340G这类USB转TTL模块作为中介。实测发现,市面上有些劣质转换模块会出现波特率漂移,建议选择带晶振的型号。连接完成后,可以用万用表测量TXD脚电压,发送数据时应有明显电压跳变。
配置串口就像给两个对话者约定好交流规则。以最常用的模式1(8位UART)为例,关键参数是波特率。我常用9600bps,计算公式是:
c复制TH1 = TL1 = 256 - (晶振频率)/(12×32×波特率)
对于11.0592MHz晶振,这个神奇的数字刚好能算出整数TH1=0xFD。有次我换用12MHz晶振,发现怎么调都有误差,后来才知道11.0592MHz是专门为串口通信设计的频率。
完整初始化代码要设置SCON寄存器(0x50表示模式1允许接收)、PCON寄存器(波特率不加倍)、TMOD寄存器(定时器1模式2)。特别提醒:EA和ES中断使能位一定要最后打开,我有次调试时中断配置被后续代码覆盖,导致接收异常。
发送字符串本质是字节的循环发送,但实际应用中有几个坑要注意:
接收字符串更考验技巧。中断方式效率高但要注意:
c复制void UART_ISR() interrupt 4 {
if(RI) {
RI = 0; //必须手动清零
buffer[i++] = SBUF;
if(SBUF == '\n' || i >= sizeof(buffer)-1) {
buffer[i] = '\0';
i = 0;
flag = 1; //设置接收完成标志
}
}
}
这个改良版中断服务程序增加了缓冲区防溢出和回车符检测。我曾遇到缓冲区溢出导致系统崩溃,后来加了长度检查才解决。
把基础收发升级成交互终端,需要解决三个问题:
c复制if(strcmp(cmd, "LED ON") == 0) {
LED = 0;
UART_SendString("LED已开启\r\n");
}
一个实用的终端还应包含帮助系统:
c复制const char help[] =
"LED ON - 开启LED\r\n"
"READ TEMP - 读取温度\r\n";
工业环境中串口通信常受干扰,我有几个实战经验:
对于长距离传输,可以考虑改用RS485差分信号。曾有个项目传输20米出现误码,换成屏蔽双绞线后问题解决。
用串口调试助手时,建议开启16进制显示模式。有次遇到发送"ABC"收到"414243",其实是正常十六进制ASCII码显示。常见故障排查步骤:
内存泄漏是另一个隐形杀手。每次处理完接收数据后,记得重置缓冲区索引。有次我的终端运行几天后死机,就是因为索引变量溢出。