学习笔记|串口通信的基础知识|同步/异步|RS232|常见的串口软件的参数|STC32G单片机视频开发教程(冲哥)|第二十集:串口通信基础

news2024/11/24 10:27:21

目录

  • 1.串口通信的基础知识
    • 串口通信(Serial Communication)
    • 同步/异步?
    • 全双工?
    • 常见的串口软件的参数
  • 2.STC32的串口通信实现原理
    • 引脚选择:实现分时复用
    • 模式选择
      • 串口1模式1,模式1波特率计算公式
  • 3.串口通信代码实现
    • 编写串口1通信程序
      • 15.5.4 串口2使用定时器2做波特率发生器
      • 新建工程16.串口2通信
    • 错误排查及代码分析
  • 总结
  • 课后练习:

1.串口通信的基础知识

百度百科:串口通信的概念
什么是通信?
例如U盘和电脑,我们电脑需要往U盘存东西,而U盘上只有四个触点,除去一个电源一个地,只剩下两个引脚了。此时我们坑定不能像点亮LED那样单纯的给他两个引脚上输出个高低电平就能写数据了对吧。总不至于输出一个高电平就能在U盘里写入“STC32位8051单片机就是牛!”这么一句话了吧。
通信指设备之间通过一定的协议进行的信息交换。
在这里插入图片描述
每次发送一位数据的称为串行通信,多位(严格来说是2位以上)一起传输的称为并行通信。
今天要讲的串口通信是串行通信的其中的一种!也是1位1位的往外发数据,不是像这个图一样8位一起发。
stc共有4个串口!串口1/2和3/4的主要区别在这里,这节课主要讲异步串口。
在这里插入图片描述
在这里插入图片描述

串口通信(Serial Communication)

是指外设和计算机间,通过数据信号线 、地线、控制线等,按位进行传输数据的一种通讯方式。这种通信方式使用的数据线少,在远距离通信中可以节约通信成本,但其传输速度比并行传输低。
在这里插入图片描述

同步/异步?

异步方式(使用较多):
在这里插入图片描述
①以字符为单位传送信息。
②相邻两字符间的间隔是任意长。
③因为一个字符中的比特位长度有限,所以需 要的接收时钟和发送时钟只要相近就可以。
④异步方式特点简单的说就是:字符间异步,字符内部各位同步。
同步方式:
在这里插入图片描述
①以数据块为单位传送信息。
②在一个数据块(信息帧)内,字符与字符间无间隔。
③因为一次传输的数据块中包含的数据较多,所以接收时钟与发送进钟严格同步,通常要有同步时钟。

全双工?

在这里插入图片描述

常见的串口软件的参数

这里的4个数据发送端和接收段必须严格保持一致。否则接收到的就是乱码。
●波特率?
例如9600的波特率意味着每秒钟可以发9600位的数据。
在这里插入图片描述
我们这里起始位就是一个位(一个二进制的一个数0或者1),1bit的变量。中间有8个数据为,然后校验位,停止位。速度9600即每秒最快可以发960个这种包,
●数据位? 有几个2进制位的数据
●校验位?
●停止位?
在这里插入图片描述

在这里插入图片描述
●传输距离
通信距离很短,如何解决?
以下分别为RS232,RS422,RS485的通信原理图。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
串口的逻辑电平只有5V或者3.3V,如果单片机是5V供电,逻辑电平只有5V(高电平),因为电平比较低,传输距离受限,
●串口有什么用
在这里插入图片描述

2.STC32的串口通信实现原理

引脚选择:实现分时复用

在这里插入图片描述

模式选择

在这里插入图片描述
在这里插入图片描述
每一种模式的配置参考手册,这里不再复述。这里主要讲串口1的模式1(应用最广泛)。

串口1模式1,模式1波特率计算公式

