STM32f103的数电采集电路的DMA设计和使用优化程序
扫描二维码
随时随地手机看文章
DMA,全称为:DirectMemoryAccess,即直接存储器访问。DMA传输方式无需CPU直接控制传输,也没有中断处理方式那样保留现场和恢复现场的过程,通过硬件为RAM与I/O设备开辟一条直接传送数据的通路,能使CPU的效率大为提高。
DMA设置的一般步骤可以总结为如下几个步骤:
1.DMA时钟使能
2.DMA设置复位
3.设置DMA基地址,内存地址,输出方向参数
4.设置DMA数据大小,优先级,使用通道参数
5.DMA工作方式初始化
6.使能DMA
7.编写中断处理函数
前端采集模块的DMA使用主要用于ADC采集结果的传输和USART串口的数据发送传输。根据《stm32中文参考手册》的DMA请求一览表,选用了DMA1的通道1作为ADC1的数据传输通道,以及DMA1通道4作为和USART串口的数据发送传输通道。此处采用了单个DMA复用多通道的设计,是因为DMA速度足以完成这些任务,而且留下其他DMA资源以便项目以后可以扩展,达到节省资源的目的。
USART使用DMA发送数据配置和使能代码
//DMA1的各通道配置
//这里的传输形式是固定的,这点要根据不同的情况来修改
//从存储器->外设模式/8位数据宽度/存储器增量模式
//DMA_CHx:DMA通道CHx
//cpar:外设地址
//cmar:存储器地址
//cndtr:数据传输量
voidDMA_USART_Config(DMA_Channel_TypeDef*DMA_CHx,u32cpar,u32cmar,u16cndtr)
{
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);//使能DMA传输
DMA_DeInit(DMA_CHx);//将DMA的通道1寄存器重设为缺省值
DMA1_MEM_LEN=cndtr;
DMA_InitStructure.DMA_PeripheralBaseAddr=cpar;//DMA外设ADC基地址
DMA_InitStructure.DMA_MemoryBaseAddr=cmar;//DMA内存基地址
DMA_InitStructure.DMA_DIR=DMA_DIR_PeripheralDST;//数据传输方向,从内存读取发送到外设
DMA_InitStructure.DMA_BufferSize=cndtr;//DMA通道的DMA缓存的大小
DMA_InitStructure.DMA_PeripheralInc=DMA_PeripheralInc_Disable;//外设地址寄存器不变
DMA_InitStructure.DMA_MemoryInc=DMA_MemoryInc_Enable;//内存地址寄存器递增
DMA_InitStructure.DMA_PeripheralDataSize=DMA_PeripheralDataSize_Byte;//数据宽度为8位
DMA_InitStructure.DMA_MemoryDataSize=DMA_MemoryDataSize_Byte;//数据宽度为8位
DMA_InitStructure.DMA_Mode=DMA_Mode_Normal;//工作在正常缓存模式
DMA_InitStructure.DMA_Priority=DMA_Priority_Medium;//DMA通道x拥有中优先级
DMA_InitStructure.DMA_M2M=DMA_M2M_Disable;//DMA通道x没有设置为内存到内存传输
DMA_Init(DMA_CHx,&DMA_InitStructure);//根据DMA_InitStruct中指定的参数初始化DMA的通道USART1_Tx_DMA_Channel所标识的寄存器
}
//开启一次DMA传输
voidDMA_USART_Enable(DMA_Channel_TypeDef*DMA_CHx)
{
DMA_Cmd(DMA_CHx,DISABLE);//关闭USART1TXDMA1所指示的通道
DMA_SetCurrDataCounter(DMA_CHx,DMA1_MEM_LEN);//DMA通道的DMA缓存的大小
DMA_Cmd(DMA_CHx,ENABLE);//使能USART1TXDMA1所指示的通道
}
ADC使用DMA传送多通道数据配置和使能代码
//DMA1的各通道配置
//这里的传输形式是固定的,这点要根据不同的情况来修改
//从存储器->外设模式/8位数据宽度/存储器增量模式
//DMA_CHx:DMA通道CHx
//cpar:外设地址
//cmar:存储器地址
//cndtr:数据传输量
voidDMA_ADC_Config(DMA_Channel_TypeDef*DMA_CHx,u32cpar,u32cmar,u16cndtr)
{
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);//使能DMA传输
DMA_DeInit(DMA_CHx);//将DMA的通道1寄存器重设为缺省值
DMA_InitStructure.DMA_PeripheralBaseAddr=cpar;//DMA外设ADC基地址
DMA_InitStructure.DMA_MemoryBaseAddr=cmar;//DMA内存基地址
DMA_InitStructure.DMA_DIR=DMA_DIR_PeripheralSRC;//内存作为数据传输的目的地
DMA_InitStructure.DMA_BufferSize=cndtr;//DMA通道的DMA缓存的大小
DMA_InitStructure.DMA_PeripheralInc=DMA_PeripheralInc_Disable;//外设地址寄存器不变
DMA_InitStructure.DMA_MemoryInc=DMA_MemoryInc_Enable;//内存地址寄存器递增
DMA_InitStructure.DMA_PeripheralDataSize=DMA_PeripheralDataSize_HalfWord;//数据宽度为16位
DMA_InitStructure.DMA_MemoryDataSize=DMA_MemoryDataSize_HalfWord;//数据宽度为16位
DMA_InitStructure.DMA_Mode=DMA_Mode_Circular;//工作在循环缓存模式
DMA_InitStructure.DMA_Priority=DMA_Priority_High;//DMA通道x拥有高优先级
DMA_InitStructure.DMA_M2M=DMA_M2M_Disable;//DMA通道x没有设置为内存到内存传输
DMA_Init(DMA_CHx,&DMA_InitStructure);//根据DMA_InitStruct中指定的参数初始化DMA的通道
}
//开启一次DMA传输
voidDMA_ADC_Enable(DMA_Channel_TypeDef*DMA_CHx)
{
DMA_Cmd(DMA_CHx,DISABLE);//关闭USART1TXDMA1所指示的通道
DMA_Cmd(DMA_CHx,ENABLE);//使能USART1TXDMA1所指示的通道
}
这里需要注意的是USART使用DMA发送数据需要每一次都重新使能,即每发送一次数据使能一下。
而ADC使用DMA传送多通道数据则只需要使能一次就可以自动循环工作,只需从数组空间读取ADC数据。