STM32串口通信使用DMA实现

在hal库使用DMA方式实现对于stm32的串口通信

stm32 在给pc机发送不断的hello windows语句时,我们可以使用中断服务程序来反向控制,是否继续发送,这里使用‘*’代表继续发送‘#’表停止发送。

首先我们需要对应的环境,使用hal库,我们就需要cubemx,可以在st公司官网上下载。我们使用的flymcu只能烧录软件,不能发送信息,所以还需要下载sscom 串口助手来帮助调试。
首先让我们进入cubemx,并且新建一个工程。

选择我们使用的stm32f103c8芯片,

对于DMA设置,DMA实现的是直接对于内存的操控,在操控工程中完全不需要cpu参与,以此可以极大的解放cpu算力,让其可以进行其他工作。我们只需要在一开始设置DMA时候设置cpu就可以了,其余则完全不需要cpu参与,同时DMA由于是直接内存操作,也能让程序执行时间更加简短。

下面我们进入cubemx的对于DMA的相关设置。

首先在cubemx上选择你的芯片

在这里插入图片描述
然后再RCC里面设置高速时钟

在这里插入图片描述
设置usart1串口数据模式

在这里插入图片描述
然后使能串口

在这里插入图片描述
然后设置DMA设置,添加两个通道

在这里插入图片描述
最后直接create code 然后直接使用keil5打开它

在这里插入图片描述

上面就是项目位置 和名称。
这样直接创建代码就行。
直接打开main.c

在这里插入图片描述

在代码main函数的while 循环中,就是我们需要写入的输出函数,
但是在这之前,我们需要定义全局变量,把我们预计要发送的语句提前定义上去。

char c;//开始指令 A:停止  B:开始
uint8_t message[]=" hello windows\n";//输出目标信息
char error[]="commanderror\n";
char tips1[]="startcmd...\n";
char tips2[]="stopcmd...\n";
char flag=1;//中断标志 #:停止发送 *.开始发送

好的,第一个c 表示pc机给stm32 发送的变量,是用来触发中断函数的。可以看到message 就是我们要不断发送的hello windows,第二个error是表示在指令不存在时的回馈,tips1 表示*继续或者开始发送。
tips2 则表示# 停止发送。
下面的flag=1时表示是否在发送的状态,1为发送,2为停止。
这里初始定义为1 ,所以串口会在一开始就不断发送message。
接下来回到我们的while语句之前,我们还需要定义中断服务函数
如下

这里还需要解释一下为什么要将message数据类型定义为uint8_t
在串口通信中,数据通常是按照字节(8位)来传输的。
使用 uint8_t(无符号8位整数)数据类型是为了确保跨多种平台和编译器的兼容性。
当我们将数据转换为 uint8_t,我们确保数据在所有系统上都是8位的,无论该系统的体系结构如何。这样,不论是在8位、16位、32位还是64位的系统上,该数据类型都能正确地处理8位的数据。
此外,uint8_t 是无符号的,这意味着其所有的8位都用于表示数值,这样可以在传输单个字节时,提供0-255的全部取值范围。因此,它经常被用来在串口通信(Serial Communication)中传输数据。

HAL_UART_Receive_IT(&huart1, (uint8_t *)&c, 1);  //设置变量为c的中断,也就是c会承接一个指令执行我们的中断服务函数
	//在中断服务函数里面,我们可以设置根据c的不同指令出现的不同操作,比如让flag变化   注意flag变化会直接影响是否正常发送

*好的,让我解释这三个量是什么,首先,这个函数是一个中断函数,它可以让程序在接受数据时还可以执行其他操作。
第一个&huart1 这是一个指向uart 结构体的指针。
第二个(uint8_t )&c 首先&c表示取c的地址,也就是它的指针,前面的括号表示将这个指针强制类型转换为uint8_t 这是一个中断函数要求的类型具体为什么这么要求可以看上文。
第三个 ‘ 1’ 表示要接受的字符长度,同时他也是个条件,当接收到对应长度的字符,此中断才会启用。
接下来说明启动中断过后会如何。
首先,中断条件一旦满足,就会进入中断服务函数,这个函数内,我们可以实现正常的所有函数操作,比如最基本的条件判断if语句,使用这个语句我们就可以判断是否继续发送。