当软件设置SCON的SMO、SM1为“01”时,串行口1则以模式Ⅰ进行工作。此模式为8位UART格式,一帧信息为10位:1位起始位,8位数据位(低位在先)和1位停止位。波特率可变,即可根据需要进行设置波特率。TxD为数据发送口,RxD为数据接收口,串行口全双工接受/发送。
模式Ⅰ的发送过程:串行通信模式发送时,数据由串行发送端TxD输出。当主机执行一条写SBUF的指令就启动串行通信的发送,写“SBUF”信号还把“1”装入发送移位寄存器的第9位,并通知TX控制单元开始发送。移位寄存器将数据不断右移送TxD端口发送,在数据的左边不断移入“O”作补充。当数据的最高位移到移位寄存器的输出位置,紧跟其后的是第9位“1”,在它的左边各位全为“0”,这个状态条件,使TX控制单元作最后一次移位输出,然后使允许发送信号“SEND”失效,完成一帧信息的发送,并置位中断请求位TI,即 TI=1,向主机请求中断处理。
模式1的接收过程:当软件置位接收允许标志位.REN,即REN=1时,接收器便对RxD端口的信号进行检测,当检测到RxD端口发送从“1”→“O”的下降沿跳变时就启动接收器准备接收数据,并立即复位波特率发生器的接收计数器,将IFFH装入移位寄存器。接收的数据从接收移位寄存器的右边移入,已装入的IFFH向左边移出,当起始位"0O"移到移位寄存器的最左边时,使RX控制器作最后一次移位,完成一帧的接收。若同时满足以下两个条件:
·RI=0;
. SM2=0或接收到的停止位为1。
则接收到的数据有效,实现装载入SBUF,停止位进入RB8,RI标志位被置l,向主机请求中断,若上述两条件不能同时满足,则接收到的数据作废并丢失,无论条件满足与否,接收器重又检测RxD端口上的"1"→"0"的跳变,继续下一帧的接收。接收有效,在响应中断后,RI标志位必须由软件清0。通常情况下,串行通信工作于模式1时,SM2设置为"0"。
在这里插入图片描述
串口1的波特率是可变的,其波特率可由定时器1或者定时器2产生。当定时器采用IT模式时(12倍速),相应的波特率的速度也会相应提高12倍。
在这里插入图片描述
在这里插入图片描述
模式2和模式3,大同小异,不深入展开。

3.串口通信代码实现

在这里插入图片描述
在这里插入图片描述
RXD和TXD接在了P4.6跟P4.7上,使用的是串口2。

编写串口1通信程序

打开手册15.5 范例程序

15.5.4 串口2使用定时器2做波特率发生器

在这里插入图片描述

新建工程16.串口2通信

复制"15.NTC温度采集"工程为"16.串口2通信",HARDWARE目录中新建usart子目录,并将usart文件夹加入include,新建usart2.c和usart2.h,:
插入头文件模板,并修改。
先编写初始化函数声明:void Usart2_Init(void);,入口参数肯定是无。函数实现(先把官方例程的初始化抄写过来):


#define	BRT		(65536 - (MAIN_Fosc / 115200+2)/4) 	//加2操作是为了让Keil编译器自动实现四舍五入运算

void Usart2_Init(void)
{
	P_SW2 = 0X80; 	//0X80=1000 0000
	S2CFG = 0X01;

	S2CON = 0X50;
	T2L = BRT;
	T2H = BRT>>8;
	T2x12 = 1;
	T2R =1;

	wptr = 0x00;
	rptr = 0x00;
	busy = 0;
}

串口要用到主频,将该定义从demo.c中移动到usart2.h中。单独写在串口里面。
初始化代码中有三个小写的变量,属于用户定义变量,需要增加定义。另外,在头文件中也要增加定义(主函数中也会使用到这些变量),使用extern关键字。

extern bit busy;
extern char wptr;
extern char rptr;
extern char buffer[16];

