STM32F103中断串口通信USART


本文基于笔者之前的博客STM32F103串口通信USART小试牛刀,在此基础上,加上中断函数,并补充HAL函数实现。


一、实验原理

实验原理可以参考笔者之前的两篇博客

STM32F103串口通信USART小试牛刀_江南烟浓雨的博客-CSDN博客

STM32F103开关控制LED灯_江南烟浓雨的博客-CSDN博客

本次串口实验的中断名称为USART1,和之前一样,初始化GPIO,初始化NVIC,初始化串口USART。这里主要介绍一下中断函数

/* USART1中断函数 */
void USART1_IRQHandler(void)
{
	unsigned char ucTemp;											//接收数据
	if(USART_GetITStatus(USART1,USART_IT_RXNE)!=RESET)				//检查
	{		
		ucTemp = USART_ReceiveData(USART1);
		USART_SendData(USART1,ucTemp);    
	}
}

中断时,调用此函数,将发送的内容通过串口发送给PC机。这里和上次实验有所不同的是,没有添加清除中断位的操作。在STM32中文参考手册中有所说明
在这里插入图片描述
在这里插入图片描述
串口接收到数据,接收中断标志位为1,但当你读USART_DR寄存器的时候,硬件会自动清除串口接收中断标志,所以我们不需要添加清除中断位地操作。

如果想使用重定向的printf函数,可以在usart.h头文件中添加stdio.h头文件。然后在usart.c中添加重定向函数

//重定向C库函数printf到串口,重定向后可使用printf函数
int fputc(int ch,FILE *f)
{
	/* 发送一个字节数据到串口 */
	USART_SendData(USART1,(unsigned char) ch);
	while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);
	return (ch);
}

//重定向C库函数scanf到串口,重写向后可使用scanf、getchar等函数
int fgetc(FILE *f)
{
	/* 等待串口输入数据 */
	while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);
	return (int)USART_ReceiveData(USART1);
}

然后在keil中勾选Use MicroLIB
在这里插入图片描述

注意:在中断函数中不能添加printf,malloc等函数,printf放在中断里,相当于中断中嵌入中断,这样的函数可能被阻塞。

二、实验代码

1.库函数

usart.h

#ifndef __USART_H
#define __USART_H
#include "stm32f10x.h"
#include<stdio.h>
void MyUSART_Init(void);
void Usart_SendByte( USART_TypeDef * pUSARTx, uint8_t ch);
void Usart_SendString( USART_TypeDef * pUSARTx, char *str);
#endif

usart.c

#include "usart.h"

//重定向C库函数printf到串口,重定向后可使用printf函数
int fputc(int ch,FILE *f)
{
	/* 发送一个字节数据到串口 */
	USART_SendData(USART1,(uint8_t) ch);
	while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);
	return (ch);
}

//重定向C库函数scanf到串口,重写向后可使用scanf、getchar等函数
int fgetc(FILE *f)
{
	/* 等待串口输入数据 */
	while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);
	return (int)USART_ReceiveData(USART1);
}

void MyUSART_Init()
{
	/* 定义GPIO、NVIC和USART初始化的结构体 */
	GPIO_InitTypeDef GPIO_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	USART_InitTypeDef USART_InitStructure;
	/* 使能GPIO和USART的时钟 */
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
	/* 将USART TX(A9)的GPIO设置为推挽复用模式 */
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9;
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStructure);
	/* 将USART RX(A10)的GPIO设置为浮空输入模式 */
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10;
	GPIO_Init(GPIOA,&GPIO_InitStructure);
	
	/* 配置串口 */
	USART_InitStructure.USART_BaudRate=115200;										//波特率了设置为115200
	USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None;	//不使用硬件流控制
	USART_InitStructure.USART_Mode=USART_Mode_Tx|USART_Mode_Rx;						//使能接收和发送
	USART_InitStructure.USART_Parity=USART_Parity_No;								//不使用奇偶校验位
	USART_InitStructure.USART_StopBits=USART_StopBits_1;							//1位停止位
	USART_InitStructure.USART_WordLength=USART_WordLength_8b;						//字长设置为8位
	USART_Init(USART1, &USART_InitStructure);	
	
	/* Usart1 NVIC配置 */
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);					//设置NVIC中断分组2
	NVIC_InitStructure.NVIC_IRQChannel=USART1_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority=0;
	NVIC_Init(&NVIC_InitStructure);
	
	/*初始化串口,开启串口接收中断 */
	USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);
	/* 使能串口1 */
	USART_Cmd(USART1,ENABLE);
	
}

