51单片机串口通信实验:零基础实现数据收发

51单片机串口通信实战:从点亮“Hello World”到全双工收发

你有没有过这样的经历?写好一段代码,烧录进单片机,然后……盯着几个LED灯猜:“它到底运行到哪一步了?”
没有反馈的开发,就像在黑暗中走路。而串口通信,就是嵌入式世界里那束最亮的手电筒光。

今天,我们就用最经典的51单片机,亲手实现一个完整的串口收发实验——让你的单片机学会“说话”,也能“听话”。零基础起步,全程不跳步,带你打通从寄存器配置到PC端双向通信的完整链路。


为什么是UART?为什么是51?

在SPI、I2C、USB满天飞的今天,我们为何还要学UART?尤其是早已“年过四十”的51单片机?

答案很简单:因为它足够简单,也足够真实

  • UART不需要时钟线,两根线(TXD、RXD)就能传数据;
  • 它不依赖复杂的协议栈,一帧数据清清楚楚:起始位 + 数据位 + 停止位;
  • 51单片机结构清晰,寄存器直观,适合理解“CPU如何控制外设”。

更重要的是——几乎所有现代MCU都保留了UART接口,STM32有,ESP32有,甚至树莓派Pico也有。你现在学的底层逻辑,未来全都能用上。

而且,当你调试一个跑飞的RTOS系统时,最终救命的,往往还是那一行通过串口打印出来的printf("Task Running...\n")

所以,别小看这个“老古董”,它是通往嵌入式核心世界的第一把钥匙


UART是怎么把字节变成高低电平的?

我们先来拆解一个问题:你在电脑上敲下字母'A',它是怎么一步步变成单片机IO口上的0和1的?

一帧数据长什么样?

UART采用异步串行通信,意思是发送和接收双方没有共用的时钟线,全靠事先约定好的速度(波特率)来同步。

以最常见的8-N-1 模式为例(8位数据、无校验、1位停止),传输一个字节'A'(ASCII码 0x41)的过程如下:

低 高高高低低低低高 高 ↓ ↓↓↓↓↓↓↓↓ ↓ [起始位] [D0 D1 D2 D3 D4 D5 D6 D7] [停止位] (1 0 0 0 0 0 1 0) ← 注意:低位先行!

也就是说,0x41的二进制是01000001,但发送时要从最低位开始,所以实际波形是:

起始(0) → 1 → 0 → 0 → 0 → 0 → 0 → 1 → 0 → 停止(1)

总共10个比特,耗时 = 10 / 波特率。比如9600bps,每帧约1.04ms。

为什么选 11.0592MHz 晶振?

你可能注意到很多51开发板都用11.0592MHz而不是更常见的12MHz。这是为啥?

因为——要精准生成标准波特率

51的UART依赖定时器1产生波特率,计算公式为:

波特率 = (2^SMOD / 32) × (fosc / (12 × (256 - TH1)))

如果我们用12MHz晶振算9600bps,会发现根本得不到整数初值,误差高达8.5%,极易丢包。

而换成11.0592MHz,配合 SMOD=1(波特率加倍),TH1=0xFD(即-3),刚好得到精确的9600bps,误差接近0。

这就是工程中的取舍:为了通信稳定,宁愿牺牲一点点运行速度。


让51单片机“开口说话”:寄存器级配置详解

现在,轮到我们的主角登场了——AT89C51内部的UART模块。

它有四个关键角色:

寄存器地址功能
SBUF0x99串行数据缓冲器,读写都走它
SCON0x98控制工作模式、启动接收、查看状态
TMOD/TH1/TL10x89, 0xF0定时器1设置,决定波特率
IE0xA8中断使能开关

第一步:选工作模式 —— 我们要用 Mode 1

SCON 寄存器决定了UART的工作方式。其中 SM0 和 SM1 组合如下:

SM1SM0模式说明
000同步移位模式(少见)
011✅ 8位UART,可变波特率(常用)
1029位UART,固定波特率
1139位UART,可变波特率

