摘要
基本串口通信通常只能接收到定长数据,无法稳定接收不定长数据,本章介绍利用STM32单片机的IDLE空闲中断,接收不定长数据。
配置工程
复制 STM32CubeMX系列教程0:创建工程 创建的工程目录GPIO_test,修改文件目录名称为USART_IDLE,双击打开GPIO_test.ioc。
配置串口及DMA
使能串口1的异步串行通信模式,开启Usart1的全局中断。添加DMA通道。
生成源码
使用Stm32Cubemx生成源码, 打开生成的源码,删除whiel循环中的语句。
修改源码
重定向printf
打开usart.h文件,在文件开头的USER CODE BEGIN Includes
下方引入stdio.h头文件
打开usart.c文件,在USER CODE BEGIN 0
与 USER CODE END 0
之间添加下列代码。
#if 1 struct __FILE {
int handle;
};
FILE __stdout; //定义_sys_exit()以避免使用半主机模式 void _sys_exit(int x)
{
x = x;
}
//重定义fputc函数
int fputc(int ch, FILE *f){
while((USART1->SR&0X40)==0);//循环发送,直到发送完毕
USART1->DR=(uint8_t)ch;
return ch;
}#endif
添加串口接收所需变量
打开uart.c
文件,在文件顶部的USER CODE BEGIN 0
下方添加下列变量
volatile uint8_t rx1_len = 0; //接收一帧数据的长度
volatile uint8_t rec1_end_flag = 0; //一帧数据接收完成标志
uint8_t rx1_buffer[BUFFER_SIZE]={0}; //接收数据缓存数组
添加串口及IDLE处理函数
打开uart.c文件,在文件末尾的USER CODE BEGIN 1
下方添加下列函数
void Usart1_IDLE(void) //USART1的IDLE接收
{
uint32_t tmp_flag = 0;
uint32_t temp;
tmp_flag =__HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE); //获取IDLE标志位
if((tmp_flag != RESET))//idle标志被置位
{
__HAL_UART_CLEAR_IDLEFLAG(&huart1);//清除标志位
HAL_UART_DMAStop(&huart1); // 停止DMA传输,防止
temp = __HAL_DMA_GET_COUNTER(&hdma_usart1_rx);// 获取DMA中未传输的数据个数
rx1_len = BUFFER_SIZE - temp; //总计数减去未传输的数据个数,得到已经接收的数据个数
rec1_end_flag = 1; // 接受完成标志位置1
}
}
void Usart1_Handle() //USART1对接收的一帧数据进行处理
{
DMA_Usart1_Send(rx1_buffer, rx1_len); //将接收到的数据回发给发送端
rx1_len = 0;//清除计数
rec1_end_flag = 0;//清除接收结束标志位
HAL_UART_Receive_DMA(&huart1,rx1_buffer,BUFFER_SIZE);//重新打开DMA接收
}
void DMA_Usart1_Send(uint8_t *buf,uint8_t len) //串口发送封装
{
if(HAL_UART_Transmit_DMA(&huart1,buf,len)!= HAL_OK) //判断是否发送正常,如果出现异常则进入异常中断函数
{
Error_Handler();
}
}
声明变量及函数
打开usart.h文件,在文件开头的USER CODE BEGIN Includes
下方添加如下语句
#include "stdio.h"
#include "string.h"
#define BUFFER_SIZE 100
extern volatile uint8_t rx1_len; //接收一帧数据的长度
extern volatile uint8_t rec1_end_flag; //一帧数据接收完成标志
extern uint8_t rx1_buffer[BUFFER_SIZE]; //接收数据缓存数组
void Usart1_Handle(void);
void DMA_Usart1_Send(uint8_t *buf,uint8_t len);//串口发送封装
void Usart1_IDLE(void);
启用IDLE中断
进入main.c文件,找到入口函数void mian(void)
, 在USER CODE BEGIN 2
下方开启串口1的DILE中断,并打开DMA接收。
__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE); //使能IDLE中断
HAL_UART_Receive_DMA(&huart1,rx1_buffer,BUFFER_SIZE); //开启DMA接收
在while语句中添加接收查询语句。
if(rec1_end_flag) //判断是否接收到1帧数据
{
Usart1_Handle(); //前往数据处理函数处理接收到的数据。
}
修改中断函数
打开stm32f4xx_it.c
文件,在文件开头引入usart.h
头文件。
向下翻stm32f4xx_it.c
文件,找到void USART1_IRQHandler(void)
函数,此函数为串口1的中断入口函数。在此函数中添加之前在usart.c
文件中创建的IDLE接收函数。
编译下载
源码修改完毕后,编译下载,打开串口助手,随意发送100个字节以内的任意长度内容进入单片机,都可得到同样的回复。
STM32单片机程序下载方法有多种,有需要请跳转
STM32程序下载0:STM32CubeProgrammer安装
STM32程序下载1:通过keil-ST-Link方式下载
STM32程序下载2:通过STM32CubePro-ST-Link下载
STM32程序下载3:通过STM32CubePro-UART下载
STM32程序下载4:通过STM32CubePro-USB下载
选择你所需要的下载方法。
如果有疑问请留言