STM32串口DMA模式发送接收数据并控制LED灯

什么是DMA

DMA即直接存储器访问,Direct Memory Access.是外设和存储器或存储器之间的告诉数据传输。DMA传输方式不用CPU直接控制传输,而是在RAM和IO设备之间直接进行数据传输的通道,大大提高CPU的效率。

通过STM32cubeMX来配置串口DMA模式

首先打开串口,这里使用的是串口2,波特率115200,字长8Bit。并且使能串口2中断。
然后给串口2的两个IO口配置DMA通道。
在这里插入图片描述在这里插入图片描述
在这里插入图片描述

在keil中编写相关程序代码

1.在uart.c中添加串口重定向函数

//串口发送函数HAL_UART_Transmit()重定向到printf()
#include "stdio.h"
#ifdef __GNUC__
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif

PUTCHAR_PROTOTYPE
{
	HAL_UART_Transmit(&huart2, (uint8_t*) &ch, 1, 0xffff);
	return ch;
}

2.在main.h中创建一个用于串口接收数据的结构体

#define RX_BUF_MAX_LEN 512
typedef struct
{
	uint8_t rx_buff[RX_BUF_MAX_LEN];//缓存区
	uint16_t len;		//接收长度
	uint8_t flag;		//接收标志位,1为接收完毕
}USRAT_RX;

3.打开stm32xxxx_it.c添加如下代码

首先定义一个结构体变量

USRAT_RX usart1_rx;

再找到串口中断服务函数

添加下列代码

void USART2_IRQHandler(void)
{
  HAL_UART_IRQHandler(&huart2);
  if(__HAL_UART_CLEAR_FLAG(&huart2,UART_FLAG_IDLE) != RESET)
  {//如果没有清除空闲中断(表示接收到了数据)
  	//清除空闲中断
	__HAL_UART_CLEAR_IDLEFLAG(&huart2);
	//停止串口2的DMA传输
	HAL_UART_DMAStop(&huart2);
	//计算接收到的数据长度
	usart1_rx.len = RX_BUF_MAX_LEN - __HAL_DMA_GET_COUNTER(&hdma_usart2_rx);
	//计算接收到的数据长度
	usart1_rx.flag = 1;
	//如果没有接收到数据
	if(usart1_rx.len == 0)
	{
		//flag置0,表示未接收到数据
		usart1_rx.flag = 0;
		//以DMA模式接收一定长度的字符串
		HAL_UART_Receive_DMA(&huart2,(uint8_t*)usart1_rx.rx_buff,RX_BUF_MAX_LEN);
		//恢复DMA传输
		HAL_UART_DMAResume(&huart2);
	}
  }
}

4.在main.c中添加代码

首先声明结构体变量

extern USRAT_RX usart1_rx;

加入串口结构体初始化函数

void Clear_Usart(USRAT_RX *usart_rx)		
//初始化(清空)串口结构体
{
	//全写0
	memset((uint8_t*)usart_rx,0,sizeof(USRAT_RX)); 
}

在主函数中添加功能

int main(void)
{
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_USART2_UART_Init();
  Clear_Usart(&usart1_rx); //初始化串口结构体
  __HAL_UART_ENABLE_IT(&huart2,UART_IT_IDLE);	//使能串口2的空闲中断
  HAL_UART_Receive_DMA(&huart2,(uint8_t*)usart1_rx.rx_buff,RX_BUF_MAX_LEN);	//打开DMA传输模式
  while (1)
  {
	if(usart1_rx.flag == 1)	//判断接收完成
		{
			printf("%s\r\n",usart1_rx.rx_buff);		//打印发送的数据
			if(strstr((const char *)usart1_rx.rx_buff,"LED_ON") != NULL)
				{
					HAL_GPIO_WritePin(LED_GPIO_Port,LED_Pin,GPIO_PIN_SET);
					printf("Turn on the LED\r\n");
				}
			else if(strstr((const char *)usart1_rx.rx_buff,"LED_OFF") != NULL)
				{
					HAL_GPIO_WritePin(LED_GPIO_Port,LED_Pin,GPIO_PIN_RESET);
					printf("Turn off the LED\r\n");
				}
			else
				{
					printf("error\r\n");
				}
				Clear_Usart(&usart1_rx);	//清空串口结构体
				HAL_UART_Receive_DMA(&huart2,(uint8_t*)usart1_rx.rx_buff,RX_BUF_MAX_LEN);		//打开DMA模式
				HAL_UART_DMAResume(&huart2);		//恢复DMA传输
		}
  }
}

5.最终效果

通过串口工具,输入LED_ON打开LED灯,并反馈Turn on the LED;输入LED_OFF则关闭LED灯,并反馈Turn off the LED;输入其他数据则反馈error。

  • 6
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值