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>© 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"); //添加逻辑值false
cJSON_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