赞
踩
目录
一、 DMA(Directional Memory Access)简介
DMA,直接存储器访问,是一种完全由硬件执行数据交换的工作方式。它由DMA控制器控制在存储器和存储器,存储器和外设之间的批量数据传输。DMA 传输方式无需 CPU 直接 控制传输,也没有中断处理方式那样保留现场和恢复现场的过程,通过硬件为 RAM 与 I/O 设备 开辟一条直接传送数据的通路,能使 CPU 的效率大为提高。
DMA能够直接不占用CPU任何资源,直接将存储器和外设连接,让二者相互访问。
DMA1的通道对应外设:
此实验需要用到USART1DMA方式串口通信,那么就需要开启DMA的通道4、5
最后点击生成代码即可
void DMA_Init(DMA_Channel_TypeDef* DMAy_Channelx,DMA_InitTypeDef* DMA_InitStruct)
该函数有两个参数,第一参数是DMA通道结构体,第二个参数是DMA_InitTypeDefDMA初始化结构体,该结构体定义为:
- typedef struct
- {
- uint32_t Direction;//传输方向,例如存储器到外设 DMA_MEMORY_TO_PERIPH
- uint32_t PeriphInc;//外设(非)增量模式,非增量模式 DMA_PINC_DISABLE
- uint32_t MemInc;//存储器(非)增量模式,增量模式 DMA_MINC_ENABLE
- uint32_t PeriphDataAlignment; //外设数据大小:8/16/32 位。
- uint32_t MemDataAlignment; //存储器数据大小:8/16/32 位。
- uint32_t Mode;//模式:外设流控模式/循环模式/普通模式
- uint32_t Priority; //DMA 优先级:低/中/高/非常高
- }DMA_InitTypeDef;
HAL_StatusTypeDef HAL_UART_Transmit_DMA(UART_HandleTypeDef *huart, const uint8_t *pData, uint16_t Size)
该函数是DMA发送函数,一共三个参数,第一个参数是指明哪个串口,第二个参数是发送的数据,为8bit,一个字符形式,第三个参数是发送数据的大小。
如果用串口1用DMA方式发送1个字符,则可以写:
- ch='a';
- HAL_UART_Transmit_DMA(&huart1,(uint8_t *)ch,1);
HAL_StatusTypeDef HAL_UART_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
接收函数同样也是三个参数,将大小为size的接收数据保存到pData中,如:
- char ReBuff[5];
- HAL_UART_Receive_DMA(&huart1,(uint8_t *)Rebuff,5);
STM32系统给上位机(win10)连续发送“hello windows!”;当上位机给stm32发送字符“stop”后,stm32暂停发送“hello windows!”;发送一个字符“start”后,stm32继续发送。
单片机首先需要开启接收中断,即调用HAL_UART_Receive_IT函数,当单片机接收到数据完成后,就调用中断回调函数HAL_UART_RxCpltCallback,可以编写逻辑,判断接收的字符是否为start,如果是就通过中断给PC机发送一个字符start,并置flag=1(在主函数循环中,flag=1,每隔1s给PC发送一次“Hello Windows!\n”),如果是stop,置flag=0。
1. 主函数编写:
- int main(void)
- {
- /* USER CODE BEGIN 1 */
-
- /* USER CODE END 1 */
-
- /* MCU Configuration--------------------------------------------------------*/
-
- /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
- HAL_Init();
-
- /* USER CODE BEGIN Init */
-
- /* USER CODE END Init */
-
- /* Configure the system clock */
- SystemClock_Config();
-
- /* USER CODE BEGIN SysInit */
-
- /* USER CODE END SysInit */
-
- /* Initialize all configured peripherals */
- MX_GPIO_Init();
- MX_DMA_Init();
- MX_USART1_UART_Init();
- HAL_UART_Receive_DMA(&huart1, (uint8_t *)&ReBuff,5);
- /* USER CODE BEGIN 2 */
-
- /* USER CODE END 2 */
-
- /* Infinite loop */
- /* USER CODE BEGIN WHILE */
- while (1)
- {
- /* USER CODE END WHILE */
-
- if(flag==1)
- {
- HAL_UART_Transmit_DMA(&huart1,(uint8_t *)SendBuff,17);
- HAL_Delay(1000);
- }
- /* USER CODE BEGIN 3 */
- }
- /* USER CODE END 3 */
- }
2. 字符匹配函数
- int StringCompare(char rcData[5],char rcData2[5]){
- for(uint8_t i = 0 ; i < 5 ; i++){
- if (rcData[i] != rcData2[i]) return 0;
- }
- return 1;
- }
3. 回调函数
- void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
- {
- if(huart->Instance==USART1)
- {
- if(StringCompare(ReBuff,start)==1)
- {
- flag=1;
- HAL_UART_Transmit_DMA(&huart1,(uint8_t *)start,5);
- }
- else if(StringCompare(ReBuff,stop)==1)
- {
- flag=0;
- HAL_UART_Transmit_DMA(&huart1,(uint8_t *)stop,5);
- }
- HAL_UART_Receive_DMA(&huart1, (uint8_t *)&ReBuff,5);
- }
- }
仿真查看时序和波特率
修改一下主函数的循环
- while (1)
- {
-
- HAL_UART_Transmit_DMA(&huart1,(uint8_t *)SendBuff,16);
- HAL_Delay(1000);
- }
仿真查看波形需要修改一下源码,直接在while1中调用流水灯程序,查看电平持续时间,仿真需要的MDK配置:
波形:
对比前面的查询和中断方式,如果传输的数据量过大,那么就会一直触发中断,从而导致中断连续发生,CPU同样也需要花费大量时间去频繁地处理中断,DMA将外设和内存直接连接,不经过CPU,直接与外界交换数据,这样就节省了CPU资源,从而提高了效率。
参考:
【精选】HAL库 STM32CubeMX实现串口DMA发送接收_stm32 dma和uart-CSDN博客
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。