编写中断服务函数,中断函数的名字可以任意取,只要后面的中断号无错误即可。
增加发送函数Usart2_Send和void Usart2_SendStr(char *p),并在头文件中声明。
在主函数中删除上节课无用内容,再调用串口初始化,demo.c中while循环内的usb串口部分可以注释掉,本节不使用。
时间部分可以留着,方便计时。
修改后的源代码如下。
demo.c中的main函数部分:

void main()					//程序开始运行的入口
{

	sys_init();				//USB功能+IO口初始化
	usb_init();				//usb库初始化

	delay_ms(500);
	Timer0_Init();			//定时器0初始化
	Usart2_Init();			//串口初始化
	IE2 = 0X01;

	EA = 1;					//CPU开放中断,打开总中断。

	Usart2_SendStr("Usart2 Test !\r\n");

	while(1)		//死循环
	{

		if( TIM_10MS_Flag==1 )									//如果10ms到了
		{
			TIM_10MS_Flag = 0;									//清空标志位
		}
		if (rptr != wptr)
		{
			Usart2_Send(buffer[rptr++]);						//字符发送
			rptr &= 0x0f;
		}

	}
}

Usart2.c:

#include "usart2.h"


#define	BRT		(65536 - (MAIN_Fosc / 115200+2)/4) 	//加2操作是为了让Keil编译器自动实现四舍五入运算

bit busy;
char wptr;
char rptr;
char buffer[16];

void Usart2_Init(void)
{
	P_SW2 = 0X80; 	//0X80=1000 0000
	S2CFG = 0X01;

	S2CON = 0X50;
	T2L = BRT;		//BRT为宏定义,
	T2H = BRT>>8;
	T2x12 = 1;
	T2R =1;

	wptr = 0x00;
	rptr = 0x00;
	busy = 0;
}

void Usart_Isr() interrupt 8
{
	if( S2TI )
	{
		S2TI = 0;
		busy = 0;
	}
	if( S2RI )
	{
		S2RI = 0;
		buffer[wptr++] = S2BUF;
		wptr &= 0X0F;
	}
}

void Usart2_Send(char dat)
{
	while(busy);
	busy = 1;
	S2BUF = dat;
}

void Usart2_SendStr(char *p)
{
	while(*p)
	{
		Usart2_Send(*p++);
	}
}

Usart2.h:

#ifndef __USART2_H
#define __USART2_H

#include "COMM/stc.h"			//调用头文件
#include "COMM/usb.h"

#define MAIN_Fosc 11059200UL	//定义为无符号长整型,避免计算溢出

//------------------------引脚定义------------------------//


//------------------------变量声明------------------------//

extern bit busy;
extern char wptr;
extern char rptr;
extern char buffer[16];

//------------------------函数声明-----------------------//
void Usart2_Init(void);
void Usart2_Send(char dat);
void Usart2_SendStr(char *p);

#endif

编译成功,下载进去看一下。注意,这里的时钟选择11.0592。使用串口线(使用usb转串口线usb-RS232),按要求接线,并选择正确的串口。
在这里插入图片描述

错误排查及代码分析

下载完成后,无反应,看一下代码,在执行主函数之前就应该执行串口发送,但是串口工具里无变化,检查串口工具参数设置,
都是对的,回过头看手册,查找问题原因,先找到初始化Usart2_Init,在手册中使用高级搜索功能,查找P_SW2:
在这里插入图片描述
找到定义:3.1.2 外设端口切换控制寄存器2(P_sW2):
在这里插入图片描述
使能访问XFR,EAXFR在sys_init中已经使能:EAXFR = 1; //扩展寄存器(XFR)访问使能,所以P_SW2 = 0X80; 不使用也是可以的。
查看S2_S:串口2功能脚选择位,开发板上的串口2需切换到P4.6和P4.7引脚上,S2_S位应置为1,这里可以使用或等于,在不影响最高位的情况下,设置S2_S位,即增加:P_SW2 |= 0X01;
再查找S2CFG,目录对应项跳转至:15.4.3 串口⒉配置寄存器(S2CFG)。这里设置W1为1,解释:W1:当需要使用串口2时,此位必须设置为“1”,否则可能会产生不可预期的错误。若不需使用串口
2,则不用特别设置W1。
搜索S2CON,跳转至15.4.1串口2控制寄存器(S2CON)。
在这里插入图片描述
S2CON = 0X50; //0X50=01010000,设置为模式1:可变波特率8位数据方式,S2REN=1:允许串口接收数据
T2L,T2H是定时器相关设置,串口需要用到1个定时器来生成波特率,也就是作为一个基准时钟。具体设置为:首先它传入的是一个数组

	T2L = BRT;		//BRT为宏定义,
	T2H = BRT>>8;
	T2x12 = 1;
	T2R =1;

