紅外溫度傳感器一般用於非接觸式的溫度檢測。在我們的系統中經常會有這樣的需求。所以我們將其設計為通用的驅動庫以備復用。這一篇我們將講述MLX90614紅外溫度傳感器驅動的設計與實現。
1、功能概述
MLX90614是一種紅外溫度計,用於非接觸式溫度測量。紅外測溫是根據被測物體的紅外輻射能量來確定物體的溫度,不與被測物體接觸,具有不影響被測物體溫度分布場,溫度分辨率高、響應速度快、測溫范圍廣、不受測溫上限的限制、穩定性好等特點。MLX90614被測目標溫度和環境溫度通過IIC接口輸出,適合於汽車空調、室內暖氣、家用電器、手持設備以及醫療設備應用等。
1.1、硬件描述
MLX90614 是一款無接觸式的紅外線溫度感應芯片,它在同一TO-39封裝內整合了紅外熱電堆感應器與一款定制的信號調節芯片。MLX90614在信號調節芯片中使用了先進的低噪音放大器,一枚17-bit ADC以及功能強大的DSP元件, 從而實現高精度溫度測量。其引腳封裝及功能如下:
MLX90614的出廠校准溫度范圍很廣:環境溫度為-40°C…125°C,目標溫度為-70°C…380°C。測量值是傳感器視場中所有物體的平均溫度。在室溫下,MLX90614的標准精確度為±0.5度。有一種特殊的醫療應用版本,在人體體溫的有限溫度范圍內精確呈現±0.2恆溫。
1.2、數據通訊
MLX90614紅外溫度傳感器具有數字PWM和SMBus(系統管理總線)輸出。10位PWM作為標准配置,可以在-20…120完美呈現測量溫度,輸出分辨率為0.14完美呈現。工廠默認的設置是SMBus總線接口。
MLX90614紅外溫度傳感器又有一個參數存儲EEPROM內存。在EEPROM內存中有限數量的地址可以由客戶更改,這些地址存儲着傳感器可修改配置信息。整個EEPROM都可以通過SMBus接口讀取。具體分配如下:
在這個EEPROM中,我們需要注意的有PWM控制寄存器以及配置寄存器。PWMCTRL寄存器的各位定義如下:
ConfigRegister1由控制位組成,用於配置模擬和數字部分,ConfigRegister1寄存器的各位定義如下:
MLX90614紅外溫度傳感器還擁有一個32個字的RAM。用於存儲一些實時更新的數據,如我們的測量數據。這一部分是只讀的,其地址分配如下:
我們了解了MLX90614紅外溫度傳感器的EEPROM和RAM的地址分配,它們的地址是分別編碼的,似乎看不出差別。那我們如何能來區別訪問它們呢?於是MLX90614紅外溫度傳感器定義有如下的功能碼:
讀寫EEPROM和RAM的命令,前三位表示命令,后5為對應所讀參數在EEPROM和RAM中的地址。標志位是只讀的,MLX90614在16位數據之后返回PEC,其中只有4位是有意義的,如果MD需要它,它可以在第一個字節之后停止通信。讀數據和讀標志的區別在於后者沒有重復的起始位。
MLX90614紅外溫度傳感器設備地址默認為0xB4,可以通過寫EEPROM來修改設備地址。
2、驅動設計與實現
我們已經了解了MLX90614紅外溫度傳感器的基本情況,接下來我們將根據這些資料開發MLX90614紅外溫度傳感器的驅動程序。
2.1、對象定義
在使用一個對象之前我們需要獲得一個對象。同樣的我們想要使用MLX90614紅外溫度傳感器對象就需要先定義MLX90614紅外溫度傳感器的對象。
2.1.1、對象的抽象
我們要得到MLX90614溫度傳感器對象,需要先分析其基本特性。一般來說,一個對象至少包含兩方面的特性:屬性與操作。接下來我們就來從這兩個方面思考一下MLX90614溫度傳感器的對象。
先來考慮屬性,作為屬性肯定是用於標識或記錄對象特征的東西。我們來考慮MLX90614紅外溫度傳感器對象屬性。作為SMBus總線設備需要一個設備地址,這一地址用來區分總線上不同設備,所以我們將設備地址作為它的一個屬性。對象的狀態標識,PWM控制寄存器、配置寄存器都只是了MLX90614紅外溫度傳感器當前所處的狀態,所以我們將它們也作為屬性。設備ID號是唯一標識各個MLX90614紅外溫度傳感器的,我們也將其作為屬性。測量的溫度信號也表示了MLX90614紅外溫度傳感器當前的狀態,我們也將他們作為屬性。標志寄存器在MLX90614紅外溫度傳感器中是16位的,但真正有效的只有4位,所以我們以8位表示。
接着我們還需要考慮MLX90614紅外溫度傳感器對象的操作問題。對於MLX90614紅外溫度傳感器來說,我們需要對它進行讀數據和寫數據,而讀寫操作依賴於具體的硬件平台,所以我們將其作為對象的操作,以回調函數的方式使用。在操作MLX90614紅外溫度傳感器的過程中,有些時序需要控制,所以需要延時函數,但延時操作依賴於具體的軟硬件平台,所以我們將其作為對象的操作,以回調函數的方式使用。
根據上述我們對MLX90614紅外溫度傳感器的分析,我們可以定義MLX90614紅外溫度傳感器的對象類型如下:
1 typedef struct MLXObject { 2 uint8_t devAddress; //對象的地址 3 uint8_t flags; //對象狀態標志 4 uint16_t pwmctrl; //PWM控制寄存器 5 uint16_t ConfigRegister; //配置寄存器 6 uint16_t ID[4]; //對象的ID值 7 float tempAmbient; //溫度值 8 float tempObject1; //溫度值 9 float tempObject2; //溫度值 10 void (*Read)(struct MLXObject *mlx,uint8_t cmd,uint8_t *rData,uint16_t rSize); //讀數據操作指針 11 void (*Write)(struct MLXObject *mlx,uint8_t cmd,uint8_t *wData,uint16_t wSize); //寫數據操作指針 12 void (*Delayus)(volatile uint32_t nTime); //延時操作指針 13 }MLXObjectType;
2.1.2、對象初始化
我們知道,一個對象僅作聲明是不能使用的,我們需要先對其進行初始化,所以這里我們來考慮MLX90614紅外溫度傳感器對象的初始化函數。一般來說,初始化函數需要處理幾個方面的問題。一是檢查輸入參數是否合理;二是為對象的屬性賦初值;三是對對象作必要的初始化配置。據此我們設計MLX90614紅外溫度傳感器對象的初始化函數如下:
1 /* 紅外溫度傳感器對象初始化 */ 2 void MLXInitialization(MLXObjectType *mlx, //MLX90614對象 3 uint8_t address, //設備地址 4 MLXRead read, //讀數據函數指針 5 MLXWrite write, //寫數據函數指針 6 MLXDelayus delayus //微秒岩石函數指針 7 ) 8 { 9 if((mlx==NULL)||(read==NULL)||(write==NULL)||(delayus==NULL)) 10 { 11 return; 12 } 13 mlx->Read=read; 14 mlx->Write=write; 15 mlx->Delayus=delayus; 16 17 mlx->tempAmbient=0.0; 18 mlx->tempObject1=0.0; 19 mlx->tempObject2=0.0; 20 21 if(address>0x00) 22 { 23 mlx->devAddress=address; 24 } 25 else 26 { 27 mlx->devAddress=MLXSlaveAddress; 28 } 29 30 mlx->Delayus(200); 31 32 GetIDFromMLX90614(mlx); 33 34 mlx->flags=(uint8_t)ReadFlagFromMLX(mlx); 35 36 mlx->pwmctrl=ReadDataFromMLX(mlx,EEPROMAccess|PWMCTRL); 37 38 mlx->ConfigRegister=ReadDataFromMLX(mlx,EEPROMAccess|ConfigRegister1); 39 }
2.2、對象操作
我們已經完成了MLX90614紅外溫度傳感器對象類型的定義和對象初始化函數的設計。但我們的主要目標是獲取對象的信息,接下來我們還要實現面向MLX90614紅外溫度傳感器的各類操作。
2.2.1、讀數據操作
我們需要從MLX90614紅外溫度傳感器讀取數據,不管這個數據是在EEPROM還是在RAM,我們都可以采用相同的方式讀取。我們已經說過,操作EEPROM和RAM的命令字節由3位命令和5位地址組成。我們實現數據讀取函數如下:
1 /*讀數據操作*/ 2 static uint16_t ReadDataFromMLX(MLXObjectType *mlx,uint8_t cmd) 3 { 4 uint8_t data[3]; 5 uint16_t tempCode=0; 6 uint8_t pec[6]; 7 8 mlx->Read(mlx,cmd,data,3); 9 10 pec[0]=mlx->devAddress; 11 pec[1]=cmd; 12 pec[2]=mlx->devAddress+1; 13 pec[3]=data[0]; 14 pec[4]=data[1]; 15 pec[5]=data[2]; 16 17 if(PECCalculation(pec,6)==0x00) 18 { 19 tempCode=(data[1]<<8)+data[0]; 20 } 21 22 return tempCode; 23 }
2.2.2、寫數據操作
我們需要向MLX90614紅外溫度傳感器寫一些數據用以配置傳感器,這些可寫的寄存器處於EEPROM之中,如配置寄存器、PWM控制信息、設備地址等。這里我們設計一個配置這些數據的操作函數。
1 /* 寫數據操作 */ 2 static void WriteDataToMLX(MLXObjectType *mlx,uint8_t cmd,uint16_t data) 3 { 4 uint8_t wData[3]; 5 uint8_t pec[4]; 6 7 pec[0]=mlx->devAddress; 8 pec[1]=cmd; 9 pec[2]=(uint8_t)data; 10 pec[3]=(uint8_t)(data>>8); 11 12 wData[0]=(uint8_t)data; 13 wData[1]=(uint8_t)(data>>8); 14 wData[2]=PECCalculation(pec,4); 15 16 mlx->Write(mlx,cmd,wData,3); 17 }
2.2.3、操作休眠模式
有些時候在我們不使用設備時,我們希望能夠讓設備休眠以節省資源,在需要時再將其喚醒投入工作。MLX90614具備有休眠的功能,這里我們看看如何使用這一功能。
1 /* 使設備進入休眠模式 */ 2 void EnterSleepModeForMLX(MLXObjectType *mlx) 3 { 4 uint8_t cmd; 5 static uint8_t pec; 6 uint8_t data[2]; 7 8 cmd=EnterSLEEPMode; 9 10 data[0]=mlx->devAddress; 11 data[1]=cmd; 12 13 pec=PECCalculation(data,2); 14 15 mlx->Write(mlx,cmd,&pec,1); 16 }
3、驅動的使用
我們已經設計並實現了MLX90614紅外溫度傳感器的驅動程序。我們還需要對這一驅動進行驗證。接下來我們將基於這一驅動程序開發獲取MLX90614紅外溫度傳感器數據的簡單應用。
3.1、聲明並初始化對象
使用基於對象的操作我們需要先得到這個對象,所以我們先要使用前面定義的MLX90614紅外溫度傳感器對象類型聲明一個MLX90614紅外溫度傳感器對象變量,具體操作格式如下:
MLXObjectType mlx;
我們聲明了這個對象變量,但還不能立即使用。我們還需要使用驅動中定義的初始化函數對這個對象變量進行初始化。初始化函數有一些用於對象初始化的參數需要輸入:
MLXObjectType *mlx,MLX90614對象
uint8_t address,設備地址
MLXRead read,讀數據函數指針
MLXWrite write,寫數據函數指針
MLXDelayus delayus,微秒延時函數指針
對於這些參數,對象變量我們已經定義了,它正是我們需要初始化的對象。在這些參數中,我們需要注意的是幾個函數指針,我們需要在應用中定義這幾個函數,並將函數指針作為參數。這幾個函數的類型如下:
1 /*定義讀MLX90614數據操作指針類型*/ 2 typedef void (*MLXRead)(struct MLXObject *mlx,uint8_t cmd,uint8_t *rData,uint16_t rSize); 3 /*定義寫MLX90614數據操作指針類型*/ 4 typedef void (*MLXWrite)(struct MLXObject *mlx,uint8_t cmd,uint8_t *wData,uint16_t wSize); 5 /*定義微秒延時操作指針類型*/ 6 typedef void (*MLXDelayus)(volatile uint32_t nTime);
對於這幾個函數我們根據樣式定義就可以了,具體的操作可能與使用的軟硬件平台有關系。在這里我們使用STM32F4的第2個I2C接口及其外設庫,所以具體函數定義如下:
1 /*從MLX90614接收數據*/ 2 static void ReceiveFromMLX(MLXObjectType *mlx,uint8_t cmd,uint8_t *rData,uint16_t rSize) 3 { 4 HAL_I2C_Master_Transmit(&hlpti2c,mlx->devAddress,&cmd,1,1000); 5 6 HAL_I2C_Master_Receive(&hlpti2c, mlx->devAddress,rData, rSize, 1000); 7 } 8 9 /*向MLX90614傳送數據*/ 10 static void TransmitToMLX(MLXObjectType *mlx,uint8_t cmd,uint8_t *tData,uint16_t tSize) 11 { 12 uint8_t data[10]; 13 data[0]=cmd; 14 15 for(int i=0;i<tSize;i++) 16 { 17 data[i+1]=tData[i]; 18 } 19 20 HAL_I2C_Master_Transmit(&hlpti2c,mlx->devAddress,data,tSize+1,1000); 21 }
對於延時函數我們可以采用各種方法實現。我們采用的STM32平台和HAL庫則可以直接使用HAL_Delay()函數。於是我們可以調用初始化函數如下:
MLXInitialization(&mlx,0xB4,ReceiveFromMLX,TransmitToMLX,HAL_Delay);
3.2、基於對象進行操作
我們定義了對象變量並使用初始化函數給其作了初始化。接着我們就來考慮操作這一對象獲取我們想要的數據。我們在驅動中已經將獲取數據並轉換為轉換值的比例值,接下來我們使用這一驅動開發我們的應用實例。
1 /*讀取溫度值*/ 2 void GetTemperatureDataFromMLX(void) 3 { 4 float tempObject; 5 float tempAmbient; 6 7 GetMLXTemperature(&mlx); 8 9 tempObject=mlx.tempObject1; 10 tempAmbient=mlx.tempAmbient; 11 }
4、應用總結
我們設計並實現了MLX90614紅外溫度傳感器的驅動程序,並在此基礎上設計了一個簡單的應用來驗證之。事實上我們在實際項目中也是使用這一驅動程序來實現應用的,並且效果良好。
讀標志與讀數據在時序控制上是有一些差別的,下發命令與接收數據之間沒有重啟的操作,這一點在操作它時需要注意。
我們在使用驅動時,一般會選擇使用GPIO模擬的I2C收發器,這樣穩定性更好。而使用硬件I2C接口及其庫函數實現時,經常會有死鎖的事情發生。我們曾多次遇到,特別是在STM32的第一路I2C接口。至於第1路I2C接口與其它的I2C接口有什么差異尚未確定。總之使用GPIO模擬I2C收發器更為穩定。