找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 10147|回復(fù): 29
打印 上一主題 下一主題
收起左側(cè)

求教STC15F2K60S2 ADC采集問題,辛苦各位群友

  [復(fù)制鏈接]
跳轉(zhuǎn)到指定樓層
樓主
ID:164172 發(fā)表于 2018-4-2 10:36 | 只看該作者 |只看大圖 回帖獎勵 |倒序瀏覽 |閱讀模式
30黑幣
1、ADC采集出現(xiàn)+-1的偏移量;
例:采集到的數(shù)值始終在570  571 572 三個數(shù)值中跳變
2、采集目標(biāo)為NTC溫感電阻
3、原理圖如下


4、ADC采集及濾波代碼如下
  1. <div>#include <adc.h>
  2. #include "math.h"

  3. #define ADC_POWER   0x80            //ADC電源控制位
  4. #define ADC_FLAG    0x10            //ADC完成標(biāo)志位
  5. #define ADC_START   0x08            //ADCADC起始控制位
  6. #define ADC_SPEEDLL 0x00            //540個始終周期
  7. #define FILTER_N 12
  8. const float Rp=10000.0; //10K
  9. const float T2 = (273.15+25.0);//T2
  10. const float Bx = 3950.0;//B
  11. const float Ka = 273.15;
  12. /*----------------------------
  13. 讀取ADC結(jié)果
  14. ----------------------------*/
  15. uint GetADCResult(uchar ch)
  16. {
  17.                 uint b;
  18.                 uint c;
  19.     ADC_CONTR = ADC_POWER | ADC_SPEEDLL | ch | ADC_START;
  20.     _nop_();                        //等待
  21.     _nop_();
  22.     _nop_();
  23.     _nop_();
  24.     while (!(ADC_CONTR & ADC_FLAG));//等待ADC轉(zhuǎn)換完成
  25.     ADC_CONTR &= ~ADC_FLAG;         //Close ADC
  26.                 b = ADC_RES;
  27.                 b = b << 2;
  28.                 c = ADC_RESL;
  29.                 b = b | c ;
  30.                 ADC_RES = 0;
  31.                 ADC_RESL = 0;
  32.     return b;                 //返回ADC結(jié)果
  33. }

  34. /****************濾波*****************/
  35. </div><div>
  36. uint filter(uchar chnn)
  37. {
  38.          uint i,j;
  39.          uint filter_temp, filter_sum = 0;
  40.          uint filter_buf[FILTER_N];
  41.          for(i = 0; i < FILTER_N; i++)
  42.          {
  43.                         filter_buf[i] = GetADCResult(chnn);
  44.                          Delay2(2);
  45.          }
  46.          for(j = 0; j < FILTER_N - 1; j++)
  47.          {
  48.         for(i = 0; i < FILTER_N - 1 - j; i++)
  49.                 {
  50.         

  51.                 if (filter_buf[i] > filter_buf[i + 1])
  52.                         {
  53.                                 filter_temp = filter_buf[i];
  54.                                 filter_buf[i] = filter_buf[i + 1];
  55.                                 filter_buf[i + 1] = filter_temp;
  56.                          }
  57.          }
  58.          }
  59.          
  60.                 for(i = 1; i < FILTER_N - 1; i++)
  61.                                         filter_sum += filter_buf[i];
  62.                 return filter_sum / (FILTER_N - 2);
  63. }
  64. /********AD數(shù)值轉(zhuǎn)換阻值**********/
  65. double AD_R(uchar chn)
  66. {
  67.         double ADR;
  68.         double b;
  69.         double a;
  70.         ADR = filter(chn);
  71.         b = 1023 - ADR;
  72.         a = 10000/b*ADR;
  73.         return a;
  74. }

  75. /************阻值轉(zhuǎn)換溫度******************/
  76. float Get_Temp(uchar chhhh)
  77. {
  78.                 float Rt;
  79.                 float temp;
  80.                 Rt = AD_R(chhhh);
  81.                 //like this R=5000, T2=273.15+25,B=3470, RT=5000*EXP(3470*(1/T1-1/(273.15+25)),  
  82.                 temp = Rt/Rp;  //Rp=10000.0; //10K
  83.                 temp = log(temp);//ln(Rt/Rp)
  84.                 temp/=Bx;//ln(Rt/Rp)/B
  85.                 temp+=(1/T2);
  86.                 temp = 1/(temp);
  87.                 temp-=Ka;
  88.                 temp = temp*10;
  89.                 return temp;
  90. }
  91. /*----------------------------
  92. 初始化ADC
  93. ----------------------------*/
  94. void InitADC()
  95. {
  96.     P1ASF = 0xff;                   //設(shè)置P1口為AD口
  97.     ADC_RES = 0;                    //清除結(jié)果寄存器
  98.     ADC_CONTR = ADC_POWER | ADC_SPEEDLL;
  99.     Delay2(2);                       //ADC上電延時



  100. /*----------------------------
  101. 延時
  102. ----------------------------*/
  103. void Delay2(uint n)
  104. {
  105.     uint x;

  106.     while (n--)
  107.     {
  108.         x = 5000;
  109.         while (x--);
  110.     }
  111. }</div><div>
  112. </div><div>請教如何能讓計算得到的溫度變得穩(wěn)定,或者濾波后的ADC數(shù)值穩(wěn)定。。。</div><div>希望各位大神能幫忙一二

  113. </div>
復(fù)制代碼



分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏 分享淘帖 頂 踩
回復(fù)

使用道具 舉報

沙發(fā)
ID:164172 發(fā)表于 2018-4-2 20:40 | 只看該作者
那位大神來幫幫我啊 怎么一個人都沒有呢   求救啊
回復(fù)

使用道具 舉報

板凳
ID:164172 發(fā)表于 2018-4-4 10:56 | 只看該作者
不是說好了  24小時必答嗎???求指教啊……那位前輩高人上帝老大來幫我一下  卡了好多天了
回復(fù)

使用道具 舉報

地板
ID:251640 發(fā)表于 2018-4-4 13:14 | 只看該作者
電源對其精度影響也比較大,弄個電源基準(zhǔn)再試試.

評分

參與人數(shù) 1黑幣 +3 收起 理由
大米飯 + 3 在我的計算中并沒有考慮到基準(zhǔn)電壓,計算采.

查看全部評分

回復(fù)

使用道具 舉報

5#
ID:213173 發(fā)表于 2018-4-4 15:42 | 只看該作者
NTC熱敏電阻的溫阻曲線是非線性的,用浮點計算的方法誤差很大。一般用廠家提供的溫阻表為基礎(chǔ)制作數(shù)組表格,用ADC轉(zhuǎn)換結(jié)果通過查表法獲取溫度值為佳。

評分

參與人數(shù) 1黑幣 +3 收起 理由
大米飯 + 3 回帖助人的獎勵!

查看全部評分

回復(fù)

使用道具 舉報

6#
ID:159139 發(fā)表于 2018-4-4 20:21 來自手機(jī) | 只看該作者
采用查表法,并使用較穩(wěn)定電源。
回復(fù)

使用道具 舉報

7#
ID:286600 發(fā)表于 2018-4-4 20:53 來自手機(jī) | 只看該作者
AD轉(zhuǎn)換時盡可能不改變單先機(jī)各腳電平,再一個是用基準(zhǔn)電壓也做AD轉(zhuǎn)換,根據(jù)基準(zhǔn)電壓值,兩個轉(zhuǎn)換值,求所測電壓。轉(zhuǎn)換值應(yīng)是多次測量棄最大最小后得的均值。

評分

參與人數(shù) 1黑幣 +3 收起 理由
大米飯 + 3 回帖助人的獎勵!

查看全部評分

回復(fù)

使用道具 舉報

8#
ID:298533 發(fā)表于 2018-4-5 13:18 | 只看該作者
你采集的值要用濾波器算法,這樣的值才穩(wěn)定

評分

參與人數(shù) 1黑幣 +3 收起 理由
大米飯 + 3 回帖助人的獎勵!

查看全部評分

回復(fù)

使用道具 舉報

9#
ID:96072 發(fā)表于 2018-4-5 13:47 | 只看該作者
網(wǎng)上有詳細(xì)的濾波器算法說明,找找下
回復(fù)

使用道具 舉報

10#
ID:164172 發(fā)表于 2018-4-7 10:00 | 只看該作者
wulin 發(fā)表于 2018-4-4 15:42
NTC熱敏電阻的溫阻曲線是非線性的,用浮點計算的方法誤差很大。一般用廠家提供的溫阻表為基礎(chǔ)制作數(shù)組表格 ...

討論的問題并不是溫度是否準(zhǔn)確,而是ADC采集的數(shù)據(jù)出現(xiàn)浮動漂移,謝謝你的回答
回復(fù)

使用道具 舉報

11#
ID:164172 發(fā)表于 2018-4-7 10:02 | 只看該作者
nklug 發(fā)表于 2018-4-4 20:53
AD轉(zhuǎn)換時盡可能不改變單先機(jī)各腳電平,再一個是用基準(zhǔn)電壓也做AD轉(zhuǎn)換,根據(jù)基準(zhǔn)電壓值,兩個轉(zhuǎn)換值,求所測 ...

我的代碼中,包含了軟濾波,主要是ADC采集數(shù)值一直在570   571  572 中來回跳轉(zhuǎn),致使計算得出的溫度一直跳變
回復(fù)

使用道具 舉報

12#
ID:164172 發(fā)表于 2018-4-7 10:04 | 只看該作者
15861476366 發(fā)表于 2018-4-5 13:18
你采集的值要用濾波器算法,這樣的值才穩(wěn)定

有濾波算法,依舊出現(xiàn)溫度跳變,這個不知道怎么樣才能解決,或者有什么更好的濾波算法
回復(fù)

使用道具 舉報

13#
ID:164172 發(fā)表于 2018-4-7 10:04 | 只看該作者
HEIZI555 發(fā)表于 2018-4-5 13:47
網(wǎng)上有詳細(xì)的濾波器算法說明,找找下

代碼中已經(jīng)包含濾波算法,并且嘗試了多種濾波算法  均不能保證每次濾波后出現(xiàn)穩(wěn)定數(shù)值
回復(fù)

使用道具 舉報

14#
ID:213173 發(fā)表于 2018-4-7 21:18 | 只看該作者
大米飯 發(fā)表于 2018-4-7 10:00
討論的問題并不是溫度是否準(zhǔn)確,而是ADC采集的數(shù)據(jù)出現(xiàn)浮動漂移,謝謝你的回答

不管你采用什么方法濾波都不容易得到非常穩(wěn)定的數(shù)值,“采集數(shù)值一直在570   571  572 中來回跳轉(zhuǎn)”說明你得到的數(shù)據(jù)已經(jīng)足夠穩(wěn)定了,只是你對數(shù)據(jù)的后期處理不到位,才致使你感覺不穩(wěn)定。
回復(fù)

使用道具 舉報

15#
ID:303420 發(fā)表于 2018-4-8 03:47 | 只看該作者
可以查表,然后換個算法試試。
回復(fù)

使用道具 舉報

16#
ID:273583 發(fā)表于 2018-4-8 07:14 | 只看該作者
NTC熱敏電阻的溫阻曲線是非線性的,用浮點計算的方法誤差很大。一般用廠家提供的溫阻表為基礎(chǔ)制作數(shù)組表格,用ADC轉(zhuǎn)換結(jié)果通過查表法獲取溫度值為佳。
與7樓意見相同!
回復(fù)

使用道具 舉報

17#
ID:301968 發(fā)表于 2018-4-8 09:35 | 只看該作者
如果數(shù)值在一個范圍內(nèi)穩(wěn)定變化,可以在三個值取平均值,那不就很穩(wěn)定了嗎?
回復(fù)

使用道具 舉報

18#
ID:301968 發(fā)表于 2018-4-8 09:36 | 只看該作者
三個值相加,取平均值使用。
回復(fù)

使用道具 舉報

19#
ID:303835 發(fā)表于 2018-4-8 17:24 | 只看該作者
求學(xué),跟著各位大佬學(xué)習(xí)
回復(fù)

使用道具 舉報

20#
ID:164172 發(fā)表于 2018-4-12 10:47 | 只看該作者
鄧文雄ABC 發(fā)表于 2018-4-8 09:35
如果數(shù)值在一個范圍內(nèi)穩(wěn)定變化,可以在三個值取平均值,那不就很穩(wěn)定了嗎?

并不是每次都是這樣的,采集三次 可能出現(xiàn)的全都是572  572 572   也可能是573 572 572   
回復(fù)

使用道具 舉報

21#
ID:644988 發(fā)表于 2019-11-23 15:25 | 只看該作者
你這個是硬件問題,103P不要串聯(lián)在電阻上,換成106P一邊接地當(dāng)濾波電容,這樣就不會跳了。
回復(fù)

使用道具 舉報

22#
ID:245004 發(fā)表于 2019-11-23 22:50 | 只看該作者
21樓的建議值得參考,雖然不一定是那個原因。電容是對于交流是導(dǎo)通的,你接到VCC起到相反的作用。
建議給Avcc接一個大電解。
前面有個別回答是不對的,這個電路不必苛求供電電壓多精準(zhǔn),或者需要什么基準(zhǔn)電壓,你可以根據(jù)公式推導(dǎo)一下就知道為什么了。
抱歉的是晚上真的沒精力看樓主的程序了,不過記得之前曾這樣做這種平滑電壓:例如,一個數(shù)組有N個變量,每次把最新的和之前的N-1個變量平均,每次淘汰最早的一個,這樣波動會降到最小。改天有精力再學(xué)習(xí)樓主的程序。


評分

參與人數(shù) 1黑幣 +40 收起 理由
admin + 40 回帖助人的獎勵!

查看全部評分

回復(fù)

使用道具 舉報

23#
ID:245004 發(fā)表于 2019-11-24 16:45 | 只看該作者
剛才看了這位朋友的程序,大概過程看明白了,那個溫度函數(shù)沒用過,詳細(xì)原理暫時不了解。對這段程序做了個簡單的修改。
主要是對ADC做了一點修改:因為每次要關(guān)閉ADC,所以下次打開應(yīng)該等待穩(wěn)定延時;
對計算函數(shù)做了一點簡化:因為偏置電阻阻值10K等于Rp,所以抵消了一步計算;
對濾波做了一點修改:因為用左移代替除法能更快一點;
以上修改對結(jié)果估計也沒啥幫助,只是共師兄習(xí)一下。因為沒有條件測試,如有錯誤望網(wǎng)友及時指正。


#include <adc.h>
#include "math.h"

#define ADC_POWER 0x80    // ADC電源控制位
#define ADC_FLAG 0x10     // ADC完成標(biāo)志位
#define ADC_START 0x08    // ADC起始控制位
#define ADC_SPEEDLL 0x00  // 540個時鐘周期
// #define BUFF_LENGTH 12
const float Rp = 10000.0;          // 10K
const float T2 = (273.15 + 25.0);  // T2
const float Bx = 3950.0;           // B
const float Ka = 273.15;
/*----------------------------
讀取ADC結(jié)果
----------------------------*/
uint GetADCResult(uchar ch) {
  ADC_CONTR = ADC_POWER | ADC_SPEEDLL;
  Delay2(2);  // ADC上電延時
  ADC_CONTR = ADC_POWER | ADC_SPEEDLL | ch | ADC_START;
  while (!(ADC_CONTR & ADC_FLAG)) {
  }                                        //等待ADC轉(zhuǎn)換完成
  ADC_CONTR &= ~ADC_FLAG;                  // Close ADC
  return ((uint)ADC_RES << 2 | ADC_RESL);  //返回ADC結(jié)果
}

/****************濾波*****************/
#define BUFF_LENGTH 18  // 過濾函數(shù)數(shù)組長度
uint filter(uchar chnn) {
  uint i;
  uint j;
  uint uiTemp;
  uint uiSum;
  uint uiBuf[BUFF_LENGTH];

  for (i = 0; i < BUFF_LENGTH; i++) {
    uiBuf[i] = GetADCResult(chnn);
    Delay2(2);
  }
  // 排序:把最大值移到數(shù)組最后,最小值留到數(shù)組最前
  for (j = 0; j < BUFF_LENGTH - 1; j++) {
    for (i = 0; i < BUFF_LENGTH - 1 - j; i++) {
      if (uiBuf[i] > uiBuf[i + 1]) {
        uiTemp = uiBuf[i];
        uiBuf[i] = uiBuf[i + 1];
        uiBuf[i + 1] = uiTemp;
      }
    }
  }
  // 取中間(BUFF_LENGTH - 2)個數(shù),求平均值
  for (i = 1; i < BUFF_LENGTH - 1; i++) {
    uiSum += uiBuf[i];
  }

  // uiSum = uiSum / (BUFF_LENGTH - 2);
  uiSum >>= 4;  // uiSum / 16
  return uiSum;
}


/********AD數(shù)值轉(zhuǎn)換阻值**********/
/*double AD_R(uchar chn) {
  double adcDataTR;  // 溫敏電阻上的分壓數(shù)據(jù)
  double adcDataR;   // 偏置電阻上的分壓數(shù)據(jù)
  double rT;         // 溫敏電阻阻值
  adcDataTR = filter(chn);
  adcDataR = 1023 - adcDataTR;
  rT = 10000 / adcDataR * adcDataTR;
  return rT;
}*/

/************阻值轉(zhuǎn)換溫度******************/
float Get_Temp(uchar chhhh) {
  // float Rt;
  float adcDataTr;  // 溫敏電阻上的分壓的ADC數(shù)據(jù)
  float temp;
  // Rt = AD_R(chhhh);
  adcDataTr = filter(chhhh);
  // like this R=5000, T2=273.15+25,B=3470,
  // RT=5000*EXP(3470*(1/T1-1/(273.15+25)),
  // temp = Rt / Rp;
  // = 10000 / adcDataR * adcDataTr / Rp;
  // 因為(Rp=上拉偏置電阻10000)
  // temp = adcDataTr / adcDataR;
  temp = adcDataTr / (1023 - adcDataTr);
  temp = log(temp);  // ln(Rt/Rp)
  temp /= Bx;        // ln(Rt/Rp)/B
  temp += (1 / T2);
  temp = 1 / (temp);
  temp -= Ka;
  temp += 0.5;  // 加0.5誤差矯正
  temp = temp * 10;
  return temp;
}
/*----------------------------
初始化ADC
----------------------------*/
void InitADC(void) {
  P1ASF = 0xff;  //設(shè)置P1口為AD口
  CLK_DIV &= ~0x20;
  ADC_RES = 0;  //清除結(jié)果寄存器
  ADC_RESL = 0;
}

/*----------------------------
延時
----------------------------*/
void Delay2(uint n) {
    uint x;

    while (n--)
    {
        x = 5000;
        while (x--);
    }
}



回復(fù)

使用道具 舉報

24#
ID:25310 發(fā)表于 2019-11-24 20:51 來自手機(jī) | 只看該作者
這是誤差之內(nèi)的數(shù)字可以接受啊,后起處理就行了
回復(fù)

使用道具 舉報

25#
ID:25310 發(fā)表于 2019-11-25 08:09 | 只看該作者
哪個并在上拉電阻上的電容有點詭異,并到NTC上倒可以理解!
回復(fù)

使用道具 舉報

26#
ID:586438 發(fā)表于 2019-11-25 08:16 | 只看該作者
我也遇到這樣的問題  我是用溫度來控制繼電器的打開和關(guān)閉   因為跳變導(dǎo)致繼電器一直嗒嗒嗒
回復(fù)

使用道具 舉報

27#
ID:644988 發(fā)表于 2019-11-25 16:40 | 只看該作者
bh2030693 發(fā)表于 2019-11-23 22:50
21樓的建議值得參考,雖然不一定是那個原因。電容是對于交流是導(dǎo)通的,你接到VCC起到相反的作用。
建議給A ...

其實我司在做項目時都是這樣做,一般做鋰電池電量檢測開關(guān)保護(hù)都是在單片機(jī)采樣腳前(盡量離IC腳要近)串個1K再用一個106P濾波,效果很好。如果要實時顯示,做個一表或取個平均值就行。一個項目要軟硬結(jié)合才是最好解決方法。
回復(fù)

使用道具 舉報

28#
ID:262356 發(fā)表于 2019-11-26 21:23 | 只看該作者
你硬件改下試試

無標(biāo)題.jpg (23.54 KB, 下載次數(shù): 132)

無標(biāo)題.jpg
回復(fù)

使用道具 舉報

29#
ID:25310 發(fā)表于 2019-11-28 09:12 | 只看該作者

這個硬件同我的想法一樣,我的AD也用了47uF,對反應(yīng)不用太快的檢測大電容確實有效。
回復(fù)

使用道具 舉報

30#
ID:25310 發(fā)表于 2019-11-28 09:24 | 只看該作者
最近我也在調(diào)試一個AD相關(guān)的項目,剛好測試了這段濾波代碼,感覺確實波動很大。用了一個最基本的平均數(shù)濾波也比這個效果好。樓主可以試一試。
        u16 Get_Adc_Average(u8 ch,u8 times)
        {
         u32 temp_val=0;
          
         u8 t;
               
        for(t=0;t<times;t++)
        {         
        temp_val+= Get_ADC10bitResult(ch);
               
        delay_us(10);
        }
        return temp_val/times;
        }
       
回復(fù)

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規(guī)則

手機(jī)版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機(jī)教程網(wǎng)

快速回復(fù) 返回頂部 返回列表