对于STM32F103来说,它的ADC是12位,一共18个通道,其中16个外部通道,2个内部通道。支持单次,连续以及间断模式扫描。
12位ADC
指的是STM32F103的ADC分辨率具有12位,位数越高采集到的ADC越精准。12位是相对于二进制数来说,也就是“111111111111”,转换为十进制就是4095,其实是0-4095,实际上是4096个数,STM32F103的引脚电压是0-3.3V,12位的ADC就会把0-3.3V切割成4096份。这样转换器得到的ADC值便可以转换为相应电压,设转换器采集到的ADC值为x,实际所求电压为y。那么公式为:y=x/4096*3.3V。
16个外部通道:
f103的芯片上有16个引脚是接到模拟电压上可以进行电压检测的,这16个通道会分给3个转换器,这三个转换器是独立的,也就是我们常见的ADC1,ADC2,ADC3。引脚和通道的对应关系可通过手册或者芯片引脚定义查询。
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA ,ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_Init(GPIOA, &GPIO_InitStructure);
首先还是走老路,初始化所用的GPIO,此次所用的是PA4和PA5。通过手册可以看到这两个口对应的是ADC1和ADC2,对应通道是通道4和通道5。
ADC_InitTypeDef ADC_InitStructure;
RCC_APB2PeriphClockCmd( RCC_APB2Periph_ADC1 ,ENABLE);
RCC_ADCCLKConfig(RCC_PCLK2_Div6);//12M 最大14M
ADC_DeInit(ADC1); //将外设 ADC1 的全部寄存器重设为缺省值
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_InitStructure.ADC_ScanConvMode = ENABLE; //连续多通道模式
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; //连续转换
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //转换不受外界决定
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //右对齐
ADC_InitStructure.ADC_NbrOfChannel = 2;//扫描通道数
ADC_Init(ADC1, &ADC_InitStructure);
/* ADC1 regular channel10 configuration */
ADC_RegularChannelConfig(ADC1, ADC_Channel_4,1, ADC_SampleTime_71Cycles5);
ADC_RegularChannelConfig(ADC1, ADC_Channel_5,2, ADC_SampleTime_71Cycles5);
/* Enable ADC1 */
ADC_Cmd(ADC1, ENABLE);
ADC_DMACmd(ADC1, ENABLE);
/* Enable ADC1 reset calibaration register */
ADC_ResetCalibration(ADC1); //复位指定的ADC1的校准寄存器
/* Check the end of ADC1 reset calibration register */
while(ADC_GetResetCalibrationStatus(ADC1));//获取ADC1复位校准寄存器的状态,设置状态则等待
/* Start ADC1 calibaration */
ADC_StartCalibration(ADC1); //开始指定ADC1的校准状态
/* Check the end of ADC1 calibration */
while(ADC_GetCalibrationStatus(ADC1)); //获取指定ADC1的校准程序,设置状态则等待
/* Start ADC1 Software Conversion */
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
DMA_Cmd(DMA1_Channel1, ENABLE); //启动DMA通道
参数 ADC_Mode :是用来设置 ADC 的模式 ,ADC的模式很多(如下图),这里选择独立模式:ADC_Mode_Independent
DMA_InitTypeDef DMA_InitStructure;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);//使能DMA时钟
DMA_DeInit(DMA1_Channel1);
DMA_InitStructure.DMA_PeripheralBaseAddr =(u32)&ADC1->DR; //DMA外设ADC基地
DMA_InitStructure.DMA_MemoryBaseAddr =(u32)&ADCConvertedValue;//内存地址
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;//dma传输方向单向
DMA_InitStructure.DMA_BufferSize = 100*2;//设置DMA在传输时缓冲区的长度 word
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//设置DMA的外设递增模式,一个外设
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//设置DMA的内存递增模式,
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;//外设数据字长
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;//内存数据字长
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;//设置DMA的传输模式:连续不断的循环模式
DMA_InitStructure.DMA_Priority = DMA_Priority_High;//设置DMA的优先级别
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;//设置DMA的2个memory中的变量互相访问
DMA_Init(DMA1_Channel1, &DMA_InitStructure);
DMA_Cmd(DMA1_Channel1, ENABLE);
因为我在代码中做了备注,这里踢几个人比较重要的点:
参数DMA_BufferSize :设置DMA在传输时缓冲区的长度 ,这里要提一下我的数据储存数组u16 ADCConvertedValue[100][2];因为采用两个通道,所以需要两个缓冲保存数据,100*2=200,DMA在运行是就会采集200个ADC值保存在数组中,100个通道4的值,100个通道5的值。取值处理会在后面介绍。
此项设置完之后DMA就回不停地采集这两个ADC通道中的ADC值并保存在数组中。我们只需要在需要的时候读取数组中的值便可。
读取ADC值并做处理
int sum;
int sum1=0;
int sum2=0;
int value1[10];
int value2[10];
int isSorted,temp1,temp2,k,p;
float a;
int i,j,c;
float ADC_Value[2];//用来保存经过转换得到的电压值
for(c=0;c<10;c++){
for(i=0;i<2;i++)
{
sum=0;
for(j=0;j<100;j++)
{
sum+=ADCConvertedValue[j][i];
}
ADC_Value[i]=(float)sum*3.3/4096/100;//求平均值并转换成电压值
}
value1[c]=(int)(ADC_Value[0]*100);//4通道电压值扩大100
value2[c]=(int)(ADC_Value[1]*100);//5通道电压值扩大100
}
---------------------
作者:呐咯密密
链接:https://bbs.21ic.com/icview-3070640-1-1.html
来源:21ic.com
此文章已获得原创/原创奖标签,著作权归21ic所有,任何人未经允许禁止转载。