STM32使用串口空闲中断接收不定长数据帧-USART_IT_IDLE使用(不使用DMA方式)

  • 前言
  • 串口空闲中断介绍
  • 清中断方法
  • 串口中断处理函数
  • 串口中断用到的全局变量定义
  • 串口初始化(使能接收中断、空闲中断)
  • 使用举例
  • 测试结果

前言

最近在使用STM32的HAL库的时候,发现竟然没有集成IDLE中断处理,本身写的HAL库处理逻辑就挺繁琐,效率又不高,还缺胳膊少腿的。平时项目中的串口接收数据都是不定长的,而IDLE中断在这一块作用是非常大的,可以大大简化数据接收过程的判断。本文将介绍基于HAL库IDLE中断接收不定长数据。

串口空闲中断介绍

STM32的IDLE的中断在串口无数据接收的情况下,是不会一直产生的,产生的条件是这样的,当清除IDLE标志位后,必须有接收到第一个数据后,才开始触发,一断接收的数据断流,没有接收到数据,即产生IDLE中断。IDLE位不会再次被置高直到RXNE位被置起(即又检测到一次空闲总线)。RXNE接收中断可以不用开启,减少进中断的次数。

USART_IT_IDLE中断,是串口收到一帧数据后,发生的中断,也可以叫做一包数据。

USART_IT_IDLE和USART_IT_RXNE区别
当接收到1个字节,会产生USART_IT_RXNE中断
当接收到一帧数据,就会产生USART_IT_IDLE中断

注意:串口空闲中断在MDK纯软件仿真模式下,是无法进入串口空闲中断的,必须借助真实的硬件环境(如STM32开发板等)。

清中断方法

//USART_IT_RXNE
__HAL_UART_CLEAR_FLAG(&huart1, UART_FLAG_RXNE); //清楚接收中断//USART_IT_IDLE
//一帧数据接收完成,清除空闲中断标志(否则会一直不断进入中断)
__HAL_UART_CLEAR_IDLEFLAG(&huart1);

串口中断处理函数

void USART1_IRQHandler(void)
{uint8_t res = 0;/* USER CODE BEGIN USART1_IRQn 0 *//* USER CODE END USART1_IRQn 0 *//* USER CODE BEGIN USART1_IRQn 1 *///接收中断if(__HAL_UART_GET_FLAG(&huart1, UART_FLAG_RXNE) != RESET){HAL_UART_Receive(&huart1, &res, 1, 1000);//将数据放入缓冲区if(rxConut < RX_BUFFER_SIZE){aRxBuffer[rxConut] = res;rxConut++;}__HAL_UART_CLEAR_FLAG(&huart1, UART_FLAG_RXNE); //清楚接收中断}//空闲中断if(__HAL_UART_GET_FLAG(&huart1, UART_FLAG_IDLE) != RESET) //接收中断(接收到的一帧数据){bFlagOneFrame = true;rxConut = 0;//一帧数据接收完成,清除空闲中断标志(否则会一直不断进入中断)__HAL_UART_CLEAR_IDLEFLAG(&huart1);}/* USER CODE END USART1_IRQn 1 */
}

串口中断用到的全局变量定义

#define RX_BUFFER_SIZE 256
uint8_t aRxBuffer[RX_BUFFER_SIZE]; //串口中断接收缓冲区
uint16_t rxConut = 0; //串口中断接收个数
bool bFlagOneFrame = false; //判断一帧数据是否接收完成

串口初始化(使能接收中断、空闲中断)