我们要的就是Mode 1,所以设置 SCON = 0x50:

SM0=0, SM1=1 → Mode 1 REN=1 → 允许接收(第4位)

即:0101 0000=0x50

第二步:让定时器1当“节拍器”

UART需要一个稳定的“心跳”来逐位采样,这个任务交给定时器1,工作在8位自动重载模式(TMOD=0x20)

配置步骤:

TMOD |= 0x20; // 定时器1,模式2(自动重载) TH1 = 0xFD; // 初值FDH → 对应9600bps TL1 = 0xFD; TR1 = 1; // 启动定时器

别忘了开启波特率加倍:

PCON |= 0x80; // SMOD = 1,提升精度

第三步:打开中断,让CPU“听得见”

如果不使用中断,主程序就得一直轮询 TI/RI 标志,效率极低。

我们可以开启串口中断,一旦收到数据或发送完成,自动跳转处理:

ES = 1; // 使能串口中断 EA = 1; // 开总中断

这样,每当 RI 或 TI 置位,就会触发中断服务函数。


实战代码:实现“你说啥我回啥”的回环测试

下面这段代码,是你能跑通的第一个真正意义上的嵌入式通信程序。

#include <reg51.h> void UART_Init(void); void UART_SendByte(unsigned char byte); void UART_SendString(char *str); /** * 串口初始化:波特率9600, 8-N-1, 开中断 */ void UART_Init() { TMOD |= 0x20; // 定时器1,模式2 PCON |= 0x80; // SMOD = 1 TH1 = 0xFD; // 9600bps @ 11.0592MHz TL1 = 0xFD; TR1 = 1; // 启动定时器 SCON = 0x50; // Mode 1, REN=1 ES = 1; // 使能串口中断 EA = 1; // 开全局中断 } /** * 发送一个字节 */ void UART_SendByte(unsigned char byte) { SBUF = byte; // 写SBUF启动发送 while (!TI); // 等待发送完成 TI = 0; // 手动清TI标志 } /** * 发送字符串 */ void UART_SendString(char *str) { while (*str) { UART_SendByte(*str++); } } /** * 串口中断服务程序 */ void UART_ISR() interrupt 4 { if (RI) { // 是否接收到数据? unsigned char dat = SBUF; UART_SendByte(dat); // 回传原数据(回显) RI = 0; // 清接收标志 } if (TI) { TI = 0; // 清发送标志(若用中断发) } } /** * 主函数 */ void main() { UART_Init(); UART_SendString("Serial Test Ready!\r\n"); while (1) { // 主循环可做其他事 } }

关键点解析:

  • SBUF是个“神奇”的寄存器:写它=发数据,读它=收数据
  • TI标志表示“上一字节已发送完毕”,必须手动清零。
  • RI表示“已收到一帧数据”,同样需软件清除。
  • 中断号4是51单片机为串口分配的固定中断向量。

烧录后,打开串口助手(如XCOM、SSCOM),输入任意字符,你会看到单片机立刻回传相同内容——恭喜,你们“通上话了”!


怎么连上电脑?TTL、RS232、USB 转换全解析

你以为TXD-RXD连上线就能通信?错!还有一个致命问题:电平不兼容

设备电平标准高电平低电平
51单片机TTL~5V~0V
PC传统串口RS232-12V左右+12V左右

直接连接轻则通信失败,重则烧毁芯片。

解法一:用 MAX232 做电平转换

MAX232 是经典方案,内部有电荷泵电路,能把+5V升压成±12V,完美适配RS232。

典型接法:

单片机 TXD → MAX232 T1IN MAX232 T1OUT → PC RXD 单片机 RXD ← MAX232 R1OUT MAX232 R1IN ← PC TXD GND ↔ GND (必须共地!)

但注意:现在大多数PC都没有DB9串口了。

解法二:USB转TTL模块(推荐新手)

