51单片机(八)串口通信

news2024/12/24 3:20:14

❤️ 专栏简介:本专栏记录了从零学习单片机的过程,其中包括51单片机和STM32单片机两部分;建议先学习51单片机,其是STM32等高级单片机的基础;这样再学习STM32时才能融会贯通。
☀️ 专栏适用人群 :适用于想要从零基础开始学习入门单片机,且有一定C语言基础的的童鞋。
🌙专栏目标:实现从零基础入门51单片机和STM32单片机,力求在玩好单片机的同时,能够了解一些计算机的基本概念,了解电路及其元器件的基本理论等。

⭐️ 专栏主要内容: 主要学习51单片机的功能、各个模块、单片机的外设、驱动等,最终玩好单片机和单片机的外设,全程手敲代码,实现我们所要实现的功能。
🌴 专栏说明 :如果文章知识点有错误的地方,欢迎大家随时在文章下面评论,我会第一时间改正。让我们一起学习,一起进步。
💑专栏主页:http://t.csdn.cn/HCD8v

本学习过程参考:https://space.bilibili.com/383400717

单片机安装软件、各种资料以及源码的路径:
https://pan.baidu.com/s/1vDTN2o8ffvczzNQGfyjHng
提取码:gdzf

本节主要介绍学习串口通信的相关知识,包括串口基础知识介绍、本节目标等;并利用两个小实验来进行练习,分别是串口向电脑发送数据以及电脑通过串口控制LED。

文章目录

  • 一、串口介绍和本节目标
    • 1.1 串口介绍
    • 1.2 本节目标
      • 1.2.1 目标1:单片机通过串口向个人电脑发送数据
      • 1.2.2 目标2:电脑通过串口控制LED
  • 二、串口向电脑发送数据
  • 三、电脑通过串口控制LED

一、串口介绍和本节目标

1.1 串口介绍

在这里插入图片描述

本节主要介绍51单片机和个人电脑之间,是如何使用串口进行通信的。

串口的硬件电路

在这里插入图片描述

电平标准

在这里插入图片描述

  • 我们单片机使用的就是TTL电平;(缺点:只能传输10米之内)
  • CAN总线以及USB使用的是RS485电平,通过两根线的压差来区分,也就是查分信号;而不是用电源正负极来区分电压。(最大传送距离可以达到千米以上)

接口及引脚定义:

在这里插入图片描述

常见的通信接口

在这里插入图片描述
相关术语

在这里插入图片描述

  • 全双工方式,在A和B双方之间存在两根通信线,通信双方使用这两根线,A在向B发送数据的同时,B也可以通过另一个线向A发数据;

  • 半双工方式,再A和B双方之间只存在一根通信线,利用这根线,通信双方可以互相发送数据,分时复用,也就是说同一时间只能有一方发送,另一方接收;

  • 同步和异步比较,同步会比异步多一根时钟线,用来实现同步的功能。

下面介绍一下51单片机里的UART。

51单片机里的UART

在这里插入图片描述

STC89C52里只集成了一个UART

在这里插入图片描述

上图是其电路图,上图中的TXD和RXD就分别连接到单片机上的RXD和TXD;也就是下图的11和10口:

在这里插入图片描述

这些其实单片机开发板已经帮我们焊好了,所以将USB插到电脑上就可以进行通信了。

串口参数和时序图

在这里插入图片描述

检验位:用于检验发送数据的正确性;一般的方法有,奇偶校验(校验发送的数据和接收的数据里的1的个数是奇数还是偶数);

串口模式图

在这里插入图片描述

上图解释了在串口内部,数据是如何进行收发的;

上图虚线右边的部分都是单片机内部的电路;

其中最左边的双向箭头表示单片机的总线;T1溢出率部分是时钟;

除此之外还有两个寄存器SBUF(串口数据缓存寄存器),这两个寄存器都叫SBUR,且拥有相同的地址;上面的为写SBUF,MCU向该寄存器写入数据,并通过TXD发送出去;下面的为读SBUF,通过RXD接收数据,然后MCU读取该寄存器中的数据。

串口和中断系统

在这里插入图片描述

串口相关寄存器

在这里插入图片描述

1.2 本节目标

1.2.1 目标1:单片机通过串口向个人电脑发送数据

具体的为,单片机每隔1s,向电脑发送一次递增的数据;如下图所示:
在这里插入图片描述

