双ADC模式时,使用库函数ADC_SoftwareStartConvCmd(ADC1, ENABLE);导致的问题。
问题来源:使用双ADC转换时,将之前写的外部触发改为软件启动转换后,ADC2采集不准确。
查看ADC_SoftwareStartConvCmd(ADC1, ENABLE);定义处:
void
ADC_SoftwareStartConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState)
{
… …
ADCx->CR2 |= CR2_EXTTRIG_SWSTART_Set;
}
#define CR2_EXTTRIG_SWSTART_Set
((uint32_t)0x00500000) //这里将22位和20位同时置1
参考手册:
SWSTART:开始转换规则通道 (Start
conversion of regular channels) 位22
由软件设置该位以启动转换,转换开始后硬件马上清除此位。如果在EXTSEL[2:0]位中选择了
SWSTART为触发事件,该位用于启动一组规则通道的转换,
0:复位状态;
1:开始转换规则通道。
EXTTRIG:规则通道的外部触发转换模式 (External
trigger conversion mode for regular
channels) 位20
该位由软件设置和清除,用于开启或禁止可以启动规则通道组转换的外部触发事件。
0:不用外部事件启动转换;
1:使用外部事件启动转换。
所以这个库函数同时使能了外部触发和软件触发。
又:
在双ADC模式里,当转换配置成由外部事件触发时,用户必须将其设置成仅触发主
ADC,从ADC设置成软件触发,这样可以防止意外的触发从转换。但是,主和从
ADC的外部触发必须同时被激活。
由于上面莫名其妙的使能了外部触发模式,这样就导致初始化时必须加上:
ADC_ExternalTrigConvCmd(ADC1, ENABLE);//外部触发使能,ADC1可以不加
ADC_ExternalTrigConvCmd(ADC2,
ENABLE);//外部触发使能,ADC2必须使能CR2第20位
这个才能采集到正确的值。去掉就会导致 从ADC 采集不准确。
查看定义:
void
ADC_ExternalTrigConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState)
{
… …
ADCx->CR2 |= CR2_EXTTRIG_Set;
}
#define CR2_EXTTRIG_Set
((uint32_t)0x00100000)//将第20位置1
查看例程寄存器版:
u16
Get_Adc(u8 ch)
{
//设置转换序列
ADC1->SQR3&=0XFFFFFFE0;//规则序列1 通道ch
ADC1->SQR3|=ch;
ADC1->CR2|=1<<22; //启动规则转换通道
while(!(ADC1->SR&1<<1));//等待转换结束
return ADC1->DR; //返回adc值
}
但初始化却使能了外部触发,这里有点疑惑:
ADC1->CR2|=1<<20;
//使用用外部触发(SWSTART)!!! 必须使用一个事件来触发
后来将库里定义的:
#define CR2_EXTTRIG_SWSTART_Set ((uint32_t)0x00500000)
改为
#define CR2_EXTTRIG_SWSTART_Set ((uint32_t)0x00400000)//即去掉CR2第20位外部触发使能:
此时不用加外部触发使能采集就很准确。
//
ADC_ExternalTrigConvCmd(ADC1, ENABLE);//外部触发使能
//
ADC_ExternalTrigConvCmd(ADC2, ENABLE);//外部触发使能
如果需要用到外部触发,前面只要配置
ADC_ExternalTrigConvCmd(ADC1, ENABLE);//外部触发使能
ADC_ExternalTrigConvCmd(ADC2, ENABLE);//外部触发使能
就已经将CR2的第20位置1了。所以这样修改应该不会影响其他。
|