標(biāo)題: 單片機(jī)芯片讀取ADC的值,數(shù)值在抖動,怎么辦? [打印本頁]

作者: c8t6    時間: 2024-3-4 16:38
標(biāo)題: 單片機(jī)芯片讀取ADC的值,數(shù)值在抖動,怎么辦?
各位大佬。我現(xiàn)在遇到了個問題。我現(xiàn)在使用的是STM32G030單片機(jī)芯片。我需要讀取一個引腳的ADC數(shù)值。我的期望是他可以比較穩(wěn)定的在一個數(shù)值,波動范圍小一點(diǎn)。現(xiàn)在結(jié)果發(fā)現(xiàn)數(shù)波動較。目前我使用了過濾采集的數(shù)值。即連續(xù)讀取10個數(shù),去2個最大2個最小,取剩下的平均值?墒沁是不行。在暫時不改電路的基礎(chǔ)上(即在采集ADC的線路加電阻電容過濾.),各位大佬教教我!

作者: 明日之星8    時間: 2024-3-4 19:33
單片機(jī)的adc,都說是12位,其實能保證有效的精度只有8位,
好一點(diǎn)的能有10位有效精度,能到11位或以上精度的單片機(jī)非
常少。本來就是附加的功能,你的期望值不能太高。
你可以選擇帶16bit-adc功能的單片機(jī)呀,或者外加專門的adc芯
片。

作者: fishafish    時間: 2024-3-4 20:16
取樣等待時間太短的原因吧
作者: Hephaestus    時間: 2024-3-4 20:29
那就多讀幾個數(shù),直到滿意為止。
作者: Y_G_G    時間: 2024-3-4 21:01
ADC引腳有個104的電容就行了,加太大電容影響"真實"數(shù)據(jù)
ADC的結(jié)果一定是抖動的,像萬用表這種也是加了濾波的
在單片機(jī)上,平均值濾波是最常用的,它基本能解決大多數(shù)的應(yīng)用
至少平均130次,然后再去掉最大和最小,數(shù)據(jù)位移一下,相對會好很多
10次就太少了
作者: 累不死的狗    時間: 2024-3-5 09:09
增加讀取時間,看看波動大不大,如果大的話考慮來個電容濾波
作者: aidianzi    時間: 2024-3-5 11:28
沒有電路不好判斷。1、檢查電源是否穩(wěn)定是否有雜波,用示波器看看,G030的基準(zhǔn)就是電源電源不穩(wěn)定測量值自然會跳;2、檢查是否切換通道,切換通道時候要預(yù)留足夠的采樣時間;3、檢查前端電路是否穩(wěn)定是否有噪聲源;4、檢查測量信號
作者: lidawei1    時間: 2024-3-5 13:37
所謂波動大不知大到什么程度?g030的adc還是可以的,這是間隔0.1秒轉(zhuǎn)換一次7號堿性電池的結(jié)果,可以參考下( 64Mhz,adc分頻=2,采樣時間=1.5,Vref直連Vdd)
1959
1958
1958
1959
1958
1958
1959
1959
1959
1958
1959
1958
1959
1960
1958
1959
1959
1958
1958
1958
1958
1959
1958

作者: c8t6    時間: 2024-3-5 14:16
Y_G_G 發(fā)表于 2024-3-4 21:01
ADC引腳有個104的電容就行了,加太大電容影響"真實"數(shù)據(jù)
ADC的結(jié)果一定是抖動的,像萬用表這種也是加了濾波 ...

很遺憾,均值濾波這個方法,我測試了一下沒有區(qū)別,還是一樣的波動
作者: c8t6    時間: 2024-3-5 14:23
aidianzi 發(fā)表于 2024-3-5 11:28
沒有電路不好判斷。1、檢查電源是否穩(wěn)定是否有雜波,用示波器看看,G030的基準(zhǔn)就是電源電源不穩(wěn)定測量值自 ...

1,電源的話,已經(jīng)使用濾波器測過了,很平穩(wěn)。
2,這個芯片使用一個ADC,我采用的是連續(xù)轉(zhuǎn)換,當(dāng)一個通道裝換結(jié)束了,自動切換到下一個通道轉(zhuǎn)換。
3,噪音的話,有一個風(fēng)扇,不過確實有一定的聲音,但是我讀取電源到芯片的卻很穩(wěn)定。
4,目前就是測量信號很不穩(wěn)定,

