本次我們來講一下ADC(Analog-to-Digital Converter)不是游戲里的AD Carry,我們將實現(xiàn)電池電壓的讀取。
ADC簡介
ADC的全稱為Analog-to-Digital Converter(模擬/數(shù)字轉(zhuǎn)換器)。
在單片機中傳輸?shù)?a target="_blank">信號均為數(shù)字信號,通過離散的高低電平表示數(shù)字邏輯的 1 和 0,但是在現(xiàn)實的物理世界中只存在模擬信號,即連續(xù)變化的信號。將這些連續(xù)變化的信號——比如熱,光,聲音,速度通過各種傳感器轉(zhuǎn)化成連續(xù)的電信號,再通過 ADC 功能將連續(xù)的模擬信號轉(zhuǎn)化成離散的數(shù)字信號給單片機進行處理。
常見的ADC類型有并聯(lián)比較型、逐次逼近型。它們的特點如下
ADC有兩個重要參數(shù),分辨率和轉(zhuǎn)換速率。
分辨率:每一個ADC模塊都會明確他的分辨率,通過bit來表示,一般的是8bit,10bit,12bit,16bit,24bit.bit越大,說明分辨率越高。
采樣率:采樣率就是ADC 采樣的速率。它是指在規(guī)定的時間內(nèi)可以采集的次數(shù),采樣率越高,采集到的點數(shù)就越多,那么對原始信號的還原率就越高。采樣率的單位是SPS(sample per sencond),每秒采樣次數(shù)。這個值越大,采樣速度越快。
下面簡單的講一下這兩種ADC的工作原理
并聯(lián)比較型
這個也是比較容易理解的一種。下圖為并聯(lián)比較型ADC的工作原理圖。
它分為分壓部分、比較部分、編碼部分。
一開始的一排電阻均為等阻值的電阻,它們將VREF(參考電壓)進行均分,也就代表這個該ADC的精度,電阻分壓后的電壓(Vr)我們將其接到比較器的。圖中V1為我們的待測電壓,當V1Vr時比較器輸出1。比如我們這個假設(shè)VREF為15V,V1為1.2V。那么在最下面的比較器中Vr為1V,V1>Vr,比較器輸出1,第二個比較器中Vr為3V,V1
之后我們在每個比較器后加上D觸發(fā)器,當我們把C(控制端)至1后,我們給D輸入1,則Q輸入1,輸入0,則Q輸出0。這里我們先給C1,此時比較器輸出的結(jié)果就被存儲到鎖存器中。然后再置0,那么無論我們的輸入電壓V1怎樣變,Q輸出的值都不變,也就保存了輸出值。這里我們改變控制C的速度很大程度決定了最大采樣率,當然最大采樣率還受比較器等器件最大頻率的限制。
但是這里輸出的還不是二進制數(shù),因此我們需要后面加一個編碼器進行編碼。上面就是并聯(lián)比較型原理的簡單描述。
這里我們也可以看出,并聯(lián)比較型的缺點就是精度想要提升就必須增加相應(yīng)的電阻、比較器、觸發(fā)器。這樣會增加物料成本與體積。但是優(yōu)點就是速度很快。
逐級比較型
下圖為逐級比較型ADC的工作示意圖,我們使用的STM32F4也是使用的這種ADC。
它可以分為控制電路、數(shù)碼寄存器、D/A轉(zhuǎn)換器、電壓比較器四個部分
首先第一步在數(shù)碼寄存器進行編碼,將高位D2編碼置1,其他位置0,之后進入D/A轉(zhuǎn)換器,將編碼出來的數(shù)字量轉(zhuǎn)變?yōu)槟M量V0。之后V0和輸入電壓Vx到比較器進行比較。如果Vx大于V0,比較器輸出1,那么控制電路就會將高位D2鎖定不變,之后將D1置1進行第二輪比較。如果此時Vx還是大于V0我們也就說明了我們V0的值更加接近Vx。我們將D0置1繼續(xù)進行第三輪比較,比如Vx還是比V0大那么說明Vx大于了ADC的量程,如果Vx
這里給出另一個圖方便大家理解
與 1/2Vref 進行比較,Vin 大于 1/2Vref,則將第一位標記為 1
與 3/4Vref 進行比較,Vin 小于 3/4Vref,則將第二位標記為 0
與 5/8Vref 進行比較,Vin 小于 5/8Vref,則將第三位標記為 0。
圖中的 Vin 通過這個三位的 ADC 后輸出的結(jié)果為 100,轉(zhuǎn)換的結(jié)果為 1/2Vref。
這里我們看出由于它需要逐次逼近因此它的轉(zhuǎn)換速度是比較慢的。而且它的分辨率和采樣速度相互矛盾,分辨率越高,采樣速率就越低。
CubeMX配置
雖然這里bsp文件已經(jīng)將我們需要的ADC1,ADC3開啟了,但是這里還是帶著大家學習一遍,便于大家使用其他STM32板子時快速配置。
首先還是看原理圖
這里可以看到電源ADC引腳為PF10,使用ADC3的通道8。
我們需要開啟ADC1和ADC3,ADC1在此處作用為讀取STM32內(nèi)部的1.2V校準電壓Vrefint,這個操作在芯片內(nèi)部實現(xiàn)沒有對應(yīng)引腳。
ADC1的具體配置如下
下表簡單描述一下CuebMX中ADC設(shè)置中的功能。
ADC3開啟通道8,具體配置如ADC1一樣。
這里我們?yōu)槭裁葱枰褂肁DC1的VREFINT呢?
VREFINT是ADC的內(nèi)部參照電壓1.2V,一般來說在STM32我們會使用Vcc作為Vref,但是實際情況中Vcc可能存在較大波動導(dǎo)致Vref不穩(wěn)定最終使得ADC采樣值不準確,因此我們使用已有的1.2V內(nèi)部參考電壓先行進行多次采樣,計算平均值。將其與ADC采樣得出的值進行對比,計算出偏移的比例,得到單位數(shù)字電壓對應(yīng)的模擬電壓值。
程序編寫
首先在RT-Thread Settings組件中打開ADC設(shè)備驅(qū)動程序
之后在硬件中打開ADC1與ADC3
新建一個app_adc.c文件
在使能設(shè)備之后有幾點需要我們注意
我們需要采樣內(nèi)部參考電壓1.2V200次,取平均值并計算單位數(shù)字電壓對應(yīng)的模擬電壓值
/* 采樣內(nèi)部參考電壓200次 /
for(int i=0;i<200;i++)
{
totalvalue+=rt_adc_read(adc_ref,ADC_REF_CHANNEL);
}
/ 計算單位數(shù)字電壓對應(yīng)的模擬電壓值 /
voltage_vrefint_proportion=2001.2f/totalvalue;
之后我們對ADC3通道8進行采樣,這里有兩個點需要注意
/* 讀取采樣值 */
value = rt_adc_read(adc_dev, ADC_DEV_CHANNEL);
rt_kprintf("the value is :%d n", value);
/* 轉(zhuǎn)換為對應(yīng)電壓值 */
vol=(double)value*voltage_vrefint_proportion*1009.0909090909090909090909090909f;
rt_kprintf("the voltage is :%d.%02d n", vol / 100, vol % 100);
我們重新看一下原理圖,我們這里采樣的是分壓電路分壓之后的值,因此我們需要計算出分壓之前的值才為我們所需的電池電壓。通過如下計算我們需要乘以10.09
并且RT-Thread中rt_kprintf是不能打印出浮點數(shù)的,如果是浮點數(shù)的話就不會打印出來,這個我之前也踩過坑,有兩個辦法,一是修改rt_kprintf函數(shù)實現(xiàn),但是printf作為一個可重入的函數(shù),打印浮點數(shù)是不安全的。因此我這里選擇方法二,我們想要保留小數(shù)點后兩位,那么我們就將值*100,之后在打印時再將值/100作為整數(shù)部分,值%100作為小數(shù)部分,如下所示。
rt_kprintf("the voltage is :%d.%02d n", vol / 100, vol % 100);
完整代碼如下,實現(xiàn)功能為輸入adc_vol_sample,輸出實際讀取到的轉(zhuǎn)換的原始數(shù)據(jù)和經(jīng)過計算后的實際電壓值。
/*
Copyright (c) 2006-2021, RT-Thread Development Team
SPDX-License-Identifier: Apache-2.0
Change Logs:
Date Author Notes
2023-01-09 Goldengrandpa the first version
/
#include
#include
#define ADC_REF_NAME "adc1" / ADC 內(nèi)部參考電壓設(shè)備名稱 /
#define ADC_REF_CHANNEL 17
#define ADC_DEV_NAME "adc3" / ADC 設(shè)備名稱 /
#define ADC_DEV_CHANNEL 8 / ADC 通道 /
static int adc_vol_sample(int argc, char argv[])
{
rt_adc_device_t adc_ref;
rt_adc_device_t adc_dev;
rt_uint32_t totalvalue;
rt_uint32_t value, vol;
double voltage_vrefint_proportion;
rt_err_t ret = RT_EOK;
/ 查找設(shè)備 /
adc_ref = (rt_adc_device_t) rt_device_find(ADC_REF_NAME);
if (adc_ref == RT_NULL)
{
rt_kprintf("adc sample run failed! can't find %s device!n", ADC_REF_NAME);
return RT_ERROR;
}
adc_dev = (rt_adc_device_t) rt_device_find(ADC_DEV_NAME);
if (adc_dev == RT_NULL)
{
rt_kprintf("adc sample run failed! can't find %s device!n", ADC_DEV_NAME);
return RT_ERROR;
}
/ 使能設(shè)備 /
ret = rt_adc_enable(adc_ref, ADC_REF_CHANNEL);
ret = rt_adc_enable(adc_dev, ADC_DEV_CHANNEL);
/ 采樣內(nèi)部參考電壓200次 /
for(int i=0;i<200;i++)
{
totalvalue+=rt_adc_read(adc_ref,ADC_REF_CHANNEL);
}
/ 計算單位數(shù)字電壓對應(yīng)的模擬電壓值 /
voltage_vrefint_proportion=2001.2f/totalvalue;
/ 讀取采樣值 /
value = rt_adc_read(adc_dev, ADC_DEV_CHANNEL);
rt_kprintf("the value is :%d n", value);
/ 轉(zhuǎn)換為對應(yīng)電壓值 /
vol=(double)valuevoltage_vrefint_proportion1009.0909090909090909090909090909f;
rt_kprintf("the voltage is :%d.%02d n", vol / 100, vol % 100);
/ 關(guān)閉通道 /
ret = rt_adc_disable(adc_dev, ADC_DEV_CHANNEL);
return ret;
}
/ 導(dǎo)出到 msh 命令列表中 */
MSH_CMD_EXPORT(adc_vol_sample, adc voltage convert sample);
硬件連接如下,這里使用的是大疆的6s電池,輸出電壓24V。
由于電池基本要沒電了因此計算出來的電壓為22.39V偏小屬于正常現(xiàn)象。
-
adc
+關(guān)注
關(guān)注
99文章
6537瀏覽量
545892 -
比較器
+關(guān)注
關(guān)注
14文章
1659瀏覽量
107467 -
D觸發(fā)器
+關(guān)注
關(guān)注
3文章
164瀏覽量
48032 -
STM32F4
+關(guān)注
關(guān)注
3文章
194瀏覽量
28221 -
ADC采樣
+關(guān)注
關(guān)注
0文章
134瀏覽量
12911 -
RT-Thread
+關(guān)注
關(guān)注
31文章
1306瀏覽量
40434
發(fā)布評論請先 登錄
相關(guān)推薦
基于rt-thread studio的sdk開發(fā)adc的應(yīng)用詳解
![基于<b class='flag-5'>rt-thread</b> studio的sdk開發(fā)<b class='flag-5'>adc</b>的應(yīng)用詳解](https://file.elecfans.com/web2/M00/1B/99/poYBAGGF3DeAQtW8AACkdUc63Zo583.png)
基于RoboMasterC板的RT-Thread使用分享—PWM擴展實驗
![基于<b class='flag-5'>RoboMasterC</b><b class='flag-5'>板</b>的<b class='flag-5'>RT-Thread</b>使用分享—PWM擴展<b class='flag-5'>實驗</b>](https://file1.elecfans.com/web2/M00/A9/CC/wKgZomUo8_GAAhxZAAGAuj1_CVg282.jpg)
RT-Thread編程指南
RT-Thread開發(fā),如何有效學習RT-Thread的五個步驟
![<b class='flag-5'>RT-Thread</b>開發(fā),如何有效學習<b class='flag-5'>RT-Thread</b>的五個步驟](https://file1.elecfans.com//web2/M00/A6/D1/wKgZomUMQKSAAGYNAADF5bX7DBc399.png)
RT-Thread Studio驅(qū)動SD卡
![<b class='flag-5'>RT-Thread</b> Studio驅(qū)動SD卡](https://file.elecfans.com/web1/M00/D9/4E/pIYBAF_1ac2Ac0EEAABDkS1IP1s689.png)
RT-Thread學習筆記 RT-Thread的架構(gòu)概述
![<b class='flag-5'>RT-Thread</b>學習筆記 <b class='flag-5'>RT-Thread</b>的架構(gòu)概述](https://file.elecfans.com/web2/M00/52/31/pYYBAGLKk5WAA__jAADjdAdXhIs410.jpg)
基于RoboMasterC型開發(fā)板的RT-Thread使用分享(一)
基于RoboMasterC型開發(fā)板的RT-Thread使用分享(二)
RT-Thread文檔_RT-Thread 潘多拉 STM32L475 上手指南
![<b class='flag-5'>RT-Thread</b>文檔_<b class='flag-5'>RT-Thread</b> 潘多拉 STM32L475 上手指南](https://file.elecfans.com/web1/M00/D9/4E/pIYBAF_1ac2Ac0EEAABDkS1IP1s689.png)
基于rt-thread的socket通信設(shè)計
![基于<b class='flag-5'>rt-thread</b>的socket通信設(shè)計](https://file1.elecfans.com/web2/M00/A9/C8/wKgZomUo6zmAAOaBAAA3J66gCyE925.jpg)
評論