周立功教授新書《面向AMetal框架與接口的編程(上)》,對AMetal框架進行了詳細介紹,通過閱讀這本書,你可以學到高度復用的軟件設計原則和面向接口編程的開發思想,聚焦自己的“核心域”,改變自己的編程思維,實現企業和個人的共同進步。
第五章為深入淺出AMetal,本文內容為5.7 A/D 轉換器。
5.7 A/D 轉換器
>>> 5.7.1 模數信號轉換
1. 基本原理
我們經常接觸的噪聲和圖像信號都是模擬信號,要將模擬信號轉換為數字信號,必須經過采樣、保持、量化與編碼幾個過程,詳見圖5.4。
圖5.4 模數信號轉換示意圖
將以一定的時間間隔提取信號的大小的操作稱為采樣,其值為樣本值,提取信號大小的時間間隔越短越能正確地重現信號。由于縮短時間間隔會導致數據量增加,所以縮短時間間隔要適可而止。注意,取樣頻率大于或等于模擬信號中最高頻率的2 倍,就能夠無失真地恢復原信號。
將采樣所得信號轉換為數字信號往往需要一定的時間,為了給后續的量化編碼電路提供一個穩定值,采樣電路的輸出還必須保持一段時間,而采樣與保持過程都是同時完成的。雖然通過采樣將在時間軸上連續的信號轉換成了不連續的(離散的)信號,但采樣后的信號幅度仍然是連續的值(模擬量)。此時可以在振幅方向上以某一定的間隔進行劃分,決定個樣本值屬于哪一區間,將記在其區間的值分配給其樣本值。圖5.4 將區間分割為0~0.5、0.5~1.5、1.5~2.5,再用0、1、2……代表各區間,對小數點后面的值按照四舍五入處理,比如,201.6 屬于201.5~202.5,則賦值202;123.4 屬于122.5~123.5,則賦值123,這樣的操作稱為量化。
量化前的信號幅度與量化后的信號幅度出現了不同,這一差值在重現信號時將會以噪聲的形式表現出來,所以將此差值稱為量化噪聲。為了降低這種噪聲,只要將量化時階梯間的間隔減小就可以了。但減小量化間隔會引起階梯數目的增加,導致數據量增大。所以量化的階梯數也必須適當,可以根據所需的信噪比(S/N)確定。
將量化后的信號轉換為二進制數,即用0 和1 的碼組合來表示的處理過程稱為編碼,“1”表示有脈沖,“0”表示無脈沖。當量化級數取為64 級時,表示這些數值的二進制的位數必須是6 位;當量化級數取為256 級時,則必須用8 位二進制數表示。
2. 基準電壓
基準電壓就是模數轉換器可以轉換的最大電壓,以8 位A/D 模數轉換器為例,這種轉換器可以將0V 到其基準電壓范圍內的輸入電壓轉換為對應的數值表示。其輸入電壓范圍分別對應4096 個數值(步長),其計算方法為:參考電壓/256=5/256=19.5mV。
看起來這里給出的10 位A/D 的步長電壓值,但上述公式還定義了該模數轉化器的轉換精度,無論如何所有A/D 的轉換精度都低于其基準電壓的精度,而提高輸出精度的唯一方法只有增加定標校準電路。
現在很多MCU 都內置A/D,即可以使用電源電壓作為其基準電壓,也可以使用外部基準電壓。如果將電源電壓作為基準電壓使用的話,假設該電壓為5V,則對3V 輸入電壓的測量結果為:(輸入電壓/基準電壓)×255=(3/5)×255=99H。顯然,如果電源電壓升高1%,則輸出值為(3/5.05)×255=97H。實際上典型電源電壓的誤差一般在2~3%,其變化對A/D 的輸出影響是很大的。
3. 轉換精度
A/D 的輸出精度是由基準輸入和輸出字長共同決定的,輸出精度定義了A/D 可以進行轉換的最小電壓變化。轉換精度就是A/D 最小步長值,該值可以通過計算基準電壓和最大轉換值的比例得到。對于上面給出的使用5V 基準電壓的8位A/D來說,其分辨率為19.5mV,也就是說,所有低于19.5mV 的輸入電壓的輸出值都為0,在19.5mV~39mV 之間的輸入電壓的輸出值為1,而在39mV~58.6mV 之間的輸入電壓的輸出值為3,以此類推。
提高分辨率的一種方法是降低基準電壓,如果將基準電壓從5V 降到2.5V,則分辨率上升到2.5/256=9.7mV,但最高測量電壓降到了2.5V。而不降低基準電壓又能提高分辨率的唯一方法是增加A/D 的數字位數,對于使用5V 基準電壓的12 位A/D 來說,其輸出范圍可達4096,其分辨率為1.22mV。
在實際的應用場合是有噪音的,顯然該12 位A/D 會將系統中1.22mV 的噪音作為其輸入電壓進行轉換。如果輸入信號帶有10mV 的噪音電壓,則只能通過對噪音樣本進行多次采樣并對采樣結果進行平均處理,否則該轉換器無法對10mV 的真實輸入電壓進行響應。
4. 累積精度
如果在放大器前端使用誤差5%的電阻,則該誤差將會導致12 位A/D 無法正常工作。也就是說,A/D 的測量精度一定小于其轉換誤差、基準電壓誤差與所有模擬放大器誤差的累計之和。雖然轉換精度會受到器件誤差的制約,但通過對每個系統單獨進行定標,也能夠得到較為滿意的輸出精度。如果使用精確的定標電壓作為標準輸入,且借助存儲在MCU 程序中的定標電壓常數對所有輸入進行糾正,則可以有效地提高轉換精度,但無論如何無法對溫漂或器件老化而帶來的影響進行校正。
5. 基準源選型
引起電壓基準輸出電壓背離標稱值的主要因素是:初始精度、溫度系數與噪聲,以及長期漂移等,因此在選擇一個電壓基準時,需根據系統要求的分辨率精度、供電電壓、工作溫度范圍等情況綜合考慮,不能簡單地以單個參數為選擇條件。
比如,要求12 位A/D 分辨到1LSB,即相當于1/212=244ppm。如果工作溫度范圍在10℃,那么一個初始精度為0.01%(相當于100ppm),溫度系數為10ppm/℃(溫度范圍內偏移100ppm)的基準已能滿足系統的精度要求,因為基準引起的總誤差為200ppm,但如果工作溫度范圍擴大到15℃以上,該基準就不適用了。
6. 常用基準源
(1)初始精度的確定
初始精度的選擇取決于系統的精度要求,對于數據采集系統來說,如果采用n 位的ADC,那么其滿刻度分辨率為1/2n,若要求達到1LSB 的精度,則電壓基準的初始精度為:
如果考慮到其它誤差的影響,則實際的初始精度要選得比上式更高一些,比如,按1/2LSB 的分辨率精度來計算,即上式所得結果再除以2,即:
(2)溫度系數的確定
溫度系數是選擇電壓基準另一個重要的參數,除了與系統要求的精度有關外,溫度系數還與系統的工作溫度范圍有直接的關系。對于數據采集系統來說,假設所用ADC 的位數是n,要求達到1LSB 的精度,工作溫度范圍是ΔT,那么基準的溫度系數TC 可由下式確定:
同樣地,考慮到其它誤差的影響,實際的TC 值還要選得比上式更小一些。溫度范圍ΔT通常以25℃為基準來計算,以工業溫度范圍-40℃~+85℃為例,ΔT 可取60℃(85℃-25℃),因為制造商通常在25℃附近將基準因溫度變化引起的誤差調到最小。
如圖5.5 所示是一個十分有用的速查工具,它以25℃為變化基準,溫度在1℃~00℃變化時,8~20 位ADC 在1LSB 分辨精度的要求下,將所需基準的TC 值繪制成圖,由該圖表可迅速查得所需的TC 值。
圖5.5 系統精度與基準溫度系數TC 的關系
TL431 和REF3325/3330 均為典型的電壓基準源產品,詳見表5.19。TL431 的輸出電壓僅用兩個電阻就可以在2.5~36V 范圍內實現連續可調,負載電流1~100mA。在可調壓電源、開關電源、運放電路常用它代替穩壓二極管。REF3325輸出2.5V,REF3330 輸出3.0V。
表5.19 電壓基準源選型參數表
REF33xx 是一種低功耗、低壓差、高精密度的電壓基準產品,采用小型的SC70-3 和SOT23-3 封裝。體積小和功耗低(最大電流為5μA)的特點使得REF33xx 系列產品成為眾多便攜式和電池供電應用的最佳選擇。在負載正常的情況下,REF33xx 系列產品可在高于指定輸出電壓180mV 的電源電壓下工作,但REF3312 除外,因為它的最小電源電壓為1.8V。
從初始精度和溫漂特性來看,REF3325/3330 均優于TL431,但是TL431 的輸出電壓范圍很寬,且工作電流范圍很大,甚至可以代替一些LDO。由于基準的初始精度和溫漂特性是影響系統整體精度的關鍵參數,因此它們都不能用于高精密的采集系統和高分辨率的場合。而對于12bits的AD 來說,由于精度要求在0.1%左右的采集系統,到底選哪個型號呢?測量系統的初始精度,均可通過對系統校準消除初始精度引入的誤差;對于溫漂的選擇,必須參考1LSB 分辨精度來進行選擇,詳見圖5.6。如果不是工作在嚴苛環境下,通常工作溫度為-10℃~50℃,溫度變化在60℃,如果考慮0.1%系統精度,溫度特性低于50ppm,則選擇REF3325/3330。
圖5.6 12bits 系統基準選擇
>>> 5.7.2 初始化
在使用ADC 通用接口前,必須先完成ADC 的初始化,以獲取標準的ADC 實例句柄。LPC82x 僅包含一個ADC(ADC0),為方便用戶使用,AMetal 提供了與ADC0 對應的實例初始化函數,其函數原型為:
函數的返回值為am_adc_handle_t 類型的ADC 實例句柄,該句柄將作為ADC 通用接口中handle 參數的實參。類型am_adc_handle_t(am_adc.h)定義如下:
因為函數返回的ADC 實例句柄僅作為參數傳遞給ADC 通用接口,不需要對該句柄作其它任何操作,因此完全不需要對該類型作任何了解。需要特別注意的是,若函數返回的實例句柄的值為NULL,則表明初始化失敗,該實例句柄不能被使用。
如需使用ADC0,則直接調用ADC0 實例初始化函即可完成ADC0 的初始化,并獲取對應的實例句柄:
ADC0 共支持12 個通道,可以采集12 路模擬信號進行模數轉換,每路模擬信號通過LPC824 的相應I/O 口輸入到ADC0 中,各通道對應的I/O 口詳見表5.20。
表5.20 各通道對應的I/O 口
>>> 5.7.3 接口函數
AMetal 提供了5 個ADC 相關的接口函數,詳見表5.21。
表5.21 ADC 通用接口函數
1. 獲取ADC 通道的采樣率
獲取當前ADC 通道的采樣率。其函數原型為:
獲取到的采樣率的單位為Samples/s。如果返回AM_OK,說明獲取成功;如果返回-AM_EINVAL,說明因參數無效導致獲取失敗,其相應的代碼詳見程序清單5.87。
程序清單5.87 am_adc_rate_get()范例程序
參數無效是由于handle 不是標準的ADC handle 或者通道號不支持造成的。
2. 設置ADC 通道的采樣率
設置ADC 通道的采樣率。實際采樣率可能與設置的采樣率存在差異,實際采樣率可由am_adc_rate_get()函數獲取。注意,在一個ADC 中,所有通道的采樣率往往是一樣的,因此設置其中一個通道的采樣率時,可能會影響其它通道的采樣率。其函數原型為:
如果返回AM_OK,說明設置成功;如果返回-AM_EINVAL,說明因參數無效導致設置失敗,其相應的代碼詳見程序清單5.88。
程序清單5.88 am_adc_rate_set()范例程序
3. 獲取ADC 通道的參考電壓
獲取ADC 通道的參考電壓,其函數原型為:
如果返回值大于0,表示獲取成功,其值即為參考電壓(單位:mV);如果返回-AM_EINVAL,說明因參數無效導致獲取失敗,其相應的代碼詳見程序清單5.89。
程序清單5.89 am_adc_vref_get()范例程序
4. 獲取ADC 通道的轉換位數
獲取ADC 通道的轉換位數,其函數原型為:
如果返回值大于0,表示獲取成功,其值即為轉換位數;如果返回-AM_EINVAL,說明因參數無效導致獲取失敗,其相應的代碼詳見程序清單5.90。
程序清單5.90 am_adc_bits_get()范例程序
5. 讀取指定通道的電壓值
直接讀取ADC 通道的電壓值(單位:mV),該函數會等到電壓值讀取完畢后返回。其函數原型為:
其中p_mv 是指向存放電壓值的緩沖區,類型am_adc_val_t 在am_adc.h 中定義,即:
length 表示緩沖區的長度,決定了實際獲取電壓值的個數。如要返回AM_OK,表示讀取通道電壓值成功,相應緩沖區中已經填充好了讀取到的電壓值;如果返回-AM_EINVAL,說明因參數無效導致獲取失敗,其相應的代碼詳見程序清單5.91。
程序清單5.91 am_adc_read_mv()范例程序
>>> 5.7.4 溫度采集
1. 電壓采集
熱敏電阻器屬于敏感元件類型,按照溫度系數的不同可分為正溫度系數熱敏電阻器(PTC)和負溫度系數熱敏電阻器(NTC)。熱敏電阻器的典型特點是對溫度敏感,在不同的溫度下其電阻值不一樣。正溫度系數熱敏電阻器(PTC)在溫度越高時電阻值越大,負溫度系數熱敏電阻器在溫度越高時電阻值越小。
AM824-Core 上有一個負溫度系數熱敏電阻器RT1,硬件電路詳見圖5.7。熱敏電阻RT1 和2KΩ的R14 構成了分壓電路,選用MF52E-103F3435FB-A,C8 使電路輸出更加穩定。當測溫范圍在0~85℃時,電阻變化范圍為27.6~1.45KΩ。當溫度變化時,熱敏電阻的阻值發生變化,單片機采集到的ADC 值也會發生變化。只要將J6 通過跳線帽短接,則R14 電阻的電壓直接通過PIO0_19 輸入到了ADC的通道7,即可使用ADC 采集其電壓值。
圖5.7 熱敏電阻電路
如程序清單5.92 所示的ntc.c 的兩個函數,其中的一個用于初始化,另一個用于讀取電壓值。由于最終的接口還不確定,所以只創建了ntc.h。
程序清單5.92 采集電壓值相關函數編寫(ntc.c)
ntc_init()僅用于初始化ADC,獲取一個標準的ADC 實例句柄。ntc_vol_get()用于獲取ADC 通道7 對應的電壓值,使用了am_adc_read_mv()函數。
為了使結果更加可信,電壓采集時使用了中值平均濾波法(防脈沖干擾平均濾波法),即去掉采樣數據中的最大值和最小值,再取余下數據的平均值作為最終結果。程序中,首先使用am_adc_read_mv()函數采集了12 個電壓值,然后將所有電壓值求和,并找出最大值和最小值,最后從和值中減去最大值和最小值后除以10 作為電壓采集值并返回。
2. 獲取阻值
假設采集的電壓值為vol,通過RT1 和R14 分壓后,則有:
通過簡單轉換后可得:
利用該公式,可以將采集的電壓值轉換為RT1 的電阻值,詳見程序清單5.93,同樣將程序直接添加到ntc.c 中。
程序清單5.93 獲取熱敏電阻的阻值(ntc.c)
為了避免小數計算,電壓的單位統一為毫伏(mV),電阻的單位統一為歐姆(Ω)。
3. 阻值與溫度的關系
在獲取熱敏電阻阻值后,將如何找到與該電阻值對應的溫度呢?不妨先從分析熱敏電阻阻值與溫度的關系開始。負溫度系數熱敏電阻的電阻值(RT)和溫度(T)呈指數關系:
其中,RT 是在溫度T(單位為K,即開爾文)時的NTC 熱敏電阻阻值,RN 是在額定溫度TN(K)的NTC 熱敏電阻阻值,B 為NTC 熱敏電阻的材料常數,又叫熱敏指數。由于該關系式是經驗公式,因此只在額定溫度 TN 或額定電阻阻值 RN 的有限范圍內才具有一定的精確度。
如何得到材料常數B 的值呢?顯然,只能通過實驗測得。假定在實驗環境下,測得在溫度 T1 ( K )時的零功率電阻值為RT1,在溫度 T2 ( K )時的零功率電阻值為RT2。零功率電阻是指在某一溫度下測量熱敏電阻值時,加在熱敏電阻上的功耗極低,低到因其功耗引起的熱敏電阻阻值變化可以忽略不計。額定零功率電阻是在環境溫度25℃條件下測得的零功率電阻值,標記為R25,通常所說NTC 熱敏電阻阻值就是指該值。
根據T1、RT1、T2、RT2 和溫度與電阻值的關系式,可以得到:
將兩個等式相除可得:
等式兩邊同時對e 取對數(ln)可得:
經過變換,可以得到B 值的計算公式為:
由此可見,只要測得兩個溫度點對應的零功率電阻值,就可以求得B 值。由于精確的測量需要有高精度的溫度測量儀和高精度的電阻測量儀,一般條件下很難完成,因此,廠家往往都會提供一些溫度點對應的零功率電阻值。比如,AM824-Core 使用的熱敏電阻,廠家提供了兩個溫度點對應的零功率電阻值:R25 = 10000Ω,R85 = 1451Ω。
根據這兩個溫度值,即可求得B 值:
注意,表達式中的溫度都是以開爾文(K)為單位的,因此需要將攝氏度(℃)轉換為開爾文溫度。其轉換關系為:
當求得B 值后,可以使用電阻值和溫度的關系式求得某溫度下的電阻值。阻值與溫度的關系式中RN 為在額定溫度TN(K)下的阻值,可以直接使用R25 對應的值,即RN=10000Ω,TN=(25+273.15)K。以60℃為例計算對應的阻值:
由此可見,上述計算過程是非常繁瑣的,且還要涉及到復雜的指數運算,所以往往會采用查表法。即先將各個溫度對應的電阻值存儲到一個表格中,當需要使用時直接查表即可。
AM824-Core 的熱敏電阻,廠家提供了如表5.22 所示的R-T 表。根據實際應用場合,這里僅列出了-20℃~ 87℃對應的電阻值,而實際上該熱敏電阻支持-40℃~125℃的溫度測量。
表5.22 熱敏電阻R-T 表
通過查表可知60℃對應的阻值為3002Ω,而計算出來的值卻是2981Ω。由于前面的公式僅僅是經驗公式,計算值與實測值往往會存在少量差異,但總體上是非常相近的,即2981Ω最接近60℃。由于溫度是連續的,且以1℃為間距,因此僅需一維數組即可存儲所有的阻值,即數組的0 號元素對應-20℃的阻值,107 號元素對應87℃的阻值。要想獲得溫度對應的阻值,則將溫度值加上20 作為數組索引即可。
由于最大阻值為70988Ω,因此每個阻值需要一個32 位的數據來保存,則數組元素的類型設定為uint32_t 類型。-20℃~87℃共計對應108 個阻值,數組大小即為108,共計108個4 字節存儲單元,即108*4 = 423 字節。注意,表格中僅-20℃和-19℃對應的阻值超過了65535,其它溫度值對應的阻值均可用16 位來表示。因此可以做一些特殊的處理,比如,將-20℃和-19℃對應的阻值單獨保存。如果測溫范圍不包含這兩個溫度,則可以去掉這兩個溫度值對應的阻值。保存溫度對應阻值的ntc.c 詳見程序清單5.94。
程序清單5.94 定義保存各個溫度值對應阻值的數組
由于數組的起始元素為-20℃對應的阻值,因此對應溫度與數組索引的關系如下:
-
對應溫度=數組索引-20
-
數組索引=對應溫度+20
由于數組索引與溫度存在20 的差值,如果需得到25℃對應的阻值,則應該在使用溫度值的基礎上加上20 作為數組的索引。即:
4. 獲取溫度值
雖然已經得到了熱敏電阻阻值與溫度的對應關系,但是如何獲取阻值對應的溫度呢?如果阻值對應的溫度剛好是整數,即阻值會與數組中某個元素相等,則只需要掃描一遍數組,如果掃描到阻值相等,即可得到對應的溫度,詳見程序清單5.95。
程序清單5.95 獲取溫度值(1)
雖然該程序實現起來很簡單,卻不實用,因為得到的阻值恰好是整數溫度的概率太小了。而事實上得到的阻值往往處于某個區間之內,比如,7500Ω對應的溫度范圍為32℃~ 33℃,那么該如何確定其溫度值呢?7500Ω與32℃對應的7712Ω相差212Ω,與33℃對應的7437Ω相差63Ω,顯然與33℃更加接近,那是不是直接取33℃就好了呢?如果對精度要求不高,得到的溫度全為整數值,如果希望更加精確,比如,要求精確到小數點后兩位?
盡管指數關系是非線性關系,其對應的阻值-溫度關系圖是曲線圖,但可以將這一曲線分解為若干小段,將每一小段中的阻值-溫度關系近似為線性關系。如將1℃溫度區間內的阻值-溫度關系近似為線性關系進行處理。假設已知區間的兩個端點(R1,T1)、(R2,T2),那么使用已知兩點求直線方程的方法,很容易得到阻值R(R1≤R≤R2)對應的溫度為:
對于上述例子來說,若測得電阻阻值為7500Ω,則區間的兩個端點為(7712,32)和(7437,33),使用上述式子可得到溫度值:
顯然,這樣求得的溫度更加精確,其相應的代碼詳見程序清單5.96。
程序清單5.96 根據溫度區間獲取溫度值
程序中使用的是帶符號數,而電阻值是用無符號數表示的,因此必須將無符號的電阻值事先存放到有符號數中再進行計算。當無符號數與有符號數混合運算時,由于無符號數優先級高,因此會先將有符號數轉換為無符號數再作運算,特別是在有負數參與運算的場合,往往會得到意想不到的結果。比如:
為什么結果等于0?因為a 是無符號數,在計算a/b 時,按照無符號數計算,則會先將-32轉換為無符號數,即4294967264,96 整除一個這個大的數,結果自然就為0 了。同時,為了避免小數的計算,將運算結果擴大了256 倍。由于測量的溫度范圍為-20℃~87℃,即便擴大256 倍后也不會超過16 位帶符號數的范圍,因此最終返回一個16 位的帶符號數。
為何要擴大256 倍而不是100 倍呢?當然,100 倍更好理解,如果擴大100 倍,即表示保留2 位小數,最小表示數值為0.01。其實擴大256 倍也是一樣的,其最小表示數值為1/256= 0.00390625,具有更高的精度。前面我們已經使用的LM75B 采集溫度值,讀取溫度值的lm75_read()函數返回的實際測量溫度值也擴大了256 倍。這樣一來,如果這里返回的溫度值同樣也擴大256 倍,則之前的程序就完全可以復用了。
為了使用ntc_temp_get_from_range()函數得到溫度值,還需要找出阻值對應溫度所在的溫度區間。如何獲取區間呢?由于阻值是順序遞減的,最簡單的方法就是順序尋找,只要找到測得的電阻值大于阻值表中某個溫度對應的阻值時,即可確定其處在的區間。如順序尋找阻值7500 的區間時,找到溫度為33℃對應的阻值7437 時,發現比其小,則說明33℃為其右邊界,左邊界為上一個溫度值,即32℃,其相應的代碼詳見程序清單5.97。
程序清單5.97 獲取溫度值(2)
實際上,當前的搜索方法效率太低,如果溫度是87℃,則要搜索108 次,直到將數組元素全部遍歷一遍為止。由于阻值是順序遞減的,則不妨用二分法。即每次與中間的數比較,根據比較結果即可將搜索范圍縮小一半,接著繼續與新的搜索范圍中的中間值比較,同樣可以根據比較結果將搜索范圍縮小一半,依此類推,每次比較都可以直接將搜索范圍縮小一半。
下面還是以7500Ω為例,數組元素總共有108 個,索引為0 ~ 107,用兩個變量low 和high 分別表示搜索范圍的下界和上界,mid 表示中間位置。
(1) 初始時,則low = 0,high = 107,中間位置即為(low+high)/2 = 53(直接按照C語言整數除法),53 位置(即溫度33℃,直接查表5.22)對應的阻值為7437,7437 小于7500,因此搜索范圍鎖定至上半部分,因此更新high = 53;
(2) 繼續搜索,low = 0,high = 53,mid = 26,26 位置對應的阻值為21363,21363 大于7500,因此搜索范圍一定在后半部分,更新low = 26;
(3) low = 26,high = 53,mid = 39,39 位置對應的阻值為12596,12596 大于7500,因此搜索范圍還是在后半部分,更新low = 39;
(4) low = 39,high = 53,mid = 46,46 位置對應的阻值為9630,9630 大于7500,因此搜索范圍還是在后半部分,更新low = 46;
(5) low = 46,high = 53,mid = 49,49 位置對應的阻值為8610,8610 大于7500,因此搜索范圍還是在后半部分,更新low = 49;
(6) low = 49,high = 53,mid = 51,51 位置對應的阻值為7999,7999 大于7500,因此搜索范圍還是在后半部分,更新low = 51;
(7) low = 51,high = 53,mid = 52,52 位置對應的阻值為7712,7712 大于7500,因此搜索范圍還是在后半部分,更新low = 52。至此,由于low 與high 之間只差1,無法再繼續分成兩部分,因此,確定要找的值一定在位置52 與53 之間,也就是阻值對應的溫度范圍為32℃~ 33℃,到此為止搜索結束。
針對108 個元素,按照二分法搜索,最多搜索7 次,其相應的代碼詳見程序清單5.98。
程序清單5.98 獲取溫度值(3)
至此,即可直接調用ntc_temp_read()獲取溫度值。相關函數編寫完畢,將ntc_init()和ntc_temp_read()函數聲明詳見程序清單5.99(ntc.h),其具體實現詳見程序清單5.100(ntc.c)。
程序清單5.99 ntc.h 文件內容
程序清單5.100 ntc.c 文件內容
ntc.c 相比于之前的代碼,新增了兩個變量:
(1) 新增變量res_val_num 用于表示數組元素的個數
在范圍搜索時,將之前的固定值107 修改為數組元素個數,這樣一來數組元素就可以繼續向后增加,比如,增加至-20℃~125℃,則所有代碼都無需任何修改。
(2) 新增變量temp_start 用于表示阻值表的起始溫度值
之前的代碼固定了起始溫度為-20℃,如果向前擴展溫度范圍為-40℃~125℃,則程序必須做相應的修改。當增加該變量后,向前擴展溫度范圍時,僅需修改該變量的值即可,此時數組的起始元素就是temp_start 溫度對應的阻值,因此對應溫度與數組索引存在如下關系:
對應溫度 = 數組索引+temp_start,數組索引 = 對應溫度-temp_start
范例程序可以直接修改此前編寫的“智能溫控儀”程序,使用熱敏電阻獲取溫度值替換之前的LM75 獲取溫度值。僅需修改3 行代碼即可:“#include "lm75.h" 修改為 #include"ntc.h",am_main()函數中的lm75_init()修改為ntc_init(),am_main()函數中的lm75_read()修改為ntc_temp_read()”,而其它復雜的鍵盤處理和數碼管顯示等均可復用。
-
轉換器
+關注
關注
27文章
8712瀏覽量
147299 -
信號處理
+關注
關注
48文章
1031瀏覽量
103297 -
周立功
+關注
關注
38文章
130瀏覽量
37658
原文標題:周立功:深入淺出AMetal——A/D 轉換器
文章出處:【微信號:ZLG_zhiyuan,微信公眾號:ZLG致遠電子】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論