安防监控项目---web网页下发命令控制蜂鸣器(蜂鸣器响起来)

文章目录

  • 前言
  • 一、蜂鸣器的CGI接口
  • 二、请求线程和硬件操作
    • 2.1 请求线程
    • 2.2 buzzer蜂鸣器线程
  • 总结


前言

书接上期,和大家分享了web下发命令控制led之后呢,相信大家已经迫不及待的想要试一下是不是蜂鸣器也能响起来呢!哈哈哈,别说是你们了,我也有点迫不及待,其实led的控制中,我们把框架已经解释的非常清楚了,所以接下来要做的事情就变得非常简单了,只需要怎么办呢,就是往框架里面添加具体的蜂鸣器控制内容;下面我们具体来看看!


一、蜂鸣器的CGI接口

首先使用CGI打通HTML和A9平台,使得两者能够沟通起来;这个文件呢最终能够生成a9_beep.cgi文件,再拷贝到A9平台的BOA服务器下的cgi-bin目录下进行存放,这样HTML在下发命令后,通过该文件进行解析控制命令字,进而通过消息队列进行进程间通信,紧接着应用层的主框架接收请求线程(pthread_client_request.c)从消息队列中读取数据,进行判断是那个类型的数据(具体是哪一个设备),之后唤醒对应的睡眠线程(pthread_buzzer.c),唤醒后进行对应的硬件操作(ioctl);

#include  
#include "cgic.h" 
#include  
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define N 8
struct msg
{
	long type;
	long msgtype;
	unsigned char text[N];
};

