搜索
bottom↓
回复: 21

最近测试STM8L051-adc总是不准经过漫长的设计终于搞了个最准的了

[复制链接]

出0入0汤圆

发表于 2021-2-25 12:38:20 | 显示全部楼层 |阅读模式
这个stm8l的adc 一开始数据总是波动很大,搞了几天自身电压测试波动很大,电池电压很稳,总之各种毛病,看了我无数个帖子实验了无数种最终得到很好的结果,目前还有一个问题就是一开始的数据过大我只能舍弃掉了。看下我设置了20组数据很准。
下面是我的代码,还请大神帮我分析下我第一次测量为啥偏大?

/*******************************************************************************
  * @函数名称        ADC_Config
  * @函数说明   ADC初始化  
  * @输出参数   无
  * @返回参数   无
  * 设计 魏明明   
*******************************************************************************/
static void ADC_Config(void)
{

  CLK_PeripheralClockConfig(CLK_Peripheral_ADC1, ENABLE);
  ADC_VrefintCmd(ENABLE); //使能内部参考电压
  ADC_Init(ADC1,ADC_ConversionMode_Continuous,ADC_Resolution_12Bit, ADC_Prescaler_2);
  ADC_SamplingTimeConfig(ADC1, ADC_Group_SlowChannels, ADC_SamplingTime_24Cycles);
  ADC_SamplingTimeConfig(ADC1, ADC_Group_FastChannels, ADC_SamplingTime_24Cycles);
  ADC_ClearFlag(ADC1,ADC_FLAG_EOC);//清除对应标志
}

static u16 VREF_zishen(void)
{
  static u8 iz;
  static u16  value1[20],fVdd1,res1=0;
  res1=0;   
   ADC_Cmd(ADC1,DISABLE);
   ADC_SamplingTimeConfig(ADC1, ADC_Group_SlowChannels, ADC_SamplingTime_16Cycles);
  ADC_ChannelCmd(ADC1,ADC_Channel_18,DISABLE);//xian guan bi zhiqian tongdaodelay_ms(2);
  ADC_ChannelCmd(ADC1,ADC_Channel_Vrefint,ENABLE);//使能内部参考电压通道 delay_ms(2);
   ADC_Cmd(ADC1,ENABLE);
  delay_ms(1);
   ADC_SoftwareStartConv(ADC1);//delay_ms(1);
   while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC));
   ADC_ClearFlag(ADC1,ADC_FLAG_EOC);//清除对应标志
  for(iz=0; iz<20; iz++)
  {
    ADC_SoftwareStartConv(ADC1);
    while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC));
   ADC_ClearFlag(ADC1,ADC_FLAG_EOC);//清除对应标志
    value1[iz]= ADC_GetConversionValue(ADC1);      
    fVdd1=50135/value1[iz]*10;
    res1=res1+fVdd1;
  }
  res1=res1/20;
  return(res1);
}  

static u16 VREF_dianchi(void)
{
  static u8 i;
  static u16  value2[20],fVdd2,res2=0;
  res2=0;
  
  ADC_Cmd(ADC1,DISABLE);
  ADC_SamplingTimeConfig(ADC1, ADC_Group_SlowChannels, ADC_SamplingTime_16Cycles);
  ADC_ChannelCmd(ADC1,ADC_Channel_Vrefint,DISABLE);//xian guan bi zhiqian tongdao
  ADC_ChannelCmd(ADC1,ADC_Channel_18,ENABLE);
  ADC_Cmd(ADC1,ENABLE);
  delay_ms(2);
  ADC_SoftwareStartConv(ADC1);
  while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC));
  ADC_ClearFlag(ADC1,ADC_FLAG_EOC);//清除对应标志
  for(i=0; i<20; i++)
  {
    ADC_SoftwareStartConv(ADC1);
    while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC));
    ADC_ClearFlag(ADC1,ADC_FLAG_EOC);//清除对应标志
    value2= ADC_GetConversionValue(ADC1);
    fVdd2=6*value2/25;
    res2=res2+fVdd2;
  }
  res2=res2/20;
  return(res2);
}

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

 楼主| 发表于 2021-2-25 12:41:12 | 显示全部楼层
ADC_SamplingTime_16Cycles 这个实验了好几个 对结果不影响  还有分屏也不影响,加了一堆延迟最后发现也不影响。

出0入0汤圆

 楼主| 发表于 2021-2-25 14:07:24 | 显示全部楼层
以下是易犯错,易忽略的地方:

1,、CR_ADON第一次置ON(其位的值为1)是把ADC唤醒,告诉其应该准备工作了,需要再​​一次置ON,其才开始进行数据的转换。

