【STM32G0】借助串口非空中断实现空闲中断的功能

1 实现原理

使用串口通信可实现数据帧的收发,完成机器人控制、采集数据的传输等任务。制定串口通信协议并定时发送一帧数据,常见的处理方法是利用空闲中断,但STM32 HAL库好像没有专用的空闲中断,自己实现起来比较麻烦,这里利用非空中断可以实现同样的功能,缺点是效率比较低,稳定性经过测试也还可以,如果有更好的思路欢迎提出。

1.1 制定串口通信协议

制定串口通信协议时一帧数据的长度和内容可以自己定义,STM32的串口传输的数据类型为uint8_t,注意取值不要超过0-255,下面给出一个电机控制的串口通信协议表做示例

字节定义
0帧头0x5A
1帧长度10
2电机1转向0/1
3电机1转速0-255
4电机2转向0/1
5电机2转速0-255
6电机3转向0/1
7电机3转速0-255
8运行时间0-60
9帧尾0xA5

1.2 分析中间变量

  • 创建接收数组g_fUART1_Buf,其长度等于串口通信协议一帧的长度
  • 创建接收一个字节的暂存变量g_fUART1_Byte,配置一个字节中断一次
  • 创建g_fNew_Pack用于主程序中判断是否接收到完整的一帧数据
  • 创建g_fNew_Pack_Cnt记录成功接收一帧数据的次数,方便调试
uint8_t g_fUART1_Byte = 0;
uint8_t g_fUART1_Buf[10] = {0};

uint8_t g_fNew_Pack = 0;
uint8_t g_fNew_Pack_Cnt = 0;

1.3 接收数据的处理

新接收到的字节g_fUART1_Byte写入接收数组g_fUART1_Buf的末尾,每接收一个字节,就将前一个字节左移,保证新接收到的字节一直往数组里填充,当接收的字节超过接收数组的长度后,继续左移,去掉旧数据,填入新数据

在这里插入图片描述

2 STM32CubeMX配置

2.1 SWD调试接口配置

SWD接口用于程序的下载、在线调试
在这里插入图片描述

2.2 时钟树配置

STM32G0系列内嵌高精度(±1%)RC振荡时钟,无需外部时钟,所以这里并未使能外部高速时钟,开发板上也没有焊接,直接在时钟树配置选项的HCLK输入64,配置最大的64MHz时钟频率即可。
在这里插入图片描述

2.3 UART1串口配置

UART1用于接收上文制定的串口通信协议,并开启非空中断
在这里插入图片描述
在这里插入图片描述

2.4 生成工程

输入工程名,选择存放路径(不要有中文),选择IDE为MDK-ARM;只生成用到的文件(目的是提高工程编译速度,减少工程占用空间),并生成单独的.c/.h文件,点击生成代码在这里插入图片描述
在这里插入图片描述

3 添加用户代码

3.1 定义全局变量

/* USER CODE BEGIN PV */
uint8_t g_fUART1_Byte = 0;
uint8_t g_fUART1_Buf[10] = {0};

uint8_t g_fNew_Pack = 0;
uint8_t g_fNew_Pack_Cnt = 0;
/* USER CODE END PV */

3.2 UART1中断初始化

  /* USER CODE BEGIN 2 */
	HAL_UART_Receive_IT(&huart1, (uint8_t*)&g_fUART1_Byte, 1);  // 启动串口非空中断,第3个参数代表1一个字节中断一次

3.3 UART1的printf重定向

/* USER CODE BEGIN 0 */
/* printf重定向 */
#include "stdio.h"
int fputc(int ch, FILE *f)
{
	uint8_t temp[1] = {ch};
	HAL_UART_Transmit(&huart1, temp, 1, 5); // huart1根据需要修改
	return ch;
}

3.4 UART1回调函数

/* USER CODE BEGIN 4 */
// 串口接收数据回调函数
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) 
{
	if(huart -> Instance == huart1.Instance ) 
	{
	    // 往接收数组里填新数据,即实现原理的1.3
		for(int i=0;i<9;i++)
		{
			g_fUART1_Buf[i] = g_fUART1_Buf[i+1];
		}
		g_fUART1_Buf[9] = g_fUART1_Byte;
		if(g_fUART1_Buf[0]==0x5a && g_fUART1_Buf[9]==0xa5) {
			g_fNew_Pack = 1;// 成功接收一帧数据,刷新标志位
		}
		HAL_UART_Receive_IT(&huart1, (uint8_t*)&g_fUART1_Byte, 1);  
	}
}

3.5 接收数据的处理

  /* USER CODE BEGIN WHILE */
  while (1)
  {
		if(g_fNew_Pack) // 主程序中判断是否成功接收一帧数据
         {
			g_fNew_Pack = 0; // 清除标志位
			g_fNew_Pack_Cnt++;
			printf("g_fNew_Pack_Cnt=%d\r\n",g_fNew_Pack_Cnt);// 输出成功接收一帧数据的次数
			for(int i=0;i<10;i++){
				printf("%x ",g_fUART1_Buf[i]);// 16进制输出接收到的一帧数据
			}
			printf("\r\n");
			// uart1_handle(); // 串口1接收数据的处理函数,根据需求自己添加

		}

    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }

4 效果演示

gif中为方便演示,除了帧头帧尾,没有使用上文串口协议定义的内容,用11 22等数据(16进制)代替
在这里插入图片描述

在这里插入图片描述

  • 0
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值