本帖最后由 RISCVLAR 于 2020-12-18 14:03 编辑
CH32V103应用教程——DMA(外设到存储器)
关于DMA,具有三种数据传输方式:存储器到存储器、存储器到外设、外设到存储器。在第十三章以及第二十七章,已讲解存储器到存储器传输方式以及存储器到外设传输方式,本章将讲解DMA外设到存储器传输方式。使用串口1作为外设,通过串口调试助手等向开发板发送数据,数据会被返回给开发板并通过串口调试助手显示。
1、DMA简介及相关函数介绍 关于DMA以及相关函数介绍在在第十三章以及第二十七章已讲解,在此不再介绍。关于DMA具体介绍,可参考CH32V103应用手册。
2、硬件设计 本章教程所用资源均为CH32V103开发板内部资源,无需进行其他硬件连接,只需进行程序配置即可。
3、软件设计 本章主要进行外设到存储器的DMA数据传输方式,其相较于存储器到存储器的传输方式,程序中对DMA配置进行一些修改即可。此外,本章还需用到串口1,在第三章基础上进行修改即可,即将串口2修改为串口1,以及对中断服务函数进行一些修改,具体如下: 关于串口1中断服务函数: void USART1_IRQHandler(void)
{
uint8_t i;
uint16_t t;
if(USART_GetITStatus(USART1,USART_IT_IDLE) == SET) //检查中断是否发生
{
DMA_Cmd(DMA1_Channel5,DISABLE); //关闭DMA传输
t = DMA_GetCurrDataCounter(DMA1_Channel5); //获取剩余的数据数量
for(i=0; i<RECEIVEBUFF_SIZE-t; i++)
{
USARTx_SendByte(USART1,ReceiveBuff[i]); // 发送一个字节数据到USART2
}
/* 等待发送完成 */
while(USART_GetFlagStatus(USART1,USART_FLAG_TC)==RESET);//向电脑返回数据(接收数据数量 = SENDBUFF_SIZE - 剩余未传输的数据数量)
DMA_SetCurrDataCounter(DMA1_Channel5,RECEIVEBUFF_SIZE); //重新设置传输的数据数量
DMA_Cmd(DMA1_Channel5,ENABLE); //开启DMA传输
USART_ReceiveData(USART1); //读取一次数据,不然会一直进中断
USART_ClearFlag(USART1,USART_FLAG_IDLE); //清除串口空闲中断标志位
}
}
此函数主要进行串口中断以及进行DMA传输,此外在串口初始化配置中,需要将中断使能改为使能空闲中断,具体如下: USART_ITConfig(USART1,USART_IT_IDLE,ENABLE); //开启空闲中断
dma.h文件 #ifndef __DMA_H
#define __DMA_H
#include "ch32v10x_conf.h"
#define RECEIVEBUFF_SIZE 1000
uint8_t ReceiveBuff[RECEIVEBUFF_SIZE];
void DMA1_CH5_Init(void); //DMA传输参数初始化配置
#endif
dma.h文件主要进行宏定义及相关函数声明; dma.c文件 #include "dma.h"
uint8_t ReceiveBuff[RECEIVEBUFF_SIZE];
/*******************************************************************************
* Function Name : DMA1_CH5_Init
* Description : Initializes Channel3 of DMA1 collection.
* Input : None
* Return : None
*******************************************************************************/
//DMA1通道5传输参数配置
void DMA1_CH5_Init(void)
{
DMA_InitTypeDef DMA_InitStructure;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); //使能DMA1时钟
DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)(&USART1->DATAR);//设置源数据地址
DMA_InitStructure.DMA_MemoryBaseAddr = (u32)ReceiveBuff; //设置目标地址
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; //设置传输方向:外设到存储器(此处外设为内部FLASH)
DMA_InitStructure.DMA_BufferSize = RECEIVEBUFF_SIZE; //设置传输大小
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //指定外设地址寄存器不变。
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //指定内存地址寄存器递增。
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; //设置外设数据单位
DMA_InitStructure.DMA_MemoryDataSize = DMA_PeripheralDataSize_Byte; //设置存储器数据单位
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; //设置对应DMA工作模式为正常模式
DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh; //DMA1通道5优先级高
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //使能DMA存储器到存储器的传输方式
DMA_Init(DMA1_Channel5, &DMA_InitStructure); //根据DMA_InitStruct中指定的参数初始化DMA1通道3
DMA_Cmd(DMA1_Channel5, ENABLE); //使能DMA1通道5
}
dma.c文件主要进行DMA初始化配置,其相较于前两章,主要修改如下: 关于源地址,改为外设地址,此处为串口1: DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)(&USART1->DATAR);
关于目标地址,改为存储器地址: DMA_InitStructure.DMA_MemoryBaseAddr = (u32)ReceiveBuff;
关于DMA传输方式及方向,改为外设到存储器: DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
关于DMA传输大小,根据目标数据进行设置: DMA_InitStructure.DMA_BufferSize = RECEIVEBUFF_SIZE;
此外,由CH32V103应用手册可知,本次所用外设串口1 USART_RX对应DMA通道5,如下图: 因此,初始化以及使能DMA通道5: DMA_Init(DMA1_Channel5, &DMA_InitStructure); //根据DMA_InitStruct中指定的参数初始化DMA1通道5
DMA_Cmd(DMA1_Channel5, ENABLE); //使能DMA1通道5
4、下载验证 将编译好的程序下载到开发板并复位,然后通过串口调试助手向单片机发送数据,单片机接收数据并通过串口调试助手显示,具体如下:
|