网站建设的商品编码,做网站导航条怎么弄,站长资讯,制作网站需要哪些知识STM32-01-认识单片机 STM32-02-基础知识 STM32-03-HAL库 STM32-04-时钟树 STM32-05-SYSTEM文件夹 STM32-06-GPIO STM32-07-外部中断 STM32-08-串口 STM32-09-IWDG和WWDG STM32-10-定时器 STM32-11-电容触摸按键 STM32-12-OLED模块 STM32-13-MPU STM32-14-FSMC_LCD 文章目录 STM…STM32-01-认识单片机 STM32-02-基础知识 STM32-03-HAL库 STM32-04-时钟树 STM32-05-SYSTEM文件夹 STM32-06-GPIO STM32-07-外部中断 STM32-08-串口 STM32-09-IWDG和WWDG STM32-10-定时器 STM32-11-电容触摸按键 STM32-12-OLED模块 STM32-13-MPU STM32-14-FSMC_LCD 文章目录 STM32-15-DMA1. DMA与中断的区别1. DMA2. 中断 2. DMA介绍3. DMA结构框图1. DMA框图2. DMA处理过程3. DMA通道 4. DMA相关寄存器5. DMA相关HAL库驱动6. 代码实现 STM32-15-DMA
1. DMA与中断的区别
**DMADirect Memory Access直接内存访问**和中断是两种不同的机制用于管理计算机系统中外围设备与处理器之间的数据传输和处理。
1. DMA
工作原理
独立传输DMA允许外设直接与系统内存交换数据而不需要通过处理器CPU。当需要大量数据传输时DMA控制器接管传输任务释放CPU去执行其他任务。传输过程DMA传输数据时CPU启动DMA传输然后DMA控制器接管整个传输过程。传输完成后DMA控制器通过中断通知CPU传输完成。
作用
提高效率DMA减少了CPU在数据传输过程中的参与使得CPU能够执行其他任务从而提高系统的整体效率。减少延迟由于DMA可以独立进行传输因此数据传输的延迟更低特别是在处理大块数据时。应用场景DMA广泛应用于音频、视频数据流、网络数据包的传输、存储设备的数据读写等场景。
对程序的影响
复杂度增加引入DMA需要对DMA控制器进行配置可能增加程序的复杂性。同步问题在DMA传输过程中程序需要处理好数据同步问题避免数据不一致性问题。
2. 中断
工作原理
中断触发中断是外设通过中断信号通知CPU某个事件发生如输入设备有新数据可读取定时器到期等。中断处理CPU响应中断后暂停当前任务跳转到相应的中断处理程序ISR执行。当中断处理程序执行完毕后CPU恢复先前任务的执行。
作用
实时响应中断机制使CPU能够实时响应外设事件保证系统对外部事件的快速反应。事件驱动中断使得程序可以基于事件驱动而不是定期轮询外设状态从而节省CPU资源。应用场景键盘输入、鼠标移动、网络数据包到达、定时器事件等。
对程序的影响
中断处理程序设计中断处理程序需要尽可能简短、快速避免长时间占用CPU。中断优先级管理系统中可能有多个中断源需要合理设计中断优先级以确保关键中断能够及时响应。上下文切换开销中断会引起上下文切换带来一定的性能开销。 总结 DMA适用于大量数据传输降低CPU负载提高系统效率。中断适用于实时事件响应保证系统对外部事件的快速处理。 两者结合使用可以构建高效、实时的嵌入式系统。例如DMA用于大数据块的传输而中断用于触发DMA传输和处理传输完成事件。 2. DMA介绍
**DMA**即直接存储器访问。DMA传输方式无需CPU直接控制传输也没有中断处理方式那样保留现场和恢复现场的过程通过硬件为RAM与I/O设备开辟一条直接传送数据的通路能使CPU的效率大为提高。STM32F103内部有2个DMA控制器DMA1有7个通道DMA2有5个通道。每个通道专门用来管理来自于一个或多个外设对存储器访问的请求还有一个仲裁器来协调各个DMA请求的优先权。特性 每个通道都直接连接专用的硬件DMA请求每个通道都支持软件触发。这些功能通过软件来配置。在七个请求间的优先权可以通过软件编程设置当软件相同时由硬件决定。独立的源和目标数据区的传输宽度模拟打包和拆包的过程。源和目标地址必须按数据传输宽度对齐。支持循环的缓冲器管理。每个通道都有3个事件标志这3个事件标志逻辑或成为一个单独的中断请求。存储器和存储器间的传输。外设和存储器存储器和外设的传输。闪存、SRAM、外设的SRAM、APB1、APB2和AHB外设均可作为访问的源和目标。可编程的数据传输数目最大为65535。
3. DMA结构框图
1. DMA框图 ①DMA请求 如果外设想要通过DMA来传输数据必须先给DMA控制器发送DMA请求DMA收到请求信号之后控制器会给外设一个应答信号当外设应答后且DMA控制器收到应答信号之后就会启动DMA的传输直到传输完毕。 ②DMA通道 DMA具有12个独立可编程的通道其中DMA1有7个通道DMA2有5个通道每个通道对应不同的外设的DMA请求。虽然每个通道可以接收多个外设的请求但是同一时间只能接收一个不能同时接收多个。 ③DMA优先级 当发生多个DMA通道请求时就意味着有先后响应处理的顺序问题这个就由仲裁器管理。仲裁器管理DMA通道请求分为两个阶段。第一阶段属于软件阶段可以在DMA_CCRx寄存器中设置有4个等级非常高高中和低四个优先级。第二阶段属于硬件阶段如果两个或以上的DMA通道请求设置的优先级一样则他们优先级取决于通道编号编号越低优先权越高比如通道0高于通道1。在大容量产品和互联型产品中DMA1控制器拥有高于DMA2控制器的优先级。
2. DMA处理过程 DMADirect Memory Access直接内存访问是一种允许外设直接与系统内存进行数据传输的机制不需要CPU的直接干预。以下是DMA处理过程的详细描述
DMA处理过程
配置DMA控制器 源地址设置数据传输的源地址可以是外设寄存器地址或内存地址。目标地址设置数据传输的目标地址可以是外设寄存器地址或内存地址。传输方向指定数据传输的方向是从外设到内存还是从内存到外设。数据长度设置需要传输的数据长度字节数。传输模式选择传输模式可以是单次传输、块传输或连续传输模式。 启动DMA传输 触发传输在配置完成后通过设置DMA控制器的启动位开始数据传输。数据搬运DMA控制器接管数据传输任务将数据从源地址搬运到目标地址。这个过程中DMA控制器直接与内存控制器和外设总线进行交互不需要CPU干预。 中断通知 传输完成中断数据传输完成后DMA控制器产生中断信号通知CPU传输已经完成。CPU执行相应的中断服务程序ISR处理后续任务。错误处理如果在传输过程中发生错误如总线错误DMA控制器也会产生中断通知CPU进行错误处理。
3. DMA通道
DMA1通道与外设的对应关系
DMA2通道与外设的对应关系
4. DMA相关寄存器
寄存器名称作用DMA_CCRxDMA通道x配置寄存器用于配置DMA核心控制寄存器DMA_ISRDMA中断状态寄存器用于查询当前DMA传输状态DMA_IFCRDMA中断标志清除寄存器用来清除DMA_ISR对应位DMA_CNDTRxDMA通道x传输数量寄存器用于控制DMA通道x每次传输的数据量DMA_CPARxDMA通道x外设地址寄存器用于存储STM32外设地址DMA_CMARxDMA通道x存储器地址寄存器用于存放存储器的地址USART_CR3USART控制寄存器3用于使能串口DMA发送 DMA通道x配置寄存器DMA_CCRx DMA中断状态寄存器DMA_ISR DMA 中断标志清除寄存器DMA_IFCR DMA通道x传输数量寄存器DMA_CNDTRx 该寄存器控制着DMA通道x的每次传输所要传输的数据量。其设置范围为0~65535。并且该寄存器的值随着传输的进行而减少当该寄存器的值为0的时候就代表此次数据传输己经全部发送完成。可以通过这个寄存器的值来获取当前DMA传输的进度。 DMA通道x外设地址寄存器DMA_CPARx 用来存储 STM32 外设的地址。 DMA通道x存储器地址寄存器DMA_CMARx 用来存放存储器的地址。
5. DMA相关HAL库驱动 使能DMA时钟 __HAL_RCC_DMA1_CLK_ENABLE();初始化DMA HAL_StatusTypeDef HAL_DMA_Init(DMA_HandleTypeDef *hdma);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_LINKDMA(g_uart1_handler, hdmatx, g_dma_handle);使能串口的DMA发送启动传输 HAL_UART_Transmit_DMA()HAL_StatusTypeDef HAL_UART_DMAStop(UART_HandleTypeDef *huart); /* 停止 */
HAL_StatusTypeDef HAL_UART_DMAPause(UART_HandleTypeDef *huart); /* 暂停 */
HAL_StatusTypeDef HAL_UART_DMAResume(UART_HandleTypeDef *huart); /* 恢复 */查询DMA传输状态 //查询DMA传输通道的状态
__HAL_DMA_GET_FLAG(g_dma_handle, DMA_FLAG_TC4);//获取当前传输剩余数据量
__HAL_DMA_GET_COUNTER(g_dma_handle);//设置对应的DMA数据流传输的数据量大小
__HAL_DMA_SET_COUNTER (g_dma_handle, 1000);DMA中断使用 //通用中断处理函数
void HAL_DMA_IRQHandler();//相关中断回调函数
//发送完成回调函数
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart);
//发送一半回调函数
void HAL_UART_TxHalfCpltCallback(UART_HandleTypeDef *huart);
//接收完成回调函数
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart);
//接收一半回调函数
void HAL_UART_RxHalfCpltCallback(UART_HandleTypeDef *huart);
//传输出错回调函数
void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart);6. 代码实现 功能 每按下按键KEY0,串口1就会以DMA方式发送数据同时在LCD上面显示传送进度。打开串口调试助手可以收到DMA发送的内容。LED0闪烁用于提示程序正在运行。 DMA初始化函数 void dma_init(DMA_Channel_TypeDef* DMAx_CHx)
{if((uint32_t)DMAx_CHx (uint32_t)DMA1_Channel7){__HAL_RCC_DMA2_CLK_ENABLE();}else{__HAL_RCC_DMA2_CLK_ENABLE();}//将DMA与USART1连接起来__HAL_LINKDMA(g_uart1_handle, hdmatx, g_dma_handle); g_dma_handle.Instance DMAx_CHx; //USART1_TX使用的DMA通道为DMA_Channel4g_dma_handle.Init.Direction DMA_MEMORY_TO_PERIPH; //模式选择为从存储器到外设g_dma_handle.Init.PeriphInc DMA_PINC_DISABLE; //外设非增量模式g_dma_handle.Init.MemInc DMA_MINC_ENABLE; //存储器增量模式g_dma_handle.Init.PeriphDataAlignment DMA_PDATAALIGN_BYTE; //外设数据长度为8位g_dma_handle.Init.MemDataAlignment DMA_MDATAALIGN_BYTE; //存储器数据长度为8位g_dma_handle.Init.Priority DMA_PRIORITY_MEDIUM; //中等优先级HAL_DMA_Init(g_dma_handle);
}主函数 int main(void)
{uint16_t i, k;uint16_t len;uint8_t mask 0;float pro 0; /* 进度 */HAL_Init(); /* 初始化HAL库 */sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */delay_init(72); /* 延时初始化 */usart_init(115200); /* 串口初始化为115200 */led_init(); /* 初始化LED */lcd_init(); /* 初始化LCD */key_init(); /* 初始化按键 */dma_init(DMA1_Channel4); /* 初始化串口1 TX DMA */lcd_show_string(30, 50, 200, 16, 16, STM32, RED);lcd_show_string(30, 70, 200, 16, 16, DMA TEST, RED);lcd_show_string(30, 90, 200, 16, 16, ATOMALIENTEK, RED);lcd_show_string(30, 110, 200, 16, 16, KEY0:Start, RED);len sizeof(TEXT_TO_SEND);k 0;for (i 0; i SEND_BUF_SIZE; i) /* 填充ASCII字符集数据 */{if (k len) /* 入换行符 */{if (mask){g_sendbuf[i] 0x0a;k 0;}else{g_sendbuf[i] 0x0d;mask;}}else /* 复制TEXT_TO_SEND语句 */{mask 0;g_sendbuf[i] TEXT_TO_SEND[k];k;}}i 0;while (1){if (key_scan(0) 1) /* KEY0按下 */{printf(\r\nDMA DATA:\r\n);lcd_show_string(30, 130, 200, 16, 16, Start Transimit...., BLUE);lcd_show_string(30, 150, 200, 16, 16, %, BLUE); /* 显示百分号 */HAL_UART_Transmit_DMA(g_uart1_handle, g_sendbuf, SEND_BUF_SIZE);/* 等待DMA传输完成此时我们来做另外一些事情比如点灯 * 实际应用中传输数据期间可以执行另外的任务 */while (1){if ( __HAL_DMA_GET_FLAG(g_dma_handle, DMA_FLAG_TC4)) /* 等待 DMA1_Channel4 传输完成 */{__HAL_DMA_CLEAR_FLAG(g_dma_handle, DMA_FLAG_TC4);HAL_UART_DMAStop(g_uart1_handle); /* 传输完成以后关闭串口DMA */break;}pro DMA1_Channel4-CNDTR; /* 得到当前还剩余多少个数据 */len SEND_BUF_SIZE; /* 总长度 */pro 1 - (pro / len); /* 得到百分比 */pro * 100; /* 扩大100倍 */lcd_show_num(30, 150, pro, 3, 16, BLUE);} lcd_show_num(30, 150, 100, 3, 16, BLUE); /* 显示100% */lcd_show_string(30, 130, 200, 16, 16, Transimit Finished!, BLUE); /* 提示传送完成 */}i;delay_ms(10);if (i 20){LED0_TOGGLE(); /* LED0闪烁,提示系统正在运行 */i 0;}}
}实验结果