stm32之串口使用和串口中断

1.定义

串口通讯(Serial Communication)是一种设备间非常常用的串行通讯方式,因为它简单便捷,因此大部分电子设备都支持该通讯方式,其通讯协议可分层为协议层和物理层。物理层规定通信协议中具有机械、电子功能的特性,从而确保原始数据在物理媒体的传播;协议层主要规定通讯逻辑,统一双方的数据打包、解包标准。通俗的讲物理层规定我们用嘴巴还是肢体交流,协议层规定我们用中文还是英文交流。下面分析一下串口通讯协议的物理层和协议层。

2.通信基础

1.通讯结构
串口通讯的物理层的主要标准是RS-232标准,其规定了信号的用途、通讯接口及信号的电平标准,其通讯结构如下:
在这里插入图片描述

在设备内部信号是以TTL电平标准传输的,设备之间是通过RS-232电平标准传输的,而且TTL电平需要经过电平转换芯片才能转化为RS-232电平,RS-232电平转TTL电平也是如此。
2.电平标准
根据使用的电平标准不同,串口通讯可分为 RS-232标准 及TTL标准,具体标准如下:
在这里插入图片描述

在电子电路中常使用TTL的电平标准,但其抗干扰能力较弱,为了增加串口的通讯距离及抗干扰能力,使用RS-232电平标准在设备之间传输信息,经常使用MA3232芯片对TTL电平及RS-232电平进行相互转换。

3.数据传输方式:
A同步:
传输以数据块为核心,在一个数据块内,字符间无间隔,接受发送同步,有sclk时钟,双方sclk连在一起,提供同步
特点:效率高,无间隔
B异步:
以字符为传输单位,每发一个字符,都得发送一个起始位,(告诉对方我开始发了)结束发送停止位。(我发完了)
特点:效率低,间隔任意

4.串口数据包组成
起始位、数据位(8位或者9位)、奇偶校验位(第9位)、起始停止位(1,15,2位)、波特率设置

5.速率类型:
比特:每秒传输的二进制位
波特:每秒传输的码源个数(串口常用)

注:这俩本质上其实是差不多的

6.通信类型
串行:一个一个传输 如:fsmc
特点:占用资源多,速度慢,看干扰强
并行:多个一起传输 如:spi usart
特点:占用资源少,速度快。抗干扰能力弱,距离近

7.通信方式
单工:数据传输只支持数据在一个方向上传输;如:打印机

半双工:允许数据在两个方向上传输。但是,在某一时刻,只允许数据在一个方向上传输,它实际上是一种切换方向的单工通信;它不需要独立的接收端和发送端,两者可以合并一起使用一个端口。如:对讲机,spi
全双工:允许数据同时在两个方向上传输。因此,全双工通信是两个单工通信方式的结合,需要独立的接收端和发送端。如:spi,usart
在这里插入图片描述

8.概念补充
1.数据包
串口通讯的数据包由发送设备通过自身的TXD接口传输到接收设备得RXD接口,在协议层中规定了数据包的内容,具体包括起始位、主体数据(8位或9位)、校验位以及停止位,通讯的双方必须将数据包的格式约定一致才能正常收发数据。

2.波特率
由于异步通信中没有时钟信号,所以接收双方要约定好波特率,即每秒传输的码元个数,以便对信号进行解码,常见的波特率有4800、9600、115200等。STM32中波特率的设置通过串口初始化结构体来实现。
3.起始和停止信号
数据包的首尾分别是起始位和停止位,数据包的起始信号由一个逻辑0的数据位表示,停止位信号可由0.5、1、1.5、2个逻辑1的数据位表示,双方需约定一致。STM32中起始和停止信号的设置也是通过串口初始化结构体来实现。
4.有效数据
有效数据规定了主题数据的长度,一般为8或9位,其在STM32中也是通过串口初始化结构体来实现的。
5.数据校验
在有效数据之后,有一个可选的数据校验位。由于数据通信相对更容易受到外部干扰导致传输数据出现偏差,可以在传输过程加上校验位来解决这个问题。校验方法有奇校验(odd)、偶校验(even)、 0 校验(space)、 1 校验(mark)以及无(noparity)。这些也都可以在串口初始化结构体中实现的。
在这里插入图片描述

3.USART简介

在这里插入图片描述