作者: eddy123    時間: 2024-3-5 15:40
多次采樣然后取平均試試看
作者: ly5117    時間: 2024-3-5 15:55
增加一級跟隨器,減少采樣對電壓的影響
作者: Y_G_G    時間: 2024-3-5 16:20
c8t6 發(fā)表于 2024-3-5 14:16
很遺憾,均值濾波這個方法,我測試了一下沒有區(qū)別,還是一樣的波動



static u32 adc_sum = 0;
u16 adc_avg = 0;
adc_sum +=ADC的數(shù)字量;
adc_avg = adc_sum >> 5;
adc_sum -= adc_avg;
更改右移位數(shù),就等于更改平均了,相對是比較平穩(wěn)
但這好處也只是相對的,平均次數(shù)越多,反應(yīng)也是越慢

作者: jun8929498    時間: 2024-3-5 18:40
取多組數(shù)值求平均值
作者: a399288395    時間: 2024-3-5 20:16
RC濾波不能; 固定的一個穩(wěn)定值是不可能的, 內(nèi)部也是通過電容充放電逐次逼近式采集; 多采集幾次,再取平均算法 ,程序上采集速度越慢越穩(wěn)。
作者: fishafish    時間: 2024-3-5 20:35
模擬電壓本來就是量子化的,沒有波動才不對
作者: c8t6    時間: 2024-3-6 11:06
fishafish 發(fā)表于 2024-3-5 20:35
模擬電壓本來就是量子化的,沒有波動才不對

我了解,在理論上是無限趨向于穩(wěn)定,有波動我也可以接受,但是他波動在忽高忽低的,而且偏差在+-20mv這我就有點(diǎn)難受了

作者: c8t6    時間: 2024-3-6 11:08
lidawei1 發(fā)表于 2024-3-5 13:37
所謂波動大不知大到什么程度?g030的adc還是可以的,這是間隔0.1秒轉(zhuǎn)換一次7號堿性電池的結(jié)果,可以參考下 ...

我的波動大約是在20mv上下偏移
1562
1542
1572
1564
1555,這些之類的波動
作者: c8t6    時間: 2024-3-6 11:09
eddy123 發(fā)表于 2024-3-5 15:40
多次采樣然后取平均試試看

目前就是這么測試的,還是有一些峰值的波動出現(xiàn),不過還沒有在期望之內(nèi)
作者: c8t6    時間: 2024-3-6 11:17
Y_G_G 發(fā)表于 2024-3-5 16:20
static u32 adc_sum = 0;
u16 adc_avg = 0;
adc_sum +=ADC的數(shù)字量;

有點(diǎn)不太了解這個原理
作者: Y_G_G    時間: 2024-3-6 12:50
c8t6 發(fā)表于 2024-3-6 11:17
有點(diǎn)不太了解這個原理

adc_sum +=ADC的數(shù)字量;//每次運(yùn)算都是把ADC的數(shù)字量累加
adc_avg = adc_sum >> 5;//位移就是除法運(yùn)算了,位移3位就是除以8,得到平均值
adc_sum -= adc_avg;//累加的這個變量每次都減去平均值,這樣做是不會溢出,每次運(yùn)算都有前面的數(shù)據(jù)參與
adc_avg 這個是最終的值
這個算法比先累加8次,再除以8,然后把累加變量清除,代碼更簡單,顯示更平


作者: lidawei1    時間: 2024-3-6 13:35
c8t6 發(fā)表于 2024-3-6 11:08
我的波動大約是在20mv上下偏移
1562
1542

波動這么大肯定不能靠濾波的方法解決,可以先檢查一下電路是否有干擾,看看電源有沒有問題,輸入的線盡量短,或者先短路輸入看看波動多少。
作者: 13696229579    時間: 2024-3-6 15:23
很可能就原始信號的噪聲吧。
作者: c8t6    時間: 2024-3-6 16:44
Y_G_G 發(fā)表于 2024-3-6 12:50
adc_sum +=ADC的數(shù)字量;//每次運(yùn)算都是把ADC的數(shù)字量累加
adc_avg = adc_sum >> 5;//位移就是除法運(yùn)算了 ...

