STM32CubeMX配置串口DMA传输实现不定长数据收发

串口简介

串口是全双工的串行通信协议。串口通信指串口按位(bit)发送和接收字节(一个字节有8位)。尽管比特字节(byte)的串行通信慢,但是串口可以在使用一根线发送数据的同时用另一根线接收数据。串口通信协议是指规定了数据包的内容,内容包含了起始位、主体数据、校验位及停止位,双方需要约定一致的数据包格式才能正常收发数据的有关规范。串口通信协议是基于串口使得通信双方能够相互沟通信息的一种约定,其定义了双方遵循的协议数据帧格式和其传输方式。因为串口通信没有时钟线,说设备双方必须约定好相同的波特率,这样才能保证数据收发准确无误。常见的波特率有4800、9600、115200等。

起始位、停止位
数据包从起始位开始,到停止位结束。起始信号用逻辑0(最开始为拉高,当拉低后表示起始)的数据位表示,停止信号由0.5、1、1.5或2个逻辑1的数据位表示,只要双方约定一致即可。
有效数据
起始位之后便是传输的主体数据内容了,也称为有效数据,其长度一般被约定为5、6、7或8位长。
数据校验
由于在通讯过程中易受到外部干扰导致传输数据出现偏差,所以在有效数据之后加上校验位解决。校验方法有奇校验(odd)、偶校验(even)、0校验(space)、1校验(mark)及无校验(noparity)。
奇校验要求有效数据和校验位中“1”的个数为奇数,比如一个8位长的有效数据为:01101001,此时共有4个“1”,为达到奇校验效果,校验位为“1”,最后传输的是8位有效数据加1位校验位,共9位。
偶校验刚好相反,要求有效数据和校验位的“1”数量为偶数,则此时为达到偶校验效果,校验位为“0”。而0校验则无论有效数据中是什么数据内容,校验位总是为“0”,1校验校验位总是为“1”。

CubeMX配置

配置好时钟。
串口配置:使用默认配置(传输数据长度为8 Bit,奇偶检验无,停止位为1 Bit, 接收和发送都使能)
在这里插入图片描述
打开DMA传输:
在这里插入图片描述
打开串口接收中断:
在这里插入图片描述生成工程;

添加代码

添加代码实现printf函数。
在usart.c中添加如下代码,记住一定要添加在
/* USER CODE BEGIN 1 /
/
USER CODE END 1 */
里面,否则一旦CubeMX重新生成工程,就会不见。

/* USER CODE BEGIN 0 */
#include "stdio.h"
/* USER CODE END 0 */

/* USER CODE BEGIN 1 */
#if 1
#pragma import(__use_no_semihosting)                             
struct __FILE
{
int handle;
};
FILE __stdout;      
void _sys_exit(int x)
{
   x = x;
}
int fputc(int ch, FILE *f)
{     
  while((USART1->SR&0X40)==0);  
  USART1->DR = (uint8_t) ch;     
  return ch;
}
#endif

/* USER CODE END 1 */

然后就可以使用printf函数了。
这里我们先了解一下串口的IDLE中断
串口IDLE中断,能自动响应你从电脑(别的串口)接收到的不定长数据。而不是一直干等着。stm32接收数据时,并不会马上把数据马上处理掉,而是写到你定义的缓冲区里,然后你串口线上一个BYTE长度的时间如果没接收到数据,就会产生了IDLE中断(只会产生一次,别担心一直会卡在里面,除非等下次再接收时)。
接着在usart.c文件代码,重写串口的空闲中断回调函数:void USAR_UART_IDLECallback(UART_HandleTypeDef *huart,uint8_t rxlen )。HAL库中没有定义IDLE的中断处理函数,所以需要我们自己定义。
在此之前我们先在usart.h中定义一些缓存数组和一些会用到的变量,和添加必要的头文件。

#include "string.h"

/* USER CODE BEGIN Private defines */
#define UART1_RX_SIZE 100	

extern uint8_t UART1_RX_BUF[];  //串口接收缓存
extern uint8_t UART1_RX_LEN;  //接收到的数据量
extern uint8_t UART1_RX_Data[];  //数据缓存

/* USER CODE END Private defines */
void USAR_UART_IDLECallback(UART_HandleTypeDef *huart,uint8_t rxlen )
{
	if(huart == &huart1)  //判断是否为串口1产生中断
	{
		memcpy(UART1_RX_Data,UART1_RX_BUF,rxlen);  //将UART1_RX_BUF的数据复制到UART1_RX_Data中,最后两位是标志不是数据
		HAL_UART_Transmit_DMA(&huart1, UART1_RX_BUF,rxlen);//将接收到的不定长数据发送到上位机
	  rxlen = 0;//清除数据长度计数
HAL_UART_Receive_DMA(&huart1,UART1_RX_BUF,UART1_RX_SIZE);//重新打开DMA接收	        
	}
}
//写完后记得在usart.h文件中声明一下