直接使用CH340、CP2102 或 FT232RL模块,它们将USB信号转为TTL电平,插上电脑就识别为虚拟COM口。

接线极其简单:

[USB-TTL模块] ↔ [51单片机] TXD → RXD RXD ← TXD GND ↔ GND

无需额外电源,即插即用,成本不到10元,强烈推荐初学者使用。


常见坑点与调试秘籍

别以为代码一烧就通,以下是新手最容易踩的五个坑:

❌ 坑1:线接反了!

记住口诀:“收对发,发对收”

单片机 TXD → 接 USB模块 RXD
单片机 RXD ← 接 USB模块 TXD

交叉接!千万别直连。

❌ 坑2:忘了共地

两个设备必须共享同一个GND参考点,否则电压基准不同,信号全乱套。

❌ 坑3:波特率不一致

PC端串口工具设置的波特率必须和单片机完全一样(9600、19200等)。建议首次测试用9600,容错性最好。

❌ 坑4:晶振不对导致波特率偏差

如果你用了12MHz晶振却按11.0592MHz算TH1值,实际波特率偏差太大,必然出错。检查你的开发板晶振型号!

❌ 坑5:中断未开启或标志未清

如果用了中断但没开ESEA,程序不会进入中断函数;如果不清RI,下次中断不会再触发。


还能怎么玩?扩展思路给你灵感

搞定基础通信后,你可以尝试这些升级玩法:

🔹 加个LED,用串口命令控制开关

if (dat == '1') P1_0 = 0; // 开灯 if (dat == '0') P1_0 = 1; // 关灯

从此你的单片机有了“远程遥控”。

🔹 上报传感器数据

接个DS18B20温度传感器,每隔5秒主动上报一次:

while (1) { float temp = ReadTemp(); printf("Temperature: %.2f°C\r\n", temp); DelayMs(5000); }

数据传到PC,可以用Python绘制成曲线图。

🔹 实现简易Modbus通信

定义自己的命令协议,比如:

  • 0x01→ 读IO状态
  • 0x02→ 设置继电器
  • 0x03→ 获取版本号

为将来学习工业通信打基础。

🔹 结合LCD屏做本地显示

一边串口上传数据给PC,一边在本地OLED/LCD上显示,构建完整的人机交互系统。


写在最后:这不是终点,而是起点

也许你觉得51单片机太老,不够“酷”。但请相信我,每一个优秀的嵌入式工程师,都曾在一个晚上,盯着串口助手等待第一个字符返回时,心跳加速过

这个实验教会你的不只是UART通信,更是:

  • 如何阅读数据手册
  • 如何配置寄存器
  • 如何处理中断
  • 如何排查硬件连接问题
  • 如何建立“软硬协同”的系统思维

这些能力,不会因为你换了STM32或RISC-V而失效。

当你有一天面对一块全新的MCU,即使没有HAL库,你也能从头写出串口驱动——因为你已经知道,那个叫SBUF的寄存器背后,藏着怎样的故事。

所以,别急着追求“高级”,先把这第一课练熟。

拿起你的开发板,焊好线路,烧录代码,然后深呼吸,按下复位键……

等那一句"Serial Test Ready!"出现在屏幕上时,你就正式踏入嵌入式的大门了。

欢迎加入这个用代码操控物理世界的游戏。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/1141601.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【C++藏宝阁】C++入门:命名空间(namespace)详解

&#x1f308;个人主页&#xff1a;聆风吟 &#x1f525;系列专栏&#xff1a;C藏宝阁 &#x1f516;少年有梦不应止于心动&#xff0c;更要付诸行动。 文章目录&#x1f4da;专栏订阅推荐&#x1f4cb;前言&#xff1a;为什么需要命名空间&#xff1f;一、命名空间的定义二、命…

DevicePairingHandler.dll文件丢失找不到问题 免费下载方法分享

