STM32F0 ADC无法配置成12位精度的问题

 在配置STM32F0的时候遇到了个棘手的问题,我本想将STM32F0的PB1引脚设置为ADC输入。PB1外部接了个并联串联了不同阻值的电阻来达到识别按键情况的目的。

这里我使用了12位精度,我按照电阻值算出了理论值,本想通过仿真的方法,读取出实测值的。结果出现了下面的结果。图中是没有按键事件发生时的KEY_value=0x03ff。也就是10位最大值。理论上如果是12位的话那么这里应该是0x0fff,至少也应该是0x0ffe。也就是说精度被错误的设置为了10位。

 

以下是我的ADC初始化程序:

void adc_init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;//定义结构体
	ADC_InitTypeDef ADC_InitStuctrue;
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB,ENABLE);//打开GPIOB的时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);//打开ADC的时钟
	
	//ADC IO配置,此处定义PB1口为ADC端口
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_1;
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AN;//GPIO模拟输入/输出模式
	GPIO_InitStructure.GPIO_OType=GPIO_OType_OD;//开漏
	GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_NOPULL;//无上拉
	GPIO_Init(GPIOB,&GPIO_InitStructure);
	
	//ADC 参数配置
	ADC_DeInit(ADC1);//重置
	ADC_InitStuctrue.ADC_Resolution=ADC_Resolution_12b;//12位精度,为最高精度
	ADC_InitStuctrue.ADC_ContinuousConvMode=DISABLE;//单次ADC
	ADC_InitStuctrue.ADC_ExternalTrigConvEdge=ADC_ExternalTrigConvEdge_None;//ADC外部触发器边缘转换
	ADC_InitStuctrue.ADC_DataAlign=ADC_DataAlign_Right;//数据右对齐
	ADC_InitStuctrue.ADC_ScanDirection=ADC_ScanDirection_Backward;//指定扫描通道的方向
	ADC_Init(ADC1,&ADC_InitStuctrue);
	
	//配置ADC采样的通道和采样周期
	//PA0对应ADC通道0
	//注意,采集的数据是否准确与采样时间有关系
	ADC_ChannelConfig(ADC1,ADC_Channel_9,ADC_SampleTime_239_5Cycles);//采样时间等于239.5个周期,最长
	//如果采集系统内部温度,则通道为16,同时要使能温度传感器
	//ADC_ChannelConfig(ADC1,ADC_Channel_16,ADC_SampleTime_239_5Cycles);
	//ADC_TempSensorCmd(ENABLE);
	
	//校准
	ADC_GetCalibrationFactor(ADC1);
	//使能ADC1
	ADC_Cmd(ADC1,ENABLE);
	//等待ADC准备
	while(ADC_GetFlagStatus(ADC1,ADC_FLAG_ADEN)==RESET);//adc启用标志

}

我找到了CFGR1寄存器中有关精度设置的位RES[1:0]。如图。

CFGR1中的第4位,第5位即是有关精度的位RES[1:0]。
RES[1:0]=00 为 12位;
RES[1:0]=01 为 10位;
RES[1:0]=10 为   8位;
RES[1:0]=11 为  6位;
也就是第4为被错误置位。
接着我找到了ADC_Init()中的如下语句。其中的tmpreg在与ADC_InitStruct这个结构体中的各个元素进行或运算后,将结果赋值给了CFGR1 寄存器。

tmpreg  |= (uint32_t)(ADC_InitStruct->ADC_Resolution | ((uint32_t)(ADC_InitStruct->ADC_ContinuousConvMode) << 13) |
             ADC_InitStruct->ADC_ExternalTrigConvEdge | ADC_InitStruct->ADC_ExternalTrigConv |
             ADC_InitStruct->ADC_DataAlign | ADC_InitStruct->ADC_ScanDirection);

  /* Write to ADCx CFGR */
  ADCx->CFGR1 = tmpreg;

接下来,我找到自己写的有关以上结构体的赋值过程。我一个个对比发现ADC_ExternalTrigConv 这个元素,我没有进行赋值(因为用不到)。而又想到之前C语言课上讲过如果是没有赋过值的变量,编译器是默认将其赋值为0。如果是0的话,那个或运算就不可能造成RES[1:0]被错误置位的情况。我在反复检查后,认定了一定是这个未赋值的变量搞得怪。

//ADC 参数配置
	ADC_DeInit(ADC1);//重置
	ADC_InitStuctrue.ADC_Resolution=ADC_Resolution_12b;//12位精度,为最高精度
	ADC_InitStuctrue.ADC_ContinuousConvMode=DISABLE;//单次ADC
	ADC_InitStuctrue.ADC_ExternalTrigConvEdge=ADC_ExternalTrigConvEdge_None;//ADC外部触发器边缘转换
	ADC_InitStuctrue.ADC_DataAlign=ADC_DataAlign_Right;//数据右对齐
	ADC_InitStuctrue.ADC_ScanDirection=ADC_ScanDirection_Backward;//指定扫描频道的方向按顺序
	ADC_Init(ADC1,&ADC_InitStuctrue);

 于是找到了这个回答:

外部全局的和静态变量,编译器基本都会(但也有时候不会)把变量初始化为0,其余内部变量都不进行初始化,值随机的。 建议:不论外部全局、静态还是内部的变量都要初始化!
真尼玛,气人啊!!!

也就是说一个变量如果你没有进行过赋值,就使用它的值,那么它的值是随机的,也就是碰巧我遇到的是错误配置成10位的情况,也许还可以是8位,6位,而且还可能影响ADC其他的比如:连续转换模式或单一模式设置、ADC外部触发方式设置、数据对齐方式设置、扫描通道的方向设置等设置!


但我在编写的过程中是参考了官方例程的啊!官方的例程 总不能有问题吧。
又回去看了一遍,我发现了个我没有用到的函数

/* Initialize ADC structure */

  ADC_StructInit(&ADC_InitStructure);

初始化ADC结构体???

这里逐个对结构体里的元素进行了赋值。我猜测着写值应该都是0x00000000才对。结果不出所料:

当时在写ADC_init()这个初始化过程我是看了这个地方的,当时觉得这个结构体初始化有什么用,反正后面要对这些变量进行赋值的。
当时还想ST为何要设计这么多的无用的库函数。
谁知道后面给自己挖了坑,尼玛,尼玛。
就是不知道GPIO初始化的那个结构体要不要初始化。为了防止以后再出现这种问题,最保险的方法全部,对全部使用到结构体进行初始化。

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值