STM32CubeIDE基础学习-USART串口通信实验(中断方式)

时间:2024-03-31 11:03:38

STM32CubeIDE基础学习-USART串口通信实验(中断方式)


文章目录

  • STM32CubeIDE基础学习-USART串口通信实验(中断方式)
  • 前言
  • 第1章 硬件介绍
  • 第2章 工程配置
    • 2.1 工程外设配置部分
    • 2.2 生成工程代码部分
  • 第3章 代码编写
  • 第4章 实验现象
  • 总结


前言

前面学习了串口使用轮询的方式实现数据收发,本文章将介绍使用中断的方式实现数据的收发。

使用中断的方式可以避免程序一直在死等,当中断触发之后就立即执行内容,大大减少了CPU的负担。


第1章 硬件介绍

本实验使用的开发板主控芯片是STM32F103C8T6,其核心原理图如下:

在这里插入图片描述

时钟来源使用的是外部高速8M晶振作为高速时钟。

开发板的TTL串口电路比较简单,采用CH340C的串口芯片,省去了外部外接晶振电路。该芯片的串口接到了主芯片的串口1上,即PA9、PA10引脚。注意它们的连接关系是需要交叉接的,不然直连是无法正常串口通信的。

在这里插入图片描述

第2章 工程配置

本实验直接采用串口轮询实验的工程作为基础模板,直接拷贝粘贴即可,然后在上面添加串口中断相关功能配置即可,其它不用修改,就不用再新建工程了。

2.1 工程外设配置部分

第一步:前面的LED、BEEP、KEY、RCC和SWD的相关配置都不用修改,保持默认的配置即可。

第二步:配置串口引脚功能。
按照下图标号步骤进行设置就可以。

在这里插入图片描述

打开串口配置界面,点击NVIC Setting界面,勾选里面的串口中断使能即可。然后在NVIC处设置中断分组和优先级,如下图所示:

在这里插入图片描述

到此,串口中断的功能就配置完成了,只添加这里串口的配置,其它的都不用修改。

2.2 生成工程代码部分

外设功能配置完成后,点击生成代码按钮就可以生成工程代码了。

前面部分代码和串口轮询的方式的是一样的,会在HAL_UART_MspInit函数多了NVIC相关配置,如下图所示:

在这里插入图片描述

在stm32f1xx_it.h文件里面,多了一个串口中断服务程序,当触发串口中断后,就会调用HAL库提供的HAL_UART_IRQHandler公共中断处理函数,进去该函数执行相关串口发送中断和串口接收中断处理。如下图所示:

在这里插入图片描述

到此,这些基础初始化代码没有问题之后就可以在工程上添加串口的相关工程代码了。

第3章 代码编写

串口中断的名字比轮询的名字多了一个IT,具体使用的函数介绍如下:

串口发送中断函数原型:
HAL_UART_Transmit_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
这个是串口中断发送函数,其中第一个参数是串口句柄,第二个是数据,第三个是数据长度。

串口接收中断函数原型:
HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
这个是串口中断接收函数,其中第一个参数是串口句柄,第二个是数据,第三个是数据长度。

串口发送和接收中断函数是没有阻塞超时时间参数的,因为中断发送和接收是触发了中断才会执行,所以不需要死等操作。

前面学习了串口轮询方式实现数据收发,接下来简单介绍一下这个串口中断发送和接收函数的使用,收发指定长度的数据。

串口要接收内容,那么首先定义一个数据接收缓冲区,用来存放接收的数据,如下图所示:

在这里插入图片描述

代码片示例如下:

/* USER CODE BEGIN PV */
uint8_t rx_buf[5];
/* USER CODE END PV */

把数组接收缓冲区定义为全局变量,方便后面在其它文件使用,不用赋初值。

在main文件调用串口中断接收函数,传入相关参数如下图所示:

在这里插入图片描述

编译下载代码后,可可以在串口调试助手数据发送区输入发送5字节数据内容,可以看到S处的数值是5则说明发送了5字节数据。

注意不要勾选⑤处的发送新行按钮,否则数据会多一个回车换行符占,它们占2字节数据长度。如下图所示:

在这里插入图片描述

由于代码只写了数据接收函数,并没有写数据发送函数,所以串口助手接收区是看不了显示内容的,为了要看到内容,则需要在代码添加串口发送函数才行,如下图所示:

在这里插入图片描述

在中断文件里面编写回调函数,添加LED翻转代码,用来指示串口中断是否被触发。在下面添加串口中断发送函数,把接收到的5字节内容转发出去。

这里需要注意一下,为了书写严谨,我用了串口基地址的判断,这个一般在工程用到多个串口时才需要这样写的,用于区分具体是哪个串口,如果工程只有一个串口,不这样写也可以的。无论多少,都建议写上,这样就不会容易出错了。

代码片示例如下:

/* USER CODE BEGIN 1 */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	if(huart->Instance == USART1)
	{
		HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);   /* 提示中断被触发 */
		HAL_UART_Transmit_IT(&huart1, rx_buf, sizeof(rx_buf));
	}
}
/* USER CODE END 1 */

外部声明一下该数组,不然会报错的。

在这里插入图片描述

写完后再次编译下载程序到开发板,发送5字节内容,可用发现开发板的LED亮了,串口助手也可用成功显示5字节的内容,如下图所示:

在这里插入图片描述

此时可以发现,只能发送一次,第二次发送没有现象了,就像程序被卡死一样。只能复位了才能发送第二次。

如果需要循环的收发的话,则需要在回调函数添加一个串口中断接收函数才行,默认只写了串口发送函数,添加如下图所示:

在这里插入图片描述

代码片示例如下:

/* USER CODE BEGIN 1 */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	if(huart->Instance == USART1)
	{
		HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);   /* 提示中断被触发 */
		HAL_UART_Transmit_IT(&huart1, rx_buf, sizeof(rx_buf));
		HAL_UART_Receive_IT(&huart1, rx_buf, sizeof(rx_buf));	
	}
}
/* USER CODE END 1 */

编写完再次下载到开发板,可以发现可以循环发送和接收数据了,串口发送和接收到5个字节内容都会让LED状态翻转。

到此,使用串口中断的方式实现数据的发送和接收的简单使用就完成了,不过这个操作只是实现指定长度的串口数据收发,如果需要接收不定长的数据,那么可以考虑使用空闲中断的方式实现,这里就不展开描述。

注意
如果串口助手发送和接收的内容不足5字节,则不会触发中断,需要等待发送和接收够5个字节的数据内容才会触发。

这个问题的使用和前面串口轮询方式的文章的第4章的超时时间参数说明章节的示例举例说明即可,问题处理方法是一样的,这里就不再描述。

第4章 实验现象

具体查看代码编写章节的现象即可。


总结

使用中断的方式实现数据的收发主要是在回调函数里面处理,还要注意要先在main文件里面使能开启接收中断才行,不然无法正常接收数据。