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

目录

  • 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,板子通过串口发送当前温度给电脑。
能独立做出这个实验的话,说明你已经快出师了。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【嘉立创EDA-PCB设计指南】4.模块化布局

前言:本文对本专栏中的【嘉立创EDA-PCB设计指南】前面绘制的原理图进行模块化布局,首先进行预布局(将每个模块放一起),然后进行精细化布局(按照原理图来精细化布局)。 目录 模块化预布局 模块…

cesium实现动态围栏

项目中使用到了cesium,需要实现动态的围栏的效果, 在网上也找了好多案例,通过着色器来实现效果,为此也有好多博主也附上了自己的代码,也许是因为使用方法不同,复制代码并修改依旧还是没有通过他们的方式实现效果【着色…

【cucumber】cluecumber-report-plugin生成测试报告

cluecumber为生成测试报告的第三方插件&#xff0c;可以生成html测报&#xff0c;该测报生成需以本地json测报的生成为基础。 所以需要在测试开始主文件标签CucumberOptions中&#xff0c;写入生成json报告。 2. pom xml文件中加入插件 <!-- 根据 cucumber json文件 美化测…

Python正则表达式Regular Expression初探

目录 Regular 匹配规则 单字符匹配 数量匹配 边界匹配 分组匹配 贪婪与懒惰 原版说明 特殊字符 转义序列 模块方法 函数说明 匹配模式 常用匹配规则 1. 匹配出所有整数 2. 匹配11位且13开头的整数 Regular Python的re模块提供了完整的正则表达式功能。正则表达式…

Github操作网络异常笔记

Github操作网络异常笔记 1. 源由2. 解决2.1 方案一2.2 方案二 3. 总结 1. 源由 开源技术在国内永远是“蛋疼”&#xff0c;这些"政治"问题对于追求技术的我们&#xff0c;形成无法回避的障碍。 $ git pull ssh: connect to host github.com port 22: Connection ti…

即插即用篇 | AKConv:具有任意采样形状和任意参数数量的卷积核

基于卷积操作的神经网络在深度学习领域取得了显著的成果,但标准卷积操作存在两个固有缺陷。一方面,卷积操作受限于局部窗口,无法捕捉其他位置的信息,而其采样形状是固定的。另一方面,卷积核的大小固定为kk,呈固定的正方形形状,而参数数量往往随大小呈平方增长。显然,不…

5. 函数调用过程汇编分析

函数调用约定 __cdecl 调用方式 __stdcall 调用方式 __fastcall 调用方式 函数调用栈帧分析 补充说明 不同的编译器实现不一样&#xff0c;上述情况只是VC6.0的编译实现即便是在同一个编译器&#xff0c;开启优化和关闭优化也不一样即便是同一个编译器同一种模式&#xff0c;3…

【每日一题】1. 牛客网——合并两个有序数组

&#x1f4da;博客主页&#xff1a;爱敲代码的小杨. ✨专栏&#xff1a;《Java SE语法》 ❤️感谢大家点赞&#x1f44d;&#x1f3fb;收藏⭐评论✍&#x1f3fb;&#xff0c;您的三连就是我持续更新的动力❤️ &#x1f64f;小杨水平有限&#xff0c;欢迎各位大佬指点&…

【Linux】安装n卡驱动以及可能遇到的问题

文章目录 1.换源以及更新2.安装依赖3. 安装n卡驱动独显与核显切换nvidia-settings消失忘记安装依赖无法进入图形化界面的急救命令行无响应办法 1.换源以及更新 目前&#xff0c;换源完全只需要鼠标点点点就可以完成了&#xff0c;打开应用列表里的Software & Updates&…

基于 IDEA 创建 Maven 工程

1. 概念梳理Maven工程的GAVP Maven工程相对之前的项目&#xff0c;多出一组gavp属性&#xff0c;gav&#xff08;表示当前工程的坐标&#xff09;需要我们在创建项目的时候指定&#xff0c;p&#xff08;表示打包方式&#xff09;有默认值&#xff08;默认为 jar 包&#xff0…