void HAL_UART_RxCpltCallback(UART_HandleTypeDef  *huart)
{
	
	//当输入的指令为#时,发送提示并改变flag
	if(c=='#')//这个地方就是设置你需要的开始结束条件,我这里设置的停止条件是#
		{
		flag=0;
		HAL_UART_Transmit(&huart1, (uint8_t *)&tips2, strlen(tips2),0xFFFF); 
	}
	
	//当输入的指令为*时,发送提示并改变flag
	else if(c=='*'){
		flag=1;
		HAL_UART_Transmit(&huart1, (uint8_t *)&tips1, strlen(tips1),0xFFFF); 
	               }
	
	//当输入不存在指令时,发送提示并改变flag
	           else {
		         flag=0;
		         HAL_UART_Transmit(&huart1, (uint8_t *)&error, strlen(error),0xFFFF); 
	               }

	                   //重新设置中断
 HAL_UART_Receive_IT(&huart1, (uint8_t *)&c, 1);  //这样中断就不止执行一次了,只需要在中断服务末尾再使用中断就行。
				 
}

好的,可以看到里面有一个transmis函数,这个就是stm32 发送到pc机的函数,我们可以看到,在c分别为#和*时,我们直接在if语句里面发送给pc机了tips1 和tips2 以及error语句。
那么怎么操控我们的message语句呢。
在主函数的while 循环中,我们这样写。

  //code start
	  
	if(flag==1)
  {
	HAL_UART_Transmit_DMA(&huart1, (uint8_t *)message, sizeof(message));
	  HAL_Delay(1000);
	 } 
		  
	//每次发送完成后检测,如果变量c进入到目标长度字符,就会触发中断服务函数,再利用中断服务来操作是否继续发送所需字符。

好的,可以看到在主函数中,我们使用if语句判断flag是否为1来判断需不需要发送,而我们又将flag定义为全局变量,各个函数的数值改变flag都会导致所有的flag数值改变,所以我们只需要在中断服务函数里面,不断给flag赋值1或者0 就行,只要赋值1 ,则全局变量改变,导致主函数flag数值变化,再导致我们继续发送。

   **但是注意在中断服务函数的末尾我们还需要定义一次中断函数,因为一个中断函数只会中断一次,
   导致的是我们只能执行一次指令,所以在中断服务函数在定义一次,就可以一直执行指令。**
   总体的顺序如下。
   定义中断
    stm32 发送message
    检测中断,检测到变量c出现对应长度的字符。
    触发中断>进入中断服务函数,实现我们需要的功能
    中断服务函数末尾再次定义中断。
    这样达成一个循环。
    在烧录程序之前,我们线使用keil的逻辑分析仪看一下usart1串口的变化情况。
    如下

请添加图片描述
然后我们使用sscom串口助手在pc上进行调试。
请添加图片描述
进去先打开串口,可以看到stm32开始不断发送hello windows语句。
这是因为我们给flag初始赋值为1.
我们先发送#,使其停止。
请添加图片描述

可以看到我们收到了预先设定的stopcmd语句,这代表中断服务程序被正确的执行了。
我们再使用* 在继续发送。
请添加图片描述
可以看到我们先收到 设定的startcmd 语句 然后stm32 开始不断向pc机发送我们需要的hello windows语句。
由此可以表示我们程序完全成功。

参考文献

  • https://www.pianshen.com/article/8285571527/

  • https://blog.csdn.net/qq_47281915/article/details/121053903

  • https://blog.csdn.net/qq_47281915/article/details/121063896

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值