/* USART1中断函数 */
void USART1_IRQHandler(void)
{
	uint8_t ucTemp;											//接收数据
	if(USART_GetITStatus(USART1,USART_IT_RXNE)!=RESET)
	{		
		ucTemp = USART_ReceiveData(USART1);
		USART_SendData(USART1,ucTemp);
	}
}

/* 发送一个字节 */
void Usart_SendByte( USART_TypeDef * pUSARTx, uint8_t ch)
{
	/* 发送一个字节数据到USART */
	USART_SendData(pUSARTx,ch);
		
	/* 等待发送数据寄存器为空 */
	while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);	
}

/* 发送字符串 */
void Usart_SendString( USART_TypeDef * pUSARTx, char *str)
{
	unsigned int k=0;
  do 
  {
      Usart_SendByte( pUSARTx, *(str + k) );
      k++;
  } while(*(str + k)!='\0');
  
  /* 等待发送完成 */
  while(USART_GetFlagStatus(pUSARTx,USART_FLAG_TC)==RESET)
  {}
}


main.c

#include "stm32f10x.h"
#include "usart.h"
int main(void)
{
	MyUSART_Init();
	while(1)
	{}	
}

2.HAL库函数

和之前一样,这里仅介绍不同的操作。首先配置串口1(USART1),将模式设置为异步,NVIC设置为Enabled。
在这里插入图片描述
然后设置中断分组
在这里插入图片描述
如果需要设置USART1的其它参数,可以在Parameter Settings中设置,笔者这里选择了默认设置
在这里插入图片描述
设置好后修改代码,和上面的库函数类似,主要是修改中断函数。首先在main.c中添加数组和相关参数的定义

char RxBuffer[256];   		//接收数据
uint8_t aRxBuffer;			//接收中断缓冲
uint8_t Uart1_Rx_Cnt = 0;	//接收缓冲计数

然后在下面添加中断回调函数

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
  /* Prevent unused argument(s) compilation warning */
  UNUSED(huart);
  /* NOTE: This function Should not be modified, when the callback is needed,
           the HAL_UART_TxCpltCallback could be implemented in the user file
   */
	RxBuffer[Uart1_Rx_Cnt++] = aRxBuffer;   									//接收数据转存
	if((RxBuffer[Uart1_Rx_Cnt-1] == 0x0A)&&(RxBuffer[Uart1_Rx_Cnt-2] == 0x0D))	//判断结束位
	{
		HAL_UART_Transmit(&huart1, (uint8_t *)&RxBuffer, Uart1_Rx_Cnt,0xFFFF);	//将收到的信息发送出去
        while(HAL_UART_GetState(&huart1) == HAL_UART_STATE_BUSY_TX);			//检测UART发送结束
		Uart1_Rx_Cnt = 0;
		memset(RxBuffer,0x00,sizeof(RxBuffer));									//清空数组
	}
	HAL_UART_Receive_IT(&huart1, (uint8_t *)&aRxBuffer, 1);						//再开启接收中断
}

因为在stm32f1xx_hal_uart.c文件中,对于中断函数中的回调函数是弱定义,所以这里的函数定义覆盖了之前的定义。对于HAL库来说,提供了一系列的函数可以操作。如果需要使用printf等函数可以参考库函数的方法,重定向函数来实现。

三、实验结果

在这里插入图片描述

四、总结

本次实验用到了中断,串口通信。对于HAL库来说,其结构和相关函数可以参考生成的代码中的资料和网络上的相关资料。

五、参考文献

为何stm32 中断处理函数里不能调用printf?_dingpan119的博客-CSDN博客