1.2.2 目标2:电脑通过串口控制LED

电脑通过串口向单片机发送数据,进而控制LED的状态,例如当发送1时,第一个LED点亮
在这里插入图片描述

当发送0时,第一个LED熄灭,同时单片机会将收到的信息原封不动发回给电脑

在这里插入图片描述

当发送十进制的55时(对应的16进制是0101 0101),所以LED等也按照0101 0101的方式点亮;

在这里插入图片描述

当发送十六进制的aa给单片机时,也会按照对应的顺序点亮LED,如下图所示:

在这里插入图片描述

二、串口向电脑发送数据

代码路径:51单片机入门教程资料\课件及程序源码\程序源码\KeilProject\8-1 串口向电脑发送数据

具体代码:

#include <REGX52.H>
#include "Delay.h"
#include "UART.h"

unsigned char Sec;

void main()
{
	UART_Init();			//串口初始化
	while(1)
	{
		UART_SendByte(Sec);	//串口发送一个字节
		Sec++;				//Sec自增
		Delay(1000);		//延时1秒
	}
}

UART.c代码如下:

#include <REGX52.H>

/**
  * @brief  串口初始化,4800bps@12.000MHz
  * @param  无
  * @retval 无
  */
void UART_Init()
{
	SCON=0x40;
	PCON |= 0x80;
	TMOD &= 0x0F;		//设置定时器模式
	TMOD |= 0x20;		//设置定时器模式
	TL1 = 0xF3;		//设定定时初值
	TH1 = 0xF3;		//设定定时器重装值
	ET1 = 0;		//禁止定时器1中断
	TR1 = 1;		//启动定时器1
}

/**
  * @brief  串口发送一个字节数据
  * @param  Byte 要发送的一个字节数据
  * @retval 无
  */
void UART_SendByte(unsigned char Byte)
{
	SBUF=Byte;
	while(TI==0);
	TI=0;
}

代码解释:

UART_Init函数其实就是在对串口相关的寄存器进行初始化配置,也就是对以下八个寄存器进行配置,下面一一解释各个寄存器的配置。
在这里插入图片描述

在UART_Init函数中,各个寄存器为什么会进行以上设置呢?

SCON

首先是SCON寄存器的配置,代码中写的是SCON=0x40;,关于SCON的设置,我们看下手册的内容,如下图所示,SCON由B0-B7 等8位构成,那么每一位分别设置成0还是1,怎么确认呢?
在这里插入图片描述
在上面的内容中有写我们最常用的就是8位UART模式,所以SM0(B7)设置为0,SM1(B6)设置为1;
在这里插入图片描述
从上图可知,
SM2是方式2和方式3用的,我们使用的方式1,所以不用管这个值,直接给0即可。
REN负责控制是否允许接收操作,我们此次是单片机向电脑发送数据,所以不涉及到接收,给0即可;
TB8和RB8也是方式2和方式3用的,我们使用的方式1,所以不用管这个值,直接给0即可;

在这里插入图片描述
对于TI和RI,上图手册中描述的有些难以理解,通俗点解释就是,参考串口模式图,其实就是图中的TI和RI:

在这里插入图片描述
TI和RI都是标志位,当TI等于1时,表示已经发送完成;当RI等于1时表示已经接收完成;当检测到发送完成时,TI必须手动置为0;当检测到接收完成时,RI必须手动置为0;

所以总结一下,在初始化时,SCON的配置如下:
从高到低以此为B7=0,B6=1,B5=0,B4=0,B3=0,B2=0,B1=0,B0=0;
SCON=0100 0000,也就是SCON=0x40

SBUF
SBUF是串口数据缓存,在初始化的时候不需要配置。

PCON
在这里插入图片描述
SMOD对应串口模式图中位置如下:
在这里插入图片描述
SMOD控制波特率是否加倍,当SMOD=0时,表示波特率除以2;当SMOD=1时,表示不除以2,也就相当于加倍。

SMOD0表示帧错误检查,如果不需要,配置0即可。

因为是初始化,所以以下几个都可以不用配置。

IE
不配置

IPH
不配置

IP
不配置

SADEN
不配置

SADDR
不配置

至此,串口部分就配置好了,剩下还需要配置定时器的初始化,结合上一节,上一节我们使用的是定时器0,但是串口部分需要定时器1,即将TMOD的高四位设置为1,低四位为0;TMOD &= 0x0F表示先把高四位清空,以便后面对其进行设置。
在这里插入图片描述
另外,在串口模式,定时器要使用双八位自动模式,
在这里插入图片描述

