完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
扫一扫,分享给好友
|
|
相关推荐
1个回答
|
|
一.关于DMA
1.什么是DMA? 答: DMA(Direct Memory Access,直接存储器访问) 是所有现代电脑的重要特色,它允许不同速度的硬件装置来沟通,而不需要依赖于CPU的大量中断负载。否则,CPU需要从来源把每一片段的资料复制到暂存器,然后把它们再次写回到新的地方。在这个时间中,CPU对于其他的工作来说就无法使用。* 2.DMA的意义是什么? 答: 简单的来说,能控制主存内部读写,这样有利于减轻CPU负担,加快读取速度。 3.串口使用DMA与不使用DMA有什么区别? 答: 区别可大了。通俗的讲:在没有DMA之前,串口每次发送数据时都要由CPU将源地址上的数据拷贝到串口发送的相关寄存器上;串口每次接收数据时都要由CPU将发送来的数据拷贝到主存上。而加了DMA后,只需要告诉DMA源地址和目标地址,DMA通道就能够自动进行数据的转移,即CPU只需要告诉DMA:串口需要发送的数据在哪里,串口接收到的数据应该存在哪里,运输的工作则交由DMA去做,运输期间CPU就可以去处理别的事情,这就大大提高了CPU的运行效率。 二.DMA的应用场景 DMA用在只需要传输数据,不需要处理数据的地方,有三种传输方式:
Stm32F4最多有:2个DMA控制器,各8个数据流,每个数据流有8个通道(或请求),每个通道有一个仲裁器,用于处理请求的优先级。 四.Stm32实现串口DMA传输 开发环境:CubeMX Vesion 5.4.0 Keil Vesion 5.28 1.CubeMX配置串口DMA 打开串口一,同时打开串口接收中断、DMA发送、DMA接收。 2.DMA串口数据发送 /* @brief DMA串口发送函数(非阻塞) * @param huart 串口句柄 * @param pData 发送的数据指针 * @param Size 数据量(数据的字节数) * @retval HAL status HAL_OK、HAL_ERROR、HAL_BUSY、HAL_TIMEOUT */ HAL_StatusTypeDef HAL_UART_Transmit_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size) 在需要的地方调用HAL_UART_Transmit_DMA(······)即可完成数据发送,例如: uint8_t data_16[4]={0x11,0x22,0x33,0x44}; uint8_t data_character[]="hello! I am 马云"; HAL_UART_Transmit_DMA(&huart1,data_16,4); HAL_Delay(1);//等待上一次发送完毕后再开启下一次发送 HAL_UART_Transmit_DMA(&huart1,data_character, sizeof(data_character)); 测试结果: 3.DMA串口数据接收 /* @brief 串口DMA接收函数 * @param huart 串口句柄 * @param pData 数据指针 * @param Size 数据量(数据字节数) * @retval HAL status HAL_OK、HAL_ERROR、HAL_BUSY、HAL_TIMEOUT */ HAL_StatusTypeDef HAL_UART_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size) 4.串口空闲中断(IDLE) 当DMA串口接收开始后,DMA通道会不断的将发送来的数据转移到主存,那么问题来了,该如何判断串口接收是否完成从而及时关闭DMA通道?如何知道接收到数据的长度?答案便是使用串口空闲中断。 串口空闲中断,对应事件标志为IDLE 检测到串口空闲线路时,该位由硬件置 1。如果 USART_CR1寄存器中 IDLEIE=1,则会生成中断。 该位由软件序列清零(读入 USART_SR 寄存器,然后读入 USART_DR 寄存器) 利用串口空闲中断,可以用如下流程实现DMA控制的任意长数据接收: 1.开启串口DMA接收 2.串口收到数据,DMA不断传输数据到存储buf 3.一帧数据发送完毕,串口暂时空闲,触发串口空闲中断 4.在中断服务函数中,可以计算刚才收到了多少个字节的数据 5.解码存储buf,清除标志位,开始下一帧接收 举个例子,如果要实现串口DMA不定长接收: /*1.首先定义3个全局变量*/ uint8_t rx_buffer[100];//接收数组 volatile uint8_t rx_len = 0; //接收到的数据长度 volatile uint8_t recv_end_flag = 0; //接收结束标志位 /*2.在main中开启IDLE中断以及串口DMA接收*/ __HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE); HAL_UART_Receive_DMA(&huart1,rx_buffer,100); /*在CubeMX生成的 UART1中断服务函数中判断接收是否结束,如果结束就计算出接收到的数据长度*/ 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 */ uint8_t tmp_flag =__HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE); //获取IDLE标志位 if((tmp_flag != RESET))//通过标志位判断接收是否结束 { recv_end_flag = 1; //置1表明接收结束 __HAL_UART_CLEAR_IDLEFLAG(&huart1);//清除标志位 HAL_UART_DMAStop(&huart1); uint8_t temp=__HAL_DMA_GET_COUNTER(&hdma_usart1_rx); rx_len =100-temp; //计算出数据长度 HAL_UART_Transmit_DMA(&huart1, rx_buffer,rx_len);//将受到的数据发送出去 HAL_UART_Receive_DMA(&huart1,rx_buffer,100);//开启DMA接收,方便下一次接收数据 } /* USER CODE END USART1_IRQn 1 */ } 在中断中加上HAL_UART_Transmit_DMA(&huart1, rx_buffer,rx_len)实现将受到的不定长数据发送出去,测试结果如下: 五.示例源码 1. HAL库+CubeMX+Stm32F405实现串口DMA不定长收发 六.同系列博客
|
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1614 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1541 浏览 1 评论
970 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
682 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1592 浏览 2 评论
1863浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
644浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
515浏览 3评论
531浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
504浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-22 00:55 , Processed in 0.511950 second(s), Total 48, Slave 41 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号