不用把他們先排序,然后在去最大最小值,然后除于個數(shù)么?
作者: c8t6    時間: 2024-3-6 16:45
Y_G_G 發(fā)表于 2024-3-6 12:50
adc_sum +=ADC的數(shù)字量;//每次運(yùn)算都是把ADC的數(shù)字量累加
adc_avg = adc_sum >> 5;//位移就是除法運(yùn)算了 ...
  1. NUM_SAMPLES = 10;
  2. while (1)
  3.     {
  4.                         
  5.                 uint32_t adc_values1[NUM_SAMPLES]={0};
  6.                 uint32_t adc_values2[NUM_SAMPLES]={0};
  7.                 uint32_t sum1 = 0;
  8.                 uint32_t sum2 = 0;

  9.                 uint32_t ADC_num7 = 0;
  10.                 uint32_t ADC_num0 = 0;
  11.                
  12.                  // 采集十次ADC1和ADC2的值
  13.                 for (int i = 0; i < NUM_SAMPLES; i++)
  14.                 {
  15.                         uint32_t A0;
  16.                         uint32_t A7;

  17.                         // 采集ADC1的值
  18.                         HAL_ADC_Start(&hadc1);
  19.                         while (HAL_ADC_PollForConversion(&hadc1, 100) != HAL_OK);
  20.                         A0 = HAL_ADC_GetValue(&hadc1);    //調(diào)整
  21.                         adc_values1[i] = (A0*3000)/4096;
  22.                         
  23.                         
  24.                         // 采集ADC2的值
  25.                         HAL_ADC_Start(&hadc1);
  26.                         while (HAL_ADC_PollForConversion(&hadc1, 100) != HAL_OK);
  27.                         A7 = HAL_ADC_GetValue(&hadc1);                        //采集
  28.                         adc_values2[i] = (A7*3000)/4096;
  29.                         
  30.                 }
  31.                
  32.                
  33.                
  34.                 bubble_sort(adc_values1,NUM_SAMPLES);
  35.                 bubble_sort(adc_values2,NUM_SAMPLES);
  36.                
  37.                 // 去掉ADC1數(shù)組中的最大值和最小值
  38.                 for (int i = 3; i < NUM_SAMPLES - 4; i++) {
  39.                         sum1 += adc_values1[i];
  40.                 }

  41.                 // 去掉ADC2數(shù)組中的最大值和最小值
  42.                 for (int i = 3; i < NUM_SAMPLES - 4; i++) {
  43.                         sum2 += adc_values2[i];
  44.                 }
  45.                
  46.                 // 計算打印平均值
  47.                 ADC_num0 = sum1 /4;
  48.                 ADC_num7 = sum2 /4;
  49.                
  50.                
  51.                 printf("\n電位器數(shù)值:%d \r\n",ADC_num0);
  52.                 printf("ADC采集數(shù)值:%d \r\n",ADC_num7);
  53.                 }
復(fù)制代碼
這是我目前的算法
作者: lidawei1    時間: 2024-3-6 18:23
c8t6 發(fā)表于 2024-3-6 16:45
這是我目前的算法

真要濾波的話設(shè)置256過采樣、右移位數(shù)8就行了,直接硬件256個數(shù)取平均,不需要什么算法。
不過覺得應(yīng)該查查是哪里出現(xiàn)的波動,短路輸入看看。
下面是輸入短路后的情況,沒有濾波,沒有過采樣。
0
1
1
1
2
0
1
1
1
0
0
0
0
0
1
0
0
0
0
0
0
0
1

作者: fishafish    時間: 2024-3-6 21:06
明顯分壓電阻太大?一般2k不會
作者: Y_G_G    時間: 2024-3-6 23:21
c8t6 發(fā)表于 2024-3-6 16:44
不用把他們先排序,然后在去最大最小值,然后除于個數(shù)么?

電路沒有很大的干擾,就不需要
我這個基本只用于電源電壓和溫度之類的ADC,之前也有過去掉兩頭的數(shù)值,但實際上沒啥區(qū)別,為了代碼簡單,就不用去最大和最小了
作者: TTQ001    時間: 2024-3-7 08:35
請先檢查參考電壓,確保電壓源穩(wěn)定且無噪聲。
作者: yaofuming    時間: 2024-3-7 09:59
ADC來的數(shù)據(jù)變化太快,你可以用定時器每隔一段時間如100ms讀取一次數(shù)據(jù),然后再處理。
作者: kk17328    時間: 2024-3-7 10:36
增加硬件濾波或者軟件濾波,但是要考慮實施性

作者: c8t6    時間: 2024-3-7 13:56
lidawei1 發(fā)表于 2024-3-6 18:23
真要濾波的話設(shè)置256過采樣、右移位數(shù)8就行了,直接硬件256個數(shù)取平均,不需要什么算法。
不過覺得應(yīng)該 ...

