久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 10041|回復: 29
打印 上一主題 下一主題
收起左側

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

  [復制鏈接]
跳轉到指定樓層
樓主
30黑幣
1、ADC采集出現+-1的偏移量;
例:采集到的數值始終在570  571 572 三個數值中跳變
2、采集目標為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完成標志位
  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結果
  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轉換完成
  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結果
  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數值轉換阻值**********/
  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. /************阻值轉換溫度******************/
  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;                   //設置P1口為AD口
  97.     ADC_RES = 0;                    //清除結果寄存器
  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>請教如何能讓計算得到的溫度變得穩定,或者濾波后的ADC數值穩定。。。</div><div>希望各位大神能幫忙一二

  113. </div>
復制代碼



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

使用道具 舉報

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

使用道具 舉報

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

使用道具 舉報

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

評分

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

查看全部評分

回復

使用道具 舉報

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

評分

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

查看全部評分

回復

使用道具 舉報

6#
ID:159139 發表于 2018-4-4 20:21 來自手機 | 只看該作者
采用查表法,并使用較穩定電源。
回復

使用道具 舉報

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

評分

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

查看全部評分

回復

使用道具 舉報

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

評分

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

查看全部評分

回復

使用道具 舉報

9#
ID:96072 發表于 2018-4-5 13:47 | 只看該作者
網上有詳細的濾波器算法說明,找找下
回復

使用道具 舉報

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

討論的問題并不是溫度是否準確,而是ADC采集的數據出現浮動漂移,謝謝你的回答
回復

使用道具 舉報

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

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

使用道具 舉報

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

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

使用道具 舉報

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

代碼中已經包含濾波算法,并且嘗試了多種濾波算法  均不能保證每次濾波后出現穩定數值
回復

使用道具 舉報

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

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

使用道具 舉報

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

使用道具 舉報

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

使用道具 舉報

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

使用道具 舉報

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

使用道具 舉報

19#
ID:303835 發表于 2018-4-8 17:24 | 只看該作者
求學,跟著各位大佬學習
回復

使用道具 舉報

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

并不是每次都是這樣的,采集三次 可能出現的全都是572  572 572   也可能是573 572 572   
回復

使用道具 舉報

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

使用道具 舉報

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


評分

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

查看全部評分

回復

使用道具 舉報

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


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

#define ADC_POWER 0x80    // ADC電源控制位
#define ADC_FLAG 0x10     // ADC完成標志位
#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結果
----------------------------*/
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轉換完成
  ADC_CONTR &= ~ADC_FLAG;                  // Close ADC
  return ((uint)ADC_RES << 2 | ADC_RESL);  //返回ADC結果
}

/****************濾波*****************/
#define BUFF_LENGTH 18  // 過濾函數數組長度
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);
  }
  // 排序:把最大值移到數組最后,最小值留到數組最前
  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)個數,求平均值
  for (i = 1; i < BUFF_LENGTH - 1; i++) {
    uiSum += uiBuf[i];
  }

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


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

/************阻值轉換溫度******************/
float Get_Temp(uchar chhhh) {
  // float Rt;
  float adcDataTr;  // 溫敏電阻上的分壓的ADC數據
  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;  //設置P1口為AD口
  CLK_DIV &= ~0x20;
  ADC_RES = 0;  //清除結果寄存器
  ADC_RESL = 0;
}

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

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



回復

使用道具 舉報

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

使用道具 舉報

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

使用道具 舉報

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

使用道具 舉報

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

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

使用道具 舉報

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

無標題.jpg (23.54 KB, 下載次數: 132)

無標題.jpg
回復

使用道具 舉報

29#
ID:25310 發表于 2019-11-28 09:12 | 只看該作者
snchj 發表于 2019-11-26 21:23
你硬件改下試試

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

使用道具 舉報

30#
ID:25310 發表于 2019-11-28 09:24 | 只看該作者
最近我也在調試一個AD相關的項目,剛好測試了這段濾波代碼,感覺確實波動很大。用了一個最基本的平均數濾波也比這個效果好。樓主可以試一試。
        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;
        }
       
回復

使用道具 舉報

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

本版積分規則

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

Powered by 單片機教程網

快速回復 返回頂部 返回列表
主站蜘蛛池模板: 精品国产欧美一区二区 | 欧美亚洲视频在线观看 | 粉嫩一区二区三区性色av | 日本免费一区二区三区四区 | 超碰在线久 | 中文字幕在线第一页 | 国产精品免费av | 亚洲国产精品一区二区久久 | 国产精品美女www爽爽爽视频 | 九九九视频 | 国产小视频在线 | 婷婷激情在线 | 欧美又大粗又爽又黄大片视频 | 99久久视频| 在线观看免费福利 | 久久久久一区二区三区四区 | 日韩欧美电影在线 | 欧美日韩大陆 | 粉嫩一区二区三区国产精品 | 国产一区二区三区四区五区加勒比 | 草草草影院 | 亚洲精品在线观 | 亚洲精品一级 | 蜜桃视频一区二区三区 | 国产伦精品一区二区三区照片91 | 亚洲综合一区二区三区 | 日本免费一区二区三区四区 | 久久欧美高清二区三区 | 国产精品99 | 久久久精品视 | 老外黄色一级片 | 嫩草黄色影院 | 日本一区二区三区在线观看 | 在线a视频 | 久久婷婷av | 日韩成人 | 99久久日韩精品免费热麻豆美女 | 久久久青草婷婷精品综合日韩 | 99精品视频一区二区三区 | 欧美精品三区 | 国产精品久久久久久久久久 |