目录
windows 10、Linux、arm cortex A9(Exynos 4412)、ubuntu20.04、zigebee通信、摄像头外设、cortex-M0;
摄像头模块;qt界面及语音识别模块;qt客户端模块;服务器模块;
下面是QT的模块:使用的模式是:QT widgets applicantion;使用的基类是:widget
处理http请求数据并再次请求百度api再次返回的json:
开发平台/开发环境:
windows 10、Linux、arm cortex A9(Exynos 4412)、ubuntu20.04、zigebee通信、摄像头外设、cortex-M0;
arm cortex A9(Exynos 4412):内部使用裁剪后的Linux系统来搭建服务器。
ubuntu20.04:使用arm-linux-gcc工具编译成可以在arm架构芯片上执行的程序。
zigbee协调节点板块与A9板使用串口通信,ZigBee 模块主要实现的是数据的透传的工作,一个 ZigBee 节点接收服务器的消息无线转到ZigBee 的另外一个节点,另外一个节点把数据发送给终端设备,完成操作。同时也可以反过来,是终端设备的环境信息。我使用的CC2530 的单片机。它是一款完全兼容 8051 的内核,同时支持 IEEE 802.15.4协议的无线射频的单片机。这个项目主要是使用 ZigBee 提供的协议栈来进行开发。使用了其中的函数接口来完成项目需求的应用程序。
数据终端采集:
数据采集模块使用的是 ARM 系列的 Cortex-M0 芯片,在这个芯片的基础之上。分别外接了以下几个设备。有温湿度、光照、三轴传感器与 RFID 射频模块。还是风扇、LED、蜂鸣器、OLED 硬件。同时集成第 94 页了 RS485、CAN 总线。在这个项目中,使用到了温湿度、光照、三轴传感器获取当前的环境信息,发送到ZigBee 的节点。从 ZigBee 的节点接收命令通过风扇、LED、蜂鸣器来模拟家中的电器设备。在这个模块中使用了 ARM 开发的一些流程,如配置寄存器让硬件工作。一些总线设备的使用,如 SPI、I2C。还有中断的机制和定时器的使用,如本项目中启用了一个 32 位的定时器来做延时操作。
项目模块:
摄像头模块;qt界面及语音识别模块;qt客户端模块;服务器模块;
项目描述:
qt客户端可以通过连接服务器后,通过语音识别,确定想要的功能,可以通过服务器显示摄像头内的视频内容,也可以通过服务器的串口通信去操控cortex M0的LED灯,风扇,蜂鸣器,服务器可以通过串口通信实时地获得cortex M0上的温度,湿度,光照信息,并发送给客户端,qt客户端还可以获取天气预报信息或者打开某一个应用。
具体代码:
1.串口模块:
serial.h:
#ifndef SERIAL_H
#define SERIAL_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <assert.h>
#include <termios.h>
#include <error.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/stat.h>
int serial_set(char *path);
int serial_write(int fd);
int serial_close(int fd);
int serial_ctrl(int fd,char *p);
int serial_getdata(int fd);
#endif
serial.c:
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <termios.h>
#include <sys/types.h>
#include <string.h>
#define N 36
int serial_set(char *path)
{
struct termios options;
/*
struct termios {
tcflag_t c_iflag;//输入标志
tcflag_t c_oflag;//输出标志
tcflag_t c_lflag;// 本地标志
tcflag_t c_cc[NCCS];//控制字符
};
*/
int fd = open(path,O_RDWR | O_NOCTTY | O_NDELAY);//打开串口
if(-1 == fd)
{
perror("open error");
return -1;
}
if(-1 == fcntl(fd,F_SETFL,0))
{
printf("fcntl error");
return -1;
}
cfsetispeed(&options,B115200);
cfsetospeed(&options,B115200);
options.c_cflag |= CLOCAL;
//修改控制模式,使得能够从串口中读取输入数据
options.c_cflag |= CREAD;
options.c_oflag &= ~(ONLCR | OCRNL);
options.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
options.c_iflag &= ~(ICRNL | INLCR);
options.c_iflag &= ~(IXON | IXOFF | IXANY);
//不使用流控制
options.c_cflag &= ~CRTSCTS;
options.c_cflag |= CS8;
options.c_cflag &= ~CSTOPB;
options.c_cflag &= ~PARENB;
options.c_iflag &= ~INPCK;
tcsetattr(fd, TCSANOW, &options); //TCSANOW更改立即发生
return fd;
}
int serial_close(int fd) //关闭串口
{
if (close(fd))
{
perror("serial close error");
return -1;
}
return 0;
}
int serial_ctrl(int fd,char *p)
{
unsigned char envbuf[36]={0,0x08,0x24,0x00};
if(strncmp(p,"light_on",8)==0)
{
//envbuf[] = {0xdd,id,24,00,命令}
//发送命令开灯
envbuf[0]=0xdd;
envbuf[4]=0x00; //开灯命令
if(write(fd,envbuf,36)<0)
{
perror("write");
return -1;
}
printf("控制:%x %x %x %x %x\n",envbuf[0],envbuf[1],envbuf[2],envbuf[3],envbuf[4]);
}
else if(strncmp(p,"light_off",9)==0)
{
//发送命令关灯
envbuf[0]=0xdd;
envbuf[4]=0x01; //关灯
if(write(fd,envbuf,36)<0)
{
perror("write");
return -1;
}
printf("控制:%x %x %x %x %x\n",envbuf[0],envbuf[1],envbuf[2],envbuf[3],envbuf[4]);
}
else if(strncmp(p,"dshi_on",9)==0)
{
//发送命令打开蜂鸣器
envbuf[0]=0xdd;
envbuf[4]=0x02;
if(write(fd,envbuf,36)<0)
{
perror("write");
return -1;
}
printf("控制:%x %x %x %x %x\n",envbuf[0],envbuf[1],envbuf[2],envbuf[3],envbuf[4]);
}
else if(strncmp(p,"dshi_off",10)==0)
{
//发送命令关闭蜂鸣器
envbuf[0]=0xdd;
envbuf[4]=0x03;
if(write(fd,envbuf,36)<0)
{
perror("write");
return -1;
}
printf("控制:%x %x %x %x %x\n",envbuf[0],envbuf[1],envbuf[2],envbuf[3],envbuf[4]);
}
else if(strncmp(p,"feng_on",7)==0)
{
printf("feng_on\n");
//发送命令打开风扇
envbuf[0]=0xdd;
envbuf[4]=0x04;
printf("控制:%x %x %x %x %x\n",envbuf[0],envbuf[1],envbuf[2],envbuf[3],envbuf[4]);
if(write(fd,envbuf,36)<0)
{
perror("write");
return -1;
}
}
else if(strncmp(p,"feng_off",8)==0)
{
//发送命令关闭风扇
envbuf[0]=0xdd;
envbuf[4]=0x08;
if(write(fd,envbuf,36)<0)
{
perror("write");
return -1;
}
printf("控制:%x %x %x %x %x\n",envbuf[0],envbuf[1],envbuf[2],envbuf[3],envbuf[4]);
}
// memset(p, 0, 32); //清空buf
return 0;
}
摄像头:
camera.h:
#ifndef _CAMERA_H
#define _CAMERA_H
#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <errno.h>
#include <linux/videodev2.h>
#include <string.h>
#include <sys/mman.h>
#define pwd "/dev/video0"
#define pwd2 "/dev/video1"
#define c_count 4
unsigned char *mmps[c_count];
unsigned long mmpsize[c_count];
int camera_init();
int camera_star(int fd);
//出队,采集数据
int dqbuf(int fd,int index);
//入队,归还数据
int qbuf(int fd,int index);
int camera_stop(int fd);
#endif
camera.c
#include "camera.h"
int camera_init()
{
int ret;
//
v4l2_std_id std;
//
struct v4l2_format fmt;
//使用非阻塞方式打开摄像头设备
int camera_fd = open(pwd,O_RDWR,0);
if(camera_fd < 0)
{
camera_fd = open(pwd2,O_RDWR | O_NONBLOCK,0);
}
if(camera_fd < 0)
{
printf("摄像头打开失败\n");
return -1;
}
printf("成功打开摄像头\n");
//使用ioctl函数对设备的io通道进行管理
//检查当前视频设备支持的标准,使用VIDIOC_QUERYSTD
/* do{
ret = ioctl(camera_fd,VIDIOC_QUERYSTD,&std);
}while(-1 == ret && errno == EAGAIN);
switch (std)
{
case V4L2_STD_NTSC:
printf("视频标准为NTSC\n");
break;
case V4L2_STD_PAL:
printf("视频标准为PAL\n");
break;
}
*/
//设置视频捕获格式
bzero(&fmt,sizeof(fmt));
//摄像头的数据流类型,必须为V4L2_BUF_TYPE_VIDEO_CAPTURE
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmt.fmt.pix.width = 640; //必须为16的倍数
fmt.fmt.pix.height = 480; //必须为16的倍数
//视频数据存储类型YUYV 或者 RGB
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG;
fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
if(-1 == ioctl(camera_fd,VIDIOC_S_FMT,&fmt))
{
printf("设置视频捕获格式失败\n");
return -2;
}
//为视频捕获分配内存
struct v4l2_requestbuffers req;
bzero(&req,sizeof(req));
req.count = c_count;
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
req.memory = V4L2_MEMORY_MMAP;
if(-1 == ioctl(camera_fd,VIDIOC_REQBUFS,&req))
{
printf("分配内存出错\n");
return -3;
}
printf("分配内存成功\n");
int i;
struct v4l2_buffer buffer;
for(i=0;i<c_count;i++)
{
buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buffer.memory = V4L2_MEMORY_MMAP;
buffer.index = i;
if(0 > ioctl(camera_fd,VIDIOC_QUERYBUF,&buffer))
{
printf("取出映射地址出错\n");
return -1;
}
//映射
mmps[i] = mmap(NULL,buffer.length,PROT_READ|PROT_WRITE,MAP_SHARED,camera_fd,buffer.m.offset);
mmpsize[i] = buffer.length;
if((void *)-1 == mmps[i])
{
printf("映射地址时出错\n");
return -2;
}
//入队操作
if(0 > ioctl(camera_fd,VIDIOC_QBUF,&buffer))
{
printf("入队失败\n");
return -3;
}
}
printf("摄像头初始化成功...\n");
return camera_fd;
}
int camera_star(int fd)
{
//开始采集
enum v4l2_buf_type type=V4L2_BUF_TYPE_VIDEO_CAPTURE;
if(0 > ioctl(fd,VIDIOC_STREAMON,&type))
{
perror("采集失败:");
return -1;
}
printf("开始采集...\n");
return 0;
}
//出队,采集数据
int dqbuf(int fd,int index)
{
struct v4l2_buffer buffer;
bzero(&buffer,sizeof(buffer));
buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buffer.memory=V4L2_MEMORY_MMAP;
buffer.index = index;
if(0 > ioctl(fd,VIDIOC_DQBUF,&buffer))
{
printf("读取视频内容失败\n");
perror("read");
return -1;
}
return 0;
}
//入队,归还数据
int qbuf(int fd,int index)
{
struct v4l2_buffer buffer;
bzero(&buffer,sizeof(buffer));
buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buffer.memory=V4L2_MEMORY_MMAP;
buffer.index = index;
if(0 > ioctl(fd,VIDIOC_QBUF,&buffer))
{
printf("入队失败\n");
return -1;
}
return 0;
}
/*
int getpic(int fd)
{
//映射队列空间到用户空间VIDIOC_QUERYBUF,VIDIOC_QBUF
struct v4l2_buffer buffer;
int i=0;
while(1)
{
//出对,获得采集数据
bzero(&buffer,sizeof(buffer));
buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buffer.memory=V4L2_MEMORY_MMAP;
buffer.index = i;
if(0 > ioctl(fd,VIDIOC_DQBUF,&buffer))
{
printf("读取视频内容失败\n");
perror("read");
return -4;
}
//测试图片
FILE *file = fopen("1.jpg","w+");
fwrite(mmps[buffer.index],buffer.length,1,file);
fclose(file);
//入对
if(0 > ioctl(fd,VIDIOC_QBUF,&buffer))
{
printf("入队失败\n");
return -5;
}
i++;
i=i%4;
}
return 0;
}
*/
int camera_stop(int fd)
{
//停止采集
int type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if(0 > ioctl(fd,VIDIOC_STREAMOFF,&type))
{
printf("停止摄像头错误\n");
return -1;
}
printf("停止摄像头\n");
return 0;
}
/*
int main()
{
int camera_fd = camera_init();
if(0 > camera_fd)
{
return -1;
}
if(0 > camera_star(camera_fd))
{
return -1;
}
int i=0;
while(1)
{
if(0 > dqbuf(camera_fd,i))//出队,从mmps映射的地址读取数据
{
return -1;
}
FILE *file = fopen("1.jpg","w+");
fwrite(mmps[i],mmpsize[i],1,file);
fclose(file);
if(0 > qbuf(camera_fd,i))//入队
{
return -1;
}
i++;
i%=4;
}
//getpic(camera_fd);
camera_stop(camera_fd);
return 0;
}
*/
摄像头服务器:
camera_server.h:
#ifndef _CAMERA__SERVER_H
#define _CAMERA__SERVER_H
#include "camera.h"
#include <pthread.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <ctype.h>
#include <pthread.h>
int camera_all();
void * camera_close_thread(void * fd);
void * camera_send_thread(void * fd);
void * camera_thread(void * fd);
#endif
camera_server.c:
#include "camera_server.h"
int camera_fd = -1;
int socket_fd = -1;
char * pic_buf [4] = {NULL,NULL,NULL,NULL};
long unsigned int pic_len = 0;
int camera_i=0;
void * camera_thread(void * fd)
{
printf("开始摄像头线程\n");
if(0 > camera_star(camera_fd))
{
pthread_exit(NULL);
}
while(1)
{
if(0 > dqbuf(camera_fd,camera_i))//出队,从mmps映射的地址读取数据
{
pthread_exit(NULL);
}
if(NULL == pic_buf[0])
{
pic_len= mmpsize[camera_i];
pic_buf[0] = (char *)malloc(pic_len);
pic_buf[1] = (char *)malloc(pic_len);
pic_buf[2] = (char *)malloc(pic_len);
pic_buf[3] = (char *)malloc(pic_len);
}
bzero(pic_buf[camera_i],pic_len);
memcpy(pic_buf[camera_i],mmps[camera_i],pic_len);
if(0 > qbuf(camera_fd,camera_i))//入队
{
pthread_exit(NULL);
}
camera_i++;
camera_i%=4;
}
pthread_exit(NULL);
}
void * camera_send_thread(void * fd)
{
int connfd = *(int *)fd;
int j=0;
char len[10]={0};
char buf[10]={0};
while(1)
{
if(0>=read(connfd,buf,sizeof(buf)))
{
printf("客户端退出\n");
break;
}
else
{
sprintf(len,"%ld",pic_len);
send(connfd,len,sizeof(len),0);
j=camera_i-1;
if(-1 == j)
{
j = 3;
}
send(connfd,pic_buf[j],pic_len,0);
}
}
printf("发送结束\n");
pthread_exit(NULL);
}
void * camera_close_thread(void * fd)
{
while(1)
{
char cmd[16];
bzero(cmd,sizeof(cmd));
scanf("%s",cmd);
getchar();
if(0 == strcmp(cmd,"quit"))
{
printf("摄像头服务器关闭。。。\n");
break;
}
}
camera_stop(camera_fd);
exit(0);
}
int camera_all()
//int main()
{
//创建套接字
socket_fd = socket(AF_INET,SOCK_STREAM,0);
if(-1 == socket_fd)
{
perror("socket");
return -1;
}
printf("摄像头网络套接字创建成功\n");
//优化2:解决地址冲突
int opt = 1;
setsockopt(socket_fd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));
//填充ip,端口,协议等
struct sockaddr_in ser_addr = {
.sin_family = AF_INET,
.sin_port = htons(8888),//端口号1024-49151
.sin_addr.s_addr = inet_addr("0.0.0.0")
};
//绑定ip和端口等信息
int ret = bind(socket_fd,(struct sockaddr *) &ser_addr,sizeof(ser_addr));
if(-1 == ret)
{
perror("bind");
return -1;
}
printf("绑定成功\n");
//建立监听
ret = listen(socket_fd,4);
if(-1 == ret)
{
perror("listen");
return -1;
}
printf("建立监听。。。\n");
struct sockaddr_in accept_addr;
bzero(&accept_addr,sizeof(accept_addr));
socklen_t addrlen = sizeof(accept_addr);
//初始化摄像头
camera_fd = camera_init();
if(0 > camera_fd)
{
pthread_exit(NULL);
}
pthread_t tid1,tid2,tid3;
if(-1 == pthread_create(&tid1,NULL,camera_thread,NULL))
{
printf("摄像头线程启动失败\n");
return -1;
}
pthread_detach(tid1);
while(1)
{
int connfd = accept(socket_fd,(struct sockaddr *)&accept_addr,&addrlen);
if(-1 == pthread_create(&tid2,NULL,camera_close_thread,NULL))
{
printf("关闭摄像头线程启动失败\n");
return -1;
}
pthread_detach(tid2);
printf("客户端连接成功\n");
printf("IP:%s,port:%d,addrlen:%d\n",inet_ntoa(accept_addr.sin_addr),accept_addr.sin_port,addrlen);
printf("启动摄像头发送线程\n");
if(-1 == pthread_create(&tid3,NULL,camera_send_thread,(void *)&connfd))
{
printf("摄像头线程启动失败\n");
return -1;
}
pthread_detach(tid3);
}
}
服务器:
server.h
#ifndef SER_H
#define SER_H
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/ip.h>
#include<netinet/in.h>
#include<stdio.h>
#include<stdlib.h>
#include<arpa/inet.h>
#include<pthread.h>
#include<string.h>
#include<unistd.h>
#include<semaphore.h>
#define N 16
#define SIZE 36
typedef struct sockaddr_in SA_in;
typedef struct sockaddr SA;
typedef unsigned short uint_16_t;
typedef unsigned int uint_32_t;
int tcp_init(const char *ip,const int port ,const int backlog);
int getorder(const int connfd);
void *sendvideo(void *arg);
void *serial_cntl(void *arg);
void *senddata_cli(void *arg);
#endif
server.c
#include "camera_server.h"
int camera_fd = -1;
int socket_fd = -1;
char * pic_buf [4] = {NULL,NULL,NULL,NULL};
long unsigned int pic_len = 0;
int camera_i=0;
void * camera_thread(void * fd)
{
printf("开始摄像头线程\n");
if(0 > camera_star(camera_fd))
{
pthread_exit(NULL);
}
while(1)
{
if(0 > dqbuf(camera_fd,camera_i))//出队,从mmps映射的地址读取数据
{
pthread_exit(NULL);
}
if(NULL == pic_buf[0])
{
pic_len= mmpsize[camera_i];
pic_buf[0] = (char *)malloc(pic_len);
pic_buf[1] = (char *)malloc(pic_len);
pic_buf[2] = (char *)malloc(pic_len);
pic_buf[3] = (char *)malloc(pic_len);
}
bzero(pic_buf[camera_i],pic_len);
memcpy(pic_buf[camera_i],mmps[camera_i],pic_len);
if(0 > qbuf(camera_fd,camera_i))//入队
{
pthread_exit(NULL);
}
camera_i++;
camera_i%=4;
}
pthread_exit(NULL);
}
void * camera_send_thread(void * fd)
{
int connfd = *(int *)fd;
int j=0;
char len[10]={0};
char buf[10]={0};
while(1)
{
if(0>=read(connfd,buf,sizeof(buf)))
{
printf("客户端退出\n");
break;
}
else
{
sprintf(len,"%ld",pic_len);
send(connfd,len,sizeof(len),0);
j=camera_i-1;
if(-1 == j)
{
j = 3;
}
send(connfd,pic_buf[j],pic_len,0);
}
}
printf("发送结束\n");
pthread_exit(NULL);
}
void * camera_close_thread(void * fd)
{
while(1)
{
char cmd[16];
bzero(cmd,sizeof(cmd));
scanf("%s",cmd);
getchar();
if(0 == strcmp(cmd,"quit"))
{
printf("摄像头服务器关闭。。。\n");
break;
}
}
camera_stop(camera_fd);
exit(0);
}
int camera_all()
//int main()
{
//创建套接字
socket_fd = socket(AF_INET,SOCK_STREAM,0);
if(-1 == socket_fd)
{
perror("socket");
return -1;
}
printf("摄像头网络套接字创建成功\n");
//优化2:解决地址冲突
int opt = 1;
setsockopt(socket_fd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));
//填充ip,端口,协议等
struct sockaddr_in ser_addr = {
.sin_family = AF_INET,
.sin_port = htons(8888),//端口号1024-49151
.sin_addr.s_addr = inet_addr("0.0.0.0")
};
//绑定ip和端口等信息
int ret = bind(sock

本文介绍了一个使用Qt界面和语音识别技术的智能家居控制系统,该系统通过服务器与ARM Cortex-M0进行串口通信,实现对LED、风扇、蜂鸣器的控制,同时获取并显示环境信息。系统利用百度API获取天气预报,并能通过摄像头显示视频内容。代码包括串口、摄像头、服务器、HTTP请求等模块。
最低0.47元/天 解锁文章

被折叠的 条评论
为什么被折叠?



