目錄
1、項目概述
2、模組簡介
2.1、NSA2862物聯網專用橋式傳感器調理晶片
2.2、Metallux ME501/ME505陶瓷壓力傳感器
3、驅動原理
4、項目實作
近期基于Metallux ME501/ME505陶瓷壓力傳感器模組和NSA2862物聯網調理晶片設計一款工業級壓力傳感器,并使用華大半導體HC32L136 MCU實作控制,特将項目心得與體會分享給各位朋友,目前全網僅此一篇,請多多支援~
本項目傳感器基于Metallux ME501/ME505陶瓷壓力傳感器模組和納芯微NSA2862物聯網調理晶片,微控制器基于華大半導體HC32L136,在保證高性能的前提下,支援待機與休眠喚醒,具備超低的功耗,可連續工作10年而無需更換電池,可大規模應用在智慧城市、工業物聯網等領域。
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLicmbw5iNkRmZ5YGO5czNkZmN1QTYiZTM0U2NhJGNxMjN2IWZj9CX5d2bs92Yl1iclB3bsVmdlR2LcNWaw9CXt92Yu4GZjlGbh5yYjV3Lc9CX6MHc0RHaiojIsJye.png)
參數特性所示所示:
超低待機功耗:<100nA
低溫漂内置參考電壓
高精度 1X~256X增益可變儀表放大器
24位 ADC用于主信号測量
24位 ADC用于溫度測量
支援内置溫度傳感器和外部溫度傳感器
雙路恒流源輸出
1X~8X ADC數字增益
多種 ODR 設定,支援 50/60Hz 工頻抑制
基于内置 MCU的通用傳感器校準邏輯
EEPROM,可多次程式設計
支援 SPI和 I2C及OWI接口
封裝:TSSOP20
工作溫度範圍:-40℃~105℃
晶片功能框圖如下圖所示:
壓力傳感器一般用于對傳感器敏感器件所處氣體或液體氛圍的壓力測量,一般用于回報給系統主要單元,實作系統精确控制。壓力傳感器作為傳感器中的一大門類,在汽車、工業、家電、消費電子等不同行業均有廣泛的應用。常用壓力傳感器從感測原理來區分,主要包括如下幾大類:
矽壓阻技術
陶瓷電阻技術
玻璃微熔技術
陶瓷電容技術
矽壓阻技術由半導體的壓阻特性來實作,半導體材料的壓阻特性取決于材料種類、摻雜濃度和晶體的晶向等因素。該技術可以采用半導體工藝實作,具有尺寸小,産量高、成本低、信号輸出靈敏度高等優勢。不足之處主要展現在媒體耐受程度低,溫度特性差和長期穩定性較差等方面。常見于中低壓量程範圍,如5kPa~700kPa。業界也有通過特殊封裝工藝提高矽壓阻技術的媒體耐受程度的方案,如充油、背壓等技術,但也會帶來成本大幅增加等問題。
陶瓷電阻技術采用厚膜印刷工藝将惠斯通電橋印刷在陶瓷結構的表面,利用壓敏電阻效應,實作将媒體的壓力信号轉換為電壓信号。陶瓷電阻技術具有成本适中,工藝簡單等優勢,目前國内有較多廠家提供陶瓷電阻壓力傳感器芯體。但該技術信号輸出靈敏度低,量程一般限定在500kPa~10MPa,且正常中空結構,僅靠膜片承壓,抗過載能力差,當待測媒體壓力過載時,陶瓷電阻傳感器會存在膜片破裂,媒體洩露的風險。
玻璃微熔技術采用高溫燒結工藝,将矽應變計與不鏽鋼結構結合。矽應變計等效的四個電阻組成惠斯通電橋,當不鏽鋼膜片的另一側有媒體壓力時,不鏽鋼膜片産生微小形變引起電橋變化,形成正比于壓力變化的電壓信号。玻璃微熔工藝實作難度較大,成本高。主要優勢是媒體耐受性好,抗過載能力強,一般适用于高壓和超高壓量程,如10MPa~200MPa,應用較為受限。
陶瓷電容技術采用固定式陶瓷基座和可動陶瓷膜片結構,可動膜片通過玻璃漿料等方式與基座密封固定在一起。兩者之間内側印刷電極圖形,進而形成一個可變電容,當膜片上所承受的媒體壓力變化時兩者之間的電容量随之發生變化,通過調理晶片将該信号進行轉換調理後輸出給後級使用。陶瓷電容技術具有成本适中,量程範圍寬,溫度特性好、一緻性、長期穩定性好等優勢。國際上來看廣泛應用于汽車與工業過程控制等領域,分别以美國森薩塔和瑞士E+H為代表。由于電容信号不同于電阻信号,對信号處理電路要求較高,傳感器設計時需要将電容和信号調理晶片ASIC協同考慮,國内目前僅蘇州納芯微電子股份有限公司能夠同時提供兩者整合的完整解決方案。
陶瓷電容作為壓力傳感器中一種主要技術路線,主要由瓷環、陶瓷膜片和陶瓷蓋闆三部分組成,具有耐腐蝕、抗沖擊、媒體相容性好的優點。Metallux ME501/ME505傳感器工作原理是陶瓷電阻技術,其由雷射可調PTC電阻進行熱補償,陶瓷的使用確定了整個測量範圍内的高線性度,将遲滞效應降到最低,傳感器結構如下所示:
本項目中微控制器華大半導體HC32L136驅動NSA2862傳感器調理晶片基于I2C通信協定,I2C 是雙線雙向的同步串行總線,它利用一根時鐘線和一根資料線在連接配接總線的兩個器件之間進行資訊的傳遞,為裝置之間資料交換提供了一種簡單高效的方法。每個連接配接到總線上的器件都有唯一的位址,任何器件既可以作為主機也可以作為從機,但同一時刻隻允許有一個主機。I2C 标準是一個具有沖突檢測機制和仲裁機制的真正意義上的多主機總線,它能在多個主機同時請求控制總線時利用仲裁機制避免資料沖突并保護資料。I2C 總線控制器,能滿足 I2C 總線的各種規格并支援所有與 I2C 總線通信的傳輸模式。
通常标準 I2C 傳輸協定包含四個部分:起始(S)或重複起始信号(Sr),從機位址及讀寫位,傳輸資料,停止信号(P)。I2C 傳輸協定圖如下所示:
當起始信号産生後,主機立即傳輸資料的第一位元組:7 位從機位址 + 讀寫位,讀寫位控制從機的資料傳輸方向(0:寫;1:讀)。被主機尋址的從機會通過在第 9 個 SCL時鐘周期将 SDA 置為低電平作為應答。
資料傳輸過程中,一個 SCL 時鐘脈沖傳輸一個資料位,且 SDA 線隻有在 SCL 為低時才可以改變。I2C 總線上位傳輸圖如下所示:
華大半導體I2C 元件可實作 8 位的雙向資料傳輸,傳輸速率在标準模式下可達到 100Kbps 而在高速模式下可達 400Kbps,在超高速模式下可達 1Mbps,并且可以在四種模式下工作:主機發送模式、主機接收模式、從機接收模式、從機發送模式。 還有一種特殊模式廣播呼叫模式,其操作方式與從機接收模式類似。
華大半導體HC32L136 I2C 控制器支援以下特性:
支援主機發送/接收,從機發送/接收四種工作模式
支援标準(100Kbps) / 快速(400Kbps) / 高速(1Mbps) 三種工作速率
支援 7 位尋址功能
支援噪聲過濾功能
支援廣播位址
支援中斷狀态查詢功能
I2C功能子產品如下圖所示:
///< IO端口配置
void App_PortCfg(void)
{
stc_gpio_cfg_t stcGpioCfg;
DDL_ZERO_STRUCT(stcGpioCfg);
Sysctrl_SetPeripheralGate(SysctrlPeripheralGpio,TRUE); //開啟GPIO時鐘門控
stcGpioCfg.enDir = GpioDirOut; ///< 端口方向配置->輸出
stcGpioCfg.enOD = GpioOdEnable; ///< 開漏輸出
stcGpioCfg.enPu = GpioPuEnable; ///< 端口上拉配置->使能
stcGpioCfg.enPd = GpioPdDisable; ///< 端口下拉配置->禁止
Gpio_Init(GpioPortB,GpioPin8,&stcGpioCfg); ///< 端口初始化
Gpio_Init(GpioPortB,GpioPin9,&stcGpioCfg);
Gpio_SetAfMode(GpioPortB,GpioPin8,GpioAf1); ///< 配置PB08為SCL
Gpio_SetAfMode(GpioPortB,GpioPin9,GpioAf1); ///< 配置PB09為SDA
}
I2C配置代碼如下所示:
///< I2C 子產品配置
void App_I2cCfg(void)
{
stc_i2c_cfg_t stcI2cCfg;
DDL_ZERO_STRUCT(stcI2cCfg); ///< 初始化結構體變量的值為0
Sysctrl_SetPeripheralGate(SysctrlPeripheralI2c0,TRUE); ///< 開啟I2C0時鐘門控
stcI2cCfg.u32Pclk = Sysctrl_GetPClkFreq(); ///< 擷取PCLK時鐘
stcI2cCfg.u32Baud = 100000; ///< 100K
stcI2cCfg.enMode = I2cMasterMode; ///< 主機模式
stcI2cCfg.bGc = FALSE; ///< 廣播位址應答使能關閉
I2C_Init(M0P_I2C0,&stcI2cCfg); ///< 子產品初始化
}
第3步:編寫接收驅動函數,主機接收狀态圖如下所示:
接收驅動代碼如下所示:
/**
******************************************************************************
** \brief 主機接收函數
**
** \param u8Addr從機記憶體位址,pu8Data讀資料存放緩存,u32Len讀資料長度
**
** \retval 讀資料是否成功
**
******************************************************************************/
en_result_t I2C_MasterReadData(M0P_I2C_TypeDef* I2CX,uint8_t u8Addr,uint8_t *pu8Data,uint32_t u32Len)
{
en_result_t enRet = Error;
uint8_t u8i=0,u8State;
I2C_SetFunc(I2CX,I2cStart_En);
while(1)
{
while(0 == I2C_GetIrq(I2CX))
{}
u8State = I2C_GetState(I2CX);
switch(u8State)
{
case 0x08: ///< 已發送起始條件,将發送SLA+W
I2C_ClearFunc(I2CX,I2cStart_En);
I2C_WriteByte(I2CX,I2C_SLAVEADDR);
break;
case 0x18: ///< 已發送SLA+W,并接收到ACK
I2C_WriteByte(I2CX,u8Addr); ///< 發送從機記憶體位址
break;
case 0x28: ///< 已發送資料,接收到ACK, 此處是已發送從機記憶體位址u8Addr并接收到ACK
I2C_SetFunc(I2CX,I2cStart_En); ///< 發送重複起始條件
break;
case 0x10: ///< 已發送重複起始條件
I2C_ClearFunc(I2CX,I2cStart_En);
I2C_WriteByte(I2CX,I2C_SLAVEADDR|0x01);///< 發送SLA+R,開始從從機讀取資料
break;
case 0x40: ///< 已發送SLA+R,并接收到ACK
if(u32Len>1)
{
I2C_SetFunc(I2CX,I2cAck_En); ///< 使能主機應答功能
}
break;
case 0x50: ///< 已接收資料位元組,并已傳回ACK信号
pu8Data[u8i++] = I2C_ReadByte(I2CX);
if(u8i==u32Len-1)
{
I2C_ClearFunc(I2CX,I2cAck_En); ///< 已接收到倒數第二個位元組,關閉ACK應答功能
}
break;
case 0x58: ///< 已接收到最後一個資料,NACK已傳回
pu8Data[u8i++] = I2C_ReadByte(I2CX);
I2C_SetFunc(I2CX,I2cStop_En); ///< 發送停止條件
break;
case 0x38: ///< 在發送位址或資料時,仲裁丢失
I2C_SetFunc(I2CX,I2cStart_En); ///< 當總線空閑時發起起始條件
break;
case 0x48: ///< 發送SLA+R後,收到一個NACK
I2C_SetFunc(I2CX,I2cStop_En); ///< 發送停止條件
I2C_SetFunc(I2CX,I2cStart_En); ///< 發送起始條件
break;
default:
I2C_SetFunc(I2CX,I2cStart_En); ///< 其他錯誤狀态,重新發送起始條件
break;
}
I2C_ClearIrq(I2CX); ///< 清除中斷狀态标志位
if(u8i==u32Len) ///< 資料全部讀取完成,跳出while循環
{
break;
}
}
enRet = Ok;
return enRet;
}
第4步:編寫發送驅動函數,主機發送狀态圖如下所示:
發送驅動代碼如下所示:
/**
******************************************************************************
** \brief 主機發送函數
**
** \param u8Addr從機記憶體位址,pu8Data寫資料,u32Len寫資料長度
**
** \retval 寫資料是否成功
**
******************************************************************************/
en_result_t I2C_MasterWriteData(M0P_I2C_TypeDef* I2CX,uint8_t u8Addr,uint8_t *pu8Data,uint32_t u32Len)
{
en_result_t enRet = Error;
uint8_t u8i=0,u8State;
I2C_SetFunc(I2CX,I2cStart_En);
while(1)
{
while(0 == I2C_GetIrq(I2CX))
{;}
u8State = I2C_GetState(I2CX);
switch(u8State)
{
case 0x08: ///< 已發送起始條件
I2C_ClearFunc(I2CX,I2cStart_En);
I2C_WriteByte(I2CX,I2C_SLAVEADDR); ///< 從裝置位址發送
break;
case 0x18: ///< 已發送SLA+W,并接收到ACK
I2C_WriteByte(I2CX,u8Addr); ///< 從裝置記憶體位址發送
break;
case 0x28: ///< 上一次發送資料後接收到ACK
I2C_WriteByte(I2CX,pu8Data[u8i++]); ///< 繼續發送資料
break;
case 0x20: ///< 上一次發送SLA+W後,收到NACK
case 0x38: ///< 上一次在SLA+讀或寫時丢失仲裁
I2C_SetFunc(I2CX,I2cStart_En); ///< 當I2C總線空閑時發送起始條件
break;
case 0x30: ///< 已發送I2Cx_DATA中的資料,收到NACK,将傳輸一個STOP條件
I2C_SetFunc(I2CX,I2cStop_En); ///< 發送停止條件
break;
default:
break;
}
if(u8i>u32Len)
{
I2C_SetFunc(I2CX,I2cStop_En); ///< 此順序不能調換,出停止條件
I2C_ClearIrq(I2CX);
break;
}
I2C_ClearIrq(I2CX); ///< 清除中斷狀态标志位
}
enRet = Ok;
return enRet;
}
第5步:為驗證I2C通信是否成功,向NSA2862空閑寄存器0XCF中執行讀資料0X55并讀取出來,空閑寄存器位址如下表所示:
驗證示例代碼如下所示:
uint8_t u8Senddata[2] = {0x00,0x55};
uint8_t u8Recdata[1]={0x00};
///< 向I2C總線發起開始信号
I2C_SetFunc(M0P_I2C1,I2cStart_En);
///< 寫資料
I2C_MasterWriteData(M0P_I2C0,0x30,&u8Senddata[0],1);
I2C_MasterWriteData(M0P_I2C0,0xCF,&u8Senddata[1],1);
delay1ms(100);
///< 讀資料
I2C_MasterReadData(M0P_I2C0,0xCF,u8Recdata,1);
///< 序列槽列印
for(int i=0;i<1;i++)
{
Uart_SendDataIt(M0P_UART1,u8Recdata[i]); //啟動UART1發送資料
delay1ms(3);
}
使用示波器檢視效果,程式運作時鐘信号波形如下所示:
程式運作資料信号波形如下所示:
序列槽輸出效果如下所示:
說明可以實作正常的I2C資料讀寫。
第6步:讀取壓力傳感器數值,寄存器位址如下表所示:
讀取傳感器數值代碼如下所示:
uint8_t u8Senddata[2] = {0x00,0x40};
uint8_t u8Recdata[4]={0x00};
///< 向I2C總線發起開始信号
I2C_SetFunc(M0P_I2C1,I2cStart_En);
///< 寫入寄存器啟動使RAW_P=0
I2C_MasterWriteData(M0P_I2C0,0x30,&u8Senddata[0],1);
I2C_MasterWriteData(M0P_I2C0,0xA5,&u8Senddata[1],1);
delay1ms(100);
///< 讀取經過校正的傳感器資料
I2C_MasterReadData(M0P_I2C0,0x06,u8Recdata,1);
I2C_MasterReadData(M0P_I2C0,0x07,u8Recdata+1,1);
I2C_MasterReadData(M0P_I2C0,0x08,u8Recdata+2,1);
for(int i=0;i<3;i++)
{
Uart_SendDataIt(M0P_UART1,u8Recdata[i]); //啟動UART1發送資料
delay1ms(3);
}
資料0X014ADD就是校準後ME501壓力數值(2的補碼形式)。