梁永恩,万世明
基于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