当前位置:网站首页>查询法,中断法实现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 
	}
}

原网站

版权声明
本文为[三态门]所创,转载请带上原文链接,感谢
https://blog.csdn.net/m0_63741844/article/details/125287331