接下来是3个变量。如果说TI需要发送数据,发送完了以后把这个变量给他清零。发送时先检测一下busy,如果等于1,说明上次的数据还没有发完,阻塞,继续等待。
如果发送完了,先把busy置1,然后把数据写入S2BUF的位里面,之后开始发送,看一下手册15.3.6串口1模式1,模式1波特率计算公式中的时序图,和串口2同理,数据发送完之后,才会变成高电平,
在这里插入图片描述
也就是执行if( S2TI ):S2T:串口2发送中断请求标志位。在模式0中,当串口发送数据第8位结束时,由硬件自动将S2TI置1,向主机请求中断,响应中断后S2TI必须用软件清零。在其他模式中,则在停止位开始发送时由硬件自动将S2TI置1,向CPU发请求中断,响应中断后S2TI必须用软件清零。满足条件后S2TI清0,这个BUSY其实是个忙碌标志位。也就是等于0的时候他才能发送数据,把数据直接写进S2BUF寄存器中就可以自动发送。S2BUF进行读操作,实际是读取串口接收缓冲区,对S2BUF进行写操作则是触发串口开始发送数据。
void Usart2_SendStr(char *p) //发送整个字符。while(*p)可以用这个判断他这个字符是否为空,这里用到了一个指针的技巧,首先传入的是一个数组或者说是地址,把里面的数不断发送出去,直到发送至最后一位。发完之后结束。这样写以后,如果想发字符串只要在双引号内写入即可。
接收到8位数值后,RI会变高,进入中断,if( S2RI ),进入后先清0,将读到的数据存入,只会把地址加1,也就是接收到的数值位数。每接收到1个就加1,接收到的最大值是0x0f=16。
接下来,demo.c中判断:if (rptr != wptr),如果rptr不等于tptr,那就就将rptr的数值不断累加,然后直到等于这个数值。
可以看到,分析过程代码段中仅增加了1行:P_SW2 |= 0X01; //开发板上的串口2需切换到P4.6和P4.7引脚上。
重新编译,手动下载,可以看到数值显示了,需要打印的参数显示出来了,也可以再把需要的数据写进去,可以回显出来,可以试试。
这里的演示功能仅为上电显示一段文字,运行过程中发送什么文字,返回显示同样的文字。重点需要注意默认选择的引脚。写的时候一定要按照实际电路引脚去写。

总结

1.学会串口的一专业名词。
2.学会串口的配置和使用(也可以去学习一下试验箱代码,里面的代码非常全面)
总共有4个串口,例程包里4个串口都有示例代码,基本上所有用的的代码均已涵盖,示例里的初始化也写的非常详细,可以选择不一样的定时器,只有定时器2可以同时为4个串口作为波特率发生器,

课后练习:

1.串口发送字符Ax\r\n,(x表示0-7)板子点亮对应LED
2.串口发送Bxxxx\r\n,xxxx表示一个四位数,四位数码管显示这个4位数
2.串口发送Z\r\n,板子给电脑发送“Hello STC”;
3.串口发送字符Cx\r\n,(x表示0-1)板子打开/关闭蜂鸣
4.串口发送字符Dx\r\n,板子通过串口发送当前温度给电脑。
能独立做出这个实验的话,说明你已经快出师了。

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

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