USART(通用同步异步收发器)是一个串行通信设备,可以灵活地与外部设备进行全双工数据交换。有别于 USART 还有一个UART,它是在 USART 基础上裁剪掉了同步通信功能,只有异步通信。简单区分同步和异步就是看通信时需不需要对外提供时钟输出,我们平时用的串口通信基本都是 UART。USART 在 STM32 应用最多莫过于“打印”程序信息,一般在硬件设计时都会预留一USART 通信接口连接电脑,用于在调试程序是可以把一些调试信息“打印”在电脑端的串口调试助手工具上,从而了解程序运行是否正确、如果出错哪具体哪里出错等等。

4.串口结构体参数

在这里插入图片描述

5.串口相关函数

void USART_Init //初始化函数
(USART_TypeDef* USARTx, USART_InitTypeDef* USART_InitStruct);
void USART_Cmd //串口使能函数
(USART_TypeDef* USARTx, FunctionalState NewState);
void USART_ITConfig //中断配置函数
(USART_TypeDef* USARTx, uint16_t USART_IT, FunctionalState NewState);
void USART_SendData //串口发送函数
(USART_TypeDef* USARTx, uint16_t Data);
uint16_t USART_ReceiveData //串口接收读取函数
(USART_TypeDef* USARTx);
FlagStatus USART_GetFlagStatus //获取相应的串口标志位
(USART_TypeDef* USARTx, uint16_t USART_FLAG);
ITStatus USART_GetITStatus //中断状态位获取
(USART_TypeDef* USARTx, uint16_t USART_IT);
在这里插入图片描述

6.串口配置

1.配置时钟:gpio,串口,引脚复用
2.配置gpioA9,10结构体
3.配置串口结构体
4.初始化,打开串口
5串口发送函数配置
在这里插入图片描述
附上参数.c文件代码



#include "stm32f10x.h"
#include "usart.h"

void usart_init(void)
{

	GPIO_InitTypeDef  gpioinitStructure;//结构体变量定义,结构体定义要在时钟之前

	USART_InitTypeDef usartinitStucture;
	
	
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA, ENABLE );
RCC_APB2PeriphClockCmd( RCC_APB2Periph_AFIO, ENABLE );
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);//配置gpio,串口,串口复用时钟


//先配置tx输出引脚io(pa9)
gpioinitStructure.GPIO_Pin  =GPIO_Pin_9;//选择引脚
gpioinitStructure.GPIO_Speed=GPIO_Speed_50MHz;//选择电平大小,初始状态无电平
gpioinitStructure.GPIO_Mode =GPIO_Mode_AF_PP;//用推挽输出

GPIO_Init(GPIOA,&gpioinitStructure );//端口初始化
//再配置rx输出引脚io(pa10)
  gpioinitStructure.GPIO_Pin =GPIO_Pin_10;
gpioinitStructure.GPIO_Speed=GPIO_Speed_50MHz;//选择电平大小,初始状态无电平

	gpioinitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;

GPIO_Init(GPIOA,&gpioinitStructure );//再次端口初始化,因为过程相同且都是gpio所以不用再定义

	//串口结构体的配置
usartinitStucture.USART_BaudRate								=115200;//波特率

usartinitStucture.USART_HardwareFlowControl			=USART_HardwareFlowControl_None;//无限流
usartinitStucture.USART_Parity				          =USART_Mode_Rx  |  USART_Mode_Tx;//输入输出模式
usartinitStucture.USART_WordLength							=USART_Parity_No;//无校验位
usartinitStucture.USART_StopBits								=USART_StopBits_1;//一个停止位
usartinitStucture.USART_Mode										=USART_WordLength_8b;//有效数据长度8bit

USART_Init(USART1,&usartinitStucture);//串口1初始化
USART_Cmd(USART1,ENABLE);//打开串口1


7.串口中断配置

1.配置时钟:gpio,串口,引脚复用
2.串口中断组选择
3.配置gpioA9,10,串口结构体与初始化
4.串口与中断控制器联系配置
5.打开串口
6.串口发送函数配置

.c文件

#include "stm32f10x.h"
#include "usart.h"

void usart_init(void)//串口发送接收和串口中断配置
{

	GPIO_InitTypeDef  gpioinitStructure;//结构体变量定义,结构体定义要在时钟之前

	USART_InitTypeDef usartinitStucture;
	NVIC_InitTypeDef  NVICinitStucture;

	
	//1.串口中断组的选择
	NVIC_PriorityGroupConfig( NVIC_PriorityGroup_2);
	
	//2.打开gpio,引脚复用和串口时钟
	RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA, ENABLE );
	RCC_APB2PeriphClockCmd( RCC_APB2Periph_AFIO, ENABLE );
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);//配置gpio,串口,串口复用时钟


//3.先配置tx输出引脚io(pa9)
gpioinitStructure.GPIO_Pin  =GPIO_Pin_9;//选择引脚
gpioinitStructure.GPIO_Speed=GPIO_Speed_50MHz;//选择电平大小,初始状态无电平
gpioinitStructure.GPIO_Mode =GPIO_Mode_AF_PP;//选择输出方式,用推挽输出

GPIO_Init(GPIOA,&gpioinitStructure );//端口初始化
//4.再配置rx输出引脚io(pa10)
  gpioinitStructure.GPIO_Pin =GPIO_Pin_10;
	gpioinitStructure.GPIO_Speed=GPIO_Speed_50MHz;//选择电平大小,初始状态无电平

	gpioinitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;

	GPIO_Init(GPIOA,&gpioinitStructure );//再次端口初始化,因为过程相同且都是gpio所以不用再定义

	//5.串口结构体的配置
usartinitStucture.USART_BaudRate								=115200;//波特率

usartinitStucture.USART_HardwareFlowControl			=USART_HardwareFlowControl_None;//无限流
usartinitStucture.USART_Parity				          =USART_Mode_Rx  |  USART_Mode_Tx;//输入输出模式
usartinitStucture.USART_WordLength							=USART_Parity_No;//无校验位
usartinitStucture.USART_StopBits								=USART_StopBits_1;//一个停止位
usartinitStucture.USART_Mode										=USART_WordLength_8b;//有效数据长度8bit

USART_Init(USART1,&usartinitStucture);//串口1初始化
//6.串口和中断控制器联系配置
USART_ITConfig(USART1, USART_IT_RXNE,ENABLE );

//7.打开串口1
USART_Cmd(USART1,ENABLE);

//8.串口中断控制器结构体配置与初始化
	NVICinitStucture.NVIC_IRQChannel									=USART1_IRQn;//中断通道,选择串口中断
	NVICinitStucture.NVIC_IRQChannelPreemptionPriority=1;//配置中断优先级
	NVICinitStucture.NVIC_IRQChannelCmd								=ENABLE;//使能打开
	NVICinitStucture.NVIC_IRQChannelSubPriority				=1;//配置中断子优先级



	NVIC_Init(&NVICinitStucture);//串口结构体初始化

}
void USARTSendByte(USART_TypeDef* USARTx, uint16_t Data)//串口发送字符函数封装
{
		 USART_SendData(USARTx, Data);//串口1发送字符0
		 while(USART_GetFlagStatus(USARTx,USART_FLAG_TXE)==RESET);//如果数据寄存器空标志位为空,则已经成功发送数据跳出
}
void USARTSendstr(USART_TypeDef* USARTx,char*str)//串口发送字符串函数封装
{
		uint16_t i=0;
		do
		{
		USARTSendByte(USARTx,*(str+i));//串口发送字符函数封装
		i++;

		}while(*(str+i)!='\0');
		
		
while(USART_GetFlagStatus(USARTx,USART_FLAG_TC)==RESET);//如果数据寄存器空标志位为空,则已经成功发送数据跳出
//检测字符串用tc,检测字符用txc
}


int fputc(int ch,FILE *f)//串口更改printf实现向电脑输出,这边只用单个字符的但函数进行多次调用
{
			 USART_SendData(USART1,(uint8_t) ch);//串口1发送字符
			while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);//如果数据寄存器空标志位为空,则已经成功发送数据跳出
			return   ch;
}
int fget(int ch,FILE *f)//串口更改scanf函数实现向电脑接收一个数据
{
			while(USART_GetFlagStatus(USART1,USART_FLAG_RXNE)==RESET);//如果数据寄存器空标志位为空,判断数据是否接受成功

//接受用rxne,输入用txe
	return (int)USART_ReceiveData(USART1);

	
}

main函数中断服务函数

在这里插入图片描述
注:这里不用清除中断标志位也行

  • 18
    点赞
  • 97
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

打酱油的;

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值