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

news/2024/6/17 4:28:41 标签: linux, ARM, 嵌入式, 嵌入式硬件, 安防监控, 服务器

文章目录

  • 前言
  • 一、蜂鸣器的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 <stdio.h> 
#include "cgic.h" 
#include <string.h> 
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <sys/ipc.h>
#include <sys/msg.h>

#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, "<HTML><HEAD>\n"); 
	fprintf(cgiOut, "<TITLE>My CGI</TITLE></HEAD>\n"); 
	fprintf(cgiOut, "<BODY>"); 

	fprintf(cgiOut, "<H2>send sucess</H2>");

	//fprintf(cgiOut, "<a href='.html'>返回</a>"); 
	fprintf(cgiOut, "<meta http-equiv=\"refresh\" content=\"1;url=../a9_zigbee%d.html\">", sto_no[0]);
	fprintf(cgiOut, "</BODY>\n"); 
	fprintf(cgiOut, "</HTML>\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的驱动哦!


总结

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


http://www.niftyadmin.cn/n/5145408.html

相关文章

Eureka处理流程

1、Eureka Server服务端会做什么 1、服务注册 Client服务提供者可以向Server注册服务&#xff0c;并且内部有二层缓存机制来维护整个注册表&#xff0c;注册表是Eureka Client的服务提供者注册进来的。 2、提供注册表 服务消费者用来获取注册表 3、同步状态 通过注册、心跳机制…

代码随想录算法训练营第四十一天 | LeetCode 416. 分割等和子集

代码随想录算法训练营第四十一天 | LeetCode 416. 分割等和子集 文章链接&#xff1a;01背包理论基础 01背包理论基础&#xff08;滚动数组&#xff09; 分割等和子集 视频链接&#xff1a;01背包理论基础 01背包理论基础&#xff08;滚动数组&#xff09; 分割等和子集 1. 01 …

Unity计时器

using UnityEngine; using System.Collections;public class Timer : MonoBehaviour {public float duration 1.0f; // 定时器持续时间public bool isLooping false; // 是否循环public bool isPaused false; // 是否暂停计时器private float currentDuration 0.0f; // 当前…

[笔记] 字符串输入 #字符输入

字符串的多组输入格式 scanf("%c", &ch)读取单个字符&#xff0c;用EOF作为结束的判断标志。 刷题记录&#xff1a;[题] 查找最大元素 #字符输入 逐个字符手动读取&#xff0c;因为题目的要求&#xff0c;要对每个字符逐个操作&#xff0c;所以就输入的时候顺便…

深度学习之基于YoloV5火灾烟雾报警系统(GUI界面)

欢迎大家点赞、收藏、关注、评论啦 &#xff0c;由于篇幅有限&#xff0c;只展示了部分核心代码。 文章目录 一项目简介 二、功能三、火灾烟雾报警系统四. 总结 一项目简介 YoloV5 是深度学习中用于目标检测的一种算法&#xff0c;可以对输入的图像进行识别&#xff0c;标识出…

55个Java毕设项目推荐【源码好优多】

55个Java毕设项目推荐&#xff0c;实践出真知&#xff0c;现在要想知道自己的到底技术达不达标&#xff0c;项目就是检验的唯一标准。 下面是我整理准备的55个Java毕设项目合集&#xff1a; 1、网上订购管理系统 2、健康管理系统 3、项目辅导视频 4、医院在线挂号 5、在线花店…

YOLOV8最简图像分割推理代码

安装YOLOV8 首先要去YOLOV8的官网安装库 YOLOV8官方网站 # Install the ultralytics package from PyPI pip install ultralytics安装opencv pip install opencv-pythonimport cv2 from ultralytics import YOLO# Load the YOLOv8 model model YOLO(yolov8n-seg.pt)# Open …

exe4j打包jar包

1. 确保jre包&#xff08;环境变量&#xff09;在运行的jar包旁边 1.2. 3. 4. 5. 6. 8. -Dfile.encodingutf-8 9. 10. 12 选中刚才同目录的jre包&#xff08;环境变量&#xff09; 接下来默认即可