相关文章

C++深入学习part_2

面向对象思想 这一节Java里面都有类似的概念,比较简单,就不写的太啰嗦了。 首先是认识以前面向过程的思想: 而现在再来感受一下面向对象的思想: 这玩意儿学过Java的话应该是比较简单的,就不再赘述了。 类的定义 代…

数据安全防护:云访问安全代理(CASB)

云访问安全代理(Cloud Access Security Broker,CASB),是一款面向应用的数据防护服务,基于免应用开发改造的配置方式,提供数据加密、数据脱敏功能。数据加密支持国密算法,提供面向服务侧的字段级…

玄子Share- IDEA 2023 Web 热部署

玄子Share- IDEA 2023 热部署 添加热部署依赖 普通 Web 项目使用热部署插件需指定版本 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><version>3.1.3</version><!-…

nrm 安装教程(图文教程)

序&#xff1a; 1、都知道nvm解决的是node版本切换的问题&#xff0c;nrm 解决的是则是npm指向的问题。 2、雪狼的公众号&#xff1a;“程序员野区”&#xff0c;也许未来的莫一天&#xff0c;你会用到&#xff0c;不凡先进来瞅瞅公众号都分享了啥内容 正文&#xff1a; 1、安…

vue3+elementPlus:el-select选择器里添加按钮button

vue3elementPlus&#xff1a;el-select选择器里添加按钮button&#xff0c;在el-select的option后面添加button //html <el-select class"selectIcon" value-key"id" v-model"store.state.HeaderfilterText" multiple collapse-tagscollapse-…

力扣(LeetCode)2034. 股票价格波动(C++)

哈希表有序集合 请看本题解的分析&#xff1a; 题目的关键是四大操作&#xff0c;其中 current/maximum/minimum 明示我们&#xff0c;数据流应有快速找到一些数据的能力&#xff1a; 时间戳最大的股票所对应的价格&#xff0c;即题目所定义的最新股票价格在当前数据流节点&a…

Headless CMS(strapi)

Headless CMS(strapi) 玩了玩微信小程序的cms&#xff0c;感觉还挺好的&#xff0c;不过目前处于公测阶段&#xff0c;后续应该还是要收费的&#xff0c;不过这个操作还挺好的。文档地址 不过其获取图片的时候默认用到的是小城云开发环境的链接样式&#xff0c;如果用在公开网…

【Zookeeper专题】Zookeeper经典应用场景实战(二)

目录 前置知识课程内容一、Zookeeper分布式锁实战1.1 什么是分布式锁1.2 基于数据库设计思路1.3 基于Zookeeper设计思路一1.4 基于Zookeeper设计思路二1.5 Curator 可重入分布式锁工作流程1.6 总结 二、基于Zookeeper实现服务的注册与发现2.1 设计思路2.2 Zookeeper实现注册中心…

聊聊分布式架构04——RPC通信原理

目录 RPC通信的基本原理 RPC结构 手撸简陋版RPC 知识点梳理 1.Socket套接字通信机制 2.通信过程的序列化与反序列化 3.动态代理 4.反射 思维流程梳理 码起来 服务端时序图 服务端—Api与Provider模块 客户端时序图 RPC通信的基本原理 RPC&#xff08;Remote Proc…

算法通过村第十二关-字符串|黄金笔记|冲刺难题

文章目录 前言最长公共前缀纵向比较横向比较 字符串压缩问题表示数值的字符串总结 前言 提示&#xff1a;我有时候在想&#xff0c;我是真的不太需要其他人&#xff0c;还是因为跟他们在一起时没法自己&#xff0c;所以才保持距离。我们的交谈就像是平行而毫无交集的自言自语。…

高压功率放大器是什么东西