2、请在ADC进入低功耗时才改变其分频值,否则,其可能对时钟产生一个干扰,固读回来的值不准,所以我们在非低功耗的时候切换通道应该忽略第一次转换的值,因为其不准。

3、读取转换值时,应该看其是怎么存储的,右对齐先读低位,左对齐则先读高位。

4、一旦ADC上电开始转换,则所有的I/O口禁止输出。

5、可以用外部条件,或者定时器触发中断。

6、为了避免误触发事件,可以使用RSET指令来设置EXTTIG位,不用改变寄存器的其他值。

7、读回的数据加上0X30则是转换为ASCII码,

8、可以通过清除ADON或者CONT来停止转换。​

出0入4汤圆

发表于 2021-2-25 18:24:55 来自手机 | 显示全部楼层
第四条,不让别的io口干活还有什么意义呀?

出0入20汤圆

发表于 2021-2-25 18:42:38 | 显示全部楼层
难道是传说中的散弹枪式编程?

出0入0汤圆

 楼主| 发表于 2021-2-28 12:04:11 | 显示全部楼层
lzg1987 发表于 2021-2-25 18:24
第四条,不让别的io口干活还有什么意义呀?

这个是我网上搜到的,我觉得可能有用先贴在这里。

出0入0汤圆

 楼主| 发表于 2021-2-28 12:04:28 | 显示全部楼层
Error.Dan 发表于 2021-2-25 18:42
难道是传说中的散弹枪式编程?

哎,没办法能力有限。。。。。。。

出0入0汤圆

发表于 2021-2-28 12:13:50 来自手机 | 显示全部楼层
不让其它io干活,这个严重了

出105入79汤圆

发表于 2021-3-1 02:57:17 | 显示全部楼层
其他io可能过流 , 采集电阻可能过大

出0入0汤圆

发表于 2021-3-1 08:29:58 | 显示全部楼层
对于慢速的应用,其它IO口可以暂时不改变状态,但不让输出恐怕很难做到,总不能因为要采集某模块的输出电流,先把对应的输出口关掉,暂时不改变状态还好做到。但对于快速的应用,这几乎就是不可能的了。

出0入0汤圆

 楼主| 发表于 2021-3-4 09:17:47 | 显示全部楼层
看网上这么说的:ADC通道切换后,第一次采样值是上一个通道的值,如果需要采样当前通道值,就需要继续采样一次。

也就是说STM8S003单片机,在多通道采样时,采样通道小于等于3个以内时,通道切换中采样值不会延迟。当同时采样通道大于3个时,通道切换中采样值会有延迟,需要将第一次采样到的值扔掉,第二次采样的值才可以使用。
————————————————
版权声明:本文为CSDN博主「qq_511386807」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_20222919/article/details/107949250

出0入362汤圆

发表于 2021-3-4 09:30:18 | 显示全部楼层
这货不是有DMA吗, 干嘛不用?

出100入101汤圆

发表于 2021-3-4 09:44:18 来自手机 | 显示全部楼层
Error.Dan 发表于 2021-2-25 18:42
难道是传说中的散弹枪式编程?

啥叫散弹枪式编程?

出0入0汤圆

 楼主| 发表于 2021-3-4 09:57:26 | 显示全部楼层
现在我有个思路就是先用内部基准电压测量供电电压,然后在用这个供电电压测量单片机引脚的电压,这样不就准了吗?
我先试验下看看行不行。

出0入0汤圆

 楼主| 发表于 2021-3-4 18:31:50 | 显示全部楼层
static void adcce(void)
{
  //参考正电压=VDD=1.224/测量内部VREF*4096
  //测量内部温度电压=ADC寄存器/4095×参考正电压=ADC寄存器/测量内部VREF*1.224。
  static u8 ia,ib,ic;
  static u16  value1[20],fVdd1,res1=0,value2[20],res2=0,value3[20],res3=0;
  static u32 fVdd2,fVdd3;
  res1=0; res2=0,res3=0;  
  ADC_Cmd(ADC1,DISABLE);//  ADC_SamplingTimeConfig(ADC1, ADC_Group_SlowChannels, ADC_SamplingTime_24Cycles);
  ADC_ChannelCmd(ADC1,ADC_Channel_TempSensor,DISABLE);
  ADC_ChannelCmd(ADC1,ADC_Channel_18,DISABLE);//xian guan bi zhiqian tongdaodelay_ms(2);
  ADC_ChannelCmd(ADC1,ADC_Channel_Vrefint,ENABLE);//使能内部参考电压通道 delay_ms(2);
  ADC_Cmd(ADC1,ENABLE);
// delay_ms(1);
  ADC_SoftwareStartConv(ADC1);//delay_ms(1);
  while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC));
  ADC_ClearFlag(ADC1,ADC_FLAG_EOC);//清除对应标志
  for(ia=0; ia<20; ia++)
  {
    ADC_SoftwareStartConv(ADC1);
    while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC));   
    value1[ia]= ADC_GetConversionValue(ADC1);
    res1+= value1[ia];   
    ADC_ClearFlag(ADC1,ADC_FLAG_EOC);//清除对应标志
  }
  Vzs=10035200/res1; //Vzs=(1.225*4096/(res1/20))*100
  
  ADC_Cmd(ADC1,DISABLE); // ADC_SamplingTimeConfig(ADC1, ADC_Group_SlowChannels, ADC_SamplingTime_24Cycles);
  ADC_ChannelCmd(ADC1,ADC_Channel_Vrefint,DISABLE);
  ADC_ChannelCmd(ADC1,ADC_Channel_TempSensor,DISABLE);
  ADC_ChannelCmd(ADC1,ADC_Channel_18,ENABLE);
  ADC_Cmd(ADC1,ENABLE);
