#include "dma.h"
#include "stdio.h"
#if (ADC_DMA_USE_BUFF==1)
uint16_t ADC_DMA_Buff[10]; //用来作为DMA的目标地址 待采集通道的整数倍
#elif (ADC_DMA_USE_BUFF==0)
uint16_t ADC_DMA_Date=0;
#endif
/*
DMA 直接内存访问(Direct Memory Access)
DMA是的独立的功能,分为DMA1和DMA2
DMA可以和ADC UART SPI IIC等外设一块使用
我们采样: ADC+DMA的使用
配置ADC:
结构体:GPIO ADC
实现光照:PA5 ADC12_IN5 -- 硬件原理图决定
实现烟雾:PC1 ADC123_IN11
配置DMA:
结构体:DMA
使用ADC1采集,ADC1的通道在DMA1上,所以DMA1和ADC1一块使用 -- 参考手册 中文表59决定
源地址: ADC_DR ADC外设里面的寄存器
目标地址:ADC_DMA_Buff 内存的地址里面
*/
void ADC_DMA_Config(void)
{
//1.开GPIOA时钟
//void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState); stm3210x_rcc.h 693行
//void RCC_APB1PeriphClockCmd(uint32_t RCC_APB1Periph, FunctionalState NewState);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOC,ENABLE);
//2.定义结构体
//void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct); stm32f10x_gpio.h 351行
GPIO_InitTypeDef GPIO_InitStruct={0};
//3.给结构体赋值
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AIN;//工作模式 模拟输入 (1)看官方例程 (2)参考手册8.1.11
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_5; //引脚
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; //工作速度
//4.调用XXX_init函数,将参数写入到寄存器中
GPIO_Init(GPIOA,&GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_1; //引脚
GPIO_Init(GPIOC,&GPIO_InitStruct);
//5.开ADC1的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
//6.对ADC分频 参考手册11.1中 描述时钟不能操作14M ADC1挂载在APB2上,时钟为72M,进行6分频 变成12M<14M
//void RCC_ADCCLKConfig(uint32_t RCC_PCLK2); stm32f10x_rcc.h 680行
RCC_ADCCLKConfig(RCC_PCLK2_Div6);
//7.定义结构体 xxx_init
//void ADC_Init(ADC_TypeDef* ADCx, ADC_InitTypeDef* ADC_InitStruct); stm32f10x_adc.h 429行
ADC_InitTypeDef ADC_InitStruct={0};
//8.对结构体赋值
ADC_InitStruct.ADC_ContinuousConvMode = ENABLE; //连续转换 给1次命令,之后自动转换 ADC_SoftwareStartConvCmd(ADC1,ENABLE);
ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right; //数据靠右对齐 16位的DR寄存器 12位的分辨率 转换结果最多12位,靠右对齐方便读取数据
ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //不外部触发 通过软件触发转换
ADC_InitStruct.ADC_Mode = ADC_Mode_Independent; //独立模式 ADC1和ADC2独立工作
ADC_InitStruct.ADC_NbrOfChannel = 2; //待转换的通道数量 -- 更改
ADC_InitStruct.ADC_ScanConvMode = ENABLE; //1个通道也可以配置扫描
//9.调用xxx_init函数将参数写入到寄存器中
ADC_Init(ADC1,&ADC_InitStruct);
//10.开DMA1的时钟
//void RCC_AHBPeriphClockCmd(uint32_t RCC_AHBPeriph, FunctionalState NewState); stm32f10x_rcc.h 692行
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);
//11.定义DMA相关的结构体
//void DMA_Init(DMA_Channel_TypeDef* DMAy_Channelx, DMA_InitTypeDef* DMA_InitStruct); stm32f10x_dma.h 411行
DMA_InitTypeDef DMA_InitStruct={0};
//12.给结构体赋值
#if (ADC_DMA_USE_BUFF==1)
DMA_InitStruct.DMA_BufferSize = sizeof(ADC_DMA_Buff)/sizeof(ADC_DMA_Buff[0]); //能够存放的转换后数据的数量
DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t)ADC_DMA_Buff; //内存的基地址
DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable; //内存递增 目标地址有10个存储空间
#elif (ADC_DMA_USE_BUFF==0)
DMA_InitStruct.DMA_BufferSize = 1; //能够存放的转换后数据的数量
DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t)&ADC_DMA_Date; //内存的基地址
DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Disable; //内存递增
#endif
DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralSRC; //外设ADC作为数据的来源
DMA_InitStruct.DMA_M2M = DMA_M2M_Disable; //使用外设ADC-->内存 不使用内存到内存
DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;//数据宽度为半字 ADC1转换结果存放在ADC_DR低16位
DMA_InitStruct.DMA_Mode = DMA_Mode_Circular; //循环模式 目标地址占用完之后,会重头覆盖
/*
ADC1 0x40012400 -- 0x00127FF 数据手册存储器映像
ADC_DR 相对于外设起始地址偏移 0x4C 参考手册 11.12.14的偏移地址
ADC1_DR 0x40012400+0x4C
*/
DMA_InitStruct.DMA_PeripheralBaseAddr = 0x4001244C; //ADC1_DR寄存器的地址
DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; //外设数据宽度
DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设地址寄存器不累加 每次ADC转换的结果都存放在ADC1_DR 会覆盖
DMA_InitStruct.DMA_Priority = DMA_Priority_High; //DMA通道的优先级
//12.调用xxx_init函数将参数写入到寄存器中
DMA_Init(DMA1_Channel1,&DMA_InitStruct); //参考手册 10.3.7 DMA的通道 ADC1接在DMA1的通道1
//13.开ADC1的DMA功能
//void ADC_DMACmd(ADC_TypeDef* ADCx, FunctionalState NewState); stm32f10x_adc.h 432行
ADC_DMACmd(ADC1,ENABLE);
//14.配置ADC规则通道
//参数1 使用哪个ADC转换 ADC1 ADC2 ADC3
//参数2 转换哪个通道 PA5 ADC12_IN5
//参数3 规则组采样顺序 -- ADC_SQR
//参数4 ADC 通道的采样时间值 周期越大:时间越长,准确率越高
//参考手册 11.6 TCONV = 采样时间+ 12.5个周期
//TCONV = 采样时间+ 12.5个周期=55+12.5=67.5周期
//分频之后 ADC1的频率位12M 周期t=1/12000000S
//转换完成需要的时间 T =67.5周期*t=(67.5/12000000)s -- 更改
ADC_RegularChannelConfig(ADC1, ADC_Channel_5, 1, ADC_SampleTime_55Cycles5); //stm32f10x_adc.h 440行
ADC_RegularChannelConfig(ADC1, ADC_Channel_11, 2, ADC_SampleTime_55Cycles5); //stm32f10x_adc.h 440行
//15.使能ADC stm32f10x_adc.h 431行
ADC_Cmd(ADC1, ENABLE);
//16.使能DMA1
//void DMA_Cmd(DMA_Channel_TypeDef* DMAy_Channelx, FunctionalState NewState); //stm32f10x_adc.h 413行
DMA_Cmd(DMA1_Channel1,ENABLE);
//参考手册 11.4中 描述 开机必须校准1次
//17.重置指定的 ADC 的校准寄存器 参考手册11.12.3 位3 stm32f10x_adc.h 434行
ADC_ResetCalibration(ADC1);
//18.等待校准寄存器初始化 参考手册11.12.3 位3 stm32f10x_adc.h 435行
while(ADC_GetResetCalibrationStatus(ADC1));
//19.启动校准 参考手册11.12.3 位2 stm32f10x_adc.h 435行
ADC_StartCalibration(ADC1);
//20.等待校准结束 参考手册11.12.3 位2 stm32f10x_adc.h 436行
while(ADC_GetCalibrationStatus(ADC1));
//21.启动转换
// void ADC_SoftwareStartConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState); //stm32f10x_adc.h 438行
ADC_SoftwareStartConvCmd(ADC1,ENABLE);
}
uint16_t Senor_DMA_Light=0; //存放光照值
uint16_t Senor_DMA_Smoke=0; //存放烟雾值oo
//平均值滤波
void ADC_DMA_Get_Date(void)
{
uint64_t temp_date=0;
temp_date=ADC_DMA_Buff[0]+ADC_DMA_Buff[2]+ADC_DMA_Buff[4]+ADC_DMA_Buff[6]+ADC_DMA_Buff[8];
Senor_DMA_Light=temp_date/5; //获取光照平均值
temp_date=ADC_DMA_Buff[1]+ADC_DMA_Buff[3]+ADC_DMA_Buff[5]+ADC_DMA_Buff[7]+ADC_DMA_Buff[9];
Senor_DMA_Smoke=temp_date/5; //获取烟雾平均值
printf("光照采样值:%d\r\n",Senor_DMA_Light);
printf("光照的电压:%.2f\r\n",Senor_DMA_Light*3.3/4096); //2^12为4096 参考电压/2^分辨率=采样口电压/采样值
printf("烟雾采样值:%d\r\n",Senor_DMA_Smoke);
printf("烟雾的电压:%.2f\r\n",Senor_DMA_Smoke*3.3/4096); //2^12为4096 参考电压/2^分辨率=采样口电压/采样值
}
STM32----ADC+DMA+双通道
最新推荐文章于 2024-08-15 03:34:08 发布