在使用电脑系统时经常会出现丢失找不到某些文件的情况&#xff0c;由于很多常用软件都是采用 Microsoft Visual Studio 编写的&#xff0c;所以这类软件的运行需要依赖微软Visual C运行库&#xff0c;比如像 QQ、迅雷、Adobe 软件等等&#xff0c;如果没有安装VC运行库或者安装…

揭秘大数据领域 Eureka 的服务发现的缓存更新机制

揭秘大数据领域 Eureka 的服务发现的缓存更新机制 关键词:大数据、Eureka、服务发现、缓存更新机制、微服务 摘要:在大数据和微服务架构盛行的今天,服务发现是保障系统高效运行的关键环节。Eureka 作为 Netflix 开源的服务发现框架,在业界得到了广泛应用。其缓存更新机制对…

零基础学习JLink下载的完整操作流程

从零开始掌握J-Link固件烧录&#xff1a;深入理解调试原理与实战技巧 你是否曾遇到这样的场景&#xff1f; 编译好的程序无法下载到STM32板子上&#xff0c;Keil提示“Cortex-M Debug Error”&#xff1b;或者在产线批量烧录时&#xff0c;每台设备都要手动点击“Program”&a…

Arduino寻迹小车图解说明:电路连接全解析

从零搭建Arduino寻迹小车&#xff1a;电路连接与控制逻辑全拆解你有没有试过看着别人做的智能小车自动沿着黑线跑&#xff0c;心里痒痒也想动手做一个&#xff1f;别急——其实它没那么神秘。今天我们就来手把手拆解一台Arduino寻迹小车的完整实现过程&#xff0c;不讲空话&…

DevicePairingProxy.dll文件丢失找不到问题 免费下载方法分享

在使用电脑系统时经常会出现丢失找不到某些文件的情况&#xff0c;由于很多常用软件都是采用 Microsoft Visual Studio 编写的&#xff0c;所以这类软件的运行需要依赖微软Visual C运行库&#xff0c;比如像 QQ、迅雷、Adobe 软件等等&#xff0c;如果没有安装VC运行库或者安装…

虚拟机性能优化实战技术文章大纲CPU分配策略:核心数、亲和性设置

虚拟机性能优化实战技术文章大纲虚拟机性能优化概述虚拟机性能优化的定义与重要性常见性能瓶颈与挑战优化目标&#xff1a;资源利用率、响应速度、稳定性硬件资源配置优化CPU分配策略&#xff1a;核心数、亲和性设置内存分配&#xff1a;动态内存管理、大页内存启用磁盘I/O优化…

Arduino IDE环境搭建实战案例(新手必看)

从零开始玩转硬件编程&#xff1a;Arduino IDE 环境搭建实战全记录 你有没有过这样的经历&#xff1f;买了一块 Arduino 开发板&#xff0c;兴致勃勃插上电脑&#xff0c;结果打开 Arduino IDE 却发现“端口灰了”、“上传失败”、“找不到设备”……明明照着教程一步步来&…

曾仕强老师谈婚姻前应该做什么

网址&#xff1a;曾仕强老师谈婚姻前应该做什么

【2025最新】基于SpringBoot+Vue的洗衣店订单管理系统管理系统源码+MyBatis+MySQL

&#x1f4a1;实话实说&#xff1a;CSDN上做毕设辅导的都是专业技术服务&#xff0c;大家都要生活&#xff0c;这个很正常。我和其他人不同的是&#xff0c;我有自己的项目库存&#xff0c;不需要找别人拿货再加价。我就是个在校研究生&#xff0c;兼职赚点饭钱贴补生活费&…

ModbusPoll下载通信测试:操作指南从零实现

从零开始用 ModbusPoll 测试通信&#xff1a;手把手带你跑通第一次读取 你有没有过这样的经历&#xff1f; 新接了一个智能电表&#xff0c;说明书上写着“支持 Modbus RTU”&#xff0c;但怎么都读不出数据&#xff1b;或者调试PLC时&#xff0c;不确定寄存器地址对不对&…

DeviceDisplayStatusManager.dll文件丢失找不到问题 免费下载方法分享

