外设驱动库开发笔记6:AD719x系列ADC驱动
前面我們討論了AD7705這種ADC器件的驅(qū)動開發(fā),在實(shí)際中我們使用更多的是AD719x系列的ADC芯片、包括有AD7191、AD7192和AD7193等。接下來我們就來設(shè)計(jì)并開發(fā)AD719x的驅(qū)動程序。
1、功能概述
AD7192是一款適合高精密測量應(yīng)用的低噪聲完整模擬前端,內(nèi)置一個低噪聲、 24 位Σ-Δ型模數(shù)轉(zhuǎn)換器 (ADC)。片內(nèi)低噪聲增益級意味著可直接輸入小信號。
1.1、硬件結(jié)構(gòu)
AD7192可配置為兩路差分輸入或四路偽差分輸入。片內(nèi)通道序列器可以使能多個通道,AD7192 按順序在各使能通道上執(zhí)行轉(zhuǎn)換,這可以簡化與器件的通信。 片內(nèi) 4.92 MHz時鐘可以用作 ADC 的時鐘源; 或者也可以使用外部時鐘或晶振。 該器件的輸出數(shù)據(jù)速率可在 4.7 Hz 至 4.8 kHz 的范圍內(nèi)變化。
AD7192提供兩種數(shù)字濾波器選項(xiàng)。 濾波器的選擇會影響以編程輸出數(shù)據(jù)速率工作時的均方根噪聲和無噪聲分辨率、建立時間以及 50 Hz/60 Hz 抑制。 針對要求所有轉(zhuǎn)換均需建立的應(yīng)用, AD7192 具有零延遲特性。
其功能結(jié)構(gòu)圖如下:
1.2、內(nèi)部寄存器
AD7192內(nèi)部具有多個寄存器,對AD7192的操作就是通過這些片內(nèi)寄存器進(jìn)行控制和數(shù)據(jù)寄存器/數(shù)據(jù)寄存器加狀態(tài)信息配置。這些寄存器包括:通信寄存器、狀態(tài)寄存器、模式寄存器、配置寄存器、ID寄存器、GPOCON寄存器、失調(diào)寄存器以及滿量程寄存器。其中通信寄存器和狀態(tài)寄存器共享地址,讀操作時針對的是狀態(tài)寄存器,寫操作時針對的是通訊寄存器。對任何寄存器的操作都是從寫通訊寄存器開始。
1.2.1、通信寄存器
通信寄存器是一個 8 位只寫寄存器。與該器件的所有通信均必須以對通信寄存器的寫操作開始。寫入通信寄存器的數(shù)據(jù)決定下一個操作是讀操作還是寫操作,以及此操作發(fā)生在哪一個寄存器。通訊寄存器的格式如下:
其中RS2、RS1、RS0這些位用于指示下一次操作的寄存器是哪一個寄存器,具體如下:
我們使用比較多的就是狀態(tài)寄存器、模式寄存器、配置寄存器以及數(shù)據(jù)寄存器。后續(xù)會進(jìn)一步了解這些寄存器。
1.2.2、狀態(tài)寄存器
狀態(tài)寄存器是一個8位只讀寄存器。要訪問ADC狀態(tài)寄存器,用戶必須寫入通信寄存器,選擇下一個操作為讀操作,并將 0 載入位RS2、位RS1 和位RS0。狀態(tài)寄存器的格式如下:
CHD0、CHD1、CHD2這些位指示哪一通道對應(yīng)數(shù)據(jù)寄存器的內(nèi)容。這些位不是指示目前正在轉(zhuǎn)換哪一通道,而是指示產(chǎn)生數(shù)據(jù)寄存器所含轉(zhuǎn)換結(jié)果時選定了哪一通道。
1.2.3、模式寄存器
模式寄存器是一個24位寄存器,可以從中讀取數(shù)據(jù),也可以將數(shù)據(jù)寫入其中。此寄存器用來選擇工作模式、輸出數(shù)據(jù)速率和時鐘源。模式寄存器的格式如下:
AD7192的工作模式有模式寄存器的MD2、MD1、MD0這幾位來決定。具體的配置如下:
我們配置什么樣的工作模式?jīng)Q定了后續(xù)的操作。默認(rèn)情況下為連續(xù)模式,應(yīng)用比較多的有單次模式、校準(zhǔn)模式等。
1.2.4、配置寄存器
配置寄存器是一個 24 位寄存器,可以從中讀取數(shù)據(jù),也可以將數(shù)據(jù)寫入其中。此寄存器用來配置 ADC 的單極性或雙極性模式,使能或禁用緩沖器,使能或禁用激勵電流,選擇增益,以及選擇模擬輸入通道。
其中G2、G1、G0等位用于配置通道的增益。可以實(shí)現(xiàn)1倍、8倍、16倍、32倍、64倍、128倍等增益,輸入的范圍也對應(yīng)調(diào)整,具體如下:
位CH7、CH6、CH5、CH4、CH3、CH2、CH1、CH0用于設(shè)置使用的通道。每一位對應(yīng)一個通道,具體配置方式如下:
其中CH0與CH4、CH5不可同時使用,CH1與CH6、CH7不能同時使用。CH0和CH1是差分輸入,CH4、CH5、CH6、CH7是單端輸入。
余下的ID寄存器、GPOCON寄存器、失調(diào)寄存器以及滿量程寄存器比較容易理解不再說明。
2、驅(qū)動設(shè)計(jì)與實(shí)現(xiàn)
我們已經(jīng)了解AD7192的基本情況,接下來我們將據(jù)此來開發(fā)AD7192的驅(qū)動程序。
2.1、對象設(shè)計(jì)
我們的驅(qū)動程序依然設(shè)計(jì)為基于對象的操作。所以首先我們需要先設(shè)計(jì)對象。而關(guān)于對象的設(shè)計(jì)過程包括兩方面內(nèi)容:對象類型的定義;對象的初始化。
2.1.1、抽象對象類型
對于一個AD7192對象,我們首先考慮到它有8個寄存器,這些寄存器決定了它的操作特性,所以我們記錄這些寄存器的值用以標(biāo)識它的狀態(tài)。此外增益與極性雖然存在于配置寄存器中,但我們希望在初始化的時候明確的指定它,所以我們也將其作為屬性以標(biāo)識AD7192對象的配置狀態(tài)。
而對于片選信號的控制、轉(zhuǎn)換就緒信號的讀取,總線數(shù)據(jù)的輸入輸出這些依賴于硬件電路的操作,我們都將其作為對象的操作來實(shí)現(xiàn)。此外,延時操作在不同的硬件平臺、有無操作系統(tǒng)的情況下,實(shí)現(xiàn)方式大相徑庭,因此我們也將其作為對象的操作以便靈活處理。
據(jù)此我們可以抽象得AD7192對象類型為:
/*定義用于操作的結(jié)構(gòu)體*/ typedef struct Ad7192Object {uint32_t polar;??? ??????????????????????? //通道的極性uint32_t gain;??????? ???????????? //通道增益uint32_t Registers[8];???????? //存放寄存器值的數(shù)組void (*ReadWrite)(uint8_t *wData,uint8_t *rData,uint16_t size);??????????? //實(shí)現(xiàn)讀寫操作void (*ChipSelect)(AD7192CSType cs);???????????????????? //實(shí)現(xiàn)片選uint16_t (*GetReadyInput)(void);????????????????????????????????????? //實(shí)現(xiàn)Ready狀態(tài)監(jiān)視void (*Delay)(volatile uint32_t nTime);?????????????? //實(shí)現(xiàn)ms延時操作 }Ad7192ObjectType;2.1.2、初始化函數(shù)
在使用AD7192前先對其實(shí)行初始化,所以我們需要一個對象初始化函數(shù)。初始化函數(shù)主要包括三個方面的內(nèi)容:檢查對象即各種初始輸入是否有效;為對象的屬性賦初值以及為操作指定函數(shù)指針;對AD7192做前期配置。
關(guān)于AD7192的前期配置,首先是軟件復(fù)位,連續(xù)寫入40個1就可對AD7192實(shí)現(xiàn)復(fù)位。復(fù)位完成后,對零點(diǎn)和量程進(jìn)行校準(zhǔn)。而后獲取各寄存器的當(dāng)前狀態(tài)。初始化函數(shù)的具體實(shí)現(xiàn)代碼如下:
/*AD7192初始化配置*/ AD7192ErrorType AD7192Initialization(Ad7192ObjectType *adObj,uint32_t Channels,AD7192PolarType polar,AD7192GainType gain,AD7192ReadWriteType readWrite,AD7192ChipSelectType cs,AD7192GetReadyInputType ready,AD7192DelaymsType delayms) {uint32_t polarity[]={UB_UNI,UB_BI};uint32_t gains[]={GAIN_1,GAIN_8,GAIN_16,GAIN_32,GAIN_64,GAIN_128};if((adObj==NULL)||(readWrite==NULL)||(ready==NULL)||(delayms==NULL)){return AD7192_InitError;}if(cs==NULL){adObj->ChipSelect=AD719xChipSelect;}else{adObj->ChipSelect=cs;}adObj->polar=polarity[polar];adObj->gain=gains[gain];adObj->Registers[REG_COM_STA]=0x00;adObj->Registers[REG_MODE]=0x00;adObj->Registers[REG_CONF]=0x00;adObj->Registers[REG_DATA]=0x00;adObj->Registers[REG_ID]=0x00;adObj->Registers[REG_GPOCON]=0x00;adObj->Registers[REG_OFFSET]=0x00;adObj->Registers[REG_FS]=0x00;adObj->ReadWrite=readWrite;adObj->GetReadyInput=ready;adObj->Delay=delayms;AD7192SoftwareReset(adObj);adObj->Delay(1);AD7192InternalZeroScaleCalibration(adObj,Channels);adObj->Delay(1);AD7192InternalFullScaleCalibration(adObj,Channels);/*讀取并存儲全部寄存器的值*/ReadAD7192Register(adObj,REG_COM_STA, 8, REG_COM_STA);return AD7192_OK; }2.2、對象操作
對象初始化后就可對其進(jìn)行操作。我們無論對AD7192進(jìn)行何種操作,其目的都是為了得到我們想要的數(shù)據(jù)。而從AD7192讀取轉(zhuǎn)換的結(jié)果有2種方式:單次獲取和連續(xù)獲取。接下來我們就按此來說明AD7192的驅(qū)動設(shè)計(jì)。
2.2.1、實(shí)現(xiàn)單次數(shù)據(jù)轉(zhuǎn)換
單次轉(zhuǎn)換模式下,AD7192 在完成轉(zhuǎn)換后處于關(guān)斷模式。 將模式寄存器中的MD2、MD1和MD0分別設(shè)置為0、0、1,便可啟動單次轉(zhuǎn)換,此時AD7192將上電,執(zhí)行單次轉(zhuǎn)換,然后返回關(guān)斷模式。時序圖如下所示:
單次轉(zhuǎn)換數(shù)據(jù)獲取具體實(shí)現(xiàn)代碼如下:
/*單次轉(zhuǎn)換數(shù)據(jù)獲取*/ uint32_t GetSingleConvertionValue(Ad7192ObjectType *adObj,uint32_t Channels) {uint32_t dataCode=0;AD7192StartSingleConvertion(adObj,Channels);adObj->Delay(1);dataCode = AD7192ReadConvertingData(adObj);dataCode =dataCode & 0x00FFFFFF;ReadAD7192Register(adObj,REG_DATA, 1,REG_DATA);return dataCode; }2.2.2、實(shí)現(xiàn)連續(xù)數(shù)據(jù)轉(zhuǎn)換
連續(xù)轉(zhuǎn)換模式是上電后的默認(rèn)轉(zhuǎn)換模式。AD7192連續(xù)轉(zhuǎn)換,每次完成轉(zhuǎn)換后,狀態(tài)寄存器中的RDY位變?yōu)榈碗娖健H绻?/span>CS為低電平,則完成一次轉(zhuǎn)換時,DOUT/RDY 線路也會變?yōu)榈碗娖健H粢x取轉(zhuǎn)換結(jié)果,用戶需要寫入通信寄存器,指示下一操作為讀取數(shù)據(jù)寄存器。從數(shù)據(jù)寄存器中讀取數(shù)據(jù)字后,DOUT/RDY變?yōu)楦唠娖健r序圖如下所示:
連續(xù)轉(zhuǎn)換數(shù)據(jù)獲取具體實(shí)現(xiàn)代碼如下:
/*連續(xù)轉(zhuǎn)換數(shù)據(jù)獲取,dataCodes為8個元素的數(shù)組對應(yīng)8個通道*/ void GettContinuousConvertionValue(Ad7192ObjectType *adObj,uint32_t Channels,uint32_t *dataCodes,int number) {uint32_t dataCode=0;uint8_t status=255;AD7192StartContinuousConvertion(adObj,Channels);for(int i=0;i<number;i++){dataCode = AD7192ReadConvertingData(adObj);status=((uint8_t)dataCode)&0x07;dataCode =(dataCode>>8) & 0x00FFFFFF;dataCodes[status]=dataCode;} }2.2.3、零點(diǎn)和量程校準(zhǔn)
零點(diǎn)和量程校準(zhǔn)包括內(nèi)部校準(zhǔn)和外部校準(zhǔn),我們這里使用內(nèi)部校準(zhǔn)。
/*內(nèi)部零點(diǎn)校準(zhǔn)*/ static void AD7192InternalZeroScaleCalibration(Ad7192ObjectType *adObj,uint32_t Channels) {//配置寄存器:斬波禁用,基準(zhǔn)電壓1,AI1-AI4單通道4路,禁用激勵電流,禁用基準(zhǔn)電壓檢測,禁用緩沖器adObj->Registers[REG_CONF] = 0;adObj->Registers[REG_CONF] = CHOP_DIS|REF_IN1|Channels|BURN_DIS|REFDET_DIS|BUF_DIS|adObj->polar|adObj->gain;WriteAD7192Register(adObj,REG_CONF,1);//模式寄存器:內(nèi)部零點(diǎn)校準(zhǔn),禁用狀態(tài)同傳,內(nèi)部時鐘輸出,斬波4,使能奇偶校驗(yàn),不分頻,僅用單周期轉(zhuǎn)換使能,禁用60Hz陷波,FS=128adObj->Registers[REG_MODE] = 0;adObj->Registers[REG_MODE] = MODE_INZCL|DAT_STA_DIS|INCLK_MCLK2EN|SINC_4|ENPAR_EN|CLK_DIV_DIS|SINGLECYCLE_DIS|REJ60_DIS|0x080;WriteAD7192Register(adObj,REG_MODE, 1);adObj->ChipSelect(AD7192CS_Enable);while(adObj->GetReadyInput()== 1){;}?????????????? //等待RDY為0;adObj->ChipSelect(AD7192CS_Disable); }/*內(nèi)部量程校準(zhǔn)*/ static void AD7192InternalFullScaleCalibration(Ad7192ObjectType *adObj,uint32_t Channels) {//配置寄存器:斬波禁用,基準(zhǔn)電壓1,AI1-AI4單通道4路,禁用激勵電流,禁用基準(zhǔn)電壓檢測,禁用緩沖器adObj->Registers[REG_CONF] = 0;adObj->Registers[REG_CONF] = CHOP_DIS|REF_IN1|Channels|BURN_DIS|REFDET_DIS|BUF_DIS|adObj->polar|adObj->gain;WriteAD7192Register(adObj,REG_CONF, 1);//模式寄存器:內(nèi)部量程校準(zhǔn),禁用狀態(tài)同傳,內(nèi)部時鐘輸出,斬波4,使能奇偶校驗(yàn),不分頻,禁用單周期轉(zhuǎn)換使能,禁用60Hz陷波,FS=128adObj->Registers[REG_MODE] = 0;adObj->Registers[REG_MODE] = MODE_INFCL|DAT_STA_DIS|INCLK_MCLK2EN|SINC_4|ENPAR_EN|CLK_DIV_2|SINGLECYCLE_DIS|REJ60_DIS|0x080;?????????????WriteAD7192Register(adObj,REG_MODE, 1);adObj->ChipSelect(AD7192CS_Enable);while(adObj->GetReadyInput()== 1){;}?????????????? //等待RDY為0;adObj->ChipSelect(AD7192CS_Disable); }2.2.4、實(shí)現(xiàn)內(nèi)部溫度轉(zhuǎn)換
AD7192內(nèi)置一個溫度傳感器。利用配置寄存器中的CH2位可以選擇溫度傳感器。如果CH2位設(shè)置為1,就會使能溫度傳感器。使用溫度傳感器并選擇雙極性模式時,如果溫度為0K,器件應(yīng)返回0x800000碼。為使傳感器發(fā)揮最佳性能,需要執(zhí)行單點(diǎn)校準(zhǔn)。因此,應(yīng)記錄25°C 時的轉(zhuǎn)換結(jié)果并計(jì)算靈敏度。 靈敏度約為2815碼 /°C。溫度傳感器的計(jì)算公式為 :
溫度 (K) = ( 轉(zhuǎn)換結(jié)果 – 0x800000)/2815 K
溫度 (°C) = 溫度 (K) – 273
單點(diǎn)校準(zhǔn)之后,內(nèi)部溫度傳感器的精度典型值為 ±2°C。具體的實(shí)現(xiàn)代碼如下:
/*讀取內(nèi)部溫度數(shù)據(jù),返回?cái)z氏度溫度*/ float GetTemperatureValue(Ad7192ObjectType *adObj) {uint32_t temperatureCode=0;float temp = 0.0;//模式寄存器:單次轉(zhuǎn)換模式,禁用狀態(tài)同傳,內(nèi)部時鐘輸出,斬波4,使能奇偶校驗(yàn),不分頻,禁用單周期轉(zhuǎn)換使能,禁用60Hz陷波,FS=128adObj->Registers[REG_MODE] = 0;adObj->Registers[REG_MODE] = MODE_SING|DAT_STA_DIS|INCLK_MCLK2EN|SINC_4|ENPAR_EN|CLK_DIV_DIS|SINGLECYCLE_DIS|REJ60_DIS|0x080;WriteAD7192Register(adObj,REG_MODE, 1);//配置寄存器:斬波禁用,基準(zhǔn)電壓1,內(nèi)部溫度,禁用激勵電流,禁用基準(zhǔn)電壓檢測,禁用緩沖器adObj->Registers[REG_CONF] = 0;?adObj->Registers[REG_CONF] = CHOP_DIS|REF_IN1|TEMP|BURN_DIS|REFDET_DIS|BUF_DIS|UB_BI|GAIN_1;WriteAD7192Register(adObj,REG_CONF, 1);temperatureCode = AD7192ReadConvertingData(adObj);temp = (temperatureCode-0x800000)/2815.0-273;return temp; }3、驅(qū)動的使用
我們已經(jīng)設(shè)計(jì)并實(shí)現(xiàn)了AD7192模數(shù)轉(zhuǎn)換器的驅(qū)動。現(xiàn)在我們將考慮如何使用這一驅(qū)動實(shí)現(xiàn)基于AD7192模數(shù)轉(zhuǎn)換器的簡單應(yīng)用。
3.1、聲明并初始化對象
使用基于對象的操作我們需要先得到這個對象,所以我們先要使用前面定義的AD7192模數(shù)轉(zhuǎn)換器對象類型聲明一個AD7192模數(shù)轉(zhuǎn)換器對象變量,具體操作格式如下:
Ad7192ObjectType ad7192;
聲明了這個對象變量并不能立即使用,我們還需要使用驅(qū)動中定義的初始化函數(shù)對這個變量進(jìn)行初始化。這個初始化函數(shù)所需要的輸入?yún)?shù)如下:
Ad7192ObjectType *adObj,所要初始化的對象變量
uint32_t Channels,需要初始化的通道
AD7192PolarType polar,通道初始化的極性
AD7192GainType gain,通道的增益
AD7192ReadWriteType readWrite,讀寫操作函數(shù)
AD7192ChipSelectType cs,片選信號操作函數(shù)
AD7192GetReadyInputType ready,就緒信號檢測函數(shù)
AD7192DelaymsType delayms,毫秒延時函數(shù)
對于這些參數(shù),對象變量我們已經(jīng)定義了。所需要初始化的通道、通道的信號極性、采用的增益倍數(shù)根據(jù)實(shí)際情況選擇,通道為宏定義、極性和增益為枚舉。主要的是我們需要定義幾個函數(shù),并將函數(shù)指針作為參數(shù)。這幾個函數(shù)的類型如下:
/*定義讀寫操作函數(shù)指針類型*/ typedef void (*AD7192ReadWriteType)(uint8_t *wData,uint8_t *rData,uint16_t size);/*實(shí)現(xiàn)片選*/ typedef void (*AD7192ChipSelectType)(AD7192CSType cs);/*實(shí)現(xiàn)Ready狀態(tài)監(jiān)視*/ typedef uint16_t (*AD7192GetReadyInputType)(void);/*實(shí)現(xiàn)ms延時操作*/ typedef void (*AD7192DelaymsType)(volatile uint32_t nTime);對于這幾個函數(shù)我們根據(jù)樣式定義就可以了,具體的操作可能與使用的硬件平臺有關(guān)系。片選操作函數(shù)用于多設(shè)備需要軟件操作時,如采用硬件片選可以傳入NULL即可。具體函數(shù)定義如下:
/*定義讀寫操作函數(shù)指針類型*/ void AD7192ReadWrite(uint8_t *wData,uint8_t *rData,uint16_t size) {HAL_SPI_TransmitReceive(&ad77192hspi,wData,rData,size,1000); }/*實(shí)現(xiàn)片選*/ void AD7192ChipSelect(AD7192CSType cs) {if(AD7192CS_Enable==cs){HAL_GPIO_WritePin(GPIOF, GPIO_PIN_4, GPIO_PIN_RESET);}else{HAL_GPIO_WritePin(GPIOF, GPIO_PIN_4, GPIO_PIN_SET);} }/*實(shí)現(xiàn)Ready狀態(tài)監(jiān)視*/ uint16_t AD7192GetReadyInput(void) {return HAL_GPIO_ReadPin(GPIOC,GPIO_PIN_0); }對于延時函數(shù)我們可以采用各種方法實(shí)現(xiàn)。我們采用的STM32平臺和HAL庫則可以直接使用HAL_Delay()函數(shù)。于是我們可以調(diào)用初始化函數(shù)如下:
AD7192Initialization(&ad7192,AIN1_AIN2|AIN3_AIN4,AD7192_Unipolar,AD7192Gain1,AD7192ReadWrite,AD7192ChipSelect,AD7192GetReadyInput,HAL_Delay);
3.2、基于對象進(jìn)行操作
我們定義了對象變量并使用初始化函數(shù)給其作了初始化。接著我們就來考慮操作這一對象獲取我們想要的數(shù)據(jù)。在驅(qū)動中我們已經(jīng)封裝了單次或是連續(xù)獲取某一通道模數(shù)轉(zhuǎn)換數(shù)據(jù)的函數(shù)。接下來我們就采用我們封裝的AD7192數(shù)模轉(zhuǎn)換其的驅(qū)動獲取通道的數(shù)據(jù)。
/* 單次獲取兩個差分通道的值 */ void GetDifferentialData(void) {uint16_t dataCode[2];dataCode[0]=GetSingleConvertionValue(&ad7192,AIN1_AIN2);dataCode[1]=GetSingleConvertionValue(&ad7192,AIN3_AIN4); }因?yàn)槌跏蓟瘮?shù)初始化為兩個差分通道,所以我們的函數(shù)就是獲取了兩個差分通道的轉(zhuǎn)換值。獲取了ADC的數(shù)據(jù)后就可以根據(jù)每個通道所對應(yīng)的物理量量程范圍計(jì)算得到物理量值。
4、應(yīng)用總結(jié)
在這一篇中我們設(shè)計(jì)并實(shí)現(xiàn)了AD7192數(shù)模轉(zhuǎn)換器的驅(qū)動程序。并使用這一驅(qū)動程序?qū)崿F(xiàn)了單次獲取兩個差分通道轉(zhuǎn)換數(shù)據(jù)的簡單應(yīng)用。得到了我們想要的結(jié)果,這說明我們的驅(qū)動設(shè)計(jì)是正確的。
在使用驅(qū)動時需要注意。選擇通道時,由于可以是2個差分通道和4個單端通道,所以差分通道一不可以與AIN1、AIN2同時使用,同樣的差分通道二不能與AIN3、AIN4同時使用。
在使用驅(qū)動時需注意,采用SPI接口的器件需要考慮片選操作的問題。如果片選信號是通過硬件電路來實(shí)現(xiàn)的,我們在初始化時給其傳遞NULL值。如果是軟件操作片選則傳遞我們編寫的片選操作函數(shù)。
完整的源代碼可在GitHub下載:https://github.com/foxclever/ExPeriphDriver
歡迎關(guān)注:
總結(jié)
以上是生活随笔為你收集整理的外设驱动库开发笔记6:AD719x系列ADC驱动的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 外设驱动库开发笔记19:BMP280压力
- 下一篇: STM32一种基于NTC的控温电路及软件