即M1、M0要设置为1、0,即TMOD |= 0x20

另外TH1和TL1涉及到波特率的设置,如下图所示:
在这里插入图片描述

TL1和TH1的值的设置,我们可以使用STC-ISP里带的波特率计算器生成工具来生成代码,如下进行配置:

在这里插入图片描述
然后拿出其中的TL1和TH1的配置即可。

所以代码如下:

TMOD &= 0x0F;		//设置定时器模式
TMOD |= 0x20;		//设置定时器模式
TL1 = 0xF3;		//设定定时初值
TH1 = 0xF3;		//设定定时器重装值
ET1 = 0;		//禁止定时器1中断
TR1 = 1;		//启动定时器1

所以整体的UART_Init函数代码就写好了:

void UART_Init()
{
	SCON=0x40;
	PCON |= 0x80;
	TMOD &= 0x0F;		//设置定时器模式
	TMOD |= 0x20;		//设置定时器模式
	TL1 = 0xF3;		//设定定时初值
	TH1 = 0xF3;		//设定定时器重装值
	ET1 = 0;		//禁止定时器1中断
	TR1 = 1;		//启动定时器1
}

初始化函数写好后,下面就是串口向电脑发送数据,写一个发送数据的函数,如下:

/**
  * @brief  串口发送一个字节数据
  * @param  Byte 要发送的一个字节数据
  * @retval 无
  */
void UART_SendByte(unsigned char Byte)
{
	SBUF=Byte;
	while(TI==0);
	TI=0;
}