【学习记录24】vue3自定义指令

一、在单vue文件中直接使用 1、html部分 <template><divstyle"height: 100%;"v-loading"loading"><ul><li v-for"item in data">{{item}} - {{item * 2}}</li></ul></div> </template> 2、js…

Redis(01)——常用指令

基础指令 select 数字&#xff1a;切换到其他数据库flushdb&#xff1a;清空当前数据库flushall&#xff1a;清空所有数据库dbsize&#xff1a;查看数据库大小exists key1[key2 …]&#xff1a;判断当前的key是否存在keys *&#xff1a;查看所有的keyexpire key 时间&#xff…

智慧校园统一信息门户平台介绍

统一信息门户平台是以统一身份认证平台为基础,将校内分散、异构的应用和信息资源进行整合,通过统一的访问入口,实现各种应用系统的无缝接入和集成,并围绕校内人员之间的人际关系,构建一个支持信息访问、传递、以及协作的集成化环境,实现个性化业务应用的高效开发、集成、…

Python使用graphviz绘制模块间数据流

graphviz官方参考链接&#xff1a; http://www.graphviz.org/documentation/ https://graphviz.readthedocs.io/en/stable/index.html 文章目录 需求描述环境配置实现思路代码实现 需求描述 根据各模块之间的传参关系绘制出数据流&#xff0c;如下图所示&#xff1a; 并且生成…

LabVIEW扫描探针显微镜系统开发

在纳米技术对高精度材料特性测量的需求日益增长。介绍了基于LabVIEW开发的扫描探针显微镜&#xff08;SPM&#xff09;系统。该系统不仅可以高效地测量材料的热物性&#xff0c;还能在纳米尺度上探究热电性质&#xff0c;为材料研究提供了强大的工具。 系统基于扫描探针显微技…

自我摸索:如何运营并玩转CSDN?

自注册CSDN以来已有七年之久&#xff0c;但真正运营CSDN也是最近一年的事情&#xff0c;大概就是22年底&#xff0c;参加2022 博客之星 的竞选。接触了很多大佬&#xff0c;也学习模仿着开始玩转CSDN&#xff0c;虽然没有同期运营的大佬们玩的6&#xff0c;但也有一些经验可以来…

【JavaEE进阶】实现验证码

文章目录 &#x1f332;实现说明&#x1f343;Kaptcha插件介绍&#x1f6a9;插件原理&#x1f6a9;引入依赖&#x1f6a9;⽣成验证码&#x1f6a9;Kaptcha详细配置 &#x1f340;准备⼯作&#x1f334;约定前后端交互接⼝&#x1f6a9;需求分析&#x1f6a9;接⼝定义&#x1f6…

【算法练习Day50】下一个更大元素II接雨水

​&#x1f4dd;个人主页&#xff1a;Sherry的成长之路 &#x1f3e0;学习社区&#xff1a;Sherry的成长之路&#xff08;个人社区&#xff09; &#x1f4d6;专栏链接&#xff1a;练题 &#x1f3af;长路漫漫浩浩&#xff0c;万事皆有期待 文章目录 下一个更大元素II接雨水单调…

Java毕业设计第90期-基于springboot的学习英语管理系统

获取源码资料&#xff0c;请移步从戎源码网&#xff1a;从戎源码网_专业的计算机毕业设计网站 项目介绍 基于springboot的学习英语管理系统&#xff1a;前端 thymeleaf、jquery&#xff0c;后端 maven、springmvc、spring、mybatis&#xff0c;角色分为管理员、用户&#xff…

小程序进阶学习(音乐首页-轮播图)

轮播图 样式 轮播图的重点是轮播图的大小&#xff0c;因为每个手机的屏幕大小不一样&#xff0c;但是轮播图的大小是固定的就需要一些技术获取到手机的轮播图大小&#xff0c;然后再设置图片的大小和轮播图边框的大小。 页面代码 <van-searchvalue"{{ value }}"s…