int cgiMain() 
{ 
	key_t key;
	char buf[N];
	char sto_no[2];
	int msgid;
	struct msg msg_buf;
	memset(&msg_buf,0,sizeof(msg_buf));
	
	cgiFormString("beep",buf,N); 			//beep网页键值进行接收,接收8个字节
	cgiFormString("store",sto_no,2);  

	if((key = ftok("/tmp", 'g')) < 0) 		//创建IPC对象键值(生成一个IPC对象),用于消息队列,参数1是指定的文件名,参数2是子序号
	{
		perror("ftok");
		exit(1);
	}

	if((msgid = msgget(key, 0666)) < 0) 	//创建一个消息队列
	{
		perror("msgget");
		exit(1);
	}

	switch (buf[0])
	{
		case '0':
			{
				//关闭蜂鸣器
				msg_buf.text[0] = ((sto_no[0] - 48)) << 6 | (1 << 4) | (0 << 0); 		//sto_no[0]-48表示从网页拿到的是字符串,这里需要转化为数字,48就是0的ASCII码,再向左移动6位(协议制定6 7位为平台编号)
																						//4-5位置为为设备编号,表示操作哪一个设备,led还是蜂鸣器,0-4位(操作掩码)表示关闭打开等操作
				break;
			}
		case '1':
			{
				//打开蜂鸣器
				msg_buf.text[0] = ((sto_no[0] - 48)) << 6 | (1 << 4) | (1 << 0);
				break;
			}
		case '2':
			{
				//自动报警关闭
				msg_buf.text[0] = ((sto_no[0] - 48)) << 6 | (1 << 4) | (2 << 0);
				break;
			}			
		case '3':
			{
				//自动关闭打开
				msg_buf.text[0] = ((sto_no[0] - 48)) << 6 | (1 << 4) | (3 << 0);
				break;
			}
	}

	msg_buf.type = 1L;  			 //1L表示home1
	msg_buf.msgtype = 2L; 			 //表示设备编号led还是..
	msgsnd(msgid, &msg_buf,sizeof(msg_buf)-sizeof(long),0); //向消息队列中写入消息,将消息发出,在A9端进行接收
									//这里发送的字节数为sizeof(msg_buf)-sizeof(long)的原因是由于不需要传送消息类型,只需要传送具体的消息大小即可(也就是msg结构体的第一个变量不需要作为发送的有效字节传送)
	sto_no[0] -= 48; 				//为了后面生成是哪一个操作引起网页反馈(生成二级网页名序号)

	cgiHeaderContentType("text/html\n\n"); 
	fprintf(cgiOut, "\n"); 
	fprintf(cgiOut, "My CGI\n"); 
	fprintf(cgiOut, ""); 

	fprintf(cgiOut, "

send sucess

"
); //fprintf(cgiOut, "返回"); fprintf(cgiOut, "", sto_no[0]); fprintf(cgiOut, "\n"); fprintf(cgiOut, "\n"); return 0; }

二、请求线程和硬件操作

2.1 请求线程

#include "data_global.h"
#include "linuxuart.h"

//消息队列id
extern int msgid;
//ipc对象键值
extern key_t key;
//锁资源
extern pthread_mutex_t mutex_client_request,
        		mutex_refresh,
        		mutex_sqlite,
	        	mutex_transfer,
	        	mutex_analysis,
	        	mutex_sms,
	        	mutex_buzzer,
	         	mutex_led,
	         	mutex_camera;
//条件变量
extern pthread_cond_t  cond_client_request,
        		cond_refresh,
        		cond_sqlite,
	        	cond_transfer,
	        	cond_analysis,
	        	cond_sms,
	        	cond_buzzer,
	         	cond_led,
	         	cond_camera;
//模块的控制命令字
extern unsigned char cmd_led;
extern unsigned char  cmd_buzzer;
extern unsigned char  cmd_fan;

//GPRS模块的电话号
extern char recive_phone[12] ;
extern char center_phone[12] ;

//消息队列通信结构体
struct msg msgbuf;

void *pthread_client_request(void *arg)
{
	if((key = ftok("/tmp",'g')) < 0){
		perror("ftok failed .\n");
		exit(-1);
	}

	msgid = msgget(key,IPC_CREAT|IPC_EXCL|0666); 		//检测消息队列中是否有这个键值,如果有则返回对应的-1,没有则创建并返回创建消息队列的id
	if(msgid == -1)	{
		if(errno == EEXIST){ 							//如果已经存在
			msgid = msgget(key,0777); 					//设置权限为0777
		}else{
			perror("fail to msgget");
			exit(1);
		}
	}
	printf("pthread_client_request\n");
	
	while(1){
		bzero(&msgbuf,sizeof(msgbuf)); 					//清理操作,但一般使用memset,功能更加强大一点
		printf("wait form client request...\n"); 
		msgrcv (msgid, &msgbuf, sizeof (msgbuf) - sizeof (long), 1L, 0); //从消息队列中读取消息
		printf ("Get %ldL msg\n", msgbuf.msgtype); 		//打印消息类型
		printf ("text[0] = %#x\n", msgbuf.text[0]); 	//打印消息内容

		//判断消息类型,从而确定是哪一个设备
		switch(msgbuf.msgtype){
			case 1L:
				//1L的类型是led的消息类型,此时上锁,等待消息内容也就是控制命令字复制完成后解锁,通过pthread_cond_signal唤醒pthread_led.c这个led线程,进行led的具体硬件操作
				pthread_mutex_lock(&mutex_led);
				printf("hello led\n");
				cmd_led = msgbuf.text[0];
				pthread_mutex_unlock(&mutex_led);
				pthread_cond_signal(&cond_led);
				break;
			case 2L:
				//2L表示beep的消息类型
				//这里呢相信大家天赋异禀,看懂了上面led的,beep也不是问题
				pthread_mutex_unlock(&mutex_buzzer);
				printf("hello beep1\n");
				pthread_mutex_lock(&mutex_buzzer);
				cmd_buzzer = msgbuf.text[0];
				pthread_mutex_unlock(&mutex_buzzer);
				pthread_cond_signal(&cond_buzzer);
				break;
		}
	}
}
#endif 

2.2 buzzer蜂鸣器线程

首先呢这个线程起初处于睡眠状态,当请求线程赋值完成控制命令字后,发送信号唤醒蜂鸣器线程;

#include "data_global.h"
#include "buzzer.h"
//第2N个元素表示声调   第2N+1个元素表示该声调的时间
unsigned char MUSIC[1000] ={
	//祝你平安
	0x26,0x20,0x20,0x20,0x20,0x20,0x26,0x10,0x20,0x10,0x20,0x80,0x26,0x20,0x30,0x20,
	0x30,0x20,0x39,0x10,0x30,0x10,0x30,0x80,0x26,0x20,0x20,0x20,0x20,0x20,0x1c,0x20,
	0x20,0x80,0x2b,0x20,0x26,0x20,0x20,0x20,0x2b,0x10,0x26,0x10,0x2b,0x80,0x26,0x20,
	0x30,0x20,0x30,0x20,0x39,0x10,0x26,0x10,0x26,0x60,0x40,0x10,0x39,0x10,0x26,0x20,
	0x30,0x20,0x30,0x20,0x39,0x10,0x26,0x10,0x26,0x80,0x26,0x20,0x2b,0x10,0x2b,0x10,
	0x2b,0x20,0x30,0x10,0x39,0x10,0x26,0x10,0x2b,0x10,0x2b,0x20,0x2b,0x40,0x40,0x20,
	0x20,0x10,0x20,0x10,0x2b,0x10,0x26,0x30,0x30,0x80,0x18,0x20,0x18,0x20,0x26,0x20,
	0x20,0x20,0x20,0x40,0x26,0x20,0x2b,0x20,0x30,0x20,0x30,0x20,0x1c,0x20,0x20,0x20,
	0x20,0x80,0x1c,0x20,0x1c,0x20,0x1c,0x20,0x30,0x20,0x30,0x60,0x39,0x10,0x30,0x10,
	0x20,0x20,0x2b,0x10,0x26,0x10,0x2b,0x10,0x26,0x10,0x26,0x10,0x2b,0x10,0x2b,0x80,
	0x18,0x20,0x18,0x20,0x26,0x20,0x20,0x20,0x20,0x60,0x26,0x10,0x2b,0x20,0x30,0x20,
	0x30,0x20,0x1c,0x20,0x20,0x20,0x20,0x80,0x26,0x20,0x30,0x10,0x30,0x10,0x30,0x20,
	0x39,0x20,0x26,0x10,0x2b,0x10,0x2b,0x20,0x2b,0x40,0x40,0x10,0x40,0x10,0x20,0x10,
	0x20,0x10,0x2b,0x10,0x26,0x30,0x30,0x80,0x00,
	//路边的野华不要采
	0x30,0x1C,0x10,0x20,0x40,0x1C,0x10,0x18,0x10,0x20,0x10,0x1C,0x10,0x18,0x40,0x1C,
	0x20,0x20,0x20,0x1C,0x20,0x18,0x20,0x20,0x80,0xFF,0x20,0x30,0x1C,0x10,0x18,0x20,
	0x15,0x20,0x1C,0x20,0x20,0x20,0x26,0x40,0x20,0x20,0x2B,0x20,0x26,0x20,0x20,0x20,
	0x30,0x80,0xFF,0x20,0x20,0x1C,0x10,0x18,0x10,0x20,0x20,0x26,0x20,0x2B,0x20,0x30,
	0x20,0x2B,0x40,0x20,0x20,0x1C,0x10,0x18,0x10,0x20,0x20,0x26,0x20,0x2B,0x20,0x30,
	0x20,0x2B,0x40,0x20,0x30,0x1C,0x10,0x18,0x20,0x15,0x20,0x1C,0x20,0x20,0x20,0x26,
	0x40,0x20,0x20,0x2B,0x20,0x26,0x20,0x20,0x20,0x30,0x80,0x20,0x30,0x1C,0x10,0x20,
	0x10,0x1C,0x10,0x20,0x20,0x26,0x20,0x2B,0x20,0x30,0x20,0x2B,0x40,0x20,0x15,0x1F,
	0x05,0x20,0x10,0x1C,0x10,0x20,0x20,0x26,0x20,0x2B,0x20,0x30,0x20,0x2B,0x40,0x20,
	0x30,0x1C,0x10,0x18,0x20,0x15,0x20,0x1C,0x20,0x20,0x20,0x26,0x40,0x20,0x20,0x2B,
	0x20,0x26,0x20,0x20,0x20,0x30,0x30,0x20,0x30,0x1C,0x10,0x18,0x40,0x1C,0x20,0x20,
	0x20,0x26,0x40,0x13,0x60,0x18,0x20,0x15,0x40,0x13,0x40,0x18,0x80,0x00,
};

extern pthread_mutex_t mutex_buzzer;
extern pthread_cond_t  cond_buzzer;
//A9蜂鸣器控制线程.
void *pthread_buzzer(void *arg)
{
	printf("pthread_buzzer\n");
    
	int i = 0;
	int fd;
	beep_desc_t beeper;
	
	fd = open(BEEPER_DEV, O_RDWR);
	if ( fd == -1 ) {
		perror("open beeper failed.\n");
		return NULL;
	}
	printf("fd  :%d.\n",fd);


	while(1) {
		//pthread_mutex_unlock(&mutex_buzzer);
		pthread_mutex_lock(&mutex_buzzer);
		printf("buzzer ioctl:************\n");
		pthread_cond_wait(&cond_buzzer, &mutex_buzzer);
		printf("buzzer ioctl:************\n");
		if(cmd_buzzer == 0x51)
		{
			ioctl(fd,BEEP_ON);
			for(i = 0;i < sizeof(MUSIC)/sizeof(MUSIC[0]); i += 2)
			{
				beeper.tcnt = MUSIC[i];
				beeper.tcmp = MUSIC[i]/2;
				ioctl(fd,BEEP_FREQ,&beeper);
				usleep(MUSIC[i+1] * 20000);
			}
		}
		pthread_mutex_unlock(&mutex_buzzer);
	}
	printf("music play over....\n");
	close(fd);
}

当然一定要在A9平台加载beep的驱动哦!


总结

至此呢蜂鸣器的控制完结了,是不是感觉非常简单呢,这个就是照猫画虎了;可以说没啥技术含量,但是其中的细节还是值得大家注意的!最后呢希望大家能够遇到困难后,经过折腾后把这个操作完成!因为只有遇到了问题才能吸取教训,要是每一件事情都一次性过,那么当真正的问题出来的时候,我们往往显得黔驴技穷,所以在平时就要锻炼自己的能力,遇到问题不要着急,解决问题的过程就是成长!最后,各位小伙伴们如果有收获,可以点赞收藏哦,你们的认可是我创作的动力,一起加油!

你可能感兴趣的:(安防监控项目,linux,ARM,嵌入式,嵌入式硬件,安防监控,服务器)