高压功率放大器是一种电子设备&#xff0c;用于将低功率信号放大到高功率水平。它通常由多个功率放大器组成&#xff0c;可以处理来自各种信号源的输入信号&#xff0c;并输出具有更大功率的信号。 高压功率放大器广泛应用于许多领域&#xff0c;包括无线通信、广播、雷达、医学…

Pytorch-学习记录-1-Tensor

1. 张量 (Tensor): 数学中指的是多维数组&#xff1b; torch.Tensor data: 被封装的 Tensor dtype: 张量的数据类型 shape: 张量的形状 device: 张量所在的设备&#xff0c;GPU/CPU requires_grad: 指示是否需要计算梯度 grad: data 的梯度 grad_fn: 创建 Tensor 的 Functio…

要多搞笑才能上B站热门?

自从B站开放竖屏模式之后&#xff0c;越来越多站外的优秀创作者加入B站。这其中搞笑UP主的数量大大增加&#xff0c;有很多竖屏UP主、短视频UP主在B站发光发热。 飞瓜数据&#xff08;B站版&#xff09;热门视频显示&#xff0c;近期热度最高的是来自UP主七颗猩猩QKXX发布的竖…

three.js点击模型实现模型边缘高亮选中效果

three.jsreact实现点击模型实现高亮选中效果 1、创建一个场景 let scene, camera, renderer, controls; let stats null; // 检测动画运行时的帧数 let clock new THREE.Clock(); // getDelta()方法获得两帧的时间间隔 let FPS 30; let renderT 1 / FPS; let timeS 0;con…

机器学习基础-数据分析:房价预测

mac设置中文字体 #要设置下面两行才能显示中文 Arial Unicode MS 为字体 plt.rcParams[font.sans-serif] [Arial Unicode MS] #设置图片大小 plt.figure(figsize(20, 11), dpi200)pie官方文档 总体代码 python import pandas as pd import numpy as np import matplotlib.…

Qt/C++原创推流工具/支持多种流媒体服务/ZLMediaKit/srs/mediamtx等

一、前言 1.1 功能特点 支持各种本地视频文件和网络视频文件。支持各种网络视频流&#xff0c;网络摄像头&#xff0c;协议包括rtsp、rtmp、http。支持将本地摄像头设备推流&#xff0c;可指定分辨率和帧率等。支持将本地桌面推流&#xff0c;可指定屏幕区域和帧率等。自动启…

【大数据 | 综合实践】大数据技术基础综合项目 - 基于GitHub API的数据采集与分析平台

&#x1f935;‍♂️ 个人主页: AI_magician &#x1f4e1;主页地址&#xff1a; 作者简介&#xff1a;CSDN内容合伙人&#xff0c;全栈领域优质创作者。 &#x1f468;‍&#x1f4bb;景愿&#xff1a;旨在于能和更多的热爱计算机的伙伴一起成长&#xff01;&#xff01;&…

在供应链管理中,如何做好库存分析?库存分析有哪些监控指标?

在供应链管理中&#xff0c;库存分析是其重要的一环。库存分析的方法繁杂且广泛&#xff0c;选择正确的方法才能更好的进行库存分析&#xff0c;下面就为大家盘点一些常用的库存分析方法和监控指标&#xff0c;全程干货&#xff0c;建议收藏&#xff01; 01 如何进行库存分析&…

【MySQL】基本查询(三)聚合函数+group by

文章目录 一. 聚合函数二. group by子句结束语 建立如下表 //创建表结构 mysql> create table exam_result(-> id int unsigned primary key auto_increment,-> name varchar(20) not null comment 同学姓名,-> chinese float default 0.0 comment 语文成绩,->…

08_selenium实战——学习平台公开数据批量获取

0、:前言 该实战任务是对某视频平台中’标题’、 ‘点赞数量’、 ‘投币数量’、‘收藏数量’、‘播放次数’、以及前五条评论进行爬取。要求1:可以控制爬取视频的主题(爬取主题搜索之后的内容)要求2:可以控制爬取视频的数量要求3:对于评论数不足5条的用0填充评论内容爬虫…