【STM32】HAL库 STM32CubeMX教程四—UART串口通信详解_Z小旋-CSDN博客_hal_uart_transmit

  • 9
    点赞
  • 42
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: STM32F103串口中断是指通过配置STM32F103单片机的串口模块,在接收到数据或者数据发送完成时通过中断来处理相关的操作。中断是一种基于硬件的事件触发机制,它可以提高系统的可靠性和效率。 在使用STM32F103串口中断时,首先需要初始化串口相关的寄存器和配置,包括波特率、数据位、停止位、校验位等。然后在中断向量表中配置串口中断处理函数,通过接收中断和发送中断分别处理接收和发送数据。 当接收到数据时,串口接收中断会被触发,中断处理函数会读取接收寄存器中的数据,并进行相应的处理,如存储或者解析数据。在发送数据时,串口发送中断会被触发,中断处理函数会将要发送的数据写入发送寄存器,以便进行传输。 使用STM32F103串口中断可以实现异步通信,不需要CPU主动轮询串口状态,从而减少了CPU的负担和系统的资源占用。同时,中断机制可以确保数据的及时处理和传输,提高了系统的实时性。 总的来说,STM32F103串口中断是一种基于硬件事件的触发机制,通过配置和处理中断实现串口通信,提高了系统的可靠性和效率。 ### 回答2: STM32F103芯片支持串口中断功能。串口中断可以用来实现串口通信时的数据接收和发送。通过配置中断向量表和使能串口中断,可以实现在数据到达或发送完成时自动触发中断服务程序。 首先,需要在代码中配置串口的相关参数,包括波特率、数据位数、停止位、校验位等等。然后,使能串口中断使能位。可以通过设置串口中断使能位来决定是否开启中断功能。 当数据到达串口接收缓冲区时,串口中断标志位会被置位,触发串口中断。在中断服务程序中,可以调用相关的接收函数,从接收缓冲区中读取数据。读取数据后,可以进行相关的处理、分析或者存储。 在数据发送时,可以通过检查串口发送缓冲区是否为空,来判断是否可以发送新的数据。当发送完成后,串口中断标志位会被置位,触发串口中断。在中断服务程序中,可以调用相关的发送函数,从发送缓冲区中取出数据并进行发送。 通过使用串口中断,可以实现串口通信的高效处理,提高了系统的并发性和实时性。同时,串口中断也可以减少CPU的占用率,提高了系统的稳定性。 需要注意的是,在使用串口中断时,中断服务程序的执行时间应尽量短,以免影响系统的其他任务。特别是在高速数据传输的场景下,可能需要对中断服务程序进行优化和调整。 总之,STM32F103芯片支持串口中断功能,可以通过配置中断向量表和使能串口中断来实现串口通信的数据接收和发送。使用串口中断可以提高系统的并发性和实时性,同时降低CPU的占用率,提高系统的稳定性。 ### 回答3: STM32F103串口中断是指利用STM32F103系列微控制器内置的串口模块与外部设备进行通信时,通过中断的方式来处理数据的接收与发送。 在STM32F103系列微控制器中,每个串口模块都有自己的中断向量,通过配置相应的中断使能位以及优先级,可以实现对串口接收与发送的中断处理。 在串口接收方面,当有数据通过串口接收到微控制器时,串口模块会产生接收中断请求,并将接收到的数据存储在接收缓冲器中。此时,中断服务程序会被触发,可以在中断服务程序中读取接收缓冲器中的数据进行处理。通过中断的方式进行串口接收处理可以提高系统的实时性和响应速度。 在串口发送方面,当发送缓冲器为空时,可以触发串口发送中断中断服务程序中可以将要发送的数据写入发送缓冲器,串口模块会自动将缓冲器中的数据发送出去。通过中断的方式进行串口发送处理可以实现自动发送,并且不需要轮询发送缓冲器的状态。 通过配置串口中断,可以实现串口接收与发送的异步处理,提高系统的实时性和效率。同时,中断可以根据优先级进行处理,可以实现多种不同优先级的串口通信。 总之,STM32F103串口中断非常重要,可以实现串口数据的高效处理与通信,为系统提供了更高的可靠性和实时性。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值