4vJIO{m 3 驱动程序的设计
:Bc;.% 智能家居控制器要多个设备驱动程序,有的驱动程序可以采用标准的驱动程序,有的要专门设计。芯片SIM100-E是通过第三个串口与S3C2410相连的,所以可以直接使用标准的串口驱动程序。传感器接口和家电控制接口要设计专用的驱动程序。控制器的处理器通过外部中断来检测传感器,通过GPIO端口来控制家电,虽然它们的工作原理有所不同,但驱动程序设计的方法没有很大差别,因为在嵌入式Linux系统中设备驱动程序有一个标准的框架,设计驱动程序的大部分工作就是根据硬件结构来“填写”框架中的函数。主要的函数包括open()、read()、write()、ioctl()、release()、module_init()和module_exit()等等。
u _^=]K; 下面以传感器接口驱动程序设计为例,简介驱动程序的“填写”过程。
:G)x+0u 3.1 设备初始化模块和退出模块
1T`"/*! 设备初始化模块的主要功能是:设置和申请中断、向内核注册设备等。设备退出模块的主要功能是:释放设备所占
bHG>SW\]`? 用的资源。具体函数如下:
{.)D)8`<d int __init s3c2410_int_init(void)
mw%_yDZ{ {┅
eT?LMBn\ set_external_irq(IRQ_EINT9, ┅);//设置外部中断
)&-+:u0 request_irq(IRQ_EINT9,demo_int_handler, ┅);//申请外部中断
<C xet~x ret = register_chrdev(0, DEVICE_NAME, &s3c2410_exio_fops); //申请主设备号
<H#K `|Ag devfs_int_demo= devfs_register(NULL, “int_demo”, ┅); //注册设备文件
7 {<lH%Tn ┅}
E':Z_ ^4 void __exit s3c2410_int_exit(void)
p.olXP {┅
v#G ^W free_irq(IRQ_EINT9,NULL);//释放中断
#$QY[rf=6 devfs_unregister(devfs_int_demo); //删除设备文件
'IszS!kY unregister_chrdev(exioMajor, DEVICE_NAME); //释放主设备号
9|DC<Zn&B# ┅}
&*-2k-16 3.2 打开模块和释放模块
wkw/AZ{27 打开模块的主要功能是:初始化一些变量。具体实现函数如下:
Reo0ZU> static int s3c2410_int_open(struct inode *inode, struct file *filp)
sP!qv"u { init_MUTEX(&demodev.lock);//初始化自旋锁
E$
rSrT( init_waitqueue_head(&(demodev.wait));初始化队列
{F[Xe_=#" MOD_INC_USE_COUNT;//使用计数加1
0:p#%Nvg ┅}
-OxHQ static int s3c2410_int_release(struct inode *inode, struct file *filp)
-t?G8,, { MOD_DEC_USE_COUNT; //使用计数减1
l{g(z! ┅}
egvWPht'_ 3.3 读数据模块
>Fh@:M7z 读数据模块的主要功能是:使线程休眼,然后等待中断来唤醒。具体实现函数如下:
pj6Cvq4bD static int s3c2410_int_read(struct file *filp,char *buffer,size_t count,loff_t *ppos)
a4YyELXe {┅
fZC,%p copy_to_user(buffer,(char *)&bak,sizeof(bak)); //内核态到用户态
bHM
.&4G
interruptible_sleep_on(&demodev.wait);//进入休眠
v2Y=vr ┅}
6iC:l%|u 3.4 中断处理模块
Yn/-m
Z 中断处理模块的主要功能是:唤醒正在休眼的线程。具体实现函数如下:
I 3PnyNZ static void s3c2410_int_handler(int irq, void *dev_id, struct pt_regs *reg)
!T)>q%@ai {wake_up(&demodev.wait);//中断唤醒
~r3g~MCHS ┅}
q)X&S*-<o~ 驱动程序设计完成后,再编写Makefile文件,通过make命令生成目标文件,最后利用insmod命令向内核加载驱动程序。
xh$[E&2u 4 应用程序的设计
w.\:I[ 为了提高应用程序的运行速度,以及程序运行的稳定性,所以将应用程序设计成多线程结构,如图2所示。应用程序由7个线程和一个共享数据结构组成。
如图2 应用程序结构框图
o-_a0j 共享数据主要用于存放家电开启和关闭时间,发送短信的电话号和短信内容等信息。共享数据是通过2个设置线程来修改的。家电控制线程主要是根据控制数据、检测短信线程的内容和操作线程的内容来进行操作。发送短信线程主要是根据控制数据、检测传感器线程的内容和操作线程的内容来进行操作。应用程序的具体内容如下。
oZCO$a #include &nb
ns-x\B?^ sp; //线程库头文件
'
BpRi N ┅
(;N_lF0 int main()
pFh2@O {┅
p5\b&~
g pthread_creat(&th_a,NULL,send_msg,0); //创建发送短信线程
&x3y.}1 pthread_creat(&th_b,NULL,control_driver,0); //创建家电控制线程
fi1UUJ0
U; ┅
|NqQKot1 pthread_join(th_b,&retval); //等待家电控制线程结束
'JydaF~> pthread_join(th_a,&retval); //等待发送短信线程结束
F`l1I=; ┅}
Tym!7H2 /*发送短信线程*/
uB
BE!w_ int send_msg()
y<
84Gw_ {┅
B^
h!F8DC tty_init(); //初始化串口
fXN;N&I gprs_init(); //初始化GPRS模块
eL.S=" tty_writecmd(“at”,strlen(“at”)); //发送AT命令
Q["}U7j tty_writecmd(“at+cmgf=1”,strlen(“at+cmgf=1”));//发送修改字符集命令
lPH]fWt< tty_write(“at+cmgs=”,strlen(“at+cmgs=”)); //发送短信命令
kci H tty_writecmd(msg.send_tel,strlen(msg.send_tel)); //发送电话号码
"-9YvB# tty_writecmd(msg.send_text,strlen(msg.send_text)); //发送短信内容
xGqZ8v`v tty_end();
KQk;:1hW ┅
\6o
~ i return 0;
MkQSq
MU= }
5%9&
7 其它线程的设计方法有很多相似之处。应用程序设计完成之后,再经过交叉编译就可生成目标文件。
MDRSI g 5 结束语
d(tq;2- 将移植好的系统、驱动程序和应用程序下载到智能家居控制器上。经过测试,系统具有操作方便、可靠性高和抗干扰能力强等优点。本文的创新点是:通过智能家居控制器将家电、传感器、手机等许多独立的设备连接成为一个系统,从而方便本地和远程控制。