在stm32f1xx_it.c,找到void USART1_IRQHandler(void)函数,添加我们自己的中断处理函数。

void USART1_IRQHandler(void)
{
  /* USER CODE BEGIN USART1_IRQn 0 */

  /* USER CODE END USART1_IRQn 0 */
  HAL_UART_IRQHandler(&huart1);
  /* USER CODE BEGIN USART1_IRQn 1 */

	if((__HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE) != RESET))
	{
		__HAL_UART_CLEAR_IDLEFLAG(&huart1);  //清楚空闲状态标志

		HAL_UART_DMAStop(&huart1);  //关闭DMA传输

		UART1_RX_LEN = UART1_RX_SIZE - __HAL_DMA_GET_COUNTER(&hdma_usart1_rx);  //计算接收到的数据长度
		USAR_UART_IDLECallback(&huart1,UART1_RX_LEN );  //调用回调函数
	}
  /* USER CODE END USART1_IRQn 1 */
}

接着在main.c文件添加代码,使能串口空闲中断和启动DMA传输。还有记得观察一下ain函数中的DMA初始化函数有没有在串口初始化之前,我之前遇到过DMA初始化函数没在串口初始化之前导致程序没有达到预想的效果。

__HAL_UART_ENABLE_IT(&huart1,UART_IT_IDLE);  //使能空闲中断
	HAL_UART_Receive_DMA(&huart1,UART1_RX_BUF,UART1_RX_SIZE);  //启动DMA接收,UART1_RX_BUF:数据接收缓冲

接下我们就可以用串口做很多东西了,比如连接蓝牙,WiFi模块等进行控制单片机上的外设。
以蓝牙控制舵机为例,舵机驱动这一部分参考我前面的博客http://t.csdn.cn/4iO1r

void SG90_Select(void)
{
	if(UART1_RX_Data[0]=='S' && UART1_RX_Data[1] == 'W' && UART1_RX_Data[2] == '1') //UART1_RX_Data定义的数据接收缓冲数组
		{
			SG90_Rotate(&htim2,1,Degrees_0);
		}
    else if(UART1_RX_Data[0]=='S' && UART1_RX_Data[1] == 'W' && UART1_RX_Data[2] == '2')
    {
			SG90_Rotate(&htim2,1,Degrees_45);
		}
    else if(UART1_RX_Data[0]=='S' && UART1_RX_Data[1] == 'W' && UART1_RX_Data[2] == '3')
    {
			SG90_Rotate(&htim2,1,Degrees_90);
		}
    else if(UART1_RX_Data[0]=='S' && UART1_RX_Data[1] == 'W' && UART1_RX_Data[2] == '4')
    {
			SG90_Rotate(&htim2,1,Degrees_135);
		}
    else if(UART1_RX_Data[0]=='S' && UART1_RX_Data[1] == 'W' && UART1_RX_Data[2] == '5')
    {
			SG90_Rotate(&htim2,1,Degrees_180);
		}
}

  • 9
    点赞
  • 99
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
STM32CubeMX中使用蓝牙串口接收数据的步骤如下: 1. 首先,确保你的STM32单片机已经配置了蓝牙模块,并且串口已经正确连接。 2. 打开STM32CubeMX软件,选择你的STM32型号,并创建一个新的工程。 3. 在"Pinout & Configuration"选项卡中,选择你要使用的串口引脚,并将其配置为UART模式。 4. 在"Configuration"选项卡中,找到"USART"配置,并启用蓝牙串口接收功能。 5. 在"Project"选项卡中,生成代码并导入到你的开发环境中。 6. 在你的代码中,使用中断方式来接收蓝牙串口数据。你可以在空闲中断函数中设置一个接收完成的标志位,以便在主程序中检测数据是否接收完成。 需要注意的是,蓝牙串口的通信标准是TTL电平标准,如果你需要使用RS-232标准,则需要使用电平转换芯片。此外,根据你的通信需求,你可以选择单工通信、半双工通信或全双工通信。 希望以上信息对你有所帮助!\[1\]\[2\]\[3\] #### 引用[.reference_title] - *1* *2* [STM32CubeMX配置串口——HAL+DMA+串口空闲中断](https://blog.csdn.net/Myself_study/article/details/122745423)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [STM32CubeMX串口通讯](https://blog.csdn.net/qq_63922192/article/details/128119933)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值