运动图像检测系统: 准备: 移植Linux2.6.29运行于s3c2440板子上, 按键驱动, USB host controller驱动 声卡驱动 动态链接文件系统制作SDK-MOTION/src/fs/rootfs-motion.tar.gz madplay播放器移植 图像运动检测程序设计 报警主程序设计 1.当移动物体进入监控范围,系统报警 2.系统报警后保存移动物体图像 3.报警时播放一段指定音乐,mp3,avi格式 4.三分钟内检测到连续变化的次数超过20次,认为是在下雨,检测系统暂停2小时,2小时后重启。 有两种方式触发报警: 1.外部按键中断 2.图像有变化触发报警 ls app driver fs kernel shell tar zxvf linux2.6.29.tar.gz cd linux2.6.29 make clean cp config-motion .config 该.config文件采用NFS起根文件系统,且已经选择了声卡驱动,网眼V2000摄像头驱动。修 改.config的CMDLINE行的IP配置,NFS起根文件系统。 make menuconfig ARCH=arm CROSS_COMPILE=arm-linux-配置内核 编译内核,解压根文件系统。 按键驱动移植: SDK-MOTION/src/driver/button目录,采用上升沿触发方式。 cd motion/src/driver make clean;make 生成mini2440_buttons_rise.ko 参考madplay移植到mini2440.doc 移植完后cp madplay /nfsroot/rootfs-motion 检测程序设计: 运动图像检测最常用图像检测方法是将当前帧和前一帧(背景帧)比较,如果不同像素的点数超过阀 值,则认为图像有变化。 本项目图像检测程序采用开源软件motion: http://www.lavrsen.dk/foswiki/bin/view/Motion/WebHome 参考motion-3.2.11.1.tar.gz,motion的使用.doc 将motion和motion.conf拷贝到文件系统/nfsroot/rootfs-motion/motion 拷贝脚本文件: 报警文件11.mp3,22.mp3 count.txt用于存放计算/root/motion中图像数 key_pic_motion总的程序运行脚本 appon(motion.conf中on_event_start本) appoff(motion.conf中on_event_end) mapplay(播放器) pic.txt(记录是否有图像运动被检测到) cd /home/motion/src/shell cp -a * /nfsroot/rootfs-motion/motion 报警主程序设计: 程序中使用定时器,每三分钟比较图像连续变化次数是否超过20次,如果超过则添加一个2小时定时 器,在这2小时如有图像变化不处理,如果没有超过则添加下一个3分钟定时器。 报警主程序为app-motion.c cd /home/motion/src/app make clean;make cp app-motion /nfsroot/rootfs-motion/motion 项目测试一: NFS方式起根文件系统,要求文件系统使用动态链接的文件系统。 cd /motion ./key_pic_motion 该脚本包括按键驱动加载,检测程序运行,主程序运行。 测试按键中断: 当按键被按下时,[type1]button detect, button_value:4 [key]Now detect **key** have change 表明主程序检测到键值4被按下,开始报警。 [key]No,have not mp3 play 表明目前系统中没有mp3播放, [key]Start add 3 minute alarm! 第一次检测时,添加一个3分钟定时器。 THIS SONG IS 11.mp3 报警铃声是11.mp3 Now con_cnt=0表明当前连续变化的次数为0 测试项目二:测试运动图像 [key2]pic motion detect!表明检测到图像运动。 Now con_cnt=2表明目前检测到图像连续变化的次数是2。 测试项目三: 3分钟到达20次以上时 [pic]3alarm! con_cnt=23 Now maybe it is raining! system will sleep 7200 seconds! 测试项目四: 系统处于睡眠状态时,有外部中断或者图像运动时会提示: It is raining! system is sleeping! summary time:7200 seconds, sleep:157 seconds,nees sleep:7043 seconds 代码分析: 主要程序是app-motion.c #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/ioctl.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <signal.h> #include <sys/select.h> #include <sys/time.h> #include <errno.h> #include <sys/wait.h> #include <string.h> #include <sys/ipc.h> #include <sys/shm.h> #include <time.h> /* 1. 检测到图像变化,报警 2. 检测到外部中断,报警 3. 3分钟能连续检测图像变化20次,则暂停2小时,2小时后在开启 */ /*define globe variable*/ /*play_pid:当前播放的MP3子进程ID*/ unsigned int play_pid = 0; /*gradchild:当前播放的MP3孙子进程ID*/ unsigned int gradchild = 0; unsigned int play_flag; /*共享内存描述标记 sharemem: byte1:孙子进程ID号 byte2:是否有MP3播放标识play_flag_2 //byte3:MP3播放次数 */ int shmid; char *p_addr; #define PERM S_IRUSR|S_IWUSR /*报警铃声歌曲名,song1图像变化报警铃声 song2外部中断报警铃声*/ char *song1="11.mp3"; char *song2="22.mp3"; //char *song="234.mp3"; /*定时器时间为3分钟*/ #define THREE_ALARM 3*60 /*睡眠时间为2小时*/ #define SLEEP_TIME 2*60*60 #define CPM_CNT 20 int threemin_alarm = 1; static int con_cnt=0; int sleep_flag = 0; unsigned int time_tmp; #define max(flag) (flag) >1 ? "pic":"key" //#define DEBUG int alarm_flag; static int pic_cnt; int cnt_fd; /*计算图像变化次数,超过2次则认为有图像变化*/ #define COMPARE_CNT 5 /************************************************* Function name: count_pic Called by : 函数main Parameter : void Description : 计算图片变化数 Return : int Autor & date : ykz 10.4.25 **************************************************/ int count_pic(void) { int fd,ret; char *buf; buf = (char *)malloc(10); system("ls /root/motion | wc -l > count.txt"); lseek(cnt_fd, 0 ,SEEK_SET); ret = read(cnt_fd , buf , 10); if(ret) ret = atoi(buf); free (buf); return ret; } /************************************************* Function name: my_func_sleepalarm Called by : 函数my_func_3alarm Parameter : sing_no Description : 3分钟连续变化20次后,延时2小时后的唤醒函数 Return : void Autor & date : ykz 10.4.25 **************************************************/ void my_func_sleepalarm(int sign_no) { if( sign_no == SIGALRM){ printf("Now sleep time finished!start a new work!\n"); /*则睡眠表示sleep_flag为0*/ sleep_flag = 0; }//end sing_no } /************************************************* Function name: my_func_3alarm Called by : 函数restart_caculate_play Parameter : sing_no Description : 每隔3分钟检测图像连续变化是否超过20次 Return : void Autor & date : ykz 10.4.25 **************************************************/ void my_func_3alarm(int sign_no) { if( sign_no == SIGALRM){ struct tm *p; time_t timep; unsigned int second; printf("\n------------------warning------------------\n"); printf("[%s]3alarm!con_cnt=%d\n",max(alarm_flag),con_cnt); /*判断图像运动次数是否超过20次 如果是:则系统睡眠2小时; 不是,则系统继续添加下一个3分钟的定时器*/ if( con_cnt >= CPM_CNT){ if(play_flag){ kill(play_pid,SIGKILL); kill(gradchild,SIGKILL); wait(NULL); } //sleep (1); time(&timep); p = localtime(&timep); second = (p->tm_hour)*60*60 + (p->tm_min) * 60 + p->tm_sec; time_tmp=second; printf("Now maybe it is rainning!,system will sleep %d seconds!\n",SLEEP_TIME); con_cnt = 0; /*置睡眠标识sleep_flag为1*/ sleep_flag = 1; /*系统睡眠2小时*/ if(signal(SIGALRM,my_func_sleepalarm)<0) perror("signal"); alarm(SLEEP_TIME); } else{ printf("Nornal test!not rainning!\n"); con_cnt = 0; /*添加下一个3分钟的定时器*/ if(signal(SIGALRM,my_func_3alarm)<0) perror("signal"); alarm(THREE_ALARM); } printf("\n------------------warning------------------\n"); } //end sing_no } /************************************************* Function name: play Called by : 函数startplaymp3 Parameter : void Description : 子进程创建孙子进程播放MP3 Return : void Autor & date : ykz 10.4.2 **************************************************/ void play(void) { pid_t fd; char *c_addr; char *song_name; int play_flag_gradchild1=1; int play_flag_gradchild2=2; int i=0; /*创建孙子进程*/ fd = fork(); if(fd == -1) { perror("fork"); exit(1); } else if(fd == 0) /*孙子进程,播放MP3*/ { printf("\n--------------play mp3----------------\n"); if(alarm_flag==1) song_name=song1; else song_name=song1; printf("THIS SONG IS %s\n",song_name); /*使用madplay播放MP3*/ execl("/motion/madplay","madplay",song_name,NULL); printf("\n\n\n"); } else /*子进程*/ { /*把孙子进程的id传入共享内存*/ memcpy(c_addr,&fd,sizeof(pid_t)); /*目前在播放MP3,将播放标记传入共享内存*/ memcpy(c_addr+sizeof(int),&play_flag_gradchild1,4); /*等待孙子进程结束,只要结束: 传回play_flag_gradchild2=2,表示现在MP3没有播放*/ if(fd == wait(NULL)) { printf("\n------------------warning------------------\n"); /*通过共享内存传回play_flag_gradchild2=2,表明后面的一定不是连续的MP3播放*/ memcpy(c_addr+sizeof(int),&play_flag_gradchild2,4); printf("Gradchild normal finish!\n"); printf("------------------warning------------------\n"); }//end if(fd == wait(NULL)) } } /************************************************* Function name: startplaymp3 Called by : 函数caculate_play,restart_caculate_play Parameter : pid_t *childpid Description : 主进程创建子进程 Return : void Autor & date : ykz 10.4.2 **************************************************/ void startplaymp3(pid_t *childpid,int flag) { int ret = 0; pid_t cun_pid; /*创建子进程*/ cun_pid = fork(); if(cun_pid == -1) { perror("son fork"); exit(1); } if(cun_pid == 0) /*子进程*/ play(); if(cun_pid > 0) /*父进程*/ { *childpid = cun_pid; sleep(1); /*让孙子进程先执行*/ /*如果是图像运动变化,将全局变量con_cnt加1*/ if( flag == 2 ) con_cnt++; printf("\nNow con_cnt=%d\n",con_cnt); /*把孙子进程的pid传给父进程*/ memcpy(&gradchild,p_addr,sizeof(pid_t)); } } /************************************************* Function name: caculate_play Called by : 函数key_pic_mp3 Parameter : int flag Description : 连续播放时,计算连续播放时间,调用函数startplaymp3开始新的播放 Return : int Autor & date : ykz 10.4.2 **************************************************/ int caculate_play(int flag) { int ret; /*kill掉当前播放MP3的子进程,孙子进程*/ kill(play_pid,SIGKILL); kill(gradchild,SIGKILL); wait(NULL); /*将共享内存清空*/ memset(p_addr,‘\0‘,1024); startplaymp3(&play_pid , flag); return 1; } /************************************************* Function name: restart_caculate_play Called by : 函数key_pic_mp3 Parameter : int flag Description : 未超过连续播放时间时,有新的图像或者外部中断检测到时调用函数 Return : void Autor & date : ykz 10.4.2 **************************************************/ void restart_caculate_play(int flag) { int ret; /*add 3 minute alarm*/ if(threemin_alarm){ if(signal(SIGALRM,my_func_3alarm)<0) perror("signal"); ret = alarm(THREE_ALARM); printf("[%s]Start add 3 minute alarm!\n",max(flag)); threemin_alarm = 0; } #if 1 /*判断是否有子进程,或者孙子进程,如果有则KILL掉*/ if(play_flag){ kill(play_pid,SIGKILL); kill(gradchild,SIGKILL); wait(NULL); //sleep(1); } #endif play_pid = 0; gradchild = 0; memset(p_addr,‘\0‘,1024); /*开始播放MP3*/ startplaymp3(&play_pid,flag); } /************************************************* Function name: key_pic_mp3 Called by : 函数main Parameter : int flag Description : 当检测到有外部中断,或者图像变化时处理函数 Return : int Autor & date : ykz 10.4.2 **************************************************/ int key_pic_mp3(int flag) { printf("------------------------- KEY_PIC_MP3 ----------------------------\n"); printf("[%s]Now detect ** %s ** have change\n",max(flag),max(flag)); int ret = 0; int over_flag_2; int play_flag_2; /*sleep_flag 用于判断,检测系统是否处于2小时的睡眠状态*/ if(sleep_flag){ printf("It is rainning!system is sleeping!\n"); struct tm *p; time_t timep; unsigned int second; time(&timep); p = localtime(&timep); second = (p->tm_hour)*60*60 + (p->tm_min) * 60 + p->tm_sec; printf("summary time:%d seconds,sleep:%d seconds,need sleep:%d seconds\n", SLEEP_TIME,second-time_tmp,SLEEP_TIME-(second-time_tmp)); return 0; } alarm_flag = flag; /*从sharemem中读出是否有MP3处在播放状态标识*/ memcpy(&play_flag_2,p_addr + sizeof(int),sizeof(int)); // printf("===>key_pic_mp3,play_flag_2=%d\n",play_flag_2); play_flag = play_flag_2; /*play_flag_2:当前是否有MP3在播放 0:当前没有MP3播放 1:子进程当前处在MP3播放状态 2:孙子当前播放MP3正常结束,且当前没有MP3播放*/ /*当前有MP3在播放*/ if(play_flag_2 == 1){ printf("[%s]Yes,have mp3 play\n",max(flag)); /*调用*/ ret = caculate_play(flag); } /*当前无MP3在播放*/ else{ printf("[%s]No, have not mp3 play\n",max(flag)); restart_caculate_play(flag); } return ret; } /************************************************* Function name: main Called by : Parameter : void Description : 主函数,检测按键是否有按下,通过pic.txt检测图像是否有变化 Return : int Autor & date : ykz 10.4.2 **************************************************/ main(void) { int buttons_fd,pic_fd; char pic_buf[1]; int key_value; int flag; int ret; int tmp_cnt; /*设备文件的打开*/ buttons_fd = open("/dev/buttons", 0); if(buttons_fd < 0) { perror("open device buttons"); exit(1); } printf("open buttons sucess!\n"); /*文件pic.txt记录是否有图像变化。 1:有图像变化 0:没有图像变化*/ pic_fd = open("pic.txt",O_RDWR | O_CREAT,0666); if(pic_fd < 0) { perror("open pic.txt"); exit(1); } printf("open pic.txt success!\n"); /*文件count.txt用于图像连续变化时,记录/root/motion中图片张数*/ cnt_fd = open("count.txt",O_RDWR | O_CREAT,0666); if(cnt_fd < 0){ perror("open count.txt"); exit(1); } printf("open count.txt success!\n"); system("ls > count.txt"); /*共享内存申请*/ if((shmid = shmget(IPC_PRIVATE,20,PERM))== -1) exit(1); p_addr = shmat(shmid,0,0); memset(p_addr,‘\0‘,1024); /*主循环,首先判断是外部中断还是图像变化*/ while(1){ /*外部中断检测,监听获取键值*/ ret = read(buttons_fd, &key_value, sizeof key_value); if (ret != sizeof key_value) perror("read buttons\n"); else { if(key_value){ printf("====================================================================\n"); printf("\n\n\n====================================================================\n"); printf("[type1]button detect,buttons_value: %d\n", key_value); /*外部中断处理*/ key_pic_mp3(1); } } //end else /*图形变化检测,当有图像变化时motion会产生一个事件, 事件处理为脚本/motion/appon,该脚本先点亮LED灯; 然后向文件/motion/pic.txt写入字符"1"表明现在有图像变化被检测到; 读取文件/motion/pic.txt第一个字符 0:没有图像变化 1:有图像变化*/ lseek(pic_fd, 0 ,SEEK_SET); ret = read(pic_fd, pic_buf, 1); if(ret==1) { if(pic_buf[0] == ‘1‘){ /*有图像变化被检测到*/ printf("====================================================================\n"); printf("\n\n\n====================================================================\n"); printf("[type2]pic motion detect!\n"); lseek(pic_fd, 0 ,SEEK_SET); if((ret = write(pic_fd, "0", 1))) lseek(pic_fd, 0 ,SEEK_SET); // system("rm /root/motion/* -rf"); pic_cnt = count_pic(); //printf("first pic_cnt=%d\n",pic_cnt); /*图像运动变化处理*/ key_pic_mp3(2); } else if(pic_buf[0] == ‘0‘){ tmp_cnt = count_pic(); if( (tmp_cnt-pic_cnt) > COMPARE_CNT){ printf("====================================================================\n"); printf("\n\n\n====================================================================\n"); printf("[type3]pic motion detect!\n"); // system("rm /root/motion/* -rf"); pic_cnt = count_pic(); /*连续图像运动变化处理*/ key_pic_mp3(2); } } //end else if } sleep (2); }//end while close (cnt_fd); close (pic_fd); close (buttons_fd); exit(0); }
该项目按键驱动程序: mini2440_buttons_rise.c #include <linux/module.h> #include <linux/kernel.h> #include <linux/fs.h> #include <linux/init.h> #include <linux/delay.h> #include <linux/poll.h> #include <linux/irq.h> #include <asm/irq.h> #include <linux/interrupt.h> #include <asm/uaccess.h> #include <mach/regs-gpio.h> #include <mach/hardware.h> #include <linux/platform_device.h> #include <linux/cdev.h> #include <linux/miscdevice.h> #define DEVICE_NAME "buttons" struct button_irq_desc { int irq; int pin; int pin_setting; int number; char *name; }; static struct button_irq_desc button_irqs [] = { {IRQ_EINT8 , S3C2410_GPG0 , S3C2410_GPG0_EINT8 , 0, "KEY0"}, {IRQ_EINT11, S3C2410_GPG3 , S3C2410_GPG3_EINT11 , 1, "KEY1"}, {IRQ_EINT13, S3C2410_GPG5 , S3C2410_GPG5_EINT13 , 2, "KEY2"}, {IRQ_EINT14, S3C2410_GPG6 , S3C2410_GPG6_EINT14 , 3, "KEY3"}, {IRQ_EINT15, S3C2410_GPG7 , S3C2410_GPG7_EINT15 , 4, "KEY4"}, {IRQ_EINT19, S3C2410_GPG11, S3C2410_GPG11_EINT19, 5, "KEY5"}, }; static int key_values = 0; static DECLARE_WAIT_QUEUE_HEAD(button_waitq); static volatile int ev_press = 0; static irqreturn_t buttons_interrupt(int irq, void *dev_id) { struct button_irq_desc *button_irqs = (struct button_irq_desc *)dev_id; int down; // udelay(0); down = !s3c2410_gpio_getpin(button_irqs->pin); if (!down) { //printk("rising\n"); key_values = button_irqs->number + 1; ev_press = 1; wake_up_interruptible(&button_waitq); } else { //printk("falling\n"); ev_press = 0; return 0; } return IRQ_RETVAL(IRQ_HANDLED); } static int s3c24xx_buttons_open(struct inode *inode, struct file *file) { int i; int err = 0; for (i = 0; i < sizeof(button_irqs)/sizeof(button_irqs[0]); i++) { //printk("gpio setup\n"); s3c2410_gpio_cfgpin(button_irqs[i].pin, button_irqs[i].pin_setting); //add by ykz if (button_irqs[i].irq < 0) { continue; } /* IRQ_TYPE_EDGE_FALLING,IRQ_TYPE_EDGE_RISING,IRQ_TYPE_EDGE_BOTH */ //err = request_irq(button_irqs[i].irq, buttons_interrupt, IRQ_TYPE_EDGE_BOTH, // button_irqs[i].name, (void *)&button_irqs[i]); err = request_irq(button_irqs[i].irq, buttons_interrupt, IRQ_TYPE_EDGE_RISING, button_irqs[i].name, (void *)&button_irqs[i]); if (err) break; } if (err) { i--; for (; i >= 0; i--) { if (button_irqs[i].irq < 0) { continue; } disable_irq(button_irqs[i].irq); free_irq(button_irqs[i].irq, (void *)&button_irqs[i]); } return -EBUSY; } ev_press = 0; return 0; } static int s3c24xx_buttons_close(struct inode *inode, struct file *file) { int i; for (i = 0; i < sizeof(button_irqs)/sizeof(button_irqs[0]); i++) { if (button_irqs[i].irq < 0) { continue; } free_irq(button_irqs[i].irq, (void *)&button_irqs[i]); } return 0; } static int s3c24xx_buttons_read(struct file *filp, char __user *buff, size_t count, loff_t *offp) { unsigned long err; //int i=0; #if 0 if (!ev_press) { if (filp->f_flags & O_NONBLOCK) return -EAGAIN; else wait_event_interruptible(button_waitq, ev_press); } #endif if(count != sizeof key_values) return -EINVAL; ev_press = 0; err = copy_to_user(buff, &key_values, sizeof(key_values)); key_values = 0; return sizeof(key_values); } static unsigned int s3c24xx_buttons_poll( struct file *file, struct poll_table_struct *wait) { unsigned int mask = 0; poll_wait(file, &button_waitq, wait); //printk("poll\n"); if (ev_press){ //printk("==>read\n"); mask |= POLLIN | POLLRDNORM; } return mask; } static struct file_operations dev_fops = { .owner = THIS_MODULE, .open = s3c24xx_buttons_open, .release = s3c24xx_buttons_close, .read = s3c24xx_buttons_read, .poll = s3c24xx_buttons_poll, }; static struct miscdevice misc = { .minor = MISC_DYNAMIC_MINOR, .name = DEVICE_NAME, .fops = &dev_fops, }; static int __init dev_init(void) { int ret; ret = misc_register(&misc); printk (DEVICE_NAME"\tinitialized\n"); return ret; } static void __exit dev_exit(void) { misc_deregister(&misc); } module_init(dev_init); module_exit(dev_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("FriendlyARM Inc.");
时间: 2024-11-18 17:10:25