void MX_USART1_UART_Init(void)
{huart1.Instance = USART1;huart1.Init.BaudRate = 115200;huart1.Init.WordLength = UART_WORDLENGTH_8B;huart1.Init.StopBits = UART_STOPBITS_1;huart1.Init.Parity = UART_PARITY_NONE;huart1.Init.Mode = UART_MODE_TX_RX;huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;huart1.Init.OverSampling = UART_OVERSAMPLING_16;if (HAL_UART_Init(&huart1) != HAL_OK){Error_Handler();}__HAL_UART_ENABLE_IT(&huart1,UART_IT_RXNE);//接收中断__HAL_UART_ENABLE_IT(&huart1,UART_IT_IDLE);//空闲中断}

使用举例

/* USER CODE BEGIN Header */
/********************************************************************************* @file           : main.c* @brief          : Main program body******************************************************************************* @attention** <h2><center>&copy; Copyright (c) 2021 STMicroelectronics.* All rights reserved.</center></h2>** This software component is licensed by ST under BSD 3-Clause license,* the "License"; You may not use this file except in compliance with the* License. You may obtain a copy of the License at:*                        opensource.org/licenses/BSD-3-Clause********************************************************************************/
/* USER CODE END Header *//* Includes ------------------------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include "cJSON.h"
#include "main.h"
#include "usart.h"
#include "gpio.h"
#include "cmd_queue.h"/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes *//* USER CODE END Includes *//* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
char *strJSON; //打包成功调用cJSON_Print打印输出
cJSON *objJson;
float f1;
char *json_string = "{\"SV\":60,\"KP\":5.0,\"KI\":100,\"KD\":300}";
#define RX_BUFFER_SIZE 256
uint8_t aRxBuffer[RX_BUFFER_SIZE];
uint16_t rxConut = 0;
bool bFlagOneFrame = false;
/* USER CODE END PTD */
/*** @brief This function handles USART1 global interrupt.*/
uint8_t ucTemp;
void USART1_IRQHandler(void)
{uint8_t res = 0;/* USER CODE BEGIN USART1_IRQn 0 *//* USER CODE END USART1_IRQn 0 *//* USER CODE BEGIN USART1_IRQn 1 *///接收中断if(__HAL_UART_GET_FLAG(&huart1, UART_FLAG_RXNE) != RESET){HAL_UART_Receive(&huart1, &res, 1, 1000);//将数据放入缓冲区if(rxConut < RX_BUFFER_SIZE){aRxBuffer[rxConut] = res;rxConut++;}__HAL_UART_CLEAR_FLAG(&huart1, UART_FLAG_RXNE); //清楚接收中断}//空闲中断if(__HAL_UART_GET_FLAG(&huart1, UART_FLAG_IDLE) != RESET) //接收中断(接收到的一帧数据){bFlagOneFrame = true;rxConut = 0;//一帧数据接收完成,清除空闲中断标志(否则会一直不断进入中断)__HAL_UART_CLEAR_IDLEFLAG(&huart1);}/* USER CODE END USART1_IRQn 1 */
}void HAL_UART_RxCpltCallback(UART_HandleTypeDef * huart)
{}
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD *//* USER CODE END PD *//* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM *//* USER CODE END PM *//* Private variables ---------------------------------------------------------*//* USER CODE BEGIN PV */
void test_cjson(void);
void cJsonQueParse(char *str);
/* USER CODE END PV *//* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP *//* USER CODE END PFP *//* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 *//* USER CODE END 0 *//*** @brief  The application entry point.* @retval int*/
int main(void)
{/* USER CODE BEGIN 1 *//* USER CODE END 1 *//* MCU Configuration--------------------------------------------------------*//* Reset of all peripherals, Initializes the Flash interface and the Systick. */HAL_Init();/* USER CODE BEGIN Init *//* USER CODE END Init *//* Configure the system clock */SystemClock_Config();/* USER CODE BEGIN SysInit *//* USER CODE END SysInit *//* Initialize all configured peripherals */MX_GPIO_Init();MX_USART1_UART_Init();/* USER CODE BEGIN 2 */queue_reset();/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){//test_cjson();//    HAL_Delay(100);if(true == bFlagOneFrame){cJsonQueParse((char *)aRxBuffer);//rxConut = 0;bFlagOneFrame = false;//queue_reset();}}/* USER CODE END 3 */
}/*** @brief System Clock Configuration* @retval None*/
void SystemClock_Config(void)
{RCC_OscInitTypeDef RCC_OscInitStruct = {0};RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};/** Initializes the CPU, AHB and APB busses clocks*/RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;RCC_OscInitStruct.HSEState = RCC_HSE_ON;RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;RCC_OscInitStruct.HSIState = RCC_HSI_ON;RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK){Error_Handler();}/** Initializes the CPU, AHB and APB busses clocks*/RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK){Error_Handler();}
}void cJsonQueParse(char *str)
{//cJSON* cjson = cJSON_Parse(json_string);   //将JSON字符串转换成JSON结构体cJSON* cjson = cJSON_Parse((const char *)str);   //将JSON字符串转换成JSON结构体if(cjson == NULL){printf("cjson parse error...\r\n");}else{char *json_data = cJSON_PrintUnformatted(cjson); //JSON数据结构转换为JSON字符串printf("%s\n",json_data);//输出字符串printf("/*********************以下就是提取的数据**********************/\n");double fSV = cJSON_GetObjectItem(cjson,"SV")->valuedouble;  //解析浮点型printf("SV: %.4f\n",fSV);double fKP = cJSON_GetObjectItem(cjson,"KP")->valuedouble;  //解析浮点型printf("KP: %.4f\n",fKP);double fKI = cJSON_GetObjectItem(cjson,"KI")->valuedouble;  //解析浮点型printf("KI: %.4f\n",fKI);double fKD = cJSON_GetObjectItem(cjson,"KD")->valuedouble;  //解析浮点型printf("KD: %.4f\n",fKD);//释放内存free(json_data);cJSON_Delete(cjson); //清楚结构体}
}/* USER CODE BEGIN 4 */
void test_cjson(void)
{double  grade[4]= {66.51,118.52,61.53,128.54};int     time[4]= {123,456,789,150};cJSON *measurements = cJSON_CreateObject();             //创建一个对象cJSON_AddStringToObject(measurements,"AAA","26.55666");     //添加字符串cJSON_AddNumberToObject(measurements,"BBB",13);         //添加整型数字cJSON_AddNumberToObject(measurements,"CCC",13.55666);  //添加浮点型数字cJSON_AddFalseToObject(measurements,"gender");          //添加逻辑值falsecJSON_AddStringToObject(measurements,"status","0x8000");        //添加字符串cJSON *item1 = cJSON_CreateObject();            //创建一个对象cJSON_AddStringToObject(item1,"item1_string","China"); //添加字符串cJSON_AddNumberToObject(item1,"item1_num",2021); //添加整型数字cJSON_AddItemToObject(measurements,"item1",item1);objJson = cJSON_GetObjectItem(measurements, "AAA");f1 = strtod(objJson->valuestring, NULL);char *json_data = cJSON_PrintUnformatted(measurements); //JSON数据结构转换为JSON字符串printf("%s\n",json_data);//输出字符串free(json_data);cJSON_Delete(measurements);//清除结构体}/* USER CODE END 4 */
int fputc(int ch,FILE *f)
{uint8_t temp[1]= {ch};HAL_UART_Transmit(&huart1,temp,1,2);        //UartHandle是串口的句柄
}/*** @brief  This function is executed in case of error occurrence.* @retval None*/
void Error_Handler(void)
{/* USER CODE BEGIN Error_Handler_Debug *//* User can add his own implementation to report the HAL error return state *//* USER CODE END Error_Handler_Debug */
}#ifdef  USE_FULL_ASSERT
/*** @brief  Reports the name of the source file and the source line number*         where the assert_param error has occurred.* @param  file: pointer to the source file name* @param  line: assert_param error line source number* @retval None*/
void assert_failed(uint8_t *file, uint32_t line)
{/* USER CODE BEGIN 6 *//* User can add his own implementation to report the file name and line number,tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) *//* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT *//************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

测试结果

资料来源:
https://www.cnblogs.com/ZzJan/p/13530768.html

https://blog.csdn.net/zhangxuechao_/article/details/79126474

https://blog.csdn.net/qq_42263055/article/details/114852446

STM32使用串口空闲中断接收不定长数据帧-USART_IT_IDLE使用(不使用DMA方式)相关推荐

  1. STM32单片机串口空闲中断接收不定长数据

    在使用单片机的串口通信功能时,常用的接收数据方法是通过固定的字节数来判断一帧数是否发送完成,或者是通过固定的结束标志位来表示一帧数据发送完成.但是有时候会遇到发送的数据长度不固定,也没有固定的结束标志 ...

  2. stm32串口空闲中断接收不定长数据

    串口空闲中断接收不定长数据 空闲中断是接受数据后出现一个byte的高电平(空闲)状态,就会触发空闲中断.并不是空闲就会一直中断,准确的说应该是上升沿(停止位)后一个byte,如果一直是低电平是不会触发 ...

  3. STM32H7 DMA USART空闲中断接收不定长数据

    1.关键设置 2.代码 2.1 bsp_usart.h /*********************************************************************** ...

  4. STM32单片机串口空闲中断+DMA接收不定长数据

    在上一篇文章STM32单片机串口空闲中断接收不定长数据中介绍了利用串口空闲中断接收不定长数据,这种方式有一个问题就是串口每接收到一个字节就会进入一次中断,如果发送的数据比较频繁,那么串口中断就会不停打 ...

  5. stm32的串口DMA空闲中断接收不等长数据,stm32F1的usart1-DMA-IDLE收发

    stm32的DMA收发原理,和stm32F4 + USART2 +DMA +IDLE使用,见另一篇:https://blog.csdn.net/Mark_md/article/details/1072 ...

  6. stm32的串口DMA空闲中断接收不等长数据,stm32F4的usart2-DMA-IDLE收发

    1. 串口为什么要使用DMA?好处? 提高系统实时性:stm32单片机的串口没有FIFO,使用字节中断的方式去接收,会频繁进入中断,影响系统实时性.好在stm32的串口可以级联DMA使用,在大数据量连 ...

  7. bufferedreader接收不到数据_FreeRTOS例程3-串口中断接收不定长的数据与二值信号量的使用

    1 基础知识点 1.1 串口中断种类 串口中断属于STM32本身的资源,不涉及到FreeRTOS,但可与FreeRTOS配合使用. 串口接收中断 中断标志为:USART_IT_RXNE,即rx non ...

  8. STM32LL库——USART中断接收不定长信息

    通用同步异步收发器(USART)既是串口,可以与电脑上的串口助手连接,是调试单片机的重要方式.双向通信至少需要2个引脚:接受数据输入(RX)和发送数据输出(TX). 首先在STM32CubeMX中配置 ...

  9. STM32 利用空闲中断接收数据

    STM32 利用串口空闲中断接收不定长数据 利用cubeMX打开DMA串口接收中断 利用CubeMX打开串口中断 HAL_NVIC_SetPriority(USART2_IRQn, 0, 0); HA ...

最新文章

  1. xx学OD -- 消息断点 RUN跟踪(上)
  2. pandas使用groupby函数、agg函数获取每个分组聚合对应的均值(mean)实战:计算分组聚合单数据列的均值、计算分组聚合多数据列的均值
  3. php和python哪个用了开发web好-php与python谁更适合web开发?为什么?
  4. 【Auto.js】QQ自动回赞_简易版
  5. jQuery内置动画和多库共存
  6. MyListUtil.java list工具类
  7. c++ ifstream 文件不结束_C/C++编程笔记:你不知道的windows保存文件的坑
  8. SSH项目中根据Hibernate的映射文件生成数据库表的方案:
  9. vue获取当前月最后一天_只争朝夕,不负韶华——站在2020年第一天,回望2019最后的两个月...
  10. linux udp 端口映射,Linux下的UDP/TCP端口映射(netcat and socat)
  11. mysql 免安装 自启动_MYSQL在Win下免安装zip
  12. HTML在线电视直播网页模板,苹果cms网站添加TV电视直播教程
  13. linux ios开发环境,iOS开发环境搭建(Linux版)
  14. Istio 南北向流量管理
  15. MLB的选秀会有哪些规定和流程·棒球6号位
  16. ospfdr选举规则_OSPF:DR、BDR选举算法
  17. 只读存储器,并行存储器
  18. 超简单:快速制作一款高逼格词云图
  19. MySQL基础部分学习笔记
  20. 武汉科技大学计算机网络复习重点

热门文章

  1. html背景音乐怎么设置音量,视频中加背景音乐,怎么能设置背景音乐的音量呢背景音乐小于原视频声音...
  2. 主成分分析(PCA)-Python代码
  3. PIC18F45K80单片机串口调试总结
  4. python最优解集_python求最优解的集中算法
  5. php7的安装方法,php7 iis安装方法详解(图文)
  6. 计算机锁屏打不开,电脑锁屏打不开怎么办没反应
  7. 批处理是什么?能干什么?
  8. jaeger 是很么软件_jaeger 使用初探
  9. docker容器启动失败:Error response from daemon: Container xxx is not running
  10. 快手秋招前端实习生一面面经