即将Byte赋值给SBUF即可,(SBUF在左边,即给他赋值,此时SBUF就默认是写寄存器了。
前面提到,发送完成之后,TI被置为1,需要我们软件手动置为0,所以当检测到TI为0时,说明发送完了,手动TI=0

然后将代码写好编译后,下载到单片机,打开STC-ISP软件中的串口助手,点击打开串口,按下单片机的复位键,即可发现单片机在向电脑从0开始递增发数据,即目标1的效果;(这里需要注意,因为我们代码中写的波特率是4800,所以串口助手中一定要选择波特率为4800,即约定好波特率,否则数据会发送错误,如下图进行设置)
在这里插入图片描述

三、电脑通过串口控制LED

代码路径:51单片机入门教程资料\课件及程序源码\程序源码\KeilProject\8-2 电脑通过串口控制LED

具体代码如下:

#include <REGX52.H>
#include "Delay.h"
#include "UART.h"

void main()
{
	UART_Init();		//串口初始化
	while(1)
	{
		
	}
}

void UART_Routine() interrupt 4
{
	if(RI==1)					//如果接收标志位为1,接收到了数据
	{
		P2=~SBUF;				//读取数据,取反后输出到LED
		UART_SendByte(SBUF);	//将受到的数据发回串口
		RI=0;					//接收标志位清0
	}
}

这里需要注意的是,接收函数设置为了中断触发模式,即void UART_Routine() interrupt 4
为什么是 interrupt 4呢?因为 interrupt 4表示串口的中断函数:
在这里插入图片描述

所以相较于上一节,需要多配置中断模式;如下,初始化时,EA=1,表示启动所有中断;ES=1,表示启动串口中断:

/**
  * @brief  串口初始化,4800bps@12.000MHz
  * @param  无
  * @retval 无
  */
void UART_Init()
{
	SCON=0x50;
	PCON |= 0x80;
	TMOD &= 0x0F;		//设置定时器模式
	TMOD |= 0x20;		//设置定时器模式
	TL1 = 0xF3;		//设定定时初值
	TH1 = 0xF3;		//设定定时器重装值
	ET1 = 0;		//禁止定时器1中断
	TR1 = 1;		//启动定时器1
	EA=1;
	ES=1;
}

在中断处理函数中:

void UART_Routine() interrupt 4
{
	if(RI==1)					//如果接收标志位为1,接收到了数据
	{
		P2=~SBUF;				//读取数据,取反后输出到LED
		UART_SendByte(SBUF);	//将受到的数据发回串口
		RI=0;					//接收标志位清0
	}
}

RI==1表示如果是接收到了信息,因为RI是接收的标志位,当RI等于1时,说明已经成功接收到了数据(判断RI=1的目的是一定要保证这是接收数据触发的中断,因为发送数据也会触发该中断,从以下串口和中断系统图中可以看出,发送和接收是共用同一个中断的,所以一定要进行判断)。
在这里插入图片描述

下一步P2=~SBUF;表示将接收到的数据赋值给P2,此时SBUF在右边,说明是读取SBUF的值,此时SBUF就表示读SBUF了。后面RI=0,是表示读取到数据后,需要软件手动将RI置为0;

其他的代码,跟第二节的代码基本一致。不再详细讲解。

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

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

相关文章

网易云音乐开发--video模块开发

video页面头部搭建 首先头部的结构是这样的 这里采用的是淘宝双飞翼布局。俩端固定&#xff0c;中间自适应。 这里说一下这个flex:1 flex-grow:可拉伸 flex-shrink:可压缩 flex-basis:当前元素的宽度 flex默认值:flex-grow:0,flex-shrink:1,flex-basis:auto flex:1 flex-gr…

Linux一学就会——系统文件I/O

Linux一学就会——系统文件I/O 有几种输出信息到显示器的方式 #include <stdio.h> #include <string.h> int main() {const char *msg "hello fwrite\n";fwrite(msg, strlen(msg), 1, stdout);printf("hello printf\n");fprintf(stdout, &q…

DEJA_VU3D - Cesium功能集 之 106-鹰眼地图

前言 编写这个专栏主要目的是对工作之中基于Cesium实现过的功能进行整合,有自己琢磨实现的,也有参考其他大神后整理实现的,初步算了算现在有差不多实现小140个左右的功能,后续也会不断的追加,所以暂时打算一周2-3更的样子来更新本专栏(每篇博文都会奉上完整demo的源代码…

如何使用 YOLOv8 神经网络检测图像中的物体

对象检测是一项计算机视觉任务,涉及识别和定位图像或视频中的对象。它是许多应用的重要组成部分,例如自动驾驶汽车、机器人和视频监控。 多年来,已经开发了许多方法和算法来查找图像中的对象及其位置。执行这些任务的最佳质量来自使用卷积神经网络。 YOLO 是这项任务最流行的…

计算机网络——快速了解传输层协议

文章目录 一、TCP和UDP的区别二、TCP1.TCP报文段2.建立连接&#xff08;三次握手&#xff09;3.断开连接&#xff08;四次挥手&#xff09;4.TCP提供的支持 三、UDP参考 一、TCP和UDP的区别 传输层协议有两个——TCP和UDP&#xff0c;二者区别如下&#xff1a; 二、TCP 1.TCP…

MySQL集群

目录 主从复制 主从复制流程&#xff1a; 为什么要有relay log中继日志&#xff1f; 为什么要有主从复制&#xff0c;好处&#xff1f; 实际生产环境中。如果对MySQL数据库的读写都在一台数据库服务器中操作&#xff0c;无论是再安全性、高可用性&#xff0c;还是高并发性等…

MapReduce之WordCount本地测试

1&#xff09;需求 在给定的文本文件中统计输出每一个单词出现的总次数。 &#xff08;1&#xff09;输入数据 2&#xff09;期望输出数据 banzhang 1 cls 2 hadoop 1 jiao 1 ss 2 xue 1 2&#xff09;需求分析 按照MapReduce编程规范&#xff0c;分别编写Mapper&#x…

跨境电商支付平台-PingPong Pay(实现收银台模式沙箱支付)

介绍 PingPongCheckout 跨境支付的 API 接口文档,商户服务器和 PingPongCheckout 服务器进行交互。 供商户/平台服务方的技术开发及测试相关人员使用。 本文档分别从交互流程、通讯方式、签名方 案、交易接口、注意事项等⻆度详细介绍了 PingPongCheckout 跨境支付 API 接口的…

【C++】类和对象(中篇)

几个成员函数 类的6个默认成员函数构造函数引例特点 析构函数概念特点 拷贝构造函数概念特征 赋值运算符重载赋值运算符重载赋值运算符只能重载成类的成员函数不能重载成全局函数前置和后置重载 日期类的实现const成员函数取地址及const取地址操作符重载 类的6个默认成员函数 …

Web缓存利用分析(二)

导语&#xff1a;在上一篇文章中&#xff0c;大致介绍了一些关于Web Cache的攻击方式及CTF中的一些出现。而本篇文章则会聚焦于Web Cache在学术前沿的一些攻击利用方式的探究。 前言 在上一篇文章中&#xff0c;大致介绍了一些关于Web Cache的攻击方式及CTF中的一些出现。而本…

Web缓存利用分析(一)

导语&#xff1a;最近看到一些Web Cache方面的攻击&#xff0c;于是总结了一下&#xff0c;内容如下。 前言 最近看到一些Web Cache方面的攻击&#xff0c;于是总结了一下&#xff0c;内容如下。 背景知识 Cache是一种经典的用空间换时间的做法&#xff0c;其应用场景非常广…

Htop使用说明

目录 引言 什么是htop htop安装 htop界面介绍 htop功能介绍 引言 我们使用服务器的时候常常需要关注下自己的程序资源占用情况&#xff0c;htop就是一种互动式的进程查查看器&#xff0c;整齐用下来感觉比top的逼格高&#xff0c;造作可视化都更方便些&#xff0c;我觉得还…

《Vue.js 设计与实现》—— 02 框架设计核心要素

框架设计并非仅仅实现功能那么简单&#xff0c;里面有很多学问。例如&#xff1a; 框架应该给用户提供哪些构建产物&#xff1f;产物的模块格式如何&#xff1f; 当用户没有以预期的方式使用框架时&#xff0c;是否应该打印合适的警告信息从而提供更好的开发体验&#xff0c;让…

优化性能测试分析:如何科学利用CPU异常曲线

性能测试为保证软件质量起到重要作用&#xff0c;对于交易量较大的应用系统&#xff0c;性能测试更是一个必不可少的环节。 测试人员通常通过监测响应时间、吞吐量、应用服务器和数据库服务器的CPU及内存来衡量系统的性能是否达标&#xff0c;那么&#xff0c;在性能测试过程中…

LabVIEWCompactRIO 开发指南13 网络发布的共享变量

LabVIEWCompactRIO 开发指南13 网络发布的共享变量 跨网络共享标签的一种方法是网络共享变量。术语网络变量是指网络上可以在程序、应用程序、远程计算机和硬件之间进行通信的软件项。网络共享变量非常适合1:N或N:1设置&#xff0c;因为它们有一个内置的连接管理器来管理传入…

《Netty》从零开始学netty源码(五十六)之RecvByteBufAllocator

RecvByteBufAllocator 在创建channel的过程中会创建一个相应的配置类&#xff0c;该类存储了一些关于channel的属性&#xff0c;包括分配内存的ByteBufAllocator和预估大小的RecvByteBufAllocator&#xff0c;通过前面的学习我们知道ByteBufAllocator分配内存的时候最终会委托…

Consensus洞察|2023,Web3“脱虚向实”元年

前言 2023年对于Web3来说&#xff0c;是一个被推到主流社会前台的关键时期。 出品&#xff5c;欧科云链研究院 作者&#xff5c;毕良寰 Web3作为新兴科技&#xff0c;其发展路径在近几年尤为艰难&#xff0c;充斥着“丑闻”的2022年&#xff0c;以Luna/UST的崩溃为起点开启了…

c++类与对象(二)——赋值运算符重载与取地址操作符重载

文章目录 一.运算符重载1.运算符重载的概念2.实现Date类&#xff08;1&#xff09;> < > < ! 重载&#xff08;2&#xff09; - - 重载&#xff08;3&#xff09;前置与后置重载&#xff08;4&#xff09;日期-日期的实现&#xff08;5&#xff09;<< 与 &g…

代码随想录之额外题目

数组 1207 独一无二的出现次数 看数组的大小和长度都没有很大&#xff0c;所以可以直接用数组来做哈希表&#xff0c;用一个数组来记录出现次数&#xff0c;再用一个数组来标记出现次数的值是否出现过。就是O(n) class Solution {public boolean uniqueOccurrences(int[] arr…

Spring IOC:IOC在Spring底层中如何实现?

编译软件&#xff1a;IntelliJ IDEA 2019.2.4 x64 操作系统&#xff1a;win10 x64 位 家庭版 Maven版本&#xff1a;apache-maven-3.6.3 Mybatis版本&#xff1a;3.5.6 spring版本&#xff1a;5.3.1 文章目录 Spring系列专栏文章目录一. 什么是IOC?二. IOC在spring中的实现2.1…