梁永恩,萬世明
?
基于Android的數字溫濕度傳感器驅動開發及應用
梁永恩,萬世明
摘 要:研究了Android的架構及硬件驅動的實現原理,以數字式溫濕度傳感器DHT11為例,結合Android的硬件抽象層模式,設計了DHT11在Android平臺下的驅動實現方法并編寫了用戶測試程序,測試結果表明,系統能正確獲取傳感器的溫濕度數據,驅動程序運行正常。
關鍵詞:嵌入式;DHT11;溫濕度檢測;Android;硬件抽象層
Android是Google公司推出的完全開放的移動設備軟件開發平臺[1],目前的版本是5.0。Android最早是專門用于手機開發的,由于其開源、擴展性好、開發方便、界面美觀等優點使其得到在手機、平板電腦、智能電視、車載設備及其它移動設備領域中廣泛的應用。本文以DHT11數字溫濕度傳感器為例,介紹Andriod系統硬件底層驅動設計及應用的方法。
Android由下而上分為五個層次,其結構圖如圖1所示:

圖 1 Android 系統架構
最底層是Linux內核層,Android4.0使用Linux Kernel 3.0.1;內核層之上是硬件抽象層(Hardware Abstractor Layer,HAL),該層是對Linux內核程序的封裝,向上提供接口,屏蔽底層的實現細節;硬件抽象層之上是函數庫和運行時環境,包括標準C系統函數庫、Open GL /ES等,通過Android應用程序框架為開發者提供服務;函數庫之上是應用程序框架層,包括一系列的系統服務,如視圖系統、資源管理器、活動管理器、通知管理器等,用戶可以使用這些API開發應用程序;最上層是應用層,用戶開發的Android應用程序和Android內核應用程序(如Email、聯系人等)均位于這一層。
DHT11數字溫濕度傳感器是一款價格低廉的溫濕度傳感器模塊[2]。它包含一個電阻式感濕元件和一個NTC測溫元件,并與一個高性能8位單片機相連,可輸出已校準的溫濕度數據。DHT11的濕度測量范圍為20%~90% RH,測量誤差為±5%RH,溫度測量范圍為0~50℃,測量誤差為± 2℃,它與微處理器之間采用單總線(1-Wire Bus)進行通信,大大節省了IO口資源。由于DHT11具有成本低、穩定性好、數字信號輸出、結構簡單、擴展方便、自校準、響應速度快等優點,在暖通空調、除濕器、汽車、濕度調節器、醫療、自動控制等領域得到了廣泛的應用[3-4]。
本系統采用的嵌入式微處理器型號為S5PV210。DHT11有四個引腳,VDD為電源引腳,工作電壓為3.5V-5.5V,GND為接地引腳,DATA為雙向數據引腳,連接S5PV210的通用輸入輸出口GPH0_0,硬件連接原理圖如圖2所示:

圖 2 DHT11硬件連接原理圖
DHT11 器件采用簡化的單總線通信。一次傳送40位共5字節數據溫濕度數據,由高位到低位依次送出,具體數據格式是:8bit濕度整數數據+8bit濕度小數數據++8bit溫度整數數據+8bit溫度小數數據++8bit校驗和。校驗和數據為前四個字節相加。
Android的版本為Android 4.0.4,Linux開發環境為Ubuntu12.04,交叉編譯工具為arm-none-linux-gnueabi-gcc。由于底層驅動程序是由C/C++語言設計的,上層應用程序不能直接調用,必須通過JNI(Java Native Interface)的方式進行調用。根據Android的分層原則,應用程序訪問底層驅動的順序為:DHT11app->DTH11Service(Java)->DTH11Serv
-ice(Native)->HAL->Linux的驅動函數。DHT11的android驅動開發流程如下:
(1)編寫DHT11的Linux驅動程序(dht11_forlinux.c)。(2)編寫HAL接口(dht11.c)。
(3)編寫JNI接口(dht11Service.cpp),包裝第二步寫的HAL接口,提供框架層的JAVA服務對HAL層C接口的調用。通過NDK(Native Development Kit)生成動態連接庫。
(4)編寫框架層的JAVA服務程序(dht11Service.java),在該服務程序中包含第3步生成的動態鏈接庫文件,調用該動態鏈接庫里的函數,獲取DHT11的溫濕度數據。
(5)編寫應用程序(dht11App.java),通過調用DTH11Service訪問動態連接庫獲取數據。
3.1 DHT11硬件Linux內核層驅動程序
Linux把外部設備看作一個文件來管理,它在設備驅動程序在與硬件設備之間建立了標準的抽象接口,用戶通過open,close,read,write等系統調用對設備進行操作[5]。Linux將設備分為字符設備、塊設備、網絡設備3類,DHT11溫濕度傳感器屬于字符設備,它是按照字符流的方式被有序訪問。驅動程序的重點是定義file_operations結構體中的相關成員函數。file_operations定義如下:
static struct file_operations DHT11_fops={
.owner = THIS_MODULE,
.read = DHT11_read,
.open = DHT11_open,
.release = DHT11_release,};
對于DHT11來說,主要操作是讀取數據,DHT11_fops中的read函數對應DHT11_read函數。編寫DHT11_read函數時要根據DHT11的讀寫時序來編寫實現過程。獲取DHT11傳感器數據的讀寫時序如圖3所示:

