基于ARM的智能家居监控系统详细设计说明书.doc
基于ARM的智能家居监控系统详细设计说明书提交:审核: 提交:farsight审核:XXX核准:XXX 发行签核记录表 发 文 单 位 签 核 发 文 单 位 签 核北京开发中心技术管理部修改纪录表版本发行日期修改记录Ver:1.002009-4-9基于ARM的智能家居监控系统详细设计说明书1、 引言1.1 目的l 本说明书是为了程序员详细了解基于ARM的智能家居监控系统l 应该完成的功能和各模块输入、处理、输出关系,指导程序员正确编码;同时作为测试人员的参考资料使用l 面向的读者:程序员、测试人员、评审员;1.2 项目背景n 项目名称:基于ARM的智能家居监控系统。n 项目功能:使用FS2410开发板和GPRS模块和USB摄像头,完成对现场的监控功能,硬件资源来源于FS2410开发板自带的资源,比如温度传感器,报警器,红外传感器等。如果温度传感器特测温度高于一定的温度或者红外传感器特测有不法分子闯入,那么相应的相应的报警功能,灭火功能被开启,并通过GPRS模块通知用户现场情况,用户根据具体情况采取不同的措施给系统。完成一个远程监控的主要功能。n 系统提出者:北京市华清远见科技信息有限公司n 项目开发者:farsightn 项目管理者:farsightn 最终用户:面向用户n 其他有关背景资料。1.3 术语及缩略语定义1.3.1 术语定义:l FS2410:优龙开发板名称。l cgi : Common Gate Intergace,是HTTP服务器与你的或其它机器上的程序进行“交谈”的一种工具,其程序须运行在网络服务器上1.3.2 缩略语定义:1.4 参考资料1.4.1 文件l 基于GPRS的远程安防监控系统需求分析说明书l 基于GPRS的远程安防监控系统概要设计说明书1.4.2 资料l <<linux设备驱动程序-第三版>>l <<C prime & plus>>l <<嵌入式linux应用程序开发详解>>l <<linux设备驱动程序开发详解>>l <<深入理解linux内核>>l 优龙开发板参考资料光盘2、 主控系统详细设计2.1 程序结构图红外传感器USB摄像头GPRS灭火装置报警存储照片温度传感器火灾主控板 小偷异常现象Internet&手机2.1系统结构图2.2 程序说明:2.2.1 AD模块说明程序描述:AD驱动程序名称:s3c2410-adc.c审核:farsight日期:2008-4-26输入数据:一个模拟电压信号量输出数据:得到一个数字信号量硬件描述:AD转换器是模拟信号源和CPU之间联系的接口,它的任务是将连续变化的模拟信号转化为数字信号,以便计算机和数字系统使用。FS2410开发板用的AD转换器是ARM S3C2410自带的一个一路10位的AD转换器。并且支持触摸屏功能。最大转化率是500K,AD转换器频率的计算公式为:系统时钟/(比例值+1)。本电路的特点是通过改变滑动变阻器的阻值来改变模拟电压量。 软件是通过read,write来进行对AD的读和写的操作。原理图:涉及的datasheet: (s3c2410芯片手册)具体操作根据驱动程序和datasheet来结合注册驱动程序程alloc_chrdev_region(&devno,0,1,"AD_temperature");(动态)结束初始化cdev,并添加到内核之中cdev_add(&ADdev.cdev,devno,1);Y填充adc_remap_ops结构体的各个域。 open,release,read,writerequest_irq(IRQ_ADC,AD_interrupt,SA_INTERRUPT,"AD",NULL);(中断注册)register_chrdev_region(devno,1,"AD_temperature") 成功?序流程: 2.2.1AD模块驱动流程图驱动设计思路:在模块中有AD转换驱动和蜂鸣器的驱动,AD驱动的设计为:open函数中设置为手动启动,当应用层调用read函数时,开启AD转换,然后进入可中断的等待队列,当中断来的时候,唤醒等待队列,然后读取转换数值,在IOCTL中能控制对AD和蜂鸣器的开和关。#include <linux/fs.h>#include <linux/module.h>#include <linux/kernel.h>#include <asm-arm/arch-s3c2410/regs-gpio.h>#include <asm/io.h>#include <asm/arch/map.h>#include <asm/arch/regs-clock.h>#include <asm-arm/arch-s3c2410/regs-adc.h>#include <asm-arm/arch-s3c2410/irqs.h>#include <linux/config.h>#include <linux/module.h>N#include <linux/moduleparam.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/errno.h>#include <linux/string.h>#include <linux/interrupt.h>#include <linux/slab.h>#include <linux/fb.h>#include <linux/delay.h>#include <linux/init.h>#include <linux/ioport.h>#include <linux/cpufreq.h>#include <linux/device.h>#include <linux/dma-mapping.h>#include <asm/hardware.h>#include <asm/io.h>#include <asm/irq.h>#include <asm/mach-types.h>#include <asm/uaccess.h>#include <asm-arm/arch-s3c2410/regs-timer.h>#include <asm/semaphore.h>#define rADCCON *(volatile unsigned int*)S3C2410_ADCCON#define rADCDAT0 *(volatile unsigned int *)S3C2410_ADCDAT0#define rGPBCON *(volatile unsigned int *)S3C2410_GPBCON#define rGPBDAT *(volatile unsigned int *)S3C2410_GPBDAT#define rCLKCON *(volatile unsigned int *)S3C2410_CLKCON#define rADCTSC *(volatile unsigned int *)S3C2410_ADCTSC#define AD_MAGIC 'k'#define AD_ENABLE _IO(AD_MAGIC,1)#define AD_DISABLE _IO(AD_MAGIC,2)#define BEEP_ON _IO(AD_MAGIC,3)#define BEEP_OFF _IO(AD_MAGIC,4)#define AD_MAJOR 91static void AD_setup_cdev(void);static irqreturn_t AD_interrupt(int irq,void *dev_id,struct pt_regs *regs);static int ad_major = AD_MAJOR; int count = 0 ;int onoff = 0 ;struct AD_devwait_queue_head_t wait;struct semaphore semread;int temperature;struct cdev cdev;struct AD_dev ADdev;static void beepon(void)/开蜂鸣器 unsigned long data;unsigned long s3c2410_fclk;unsigned long s3c2410_hclk;unsigned long s3c2410_pclk;data = *(volatile unsigned long *)S3C2410_GPBCON;data &= 0x3;*(volatile unsigned *)S3C2410_GPBCON = data | 0x2;data = readl(S3C2410_TCFG0);data &= 0xff;data |= 15;writel(data, S3C2410_TCFG0);data = readl(S3C2410_TCFG1);data &= 0xf;data |= 2;writel(data, S3C2410_TCFG1);s3c2410_fclk = s3c2410_get_pll(_raw_readl(S3C2410_MPLLCON), 12*1000*1000);data = _raw_readl(S3C2410_CLKDIVN); s3c2410_hclk = s3c2410_fclk / (data & S3C2410_CLKDIVN_HDIVN) ? 2 : 1);s3c2410_pclk = s3c2410_hclk / (data & S3C2410_CLKDIVN_PDIVN) ? 2 : 1);writel(s3c2410_pclk >> 7) / 2000, S3C2410_TCNTB(0);writel( (s3c2410_pclk >> 7) / 2000) >> 1, S3C2410_TCMPB(0);data = readl(S3C2410_TCON);data &= 0x1f;data |= 0xb;writel(data, S3C2410_TCON);data &= 2;writel(data, S3C2410_TCON);static void beepoff(void)/关蜂鸣器unsigned long data;data = *(volatile unsigned *)S3C2410_GPBCON;data &= 0x3;*(volatile unsigned *)S3C2410_GPBCON = data | 0x1;*(volatile unsigned *)S3C2410_GPBDAT &= 0x1;static int AD_open(struct inode *inode,struct file *filp) unsigned long data;if(count=0)/保证只有第一个进程调用是对AD进行初始化data = rCLKCON;data |=(1<<15);rCLKCON = data;rADCDAT0 &=(1<<14);rADCTSC &=(1<<2);request_irq(IRQ_ADC,AD_interrupt,SA_INTERRUPT,"AD",NULL);rADCCON = (1<<14)|(255<<6)|(0<<3)|(0<<2)| (0<<1)|(1<<0);count+;onoff=1;return 0;static void AD_off(void)/关AD转换通过关AD的时钟来停止AD转换unsigned long data;data = rCLKCON;data &=(1<<15);rCLKCON = data; free_irq (IRQ_ADC, NULL);rADCCON |=(1<<2) ;static void AD_on(void)unsigned long data;data = rCLKCON;data |=(1<<15);rCLKCON = data;rADCDAT0 &=(1<<14);rADCTSC &=(1<<2);request_irq(IRQ_ADC,AD_interrupt,SA_INTERRUPT,"AD",NULL);rADCCON &= (1<<2);rADCCON |=(1<<0);static irqreturn_t AD_interrupt(int irq,void *dev_id,struct pt_regs *regs) / wake_up_interruptible(&ADdev.wait);return IRQ_HANDLED ;static ssize_t AD_read(struct file *filp,char _user *buf,size_t count,loff_t *ppos )if(down_interruptible(&ADdev.semread) return -ERESTARTSYS; rADCCON |= (1<<0);interruptible_sleep_on(&ADdev.wait); ADdev.temperature = (rADCDAT0&0x3ff); copy_to_user(buf,(char*)&ADdev.temperature,sizeof(ADdev.temperature); up(&ADdev.semread); return sizeof(ADdev.temperature);static ssize_t AD_write(struct file *filp, const char _user *buf, size_t count, loff_t *f_pos)return 0;static int AD_ioctl(struct inode *inodep,struct file *filp,unsigned int cmd,unsigned long arg )switch(cmd) case AD_DISABLE:if(onoff =1)AD_off();onoff=0; break; case AD_ENABLE:if(onoff = 0)AD_on(); onoff=1; break; case BEEP_ON:beepon(); break; case BEEP_OFF:beepoff(); break; default :return - ENOTTY; return 0;/处理AD开换和蜂鸣器开关的接口函数static int AD_release(struct inode* inode,struct file* flip)if(count = 0)rADCCON |=(1<<2) ;free_irq(IRQ_ADC,NULL);count-;return 0;static const struct file_operations AD_fops =.owner = THIS_MODULE,.open = AD_open,.read = AD_read,.write = AD_write,.ioctl = AD_ioctl,.release = AD_release,;static void AD_setup_cdev(void)int err,devno = MKDEV(ad_major,0);cdev_init(&ADdev.cdev,&AD_fops);ADdev.cdev.owner = THIS_MODULE;ADdev.cdev.ops = &AD_fops;err = cdev_add(&ADdev.cdev,devno,1);int AD_init(void)int result;dev_t devno = MKDEV(ad_major,0);if(ad_major)result = register_chrdev_region(devno,1,"AD_temperature"); 注册一个名字叫AD_temperature的字符设备result = alloc_chrdev_region(&devno,0,1,"AD_temperature");ad_major = MAJOR(devno);if(result<0)return result;init_waitqueue_head(&ADdev.wait);sema_init(&ADdev.semread,1);AD_setup_cdev();return 0;void AD_exit(void)count -;cdev_del(&ADdev.cdev);unregister_chrdev_region(MKDEV(ad_major,0),1);module_init(AD_init);module_exit(AD_exit);MODULE_AUTHOR("Hong XiongFei");MODULE_DESCRIPTION("A/D DEVICER");MODULE_LICENSE("GPL");由于我们的模块要单独做成一个守护进程在后台进行,并且每个模块单独完成各自的功能,AD模块的应用程序主要的工作为:循环每分钟读取一次温度,当温度大于40度的时候就调用GPRS模块的程序发送短信;并启动蜂鸣器。程序如下:#include <fcntl.h>#include <sys/ioctl.h>#include <sys/types.h>#include <stdio.h>#include <unistd.h>#include <signal.h>#include <sys/param.h>#include <sys/stat.h>#include <time.h>#include <stdlib.h>#include "sendmessage.h"#define AD_MAGIC 'k'#define AD_ENABLE _IO(AD_MAGIC,1)#define AD_DISABLE _IO(AD_MAGIC,2)#define BEEP_ON _IO(AD_MAGIC,3)#define BEEP_OFF _IO(AD_MAGIC,4)void init_daemon(void)int pid;int i;if(pid=fork()exit(0);else if(pid<0)exit(-1);setsid();if(pid=fork()exit(0);else if(pid<0)exit(-1);for(i=2;i<1023;i+)close(i);close(0);/chdir("/AD")umask(0);return;int main(int argc, char *argv) init_daemon();int fd;int tmp,ret;float temperature;int count = 0;int delay = 0;int beepon =0;fd = open("/dev/AD",O_RDWR | O_NONBLOCK);if(fd = -1)return -1;while(1)sleep(1);ret = read(fd,&tmp,sizeof(tmp);temperature = tmp*100/1023;if(tmp>60) && (count=0)ioctl(fd,BEEP_ON);system("cp /web/html/pic/safe_no.jpg /web/html/pic/safe.jpg");sendMessage("15011220315","burning:more than 60");count =1;if(count = 1)sleep(5);delay+;if(delay =2)count=0;delay=0;ioctl(fd,BEEP_OFF);2.2.4蜂鸣器报警模块说明程序描述:蜂鸣器驱动程序名称:beep.c审核:farsight日期:2008-4-26输入数据:有人闯入输出数据: 报警硬件描述:首先将蜂鸣器接到S3C2410处理器的一个GPB0管脚上。还上面的配置一样。首先配置GPBCON的GPB0为输出模式,当数据寄存器里写入1时。蜂鸣器打开,写0关闭蜂鸣器。软件上是通过ioctl来进行相应的控制的。 原理图:所涉及的datasheet(S3C2410数据手册):2.2.4蜂鸣器报警模块驱动流程图2.2.5红外模块说明程序描述:探测入侵程序名称:IrDA.c IrDA_gpio.c serial.c shmgt.c审核:farsight日期:2008-11-6输入数据:有人闯入输出数据: 报警、拍照、网页警告硬件描述:通过设置GPFCON来将GPF3设置为输入模式,然后读取相应的数据寄存器的状态来,进行对现场的分析。如果有人闯入,红外模块输出高电平,这个时候GPF3相应的数据寄存器的数值为1,反之为0.原理图:涉及的datasheet(S3C2410数据手册):GPFCON,GPFDAT三个寄存器驱动程序模块设计: 1. IrDA_gpio.c/* linux/drivers/char/IrDA_gpio.c National Semiconductor SCx200 GPIO driver. Allows a user space process to play with the GPIO pins. Copyright (c) 2001,2002 Christer Weinigel <wingelnano-> */#include <linux/device.h>#include <linux/fs.h>#include <linux/module.h>#include <linux/errno.h>#include <linux/kernel.h>#include <linux/init.h>/#include <linux/platform_device.h>#include <asm/uaccess.h>#include <asm/io.h>#include <linux/types.h>#include <linux/cdev.h>#include <asm/delay.h>#include <asm/arch-s3c2410/regs-gpio.h>#define DRVNAME "IrDA_gpio"MODULE_AUTHOR("Hongbo Liu <hongbo_bo>");MODULE_DESCRIPTION("IrDA detector");MODULE_LICENSE("GPL");/#define HELLO_MAGIC 'k'/声明一个幻数 /#define CLOSE_IRDA _IO(HELLO_MAGIC,1)/#define OPEN_IRDA _IO(HELLO_MAGIC,2)#define CLOSE_IRDA 0#define OPEN_IRDA 1#define MAX_PINS 32#define MAX_RESULT 4char status = OPEN_IRDA;static int major = 253;/* default to dynamic major */module_param(major, int, 0);MODULE_PARM_DESC(major, "Major device number");/读函数,读出红外设备的状态,函数提供count毫秒内并小于128的结果,结果以字符y或n来表示状态,设备连接在GPG10端口上static ssize_t IrDA_gpio_read (struct file *filp, char *buff, size_t count, loff_t *offp)ssize_t result = 0;int i;char dataMAX_RESULT;char status1 = "yes"char status2 = "no"if(status = OPEN_IRDA)int k = readl(S3C2410_GPFDAT);/读GPG10端口信号if ( k & ( 1<<3 ) )/判断信号电平strcpy(data,status1);elsestrcpy(data,status2);elsestrcpy(data,status2);/printk("kernel buf is %sn",data);if (copy_to_user (buff, data, count)return -EFAULT;result = count;return result;/设备打开static int IrDA_gpio_open(struct inode *inode, struct file *file)writel(readl(S3C2410_GPFCON) &(3<<6),S3C2410_GPFCON); /*设置GPG10端口为输入端口*/status = OPEN_IRDA;return 0;/设备关闭static int IrDA_gpio_release(struct inode *inode, struct file *file)return 0;static int IrDA_gpio_ioctl(struct inode *inode,struct file *file,unsigned int cmd,unsigned long arg)switch(cmd)case CLOSE_IRDA: /writel(readl(S3C2410_GPFCON) | (1 << 6),S3C2410_GPFCON);/writeb(readb(S3C2410_GPFDAT) & (1<<3),S3C2410_GPFDAT);status = CLOSE_IRDA;printk("irda closedn");break;case OPEN_IRDA:printk("irda openn");status = OPEN_IRDA;break;default:break;return 0;/操作结构指针static const struct file_operations IrDA_gpio_fileops = .owner = THIS_MODULE,.read = IrDA_gpio_read,.open = IrDA_gpio_open,.ioctl = IrDA_gpio_ioctl,.release = IrDA_gpio_release,;static struct cdev IrDA_gpio_cdev; /* use 1 cdev for IrDA */驱动模块注册static int _init IrDA_gpio_init(void)int rc;dev_t devid;if (major) devid = MKDEV(major, 0);rc = register_chrdev_region(devid, MAX_PINS, "IrDA_gpio"); else rc = alloc_chrdev_region(&devid, 0, MAX_PINS, "IrDA_gpio");major = MAJOR(devid);if (rc < 0) printk(KERN_WARNING"IrDA_gpio chrdev_region err: %dn", rc);return rc;if(0=major)major=rc;/printk(KERN_NOTICE"DEBUG IrDA device major is %dn",major);cdev_init(&IrDA_gpio_cdev, &IrDA_gpio_fileops);cdev_add(&IrDA_gpio_cdev, devid, MAX_PINS);return 0; /* succeed */驱动模块卸载static void _exit IrDA_gpio_cleanup(void)cdev_del(&IrDA_gpio_cdev);/* cdev_put(&IrDA_gpio_cdev); */unregister_chrdev_region(MKDEV(major, 0), MAX_PINS);module_init(IrDA_gpio_init);module_exit(IrDA_gpio_cleanup);2. IrDA.c#include "serial.h"#include "beep.h"#include "wdaemon.h"int main (int argc, char *argv )char bufMAX_RESULT;char tst_buf1 = "yes"char tst_buf2 = "no"char status_cnt = 0;char alarm = ENABLE;int fd,i,j;wdaemon(0);for(i=0;i<MAX_RESULT;i+)bufi='0'fd = open ("/dev/IrDA",O_RDONLY);if (fd = -1)printf("open /dev/IrDA file error!n");while(1)i = read(fd, buf, MAX_RESULT);if (0 = i)printf("read /dev/IrDA file erro