在使用电脑系统时经常会出现丢失找不到某些文件的情况&#xff0c;由于很多常用软件都是采用 Microsoft Visual Studio 编写的&#xff0c;所以这类软件的运行需要依赖微软Visual C运行库&#xff0c;比如像 QQ、迅雷、Adobe 软件等等&#xff0c;如果没有安装VC运行库或者安装…

【2025最新】基于SpringBoot+Vue的美发门店管理系统管理系统源码+MyBatis+MySQL

&#x1f4a1;实话实说&#xff1a;CSDN上做毕设辅导的都是专业技术服务&#xff0c;大家都要生活&#xff0c;这个很正常。我和其他人不同的是&#xff0c;我有自己的项目库存&#xff0c;不需要找别人拿货再加价。我就是个在校研究生&#xff0c;兼职赚点饭钱贴补生活费&…

DeviceMetadataParsers.dll文件丢失找不到问题 免费下载方法分享

在使用电脑系统时经常会出现丢失找不到某些文件的情况&#xff0c;由于很多常用软件都是采用 Microsoft Visual Studio 编写的&#xff0c;所以这类软件的运行需要依赖微软Visual C运行库&#xff0c;比如像 QQ、迅雷、Adobe 软件等等&#xff0c;如果没有安装VC运行库或者安装…

STM32CubeMX安装超详细版:Windows系统适配说明

STM32CubeMX安装全解析&#xff1a;从环境准备到首次运行&#xff0c;一次搞定 你有没有遇到过这样的情况&#xff1f; 刚下载完STM32CubeMX的安装包&#xff0c;双击运行后却弹出一个黑窗口闪退、提示“Failed to load the JVM”&#xff1b;或者安装进度条卡在“Extracting…

前后端分离师生共评作业管理系统系统|SpringBoot+Vue+MyBatis+MySQL完整源码+部署教程

&#x1f4a1;实话实说&#xff1a;CSDN上做毕设辅导的都是专业技术服务&#xff0c;大家都要生活&#xff0c;这个很正常。我和其他人不同的是&#xff0c;我有自己的项目库存&#xff0c;不需要找别人拿货再加价。我就是个在校研究生&#xff0c;兼职赚点饭钱贴补生活费&…

d3d10_1core.dll文件丢失找不到 彻底修复解决办法分享

在使用电脑系统时经常会出现丢失找不到某些文件的情况&#xff0c;由于很多常用软件都是采用 Microsoft Visual Studio 编写的&#xff0c;所以这类软件的运行需要依赖微软Visual C运行库&#xff0c;比如像 QQ、迅雷、Adobe 软件等等&#xff0c;如果没有安装VC运行库或者安装…

Keil5汉化核心要点:规避常见安装问题

Keil5汉化实战指南&#xff1a;从原理到部署&#xff0c;避开90%开发者踩过的坑在嵌入式开发的世界里&#xff0c;Keil MDK几乎是每位ARM工程师绕不开的工具。它稳定、高效&#xff0c;对Cortex-M系列微控制器的支持堪称行业标杆。但有一个痛点始终挥之不去——全英文界面。对于…

密码发生器(多位数转个位数,去除残留的\n,fgets用法)

思路&#xff1a;1.写一个能将多位数转为个位数的函数2.将字符串折叠&#xff0c;进行每列对应的ASCII码相加分别放入数组3.对残留的\n的去除问题&#xff0c;用getchar();4.fgets的用法&#xff1a;if(fgets(name,sizeof(name),stdin)!NULL)代码部分&#xff1a;

STM32CubeMX因权限打不开?手把手设置教程

STM32CubeMX启动失败&#xff1f;别再重装了&#xff01;一招彻底解决权限问题你有没有遇到过这种情况&#xff1a;刚下载完STM32CubeMX&#xff0c;双击图标——没反应&#xff1b;任务管理器里进程闪现一下就消失&#xff1b;或者弹出一堆Java错误日志&#xff0c;提示“Acce…