①内存到内存
#include "dma.h"
#include "stdio.h"#define BUF_SIZE 16uint32_t src_buf[BUF_SIZE] ={0x00000000,0x11111111,0x22222222,0x33333333,0x44444444,0x55555555,0x66666666,0x77777777,0x88888888,0x99999999,0xAAAAAAAA,0xBBBBBBBB,0xCCCCCCCC,0xDDDDDDDD,0xEEEEEEEE,0xFFFFFFFF};
uint32_t dst_buf[BUF_SIZE]={0};DMA_HandleTypeDef dma_handle={0}; void dma_init()
{__HAL_RCC_DMA1_CLK_ENABLE(); dma_handle.Instance = DMA1_Channel1; //基地址 dma_handle.Init.Direction= DMA_MEMORY_TO_MEMORY; //方向是什么 是存储器到外设 还是外设到存储器 文中代码为内存到内存 DMA_MEMORY_TO_PERIPH(此为内存到外设)//内存相关的配置 dma_handle.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE ; //数据对齐的模式 这里选择的是字节对齐的模式dma_handle.Init.MemInc=DMA_MINC_ENABLE; //数据增长的方式(偏移)//外设相关的配置dma_handle.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; //外设数据对齐的模式dma_handle.Init.PeriphInc =DMA_PINC_ENABLE ; //外设数据增长的方式 dma_handle.Init.Priority = DMA_PRIORITY_MEDIUM; //优先级(中等)dma_handle.Init.Mode = DMA_NORMAL; //模式选择(循环模式还是非循环模式) 内存到内存只支持正常模式 不支持循环模式HAL_DMA_Init(&dma_handle);}void dma_transmit(void)
{HAL_DMA_Start(&dma_handle,(uint32_t)src_buf,(uint32_t)dst_buf,sizeof(uint32_t)* BUF_SIZE); //包含三个参数 源 目标 数据长度 和handle 其中 DMA 配置为 字节传输(8 位),DataLength 的单位是 字节数 因此16个数据 每个数据4个字节while(__HAL_DMA_GET_FLAG(%dma_handle,DMA_FLAG_TC1) == RESET); ///RESET为0 SER为1 int i =0;for(i=0;i<BUF_SIZE;i++)printf("buf[%d] =%X\r\n",i,dst_buf[i]);}
输出结果如下
②外设到内存
编程步骤如下
dma.c代码如下
#include "dma.h"
#include "stdio.h"#define BUF_SIZE 16DMA_HandleTypeDef dma_handle={0};
extern UART_HandleTypeDef uart1_handle;void dma_init()
{__HAL_RCC_DMA1_CLK_ENABLE(); dma_handle.Instance = DMA1_Channel4; //基地址 dma_handle.Init.Direction= DMA_MEMORY_TO_PERIPH; //方向是什么 是存储器到外设 还是外设到存储器 文中代码为内存到内存 DMA_MEMORY_TO_PERIPH(此为内存到外设)//内存相关的配置 dma_handle.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE ; //数据对齐的模式 这里选择的是字节对齐的模式dma_handle.Init.MemInc=DMA_MINC_ENABLE; //数据增长的方式(偏移)//外设相关的配置dma_handle.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; //外设数据对齐的模式dma_handle.Init.PeriphInc =DMA_PINC_DISABLE ; //外设数据增长的方式 内存到外设的目标不能递增 dma_handle.Init.Priority = DMA_PRIORITY_MEDIUM; //优先级(中等)dma_handle.Init.Mode = DMA_NORMAL; //模式选择(循环模式还是非循环模式) 内存到内存只支持正常模式 不支持循环模式HAL_DMA_Init(&dma_handle);__HAL_LINKDMA(&uart1_handle,hdmatx,dma_handle); //第一个数据为外设句柄 第二个为出口发送数据(tx) 第三个为DMA的句柄}
uart.c文件
void USART1_IRQHandler(void)
{uint8_t receive_data = 0; if(__HAL_UART_GET_FLAG(&uart1_handle, UART_FLAG_RXNE) != RESET){ /* 获取接收RXNE标志位是否被置位 */if(uart1_rx_len >= sizeof(uart1_rx_buf)) /* 如果接收的字符数大于接收缓冲区大小, */uart1_rx_len = 0; /* 则将接收计数器清零 */HAL_UART_Receive(&uart1_handle, &receive_data, 1, 1000); /* 接收一个字符 */uart1_rx_buf[uart1_rx_len++] = receive_data; /* 将接收到的字符保存在接收缓冲区 */}if (__HAL_UART_GET_FLAG(&uart1_handle, UART_FLAG_IDLE) != RESET) /* 获取接收空闲中断标志位是否被置位 */{
// printf("recv: %s\r\n", uart1_rx_buf); /* 将接收到的数据打印出来 */
// uart1_rx_clear();
// __HAL_UART_CLEAR_IDLEFLAG(&uart1_handle); /* 清除UART总线空闲中断 *///清除空闲中断__HAL_UART_CLEAR_IDLEFLAG(&uart1_handle);//停止DMA传输,防止干扰HAL_UART_DMAStop(&uart1_handle);//获取接收到的数据长度uart1_rx_len=UART1_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(&dma_handle); //总共接受的减去剩余的即为获取接收到的数据长度//打印接收到的内容printf("recv:%s,recv_len:%d\r\n",uart1_rx_buf,uart1_rx_len);//清空接收缓冲uart1_rx_clear();//重新开启串口DMA传输HAL_UART_Receive_DMA(&uart1_handle,uart1_rx_buf,UART1_RX_BUF_SIZE);}
}
结果输出如下
利用空闲中断 和DMA传输储存在缓冲区
③外设到内存
dma.c的代码如下
#include "dma.h"
#include "stdio.h"#define BUF_SIZE 16DMA_HandleTypeDef dma_handle={0};
extern UART_HandleTypeDef uart1_handle;void dma_init()
{__HAL_RCC_DMA1_CLK_ENABLE(); dma_handle.Instance = DMA1_Channel4; //基地址 dma_handle.Init.Direction= DMA_MEMORY_TO_PERIPH; //方向是什么 是存储器到外设 还是外设到存储器 文中代码为内存到内存 DMA_MEMORY_TO_PERIPH(此为内存到外设)//内存相关的配置 dma_handle.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE ; //数据对齐的模式 这里选择的是字节对齐的模式dma_handle.Init.MemInc=DMA_MINC_ENABLE; //数据增长的方式(偏移)//外设相关的配置dma_handle.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; //外设数据对齐的模式dma_handle.Init.PeriphInc =DMA_PINC_DISABLE ; //外设数据增长的方式 内存到外设的目标不能递增 dma_handle.Init.Priority = DMA_PRIORITY_MEDIUM; //优先级(中等)dma_handle.Init.Mode = DMA_NORMAL; //模式选择(循环模式还是非循环模式) 内存到内存只支持正常模式 不支持循环模式HAL_DMA_Init(&dma_handle);__HAL_LINKDMA(&uart1_handle,hdmatx,dma_handle); //第一个数据为外设句柄 第二个为出口发送数据(tx) 第三个为DMA的句柄}
main.c代码如下
#include "sys.h"
#include "delay.h"
#include "led.h"
#include "uart1.h"
#include "dma.h"uint8_t send_buf[1000] ={0};
extern UART_HandleTypeDef uart1_handle;int main(void)
{HAL_Init(); /* 初始化HAL库 */stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */led_init();uart1_init(115200);dma_init();//printf("hello world!\r\n");int i =0;for(i=0;i<1000;i++)send_buf[i]='A';HAL_UART_Transmit_DMA(&uart1_handle,send_buf,1000);while(1){ led1_on();led2_off();delay_ms(500);led1_toggle();led2_toggle();delay_ms(500);}
}
结果如下