圖3 獲取DHT11傳感器數據的讀寫時序
主機發送開始信號后,延時等待20us-40us后讀取DH11T的回應信號,讀取總線為低電平,說明DHT11發送響應信號,DHT11發送響應信號后,再把總線拉高,準備發送數據,每一bit數據都以低電平開始, 位數據“0”的格式為50μ s的低電平和26-28μ s的高電平,位數據“1”的格式為50μ s的低電平加70μ s的高電平,可通過中斷的方式計算每bit數據的持續時間判斷該為數據是“0”還是“1”。首先定義DHT11傳感器設備的結構,如下:
struct dht11_ dev{
struct cdev cdev; //定義字符型設備
unsigned long pin; //DATA引腳,這里是GPH0_0
unsigned char value[5]; //接收5個字節數據存放在數組中
unsigned int irq;
struct timeval lasttv;
…
void (*write_bit)(unsigned long pin, char bit); //向DHT11寫入1位數據的函數
}
static ssize_t dht11_sensor_read( struct file *filp,
char _user *buf,size_t size,loff_t *f_pos) //獲取DHT11傳感器的數據
{
int result = 0;
if(dht11_reset(dht11_dev)){ //調用復位函數,獲取溫濕度數據,傳送上一次的溫濕度數據
do_gettimeofday(&dht11_dev->lasttv); //獲取當前的時間值
setup_interrupts();} //設置中斷模式,在中斷服務函數中判斷接收到的位數據是”0”還是”1”
msleep(20); //等待20ms
clear_interrupts(); //清除中斷
copy_to_user(buf, (char *)& dht11_dev->value, sizeof(dht11_dev->value));//將溫濕度數據從內核空間拷貝到用戶空間
…}
3.2 HAL設計
1.Android系統通過HAL訪問linux驅動的過程
(1)本地服務(Native Service)通過調用hw_get_module函數獲取hw_module_t結構的實例module(獲取HAL stub);
(2)通過module中hw_module_methods_t結構的實例指針methods獲得打開具體設備的HAL的open方法;
(3)在HAL的open方法的實現中調用C庫的open函數打開linux設備文件(獲取文件描述符),進而通過其他的文件操作函數實現對設備的控制(如DHT11的read操作);
為此需要定義hw_module_t、hw_device_t結構和其他相關的變量、函數,這里通過自定義的HAL結構,將上述結構等封裝起來。
2.實現過程
(1)HAL部分
1)在dht11.h文件,完成dht11_module_t、dht11_device_t的定義
struct dht11_module_t {struct hw_module_t common;};//繼承hw_module_t結構
struct dht11_device_t { //自定義的一個針對dht11的結構,包含hw_device_t和支持的API操作
struct hw_device_t common;
int fd; //具體的設備描述符
int (*dht11_read)(struct dht11_device_t *dev, char *val, int count);//讀取DHT11數據的函數
};
2)在dht11.c文件完成以下內容:定義HAL_MODULE_ INFO_SYM的自定義結構體類型的變量,將methods指定為dht11_module_methods;定義hw_module_methods_t類型變量dht11_module_methods,該變量只有一個成員變量open,該變量指定為dht11_device_open;定義了dht11_device_open函數,該函數用來打開設備,對設備對應的hw_device_t結構體的初始化,并指定設備相關的自定義函數;定義具體的獲取DHT11數據的函數,在該函數中調用Linux的底層驅動。
const struct dht11_module_t HAL_MODULE_INFO_
SYM={
common:{
tag:HARDWARE_MODULE_TAG,
id: "dht11",
name: "DHT11 Stud",
methods:&dht11_module_methods,//實現了一個open的方法供JNI層調用
}};
static struct hw_module_methods dht11_module_methods={open:dht11_device_open};
static int dht11_device_open(const struct hw_module_t * module,cost char * name,struct hw_device_t** device){
struct dht11_device_t *dev;
dev=(struct dht11_device_t *)malloc(sizeof(*dev)); memset(dev,0,sizeof(*dev));
dev->common.tag=HARDWARE_DEVICE_TAG;
dev->read= dht11_read;//實例化支持的操作,該操作調用Linux的底層驅動
*device=*dev->common;//將實例化的dht11_device_t地址返回給JNI層, JNI層可直接調用read函數。
fd=open(“dev/dht11”,O_RDWR) //打開硬件設備
}
(2)JNI部分
硬件訪問服務是使用JAVA語言實現的,為了訪問硬件,必須通過使用硬件抽象層(HAL)提供的接口,而硬件抽象層模塊是使用C++語言實現的,所以我們必須實現硬件訪問服務dht11Service的JNI方法。
進入frameworks/base/services/jni目錄,創建dht11Service.cpp文件,在該文件中定義JNI方法,包括以下幾個:
1)初始化函數,在該函數中根據DHT11_HARDWARE_ID獲取hw_module_t,并打開設備。
static jboolean dht11_init(JNIEnv *env,jclass clazz);
2)加載JNI庫函數,在該函數中完成本地方法的注冊,Framework層調用。
jint JNI_OnLoad(JavaVM* vm, void* reserved);//Framework層加載JNI庫時調用。
3)獲取DHT11的5個字節的數據的函數。
static void dht11_read(JNIEnv *env,jobject thiz, jbyteArray dhtdata );
4)注冊本地方法,Framework層可以使用這些方法,包括初始化函數及讀取DHT11數據的函數。
static int registerMethods(JNIEnv* env);
3.3 Framework層的DHT11服務
在此層的dht11Service.java文件中,定義一個類DHT11Service,在此類中加載JNI的動態庫,并在構造函數中調用本地_init()方法加載DHT11的驅動。同時提供一個對外讀取DHT11數據的函數。該函數定義如下:
public void read(byte[] bytes){
Log.i(”DHT read”); return _read(dht);}
3.4 應用程序
應用程序負責實例化框架層的服務DHT11Service,調用該類的read()方法讀寫DHT11,部分代碼如下:public void onCreate(Bundle savedInstanceState){ byte[] result = {0, 0, 0, 0, 0};
DHT11Service ds=DHT11Service();//實例化DHT11Service
ds.read(result);//通過DHT11Service提供的方法,控制底層硬件
…..}//對數據進行處理并顯示。
將內核代碼驅動編譯后生成dht11.ko,然后編譯JNI及HAL源代碼,最后通過Eclipse將Android應用程序項目生成apk文件,在S5PV210硬件平臺進行DHT11驅動測試,將測試的溫濕度數據與標準溫濕度值進行比較,測試分析的結果如表1所示:

