在上一次的博客中重新学习了DMA(附上链接:点击打开链接),这次我们便学以致用了,ADC的概念想必大家都是十分清楚了,模拟转数字,可以用在测信号,测电压,在我们的生活中有着十分巨大的作用,这次我们就来看看ADC又有哪些操作吧!
ADC流程,首先ADC采集一个信号(信号范围大都为0-3.3V,ps:3.3V可通过更改Vref寄存器修改),每隔相同时间菜一次数值发送到一个可变16位数中,下面是我们的数组定义:
__IO uint16_t ADC_ConvertedValue; //定义该16位数用来传输数据,原因是我们使用的12位AD,由于寄存器的定义方便,因此使用16位数
下面是ADC的初始化和配置代码:
void ADC1_Init(void)
{
ADC1_GPIO_Config(); //下面有详细的代码配置
ADC1_Mode_Config();
}
static void ADC1_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure; //定义写入寄存器的结构体
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); //使能时钟,注意使能的是DMA1
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOC, ENABLE); //本实验使用的是GPIOC1,使能ADC1,GPIO时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; //配置为PC.1
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //设置为模拟输入
GPIO_Init(GPIOC, &GPIO_InitStructure); // 初始化写入寄存器中
}
static void ADC1_Mode_Config(void)
{
DMA_InitTypeDef DMA_InitStructure; //定义写入DMA寄存器的结构体
ADC_InitTypeDef ADC_InitStructure; //定义写入ADC寄存器的结构体
DMA_DeInit(DMA1_Channel1); //复位初始化,配置为复位模式,下面我们再重新配置(不知道有用没)
DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address; //设置源地址
DMA_InitStructure.DMA_MemoryBaseAddr = (u32)&ADC_ConvertedValue; //设置内存地址
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; // 设置传输方向
DMA_InitStructure.DMA_BufferSize = 1; //因为我们最后一直改变一个变量,所以只有一位
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设地址固定
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable; //内存地址固定
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; //外设传输数据大小为半字
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; //内存传输数据大小为半字
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; //循环模式
DMA_InitStructure.DMA_Priority = DMA_Priority_High; //高优先级
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //禁止内存间传输数据
DMA_Init(DMA1_Channel1, &DMA_InitStructure); //将结构体写入寄存器中
DMA_Cmd(DMA1_Channel1, ENABLE); //使能DMA寄存器的1通道
/* ADC1 configuration */
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //因为只有一个通道,所以为独立ADC模式
ADC_InitStructure.ADC_ScanConvMode = DISABLE ; //一个通道,所以不使能扫描模式
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; //开启连续转换,就是不停转换
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //不使用外部触发,外部触发只有几个固定引脚,详情看手册
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //我们定义16位数,采集12位,所以要定义对齐方向,在这我们采取右对齐
ADC_InitStructure.ADC_NbrOfChannel = 1; //要转换的通道数目
ADC_Init(ADC1, &ADC_InitStructure); 将结构体写入寄存器中
RCC_ADCCLKConfig(RCC_PCLK2_Div8); //72M时钟8分频为9M PS:ADC最大时钟速率为14M,后面解释
ADC_RegularChannelConfig(ADC1, ADC_Channel_11, 1, ADC_SampleTime_55Cycles5); //初始化,采样时间为55.5us,采样序号是1,PS:采样时间最 // 为1.5us,转换时间为固定12.5us,所以相当于采集完一次数为14us
ADC_DMACmd(ADC1, ENABLE); // 使能DMA1
ADC_Cmd(ADC1, ENABLE); //使能ADC1
ADC_ResetCalibration(ADC1); //复位校准寄存器
while(ADC_GetResetCalibrationStatus(ADC1)); //等待复位校准寄存器完成
ADC_StartCalibration(ADC1); //ADC校准
while(ADC_GetCalibrationStatus(ADC1)); //等待校准完成
ADC_SoftwareStartConvCmd(ADC1, ENABLE); //使能ADC1的软件触发
}
以上就是我们用到的ADC的配置代码,若要读出ADC的数值,只需要调用我们的输出寄存器值就可完成,下面有个小例子,结合之前的串口通信代码,可将采集到的AD数值发送到电脑串口调试助手上
while (1)
{
ADC_ConvertedValueLocal =(float) ADC_ConvertedValue/4096*3.3; // 转化 PS:将0-3.3分成4096份,ADC读出的是多少份,所以以这 //样计算
printf("\r\n The current AD value = 0x%04X \r\n", ADC_ConvertedValue);
printf("\r\n The current AD value = %f V \r\n",ADC_ConvertedValueLocal); //打印,USART代码 链接:点击打开链接
Delay(0xffffee); //延时
}
以上,有问题或有建议的同学可在下面评论或者私信我,我都会看的哈哈!