当前位置: 首页 > ds >正文

HAL库配置RS485+DMA+空闲中断收发数据

前言:

(1)DMA是单片机集成在芯片内部的一个数据搬运工,它可以代替单片机对数据进行传输、存储,节约CPU资源。一般应用场景,ADC多通道采集,串口收发(频繁进入接收中断),SPI和IIC通信等

(2)STM32F2系列的DMA控制器最多有2个,每个控制器有8个数据流,每个数据流可以映射到不同的通道。例如,DMA2的数据流7可能用于某个特定外设,比如USART1的TX。(每个数据流同一时间只能服务一个外设。例如,若USART1_TX占用了DMA2_Stream7,则该流不可用于其他外设)

(3)DMA配置参数:

DMA请求源与通道选择:DMA1通道1

数据传输方向:外设 ↔ 存储器,存储器 ↔ 存储器

地址递增配置:外设地址递增和存储器地址递增(如果外设是ADC数据寄存器,关闭递增,如果存储器地址是接收数组,则开启递增)

数据宽度与对齐:外设/存储器数据宽度(串口一般是8位,ADC一般是16位)

传输模式:单次模式(串口接收)和循环模式(ADC采集数据)

正文:

1、配置时钟,烧入方式,配置RS485的接收使能脚

2、配置串口,DMA

3、串口串口收发缓存结构体

#define USART_TX_MAX_LEN 100
#define USART_RX_MAX_LEN 100
typedef struct
{unsigned char tx_buf[USART_TX_MAX_LEN]; unsigned char rx_buf[USART_RX_MAX_LEN];unsigned char rx_flag;unsigned char rx_len;
}usart_data_t;extern usart_data_t stUsart1Data;

 4、 串口初始化代码加入  开启IDLE中断、开始DMA接收

__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE); //使能IDLE中断
HAL_UART_Receive_DMA(&huart1,stUsart1Data.rx_buf,USART_RX_MAX_LEN);

5、串口中断函数中加入 接收数据代码

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_AbortReceive(&huart1);	//已经接收完一帧数据,所以这里要停止接收,然后再重新接收	uint32_t   temp =  __HAL_DMA_GET_COUNTER(&hdma_usart1_rx);// 获取DMA中未传输的数据个数 ,stUsart1Data.rx_len =  USART_RX_MAX_LEN - temp; //总计数减去未传输的数据个数,得到已经接收的数据个数stUsart1Data.rx_flag = 1;	// 接受完成标志位置1	HAL_UART_Receive_DMA(&huart1,stUsart1Data.rx_buf,USART_RX_MAX_LEN);	//开始DMA接收}/* USER CODE END USART1_IRQn 1 */
}

6、配置串口printf打印函数

void Usart1Printf(const char *format,...)
{uint16_t len;va_list args;	va_start(args,format);len = vsnprintf((char*)stUsart1Data.tx_buf,sizeof(stUsart1Data.tx_buf)+1,(char*)format,args);va_end(args);if(HAL_UART_Transmit_DMA(&huart1, stUsart1Data.tx_buf, len)!= HAL_OK)   //判断是否发送正常,如果出现异常则进入异常中断函数{Error_Handler();}}

7、RS485通信加入使能发送和接收

/* USER CODE BEGIN 1 */
void USART1_RS485_Send_Enable(void)
{HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_SET);
}void USART1_RS485_Receive_Enable(void)
{HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_RESET);
}

8、测试代码

USART1_RS485_Receive_Enable(); //默认为接收使能while (1){/* USER CODE END WHILE */if(stUsart1Data.rx_flag  == 1)  //接收完成标志{USART1_RS485_Send_Enable();Usart1Printf("%s\r\n",stUsart1Data.rx_buf);HAL_Delay(100);//等待串口DMA发送完成,如果不加入此行代码,会出现发送失败,因为还没有发送完就切换成接收模式,导致不能发送数据 USART1_RS485_Receive_Enable();stUsart1Data.rx_len = 0;//清除计数stUsart1Data.rx_flag = 0;//清除接收结束标志位memset(stUsart1Data.rx_buf,0,USART_RX_MAX_LEN);}}

9、测试结果

10、优化RS485发送

当发送数据后,我们会等待一定时间,等待发送完成后在开启串口接收,但此时资源遭到了一定的浪费

优化思路:等待触发串口发送完成中断后,使能串口接收中断

void USART1_IRQHandler(void)
{HAL_UART_IRQHandler(&huart1);if((__HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE) != RESET))  {__HAL_UART_CLEAR_IDLEFLAG(&huart1);//清除标志位HAL_UART_AbortReceive(&huart1);	//已经接收完一帧数据,所以这里要停止接收,然后再重新接收	uint32_t   temp =  __HAL_DMA_GET_COUNTER(&hdma_usart1_rx);// 获取DMA中未传输的数据个数 ,stUsart1Data.rx_len =  USART_RX_MAX_LEN - temp; //总计数减去未传输的数据个数,得到已经接收的数据个数stUsart1Data.rx_flag = 1;	// 接受完成标志位置1	HAL_UART_Receive_DMA(&huart1,stUsart1Data.rx_buf,USART_RX_MAX_LEN);	//开始DMA接收}if (HAL_UART_GetState(&huart1) == HAL_UART_STATE_READY) {// 发送完成 USART1_RS485_Receive_Enable();}
}USART1_RS485_Receive_Enable();while (1){/* USER CODE END WHILE */if(stUsart1Data.rx_flag  == 1)  //接收完成标志{USART1_RS485_Send_Enable();Usart1Printf("%s\r\n",stUsart1Data.rx_buf);
//		HAL_Delay(100);//等待串口DMA发送完成 
//		USART1_RS485_Receive_Enable();stUsart1Data.rx_len = 0;//清除计数stUsart1Data.rx_flag = 0;//清除接收结束标志位memset(stUsart1Data.rx_buf,0,USART_RX_MAX_LEN);}}

http://www.xdnf.cn/news/562.html

相关文章:

  • 修改 <li> 元素小圆点的颜色
  • @EnableAsync+@Async源码学习笔记之六
  • 对象存储概述
  • 关于学习STM32的C语言的知识
  • linux学习 4.2 目录修改相关命令
  • 在小米AX6000中通过米家控制tailscale
  • 微服务治理与可观测性
  • PCI总线和PCIe总线
  • 数据结构学习笔记 :排序算法详解与C语言实现
  • Spring 依赖冲突解决方案详解
  • AUTOSAR图解==>AUTOSAR_SWS_EFXLibrary
  • BGP选路实验
  • 2024年3月 GESP 图形化二级考级真题——找因数
  • 解锁思想道德修养的奥秘:用思维导图开启智慧之旅
  • Multi-Query Attention (MQA) PyTorch 实现
  • 《擦除序列》线性时间做法题解
  • 利用 FastAPI 实现三种推送方式
  • 企业微信自建应用开发回调事件实现方案
  • AI文生图工具推荐
  • swift-12-Error处理、关联类型、assert、泛型_
  • Java ThreadPoolExecutor 深度解析:从原理到实战
  • 编译Spring源码时遇到的错误
  • HDMI如何进行插入检测
  • QML中的3D功能--纹理应用
  • Linux字符设备驱动
  • ZLMediaKit 和 SRS的区别,哪个更好用?
  • 在Qt和OSG中动态改变部分3D模型数据
  • 大模型API中转平台选择指南:如何找到优质稳定的服务
  • 压滤机与锡泥产生效率
  • OzGIS:地理信息分析与处理软件