我這個運(yùn)行步驟是
1;風(fēng)扇啟動把高壓離子吹出來。進(jìn)過鋼網(wǎng);
2;鋼網(wǎng)采集離子,經(jīng)過放大電路放大得到電壓;
3;把得到的電壓進(jìn)行ADC轉(zhuǎn)化;
4:通過ADC判斷是否在范圍,不在范圍則改變PWM;
5:PWM改變高壓的電壓,從而也影響到鋼網(wǎng)采集的離子:

作者: c8t6    時間: 2024-3-7 13:58
kk17328 發(fā)表于 2024-3-7 10:36
增加硬件濾波或者軟件濾波,但是要考慮實施性

后續(xù)的升級是需要的,F(xiàn)在第一版本,只要確保在范圍內(nèi)即可。大約是上下浮動10mv左右
作者: c8t6    時間: 2024-3-7 13:59
Y_G_G 發(fā)表于 2024-3-6 23:21
電路沒有很大的干擾,就不需要
我這個基本只用于電源電壓和溫度之類的ADC,之前也有過去掉兩頭的數(shù)值,但實 ...

我這個的話,我使用示波器查看查看了曲線,會有一小段的起伏不定的峰值
作者: c8t6    時間: 2024-3-7 14:01
yaofuming 發(fā)表于 2024-3-7 09:59
ADC來的數(shù)據(jù)變化太快,你可以用定時器每隔一段時間如100ms讀取一次數(shù)據(jù),然后再處理。

嘗試過了。我給了固定不變的值;讀取的是比較穩(wěn)定。但是在代碼中去調(diào)節(jié)的話,就會有波動
作者: Y_G_G    時間: 2024-3-7 16:57
c8t6 發(fā)表于 2024-3-7 13:56
我這個運(yùn)行步驟是
1;風(fēng)扇啟動把高壓離子吹出來。進(jìn)過鋼網(wǎng);
2;鋼網(wǎng)采集離子,經(jīng)過放大電路放大得到電 ...

感覺這東西就跟采集空氣中的PM2.5一樣,所采集到的數(shù)據(jù)是做不到非常穩(wěn)定的值的,它本身就不是穩(wěn)定的值
你可以嘗試256次平均值看一下效果
作者: c8t6    時間: 2024-3-8 08:22
Y_G_G 發(fā)表于 2024-3-7 16:57
感覺這東西就跟采集空氣中的PM2.5一樣,所采集到的數(shù)據(jù)是做不到非常穩(wěn)定的值的,它本身就不是穩(wěn)定的值
你 ...

好的。我嘗試一下
作者: wayne_w    時間: 2024-3-8 10:05
加運(yùn)放
作者: 單片機(jī)研究協(xié)會    時間: 2024-3-8 15:53
一分鐘讀一次,就不抖了。
作者: Hephaestus    時間: 2024-3-9 00:38
c8t6 發(fā)表于 2024-3-7 13:59
我這個的話,我使用示波器查看查看了擼嵊幸恍《蔚鈉鴟歡ǖ姆逯?/blockquote>

那就是傳感器的問題了,別找ADC麻煩了,想想怎么把數(shù)據(jù)編成你想要的結(jié)果好了。
作者: MCU起航    時間: 2024-3-9 09:15
看是否是配置的問題,不過是stm32g單片機(jī)的adc確實不是說很準(zhǔn)
作者: 1253759011    時間: 2024-4-23 10:38
Y_G_G 發(fā)表于 2024-3-6 23:21
電路沒有很大的干擾,就不需要
我這個基本只用于電源電壓和溫度之類的ADC,之前也有過去掉兩頭的數(shù)值,但實 ...

這個有好處就是不用存儲數(shù)據(jù),理論上要減掉最早采集的數(shù)據(jù)
作者: 大漠落日    時間: 2024-4-23 17:14
跳變才是正常的,這個問題一直都存在,要用軟件方法進(jìn)行優(yōu)化,濾波,再顯示出來
作者: aidianzi    時間: 2024-4-23 19:00
1、檢查采樣時間;2、檢查通道切換時間;3、檢查基準(zhǔn)是否有噪聲(用示波器別用萬用表);4、檢查你信號是否不穩(wěn)定
作者: wufa1986    時間: 2024-4-24 08:04
這應(yīng)該是硬件設(shè)計不合理,電源不夠純凈,STM32單片機(jī)ADC穩(wěn)定度可以




歡迎光臨 (http://www.torrancerestoration.com/bbs/) Powered by Discuz! X3.1