Hal库_stm32开发之串口IDLE空闲中断+DMA接收不定长数据并修改数据

        本文写自于博主编写平衡智能车程序的时候,由于中断使用的较多,如定时器中断,串口中断等等。为了避免MCU运行程序时卡死,我就将串口中断改为串口IDLE空闲接收中断。可以实现不定长数据的接收;以此可以修改PID参数,对调车的朋友很友好。

实验效果如下:

接下来对Cubemx进行相关配置

使用stm32F103系列

1.配置RCC

  • 设置高速外部时钟HSE 选择外部时钟源

2.配置SYS

  • 设置成SW-Debug模式

3.配置串口

最后在开启中断即可。

 4.配置中断

  • 可按自己的需求调整中断的优先级,0-15,优先级依次降低。

 5.配置时钟树 (我一般默认72M)

 5.设置项目名称,生成工程即可。

接下来编写业务代码

1. 打开usart.c文件

//最usart.c的顶部/* USER CODE BEGIN 0 */添加下列代码
/* USER CODE BEGIN 0 */
#include <stdio.h>
volatile uint8_t rx_len = 0;  //接收一帧数据的长度
volatile uint8_t recv_end_flag = 0; //一帧数据接收完成标志
char rx_buffer[200]={0};  //接收数据缓存数组

/* USER CODE END 0 */



/* USER CODE BEGIN USART1_Init 2 */
	
//下方为自己添加的代码
	__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE); //使能IDLE中断

//DMA接收函数,此句一定要加,不加接收不到第一次传进来的实数据,是空的,且此时接收到的数据长度为缓存器的数据长度
	HAL_UART_Receive_DMA(&huart1,rx_buffer,BUFFER_SIZE);

  /* USER CODE END USART1_Init 2 */



//最usart.c的最底部添加
/* USER CODE BEGIN 1 */
/** 函数功能: 重定向c库函数printf到DEBUG_USARTx */
int fputc(int ch, FILE *f)
{
  HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xffff);
  return ch;
}
/* USER CODE END 1 */

 

2. 然后打开usart.h文件

extern DMA_HandleTypeDef hdma_usart1_rx;
extern DMA_HandleTypeDef hdma_usart1_tx;







/* USER CODE BEGIN Private defines */
#define BUFFER_SIZE  200 

extern  volatile uint8_t rx_len ;  //接收一帧数据的长度
extern volatile uint8_t recv_end_flag; //一帧数据接收完成标志
extern char rx_buffer[200];  //接收数据缓存数组
/* USER CODE END Private defines */

 3. 打开stm32f1xx_it.c文件

//添加usart.h头文件
#include "usart.h"



//找到void USART1_IRQHandler(void)函数
/* USER CODE BEGIN USART1_IRQn 0 */
	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);//清除标志位
		//temp = huart1.Instance->SR;  //清除状态寄存器SR,读取SR寄存器可以实现清除SR寄存器的功能
		//temp = huart1.Instance->DR; //读取数据寄存器中的数据
		//这两句和上面那句等效
		HAL_UART_DMAStop(&huart1); //  停止DMA传输,防止
		temp  =  __HAL_DMA_GET_COUNTER(&hdma_usart1_rx);// 获取DMA中未传输的数据个数   
		//temp  = hdma_usart1_rx.Instance->NDTR;// 读取NDTR寄存器,获取DMA中未传输的数据个数,
		rx_len =  BUFFER_SIZE - temp; //总计数减去未传输的数据个数,得到已经接收的数据个数
		recv_end_flag = 1;	// 接受完成标志位置1	
	 }
  /* USER CODE END USART1_IRQn 0 */

4. 最后在main.c函数添加以下头文件

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

5. 按自己需求编写需要修改的参数变量和代码,先附上我的;

float kp1,ki1,kd1; //PID的参数
char chage[][5] = {"kp1=", "kd1=", "kd1=", "a", "b", "c"};//用于判定



void BSP_USART_idleDMA(void)
{
	if(recv_end_flag ==1)   //判断标志位
		{
			//修改kp
			if(!memcmp(chage[0],rx_buffer,4)) //比较前四个字节
			{
				kp1 = atof(rx_buffer+4); //如果一样则修改kp1的参数,往下的同理
				printf("/***** kp = %f *****/",kp1);
			}
			//修改ki
			if(!memcmp(chage[1],rx_buffer,4))
			{
				ki1 = atof(rx_buffer+4);
				printf("/***** ki = %f *****/",ki1);
			}
			//修改kd
			if(!memcmp(chage[2],rx_buffer,4))
			{
				kd1 = atof(rx_buffer+4);
				printf("/***** kd = %f *****/",kd1);
			}

            
			rx_len=0;
			recv_end_flag=0; //清除标志位
			memset(rx_buffer,0x00,sizeof(rx_buffer)); //清空数组
		}
	HAL_UART_Receive_DMA(&huart1,(uint8_t *)rx_buffer,BUFFER_SIZE); //再次开启DMA接收
}

最后在while里调用即可

 while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
        BSP_USART_idleDMA();
  }

参考博客:STM32 HAL CubeMX 串口IDLE接收空闲中断+DMA_Z小旋的博客-CSDN博客_cubemx idle

  • 4
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值