表 3 測試分析的結果
將內核代碼驅動編譯后生成dht11.ko,然后編譯JNI及HAL源代碼,最后,通過Eclipse將Android應用程序項目生成apk文件,在S5PV210硬件平臺進行DHT11驅動測試,將測試的溫濕度數據與標準溫濕度值進行比較,測試分析的結果如表1所示。
本文結合DHT11數字溫濕度傳感器實現了基于Android HAL 架構的溫濕度傳感器的驅動程序。實驗結果表明,該驅動程序運行正常,滿足系統設計的要求。
參考文獻
[1] 胡偉.Android系統架構及其驅動研究[J].廣州廣播電視大學學報.2010,41(04):96-101.
[2] 周云輝,王嬌,錢云飛. 基于嵌入式的環境溫濕度監測系統設計[J].電子測量技術,2012,35(9):80-82.
[3] 廣州奧松電子有限公司. 數字溫濕度傳感器DHT11[EB/OL]. http://www.aosong.com, 2015-2-12.
[4] 王志宏,白翠珍. 基于DHT1 的實驗室多點溫濕度報警系統的設計[ J ]. 山西電子技術,2011(4):45-46.
[5] 姜遠志.Linux的驅動開發分析[J].無線互聯科技.2014,(01):103.
Driver and Application of Digital Temperature and Humidity Sensor Based on Android
Liang Yongen,Wan Shiming
(The Electrical and Information Engineering School of Guangdong Baiyun University, Guangzhou 510450, China)
Abstract:This thesis illustrated the hardware architecture and driver principle of Android. The design of DHT11 driver in Android OS and the user application was given by using the hardware abstraction layer. The results show that the driver run normally and the application could obtain correct data of temperature and humidity from the sensor.
Key words:Embedded; DHT11; Temperature and Humidity Measurement; Android; Hardware Abstraction Layer
收稿日期:(2015.06.30)
作者簡介:梁永恩(1978-),男(漢族),廣州人,廣東白云學校,電氣與信息工程學院,講師,碩士,研究方向:嵌入式系統,廣州,510450萬世明(1955-),男(漢族),武漢人,廣東白云學校,電氣與信息工程學院,教授,碩士,研究方向:系統工程,廣州,510450
文章編號:1007-757X(2016)02-0074-04
中圖分類號:TP274
文獻標志碼:A