当前位置:网站首页>查询法,中断法实现USART通信
查询法,中断法实现USART通信
2022-06-25 10:46:00 【三态门】
目录
前言
同步异步收发器(USART),在嵌入式开发中,受广泛应用,其作用是很重要的。
以下内容通过一个简单的通信实验来详细模块化叙述USART通信具体的API调用。
[串行通信]
同步异步串行收发器USART
上位机PC,下位机STM32,GPIO口 PA1
串口调试工具XCOM V2.6
GPIO_ReadInputDataBit();//直接获取当前串口输入状态
/*
if ((GPIOx->IDR & GPIO_Pin) != (uint32_t)Bit_RESET)
{bitstatus = (uint8_t)Bit_SET;}else {bitstatus = (uint8_t)Bit_RESET;}
*/
注意:
返回:SET OR RESET
ITStatus USART_GetITStatus(USART_TypeDef* USARTx, uint16_t USART_IT);
不仅会判断标志位是否置1,同时还会判断是否使能了相应的中断。所以在串口中断函数中,如果要获取中断标志位,通常使用该函数。
FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_FLAG);
该函数只判断标志位。在没有使能相应的中断函数时,通常使用该函数来判断标志位是否置1。
双方通信协议设置:
PC端发送"ON"
STM32接收执行:
若检测PA1端口处于高电平状态,则STM32回发"PA1 has been ON!"
若检测PA1端口处于低电平状态,则STM32回发"PA1 has been Turn ON!"
PC端发送"OFF"
STM32接收执行:
若检测PA1端口处于高电平状态,则STM32回发"PA1 has been OFF!"
若检测PA1端口处于低电平状态,则STM32回发"PA1 has been Turn OFF!"
配置固件库:
#include "stm32f10x_gpio.h" //串口固件
#include "stm32f10x_rcc.h" //时钟固件
#include "stm32f10x_usart.h" //串行通信
#include "misc.h" //外设驱动 CMSIS功能 NVIC_PriorityGroupConfig
串口通信寄存器中标志位相关配置位:
* @retval The new state of USART_FLAG (SET or RESET).
* @arg USART_FLAG_LBD: LIN Break detection flag
* @arg USART_FLAG_TXE: Transmit data register empty flag
* @arg USART_FLAG_TC: Transmission Complete flag
* @arg USART_FLAG_RXNE: Receive data register not empty flag
* @arg USART_FLAG_IDLE: Idle Line detection flag
* @arg USART_FLAG_ORE: OverRun Error flag
* @arg USART_FLAG_NE: Noise Error flag
* @arg USART_FLAG_FE: Framing Error flag
* @arg USART_FLAG_PE: Parity Error flag
PA1串口配置:
void GPIO_PA1_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能PA端口时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; //端口配置
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz
GPIO_Init(GPIOA, &GPIO_InitStructure); //根据设定参数初始化GPIOA1
GPIO_ResetBits(GPIOA,GPIO_Pin_1); //输出低
}
一、查询法
串口涉及的GPIO及其时钟初始化:(STM32F1串口默认三串口USART1、USART2、USART3)
void GPIO_USARTX_Config(USART_TypeDef* USARTX)
{
GPIO_InitTypeDef GPIO_InitStructure;
if(USARTX == USART1)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE); //使能USART1,GPIOA时钟
//USART1在APB2总线桥
//USART1_TX GPIOA.9
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.9
//USART1_RX GPIOA.10初始化
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA10
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.10
}else if(USARTX == USART2)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE); //使能USART2,GPIOA时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
//USART2在APB1总线桥,
//USART2_TX GPIOA.2
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; //PA.2
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.2
//USART2_RX GPIOA.3初始化
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;//PA3
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.3
}else if(USARTX == USART3)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE); //使能USART3,GPIOB时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
//USART3在APB1总线桥,
//USART3_TX GPIOB.10
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; //PB.10
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIOB.10
//USART3_RX GPIOB.11初始化
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;//PB.11
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIOB.11
}
}
串口配置:
void USART_Configuration(USART_TypeDef* USARTX,long bound)
{
USART_InitTypeDef USART_InitStructure;
USART_InitStructure.USART_BaudRate = bound;//串口波特率
//BaudRate = Fpaclx/(16*USARTDIV)
USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收发模式
USART_Init(USARTX, &USART_InitStructure); //初始化串口
USART_ITConfig(USARTX, USART_IT_RXNE, ENABLE);//开启串口接受中断
USART_Cmd(USARTX, ENABLE); //使能串口1
//USART_GetFlagStatus(USARTX,USART_FLAG_TC) 发送完成标志,解决首字节发送失败
}
数据发送和接收控制:
typedef enum {ERR = 0,OK = !ERR}USARTstat; //设置枚举变量
#define Max 200
unsigned char RxBuffer[Max];
unsigned char TxBuffer[Max];
数据流标志
unsigned TxCount = 0;
unsigned RxCount = 0;
这里解析下USART_ReceiveData()串口通信接收基本固件的API:
uint16_t USART_ReceiveData(USART_TypeDef* USARTx)
{
/* Check the parameters */
assert_param(IS_USART_ALL_PERIPH(USARTx));
/* Receive Data */
return (uint16_t)(USARTx->DR & (uint16_t)0x01FF); //获取到数据,写入对应数据寄存器
}
字节发送函数:(空置标志USART_FLAG_TXE)
USARTstat USARTX_SendOneByte(USART_TypeDef* USARTX,unsigned char dat)
{
vu32 cnt = 0; //超时定时
USART_SendData(USARTX,dat);
while(USART_GetFlagStatus(USARTX, USART_FLAG_TXE) == RESET) //获取寄存器空置标志位
{
cnt++;
if(cnt>100000)return ERR;
}
return OK;
}//SendString()
按帧发送数据函数:
void Send_Dat(USART_TypeDef* USARTX,unsigned char *dat)
{
while(*dat !='\0')
USARTX_SendOneByte(USARTX,*dat++)
}
字节接收函数:(寄存器接收标志位 USART_FLAG_RXNE)
unsigned char USARTX_ReceiveOneByte(USART_TypeDef* USARTX)
{
while(USART_GetFlagStatus(USARTX, USART_FLAG_RXNE) == RESET){} //获取寄存器接收标志位
return(USART_ReceiveData(USARTX));
}
按帧接收数据函数:
unsigned char Receive_Dat(USART_TypeDef* USARTX)
{
vu32 cnt = 0; //超时定时
while(1)
{
RxBuffer[RxCount++] = USARTX_ReceiveOneByte(USARTX);
if(strstr((char*)RxBuffer,"ON")!=NULL) //#include "string.h",截取匹配
{
RxCount = 0;
return 1;
}else if(strstr((char*)RxBuffer,"OFF")!=NULL)
{
RxCount = 0;
return 1;
}else if(RxCount > 3) //接收多次字节未获取正确指令
RxCount = 0;
cnt++;
if(cnt>100000)return 0;
}
}
main.c文件实例:
int main(void)
{
unsigned char cnt;
SystemInit(); //系统时钟配置,默认为72M
GPIO_PA1_Config(); //串口初始化
GPIO_USARTX_Config(USART1); //串口通信端口配置
//NVICX_Config(USART1,3,3); //串口通信NVIC中断配置
USART_Configuration(USART1,9600); //串口基准配置
while(1)
{
Send_Dat(USART1,(unsigned char*)("Welcome!\n"));
switch(Receive_Dat(USART1))
{
case 1:
if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_1)==RESET)
{
GPIO_SetBits(GPIOA,GPIO_Pin_1);
Send_Dat(USART1,(unsigned char*)("PA1 has been Turn ON!\n"));
}
else Send_Dat(USART1,(unsigned char*)("PA1 has been ON!"));
break;
case 2;......break;
}
}
}
二、中断法
采用USART中断,来响应USART串口通信的接收数据,较查询法相比,中断法减少了CPU处理的压力。
NVIC嵌套向量中断控制器相关配置:
void NVICX_Config(USART_TypeDef* USARTX,unsigned char NVIC_PP,unsigned char NVIC_SP)
{
NVIC_InitTypeDef NVIC_InitStructure;
//Usart NVIC 配置
if(USARTX == USART1)
{
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=NVIC_PP ;//抢占优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = NVIC_SP; //子优先级
}else if(USARTX == USART2)
{
NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=NVIC_PP ;//抢占优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = NVIC_SP; //子优先级
}else if(USARTX == USART3)
{
NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=NVIC_PP ;//抢占优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = NVIC_SP; //子优先级
}
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器
}
串口1中断处理:
extern unsigned char RxBuffer[];
extern vu8 RxCount;
extern vu8 RxHeader;
extern vu8 RXLen;
extern USART1_STA;
void USART1_IRQHandler(void) //串口1中断服务程序
{
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收中断(接收到的数据必须是0x0d 0x0a结尾)
{
USART_ClearITPendingBit(USART1,USART_IT_RXNE); //清除接收中断标志
RxBuffer[RxCount] = USART_ReceiveData(USART1); //缓冲读取数据
RxCount++; //缓冲区下移
RxCount &= 0xFF;
}
if(RxBuffer[RxCount-1] == 0xEA) //检测数据帧头部
RxHeader = RxCount-1;
if((RxBuffer[RxHeader] == 0xEA)&&(RxBuffer[RxCount-1]== 0x55) //检测尾部,计算数据帧长度
{
RXLen = RxCount - 1 - RxHeader;
USART1_STA = 1;
}
if(USART_GetFlagStatus(USART1, USART_FLAG_ORE)==SET) //数据溢出处理
{
USART_ClearFlag(USART1,USART_FLAG_ORE); //读SR
USART_ReceiveData(USART1); //读DR
}
}
边栏推荐
- OpenCV学习(二)---树莓派上安装opencv
- XSS attack
- 【文件包含漏洞-03】文件包含漏洞的六种利用方式
- 1-7Vmware中的快照与克隆
- Multiple environment variables
- [the path of system analyst] Chapter 6: Double inventory demand engineering (comprehensive knowledge concept)
- 2022年PMP项目管理考试敏捷知识点(2)
- A five-year technical Er, based on the real experience of these years, gives some suggestions to the fresh students
- Previous string inversion topic
- 16 enterprise architecture strategies
猜你喜欢
FPGA基于VGA显示字符及图片
【文件包含漏洞-04】经典面试题:已知某网站仅存在本地文件包含漏洞时,如何GetShell?
【文件包含漏洞-03】文件包含漏洞的六种利用方式
垃圾回收机制
Es learning
Kotlin arrays and collections (1) {create arrays, use arrays, use for in loops to traverse arrays, use array indexes, and multi-dimensional arrays}
Nuxtjs actual combat case
NuxtJS实战案例
Previous string inversion topic
网络协议学习---LLDP协议学习
随机推荐
西门子PLCS7-200使用(一)---开发环境和组态软件入门
Technical practice and development trend of video conference all in one machine
On binary tree
Cdn+cos ultra detailed steps for drawing bed construction
Is it safe to open a securities account in changtou school by mobile phone?
1-7snapshots and clones in VMWare
每日3题(2)- 找出数组中的幸运数
【图像融合】基于形态学分析结合稀疏表征实现图像融合附matlab代码
Flutter adds event listening | subscription
[paper reading | deep reading] drne:deep recursive network embedding with regular equivalence
报名开启|飞桨黑客马拉松第三期如约而至,久等啦
OpenCV学习(二)---树莓派上安装opencv
Performance memory
金仓数据库 KingbaseES 插件ftutilx
The title of my composition is - "my district head father"
Dell technology performs the "fast" formula and plays ci/cd
NETCORE performance troubleshooting
Use of Siemens plcs7-200 (I) -- Introduction to development environment and configuration software
Shen Ying, China Academy of communications and communications: font open source protocol -- Introduction to ofl v1.1 and analysis of key points of compliance
Houdini graphic notes: could not create OpenCL device of type (houdini_ocl_devicetype) problem solving