当前位置: 首页 > news >正文

【51单片机】7. 串口通信、单片机向电脑发送数据电脑发送数据点亮LED灯Demo

1. 串口的定义

  • 串口成本低、易使用、通信线路简单,可实现两个设备互相通信

  • 单片机串口可以使单片机与各式各样的模块相互通信,极大扩展了单片机应用范围,增强单片机系统硬件实力

  • 51单片机内部自带UART(Universal Asynchronous Receiver Transmitter,通用异步收发器),可实现单片机串口通信

2. 硬件电路

  • 简单双向串口通信有两根通信线(发送端TXD和接收端RXD)

  • TXD与RXD交叉连接

  • 仅需单项数据传输可以只接一根通信线

  • 电平标准不一致时需要加电平转换芯片

在这里插入图片描述

3. 电平标准

电平标准是数据1和数据0的表达方式,是传输线缆中人为规定的电压与数据的对应关系,串口常用电平标准包括:

  • TTL电平:+5V表示1,0V表示0(单片机使用

  • RS232电平:-3-15V表示1,+3+15V表示0

  • RS485电平:两线压差+2+6V表示1,-2-6V表示0(差分信号)

TTL&RS232只能传10多米后错误率就很高了,RS485可以达到千米级

4. 常见通信接口

在这里插入图片描述

  • 全双工:通信双方可以在同一时刻相互传输数据

  • 半双工:通信双方可以互相传输数据,但必须分时复用一根数据线(同一时刻只能一个人发)

  • 单工:通信只能有一方发送到另一方,不能反向传输

  • 异步:通信双方各自约定通信速率

  • 同步:通信双方靠一根时钟线约定通信速率

如某一方1s传一个,但对方0.5s接收一个,就不能达成一致,同步就通过一根时钟线约定通信速率

异步就是双方各自计时,到时间了收/发

  • 总线:链接各个设备的数据传输线路(类似一条马路将多个住户连接起来,使得住户可以相互交流)

5. 串口参数及时序图

  • 波特率:串口通信速率(发送和接收各数据位间隔时间)

  • 校验位:用与数据验证

  • 停止位:用于数据帧间隔

在这里插入图片描述

9位相较而言,多出的那一位可以用于校验(奇偶校验)

6. 串口模式图

在这里插入图片描述

SBUF:串口数据缓存寄存器,物理上是两个独立的寄存器,但占用的是相同的地址。写操作时写入发送寄存器,读操作时读出的是接收寄存器。

在这里插入图片描述

进入中断逻辑后是一个或门,只要有1个满足就会触发对应的中断

7. 串行口相关寄存器

在这里插入图片描述

  • SBUF是就是6中说的缓冲区

  • SCON是串行控制器(可位寻址),配置SM0和SM1可以控制不同工作方式:

    • 方式0:SM0=0,SM1=0;同步移位串行方式:移位寄存器

    • 方式1:SM0=0,SM1=1;8位UART,波特率可变

    • 方式2:SM0=1,SM1=0;9位UART

    • 方式3:SM0=1,SM1=1;9位UART,波特率可变

    • REN:允许/禁止串行接收控制位。REN=1允许串行接收,REN=0禁止接收

    • TI:发送中断请求标志位,在方式2中,停止位开始发送由内部硬件置位,必须使用软件复位

  • PCON是电源控制寄存器,里面的SMOD是波特率选择位

    • SMOD=1使通信方式1、2、3波特率加倍;SMOD=0各工作方式波特率加倍,复位时SMOD=0

    • SMOD0是帧错误检测有效控制位,SMOD0=1时,SCON中的SM0/FE用于帧错误检测;SMOD0=0时,SCON中的SM0/FE用于和SM1一起制定串口工作方式

8. 八位自动重载和十六位的区别

十六位记的数多,但每次都需要自己写的代码赋初值(参考定时器那一章的代码,每次溢出中断我们都需要重新给TH和TL赋初值),浪费时间。双八位就是将十六位分开,一个计数,另一个存放初值,每次计数完成后AR会自动将值赋给CNT,不用代码处理,比较快,但只有八位所以记的数少了。

串口通信设置八位自动重载,这样就不需要做手动设置了

9. 单片机通过串口向电脑发送数据

在这里插入图片描述

从波特率计算器中生成波特率设置相关的代码

接着写主代码:

#include <REGX52.H>
#include "Delay.h"unsigned char sec = 0;void UART_Init()
{SCON = 0x40;  // 模式 -> 0 1,8位UART,波特率可变PCON = 0x80;  // SMOD置1表示波特率加倍TMOD &= 0x0F;		//清除定时器1模式位TMOD |= 0x20;		//设定定时器1为8位自动重装方式TL1 = 0xF4;		//设定定时初值TH1 = 0xF4;		//设定定时器重装值ET1 = 0;		//禁止定时器1中断TR1 = 1;		//启动定时器1
}void UART_SendByte(unsigned char byteData)
{SBUF = byteData; // 填充缓冲区SBUFwhile (TI == 0) ; // 当没有到发送的时候就while等待TI = 0; // 根据规则,手动置0(手册P235)
}void main()
{UART_Init(); // 上电初始化while(1){UART_SendByte(sec); // 自动发送sec++; // sec++Delay(1000);}
}

Delay.c:

#include <INTRINS.H>void Delay(unsigned int ms)		//@11.0592MHz
{unsigned char i, j;while (ms){_nop_();i = 2;j = 199;do{while (--j);} while (--i);ms--;}
}

Delay.h:

#ifndef __DELAY_H__
#define __DELAY_H__void Delay(unsigned int ms);#endif

效果如下(见接收缓冲区数字):

(使用串口助手时,注意要选对串口,设置相同的波特率,否则会出错)

在这里插入图片描述

10. 串口代码模块化

常用代码可以直接模块化

UART.c

#include <REGX52.H>/*** @brief 串口初始化* @param 无* @retval 调用后初始化串口*/
void UART_Init() // 4800bps@11.0592MHz
{SCON = 0x40;  // 模式 -> 0 1,8位UART,波特率可变,注意,这里REN置0表示的是不接受数据,REN置1后是0x50PCON = 0x80;  // SMOD置1表示波特率加倍TMOD &= 0x0F;		//清除定时器1模式位TMOD |= 0x20;		//设定定时器1为8位自动重装方式TL1 = 0xF4;		//设定定时初值TH1 = 0xF4;		//设定定时器重装值ET1 = 0;		//禁止定时器1中断TR1 = 1;		//启动定时器1
}/*** @brief 经串口发送数据* @param byteData表示发送的数据* @retval 发送数据范围0~255*/
void UART_SendByte(unsigned char byteData)
{SBUF = byteData; // 填充缓冲区SBUFwhile (TI == 0) ; // 当没有到发送的时候就while等待TI = 0; // 根据规则,手动置0(手册P235)
}

UART.h

#ifndef __UART_H__
#define __UART_H__void UART_Init();
void UART_SendByte(unsigned char byteData);#endif

11. 电脑向单片机发送数据控制灯亮

单片机接收数据需要中断,那么在初始化时需要将中断打开,同时REN位要置1才能接收数据,UART.c修改如下,主要是改了初始化的函数:

#include <REGX52.H>/*** @brief 串口初始化* @param 无* @retval 调用后初始化串口*/
void UART_Init() // 4800bps@11.0592MHz
{SCON = 0x50;  // 模式 -> 0 1,8位UART,波特率可变,REN=1接收数据PCON = 0x80;  // SMOD置1表示波特率加倍TMOD &= 0x0F;		//清除定时器1模式位TMOD |= 0x20;		//设定定时器1为8位自动重装方式TL1 = 0xF4;		//设定定时初值TH1 = 0xF4;		//设定定时器重装值ET1 = 0;		//禁止定时器1中断TR1 = 1;		//启动定时器1// 启用接收中断ES = 1;EA = 1;
}/*** @brief 经串口发送数据* @param byteData表示发送的数据* @retval 发送数据范围0~255*/
void UART_SendByte(unsigned char byteData)
{SBUF = byteData; // 填充缓冲区SBUFwhile (TI == 0) ; // 当没有到发送的时候就while等待TI = 0; // 根据规则,手动置0(手册P235)
}

main.c中写中断的处理

#include <REGX52.H>
#include "UART.h"
#include "Delay.h"void main()
{UART_Init();while(1){}
}void UART_Rountine(void) interrupt 4
{if (RI == 1) // 因为发送和接受触发的是同一个中断,需要把发送和接收区分开{// if 是接收中断的话P2 = ~SBUF; // 点灯UART_SendByte(SBUF); // 利用发做回复RI = 0; // 该标志位需要软件置1}	
}

取反是因为低电平点灯。

效果如下:

12. 波特率计算

根据红框部分计算:

在这里插入图片描述

以江科大视频的为例,他是12MHz的晶振,选择SMOD=1(波特率倍速)。

根据软件给TH1和TL1设置的初值看:

TL1 = 0xF4;		//设定定时初值
TH1 = 0xF4;		//设定定时器重装值

F4转10进制是243,离溢出有13,即计13μs溢出一次

则溢出率是1/13μs=13MHz=0.07692MHz

又连接到÷16:0.07692/16=0.00480769MHz=4807.69Hz(12MHz的晶振有误差)

所以这个初值就是根据这个计算方式反向算出来的

13. HEX模式与文本模式

说白了文本模式就是根据你输入的16进制内容转成ASCII码

根据11的代码及ASCII码,我们将单片机回传的结果显示为文本模式,结果如下:

在这里插入图片描述

从而可以传输一些非数字的内容,同理,用电脑给单片机发字符“B”,单片机也会根据对应的16进制点灯,并回传对应的16进制内容:

在这里插入图片描述

相关文章:

  • C#迭代器
  • C# 使用HttpListener时候异常(此平台不支持此操作:System.PlatformNotSupportedException)
  • 基于大模型预测单纯性孔源性视网膜脱离的技术方案
  • 解析OpenFOAM polymesh网格文件的C/C++程序实现
  • Spring Boot的Security安全控制——认识SpringSecurity!
  • 信号(瞬时)频率求解与仿真实践(2)
  • 记录jackson解析出错
  • Python 训练营打卡 Day 50
  • 小知识点三、无刷电机闭环控制
  • 静态指令和动态指令的区别 GPT版
  • qt信号与槽--01
  • 如何设置爬虫的访问频率?
  • Hadoop 003 — JAVA操作MapReduce入门案例
  • React Native 项目实战 —— 记账本应用开发指南
  • 龙虎榜——20250613
  • 对象存储数据一致性:S3 vs Azure Blob vs GCS对比解析 (2025)
  • 前端持续集成和持续部署简介
  • 当雷达学会“读心术” 汽车舱内安全迈入新纪元
  • PyTorch框架详解(1)
  • html+css+js趣味小游戏~(附源码)
  • 河北省 建设执业注册中心网站/东莞整站优化排名
  • 政府网站建设运营情况汇报/一个具体网站的seo优化
  • wordpress 防调用/黑帽seo技巧
  • 如何做本地门户网站/凡科小程序
  • 成功网站运营案例/湖南网站建站系统哪家好
  • 网站制作字怎么放在图上面/宁波seo网络推广优化价格