嵌入式系統(tǒng)中,溫度傳感器是硬件監(jiān)控的核心組件之一,MS5607作為一款高精度的壓力/溫度傳感器,被廣泛應用在工業(yè)控制、消費電子等場景。本文基于Linux Kernel 6.1版本,深入解析drivers/input/sensors/temperature/tmp_ms5607.c驅動代碼的實現(xiàn)邏輯,帶你搞懂傳感器驅動的注冊、初始化、數(shù)據(jù)采集與上報全流程,以及如何在系統(tǒng)中獲取傳感器的狀態(tài)和數(shù)據(jù)。
一、MS5607傳感器基礎
MS5607是MEAS(TE Connectivity)推出的高精度數(shù)字壓力傳感器,集成溫度傳感功能,采用I2C接口通信,內置128位校準數(shù)據(jù)(PROM)。驅動通過讀取校準數(shù)據(jù)補償溫度和壓力的測量誤差,最終輸出-40~85℃范圍內的高精度溫度值,以及對應的壓力值。
二、驅動代碼核心結構解析
驅動代碼基于LinuxI2C子系統(tǒng)和Input子系統(tǒng)實現(xiàn),整體結構分為「驅動注冊」「核心操作函數(shù)」「數(shù)據(jù)采集與上報」三大模塊,下面逐一拆解。
2.1驅動注冊:I2C驅動框架
Linux下I2C設備驅動遵循標準的I2C驅動框架,核心是i2c_driver結構體和設備ID表,這是驅動被內核識別的基礎:
// 設備ID表:匹配I2C設備staticconststructi2c_device_id temperature_ms5607_id[] = { {"tmp_ms5607", TEMPERATURE_ID_MS5607}, {}};// I2C驅動核心結構體staticstructi2c_driver temperature_ms5607_driver = { .probe = temperature_ms5607_probe, // 設備匹配成功后執(zhí)行 .remove= (void*)temperature_ms5607_remove,// 設備卸載時執(zhí)行 .shutdown = sensor_shutdown, .id_table = temperature_ms5607_id, // 設備ID匹配表 .driver = { .name ="temperature_ms5607", #ifdef CONFIG_PM .pm = &sensor_pm_ops, // 電源管理 #endif },};// 簡化I2C驅動注冊/注銷的宏module_i2c_driver(temperature_ms5607_driver);
?module_i2c_driver:底層調用i2c_add_driver完成驅動注冊,無需手動寫init/exit函數(shù);
?probe函數(shù):I2C設備匹配成功后觸發(fā),調用sensor_register_device完成傳感器設備注冊;
?remove函數(shù):設備卸載時注銷傳感器設備,釋放資源。
2.2核心操作函數(shù):初始化與激活
驅動通過sensor_operate結構體封裝傳感器的核心操作(初始化、激活、數(shù)據(jù)上報),核心函數(shù)如下:
(1)sensor_init:傳感器初始化
初始化的核心目標是將傳感器置為「關閉狀態(tài)」,為后續(xù)激活做準備:
staticintsensor_init(structi2c_client *client){ structsensor_private_data *sensor = (structsensor_private_data *) i2c_get_clientdata(client); intresult =0; // 先禁用傳感器,確保初始狀態(tài)為OFF result = sensor->ops->active(client,0,0); if(result) { printk("%s:line=%d,errorn",__func__,__LINE__); returnresult; } sensor->status_cur = SENSOR_OFF; // 標記當前狀態(tài)為OFF g_ms5607_temp_status = sensor->status_cur;// 同步到全局狀態(tài)變量 returnresult;}
(2)sensor_active:傳感器激活與校準數(shù)據(jù)讀取
激活是傳感器從「OFF→ON」的關鍵步驟,核心是讀取校準數(shù)據(jù)(PROM),這是溫度補償?shù)幕A:
staticintsensor_active(structi2c_client *client,intenable,intrate){ intresult =0; inti =0; charprom[16]; // 僅當「啟用傳感器」且「當前為OFF」時執(zhí)行激活邏輯 if((enable)&&(g_ms5607_pr_status == SENSOR_OFF)) { // 1. 發(fā)送復位指令,重置傳感器 result =sensor_write_reg_normal(client, CMD_RESET); if(result) printk("%s:line=%d,errorn",__func__,__LINE__); // 2. 讀取128位校準數(shù)據(jù)(8組,每組2字節(jié)) memset(prom,0,16); for(i=0; i<8; i++)? ? ? ? {? ? ? ? ? ? prom[i*2]= CMD_PROM_RD + i*2; ? ?// 校準數(shù)據(jù)讀取指令? ? ? ? ? ? result =?sensor_rx_data(client, &prom[i*2],?2);? ? ? ? ? ??if(result)?return?result;? ? ? ? }? ? ? ??// 3. 校準數(shù)據(jù)轉存到全局數(shù)組C,供后續(xù)溫度計算使用? ? ? ??for?(i=0;i<8;i++)? ? ? ? {? ? ? ? ? ? C[i] = prom[2*i] <8?| prom[2*i +?1];? ? ? ? }? ? }? ? g_ms5607_temp_status = enable;?// 更新全局激活狀態(tài)? ??return?result;}
關鍵說明:MS5607的校準數(shù)據(jù)(PROM)是出廠時寫入的,包含8組補償參數(shù),決定了溫度測量的精度,必須在激活階段讀取并保存。
2.3數(shù)據(jù)采集與上報:溫度計算+Input子系統(tǒng)
sensor_report_value是驅動的核心數(shù)據(jù)處理函數(shù),負責「觸發(fā)AD轉換→讀取數(shù)據(jù)→溫度補償→上報數(shù)據(jù)」全流程:
staticintsensor_report_value(structi2c_client *client){ // 省略變量定義... if(g_ms5607_pr_status == SENSOR_OFF) { // 1. 觸發(fā)壓力(D1)AD轉換(4096倍過采樣,平衡精度/速度) sensor_write_reg_normal(client, CMD_ADC_CONV+CMD_ADC_D1+CMD_ADC_4096); msleep(10);// 等待轉換完成 result = sensor_rx_data(client, &buffer[0],3); D1 = (buffer[0] <16) | (buffer[1] <8) | buffer[2];? ? ? ??// 2. 觸發(fā)溫度(D2)AD轉換? ? ? ? sensor_write_reg_normal(client, ?CMD_ADC_CONV?+?CMD_ADC_D2?+?CMD_ADC_4096);? ? ? ? msleep(10);? ? ? ? result = sensor_rx_data(client, &buffer[0],?3);? ? ? ? D2 = (buffer[0] <16) | (buffer[1] <8) | buffer[2];? ? ? ??// 3. 基礎溫度計算(補償算法)? ? ? ? dT = D2 - ((unsigned?int)C[5] <8);? ? ? ? g_ms5607_temp = (int)(2000?+ ((long?long)dT * C[6] >>23)); // 4. 二階補償(低溫場景<20℃,提升精度)? ? ? ??if?(g_ms5607_temp 2000)? ? ? ? {? ? ? ? ? ??int?tmp = (g_ms5607_temp -?2000) * (g_ms5607_temp -?2000);? ? ? ? ? ? T2 = (int)((long?long)(dT * dT) >>31); OFF2 = (((longlong)tmp *61)*((longlong)tmp *61)) >>4; SENS2 = (longlong)((tmp*tmp) <1);
? ? ? ? ? ??if?(g_ms5607_temp -1500) {?// 超低溫額外補償? ? ? ? ? ? ? ? tmp = (g_ms5607_temp +?1500) * (g_ms5607_temp +?1500);? ? ? ? ? ? ? ? OFF2 +=?15?* tmp;? ? ? ? ? ? ? ? SENS2 +=?8?* tmp;? ? ? ? ? ? }? ? ? ? ? ? g_ms5607_temp -= T2;?// 最終溫度值? ? ? ? }? ? ? ??// 5. 通過Input子系統(tǒng)上報溫度數(shù)據(jù)? ? ? ? temperature_report_value(sensor->input_dev, g_ms5607_temp); } // 省略其他邏輯... returnresult;}
核心細節(jié):
?AD過采樣配置:代碼中使用CMD_ADC_4096(4096倍過采樣),也可切換為256/512/1024倍,過采樣率越高,精度越高但功耗/耗時越大;
?溫度單位:g_ms5607_temp的單位是0.01℃(如2500代表25.00℃);
?Input上報:通過input_report_abs上報ABS_THROTTLE類型數(shù)據(jù),input_sync同步數(shù)據(jù),用戶態(tài)可通過Input節(jié)點讀取。
三、驅動在系統(tǒng)中的體現(xiàn)
MS5607驅動依托Linux內核子系統(tǒng)實現(xiàn),在系統(tǒng)中的體現(xiàn)可分為「驅動加載」「設備注冊」「數(shù)據(jù)流轉」三個層面,以下是核心流程可視化:
3.1驅動加載流程圖

3.2系統(tǒng)層面的關鍵體現(xiàn)
1.驅動加載狀態(tài):
?查看已加載的I2C驅動:
cat /sys/bus/i2c/drivers/temperature_ms5607/;
?查看驅動日志:dmesg | grep tmp_ms5607,可排查初始化/激活錯誤。
2.Input子系統(tǒng)節(jié)點:
驅動通過Input子系統(tǒng)上報數(shù)據(jù),系統(tǒng)會生成/dev/input/eventX節(jié)點(X為設備號),可通過以下命令查看設備信息:
cat/proc/bus/input/devices | grep -A 5 tmp_ms5607
3.全局狀態(tài)變量:
驅動通過g_ms5607_temp_status(激活狀態(tài):0=OFF/1=ON)、g_ms5607_temp(溫度值)維護核心狀態(tài),內核態(tài)可直接訪問。
四、如何獲取傳感器狀態(tài)與數(shù)據(jù)
4.1內核態(tài)獲取
1.調試打印:開啟CONFIG_PR_MS5607后,驅動會打印溫度/壓力值,通過dmesg查看:
dmesg| grep sensor_report_value# 輸出示例:sensor_report_value:pressure=101325,temperature=2500
2.全局變量引用:其他內核模塊可通過extern引用全局變量:
externintg_ms5607_temp; // 溫度值(0.01℃)externintg_ms5607_temp_status;// 激活狀態(tài)printk("MS5607 Temp: %.2f℃, Status: %dn", g_ms5607_temp/100.0, g_ms5607_temp_status);
4.2用戶態(tài)獲取
方式1:讀取Input事件(原生方式)
編寫簡單的C程序讀取/dev/input/eventX節(jié)點:
#include#include #include intmain(){ intfd =open("/dev/input/eventX", O_RDONLY);// 替換為實際的eventX structinput_eventev; while(read(fd, &ev,sizeof(ev)) >0) { // 過濾溫度事件(ABS_THROTTLE類型) if(ev.type == EV_ABS && ev.code == ABS_THROTTLE) { printf("MS5607 Temperature: %.2f℃n", ev.value /100.0); } } close(fd); return0;}
方式2:擴展sysfs節(jié)點
原驅動未暴露sysfs節(jié)點,可擴展代碼添加,簡化用戶態(tài)讀?。?/p>
// 1. 定義sysfs屬性讀取函數(shù)staticssize_ttemp_show(structdevice *dev,structdevice_attribute *attr,char*buf){ returnsprintf(buf,"%.2fn", g_ms5607_temp /100.0);}staticDEVICE_ATTR(temp, S_IRUGO, temp_show,NULL);// 只讀權限// 2. 在probe函數(shù)中創(chuàng)建sysfs節(jié)點staticinttemperature_ms5607_probe(structi2c_client *client,conststructi2c_device_id *devid){ intret =sensor_register_device(client,NULL, devid, &temperature_ms5607_ops); if(!ret) { device_create_file(&client->dev, &dev_attr_temp);// 創(chuàng)建temp節(jié)點 } returnret;}
添加后,用戶態(tài)可直接讀取:
cat/sys/bus/i2c/devices/0-0048/temp# 替換為實際的I2C設備地址# 輸出示例:25.00
五、核心流程腦圖

六、總結與拓展
MS5607驅動是典型的「I2C設備+Input子系統(tǒng)」傳感器驅動實現(xiàn),核心設計思路可總結為:
1.遵循內核框架:基于I2C驅動框架完成設備匹配,基于Input子系統(tǒng)完成數(shù)據(jù)上報;
2.校準是核心:必須讀取PROM校準數(shù)據(jù),才能通過補償算法得到高精度溫度;
3.分層設計:將初始化、激活、上報封裝為獨立函數(shù),符合Linux驅動的模塊化思想。
拓展優(yōu)化方向
?內核版本適配:Kernel 6.1后I2C/Input子系統(tǒng)接口可能微調,需驗證兼容性;
?功耗優(yōu)化:結合PM子系統(tǒng),在休眠時關閉傳感器AD轉換,降低功耗;
?功能擴展:添加閾值中斷、sysfs節(jié)點配置采樣率等功能;
?精度調優(yōu):根據(jù)場景切換AD過采樣率(如低功耗場景用256倍)。
審核編輯 黃宇
-
溫度傳感器
+關注
關注
48文章
3235瀏覽量
163284 -
MS5607
+關注
關注
0文章
3瀏覽量
7663
發(fā)布評論請先 登錄
Kernel 6.1?中?MS5607?溫度傳感器驅動深度解析
評論