// delay_ms(2);
  ADC_SoftwareStartConv(ADC1);
  while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC));
  ADC_ClearFlag(ADC1,ADC_FLAG_EOC);//清除对应标志
  for(ib=0; ib<20; ib++)
  {
    ADC_SoftwareStartConv(ADC1);
    while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC));
    value2[ib]= ADC_GetConversionValue(ADC1);
    res2+=value2[ib];
    ADC_ClearFlag(ADC1,ADC_FLAG_EOC);//清除对应标志
  }
    fVdd=(u32)Vzs*res2/27307;//fVdd=(Vzs*(res2/20)/4096)


  



改进了一版

出0入0汤圆

 楼主| 发表于 2021-3-4 18:47:50 | 显示全部楼层
datasheet中写道以下一句话用于解释为什么你的第一次采样不对
The ADC uses the internal reference voltage, so the user must make sure this reference voltage is woken up before enabling the ADC after an exit from Halt or Active-halt mode. 
When enabled, the ADC needs a stabilization time (tWKUP) before starting the first conversion (refer to the device datasheet) Example: after an RTC wakeup (alarm) from Halt mode, 
the ADC is first enabled. Then, the firmware waits for a tWKUP time (3 μs) and the conversion can be started by setting the START bit in the ADC_CR1 register. 
也就是在ref电压稳定后,大概需要等待3us

出0入0汤圆

 楼主| 发表于 2021-3-4 22:57:36 | 显示全部楼层
  * @note   The channels of 1st ADC Group can be channels 0..23  
  * @note   The channels of 2nd ADC Group can be channels 24..27 (depending on the MCU
  *         package density) and Temperature Sensor and Vrefint channels.

出0入0汤圆

 楼主| 发表于 2021-3-5 10:32:59 | 显示全部楼层
不知道大家有没有stm8L很好的多通道adc程序呢?

出0入0汤圆

 楼主| 发表于 2021-3-5 15:30:41 | 显示全部楼层
想用这个单片机测量内部温度传感器但是看到这个
14.3.16 Temperature sensor
The temperature sensor is not available on STM8L05xx value line devices.
The temperature sensor can be used to measure the internal temperature of the device. It is
internally connected to the ADC TS (temperature sensor) input channel that is used to
convert the sensor output voltage into a digital value.
Note: When it is not used, this sensor can be put in power-down mode.
The TSON bit in the ADC_TRIGR1 register must be set to enable the internal ADC TS
channel connection. This connection must be enabled only if the temperature sensor
conversion is required.
The internal temperature sensor can also be used to detect temperature variations. The
output voltage of the temperature sensor is factory measured at high temperature and the
result of the ADC conversion is stored in a specific data address: the
TS_Factory_CONV_V90 byte represents the LSB of the V90 12-bit ADC conversion result
while the MSB have a fixed value: 0x3.
To reduce the temperature sensor error, the user can measure it at ambient temperature
(25°C) to redefine more accurately the average slope (avg_slope) and the offset.


这意思是stm8L不能用内部传感器?

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

 楼主| 发表于 2021-3-5 15:36:21 | 显示全部楼层
折腾了几天的stm8l051内部温度传感器 后来发现竟然没有??????坑爹啊。。

出0入0汤圆

发表于 2021-3-5 16:07:53 | 显示全部楼层
这芯片涨价太严重了,想替换掉呢

出10入210汤圆

发表于 2021-3-5 16:14:47 | 显示全部楼层
weimingshangxia 发表于 2021-2-28 12:04
这个是我网上搜到的,我觉得可能有用先贴在这里。

笔者想表达的意思应该是不让其它IO翻转,以此来减少对ADC模块的干扰。
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-4-19 07:28

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表