基于GEC6818的QT开发之——通过不同按键控制DHT11模块的数据采集与动态显示
使用环境:
ubantu16
QT5.7
开发板GEC6818
实现要求:
利用A53按键1、按键2与温湿度传感器完成QT界面动态显示温湿度记录,并指定温湿度记录超过指定范围,进行报警(LED,BEEP),按下key1时,允许进行采集;当key2按下,关闭数据采集。
效果演示视频:基于GEC6818的QT开发之——通过按键控制DHT11模块的数据采集与动态显示
视频效果为升级版。
文章目录
- 基于GEC6818的QT开发之——通过不同按键控制DHT11模块的数据采集与动态显示
- 一、驱动的加载
- 1.1 dht11驱动加载
- 1.2 按键驱动加载
- 1.3蜂鸣器驱动加载
- 二、DHT11引脚
- 三、UI界面的设置
- 四、DHT11
- 4.1 DHT11使用的QTimer类的介绍
- 4.2 dht11.cpp 代码
- 4.3 dht11.h 代码
- 五、按键
- key 相关的代码
- 六、蜂鸣器
- 七、主类的完整代码
一、驱动的加载
我们在使用GEC6818开发板时,板上是没有DHT11的,而且与前面我们使用LED相同,我们同样需要一个与DHT11相配套的驱动,关于的撰写这里就不详细描述了,但是可以参考ARM开发之基于IIC协议的TM1650驱动实现,这篇文章是关于IIC协议的TM1605的驱动编写,可以仿照这些步骤对DHT11进行驱动编写。
将驱动下载到开发板并且进行加载
相关驱动已经与工程一起打包发在文章末尾的地址了。
1.1 dht11驱动加载
rx dht11_drv
rmmod dht11_drv.ko//先卸载,没有可以不用卸载
insmod dht11_drv.ko//再加载
1.2 按键驱动加载
rx buttons_drv.ko
rmmod buttons_drv.ko//先卸载,没有可以不用卸载
insmod buttons_drv.ko//再加载
1.3蜂鸣器驱动加载
rx pwm.ko
rmmod pwm.ko//先卸载,没有可以不用卸载
insmod pwm.ko//再加载
//****这个如果提示....busy 的话则执行*****
rmmod gec6818_beep.ko
再执行
insmod pwm.ko//再加载
二、DHT11引脚
有了相关驱动后,就可以对DHT11进行数据的读取啦,根据驱动:
可以看到GEC_6818的底板引脚图:
我们可以将DHT11的引脚如下图插入对应引脚。
三、UI界面的设置
一个简单的数据显示:
可以使用以上的方法,对应的控件名称如下:
关于如何对控件进命名,更换颜色等,可以参考博客:GEC6818的QT计算器计算的结果控制LED的亮灭的中间部分。
四、DHT11
4.1 DHT11使用的QTimer类的介绍
QTimer类提供了定时器信号
和单触发定时器
。它在内部使用定时器事件来提供更通用的定时器。QTimer很容易使用:创建一个QTimer对象,使用start()来开始并且把它的timeout()连接到适当的槽函数。当这段时间过去了,它将会发射timeout()信号,对应的槽函数将被调用执行。值得注意的是当QTimer的父对象被销毁时,它也会被自动销毁。另外,QTimer的精确度依赖于底下的操作系统和硬件,绝大多数平台支持20毫秒的精确度,有些平台可以提供更高的,但是,如果您想获得更精确的毫秒级甚至微秒级的定时,不用考虑它了。
在主函数中的使用方法如下:
QTimer *my_Timer;
my_Timer = new QTimer;
connect(my_Timer,SIGNAL(timeout()),this,SLOT(Main_Function()));
my_Timer->setTimerType(Qt::PreciseTimer);
my_Timer->start(500);
4.2 dht11.cpp 代码
由于这个案例涉及多个模块,所以我有多个cpp文件和.h文件,可以先看着理解一下,完整工程在文章末尾可以进行下载。
#include "dht11.h"
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <errno.h>
#define GEC6818_GET_DHTDATA _IOR('K', 0, unsigned int) //注册宏
unsigned char get_data[2];//存放数据的数组--(全局变量)
// ----------------------dht11 get data function-------
int dht11_get_data(void)
{
int ret, cnt_yes=0, cnt_err=0;
int ultrasonic_fd = open("/dev/dht11_dev", O_RDWR);//打开dht11的设备文件
if(ultrasonic_fd < 0)//打开失败
{
perror("open dht11_dev driver");
return -1;
}
printf("检测中\n");
ret = ioctl(ultrasonic_fd, GEC6818_GET_DHTDATA, &get_data[0]);//读取
if(ret != 0)
{
cnt_err++;
perror("GEC6818_GET_DHTDATA error");
}
else
{
cnt_yes++;
printf("湿度= %hhd 温度=%hhd 错误%d 正确%d\n", get_data[1], get_data[0], cnt_err, cnt_yes);
}
sleep(1);
close(ultrasonic_fd);//关闭设备文件
return 0;
}
ps:我觉得这个驱动没写的很好,可以从上面的数据输出看出湿度的值太小了!
4.3 dht11.h 代码
#ifndef DHT11_H
#define DHT11_H
extern unsigned char get_data[4];
int dht11_get_data(void);
#endif // DHT11_H
五、按键
一共有四个按键,如下:
key 相关的代码
fd_key1=open("/dev/gecBt",O_RDONLY);
if(fd_key1<0)
{
printf("open buttons fail!\n");
}
notifier = new QSocketNotifier(fd_key1,QSocketNotifier::Read,this);
connect(notifier,SIGNAL(activated(int)),this,SLOT(key_get()));
//------------------------key----------
// 延时函数
void delay(unsigned value)
{
while(value--);
}
int beep_state=1;
int led_state=1;
void DHT11_KEY::key_get()
{
char buttonValue[4];
memset(buttonValue, 0, 4);
::read( fd_key1, buttonValue, sizeof(buttonValue));
for(int i=0;i < (int)sizeof(buttonValue); i++)
{
switch(i)
{
case 0://key1
if(buttonValue[i]=='1')
{
state=1;
printf("KEY1\n");
}
break;
case 1://key2
if(buttonValue[i]=='1')
{
state=0;
printf("KEY2\n");
}
break;
case 2://key4
if(buttonValue[i]=='1')
{
beep_state=!beep_state;//反转
printf("KEY3 press beep_state=%d\n",beep_state);
}
break;
case 3://key4
if(buttonValue[i]=='1')
{
led_state=!led_state;
printf("KEY4 press led_state=%d\n",led_state);
}
break;
}
}
Main_Function();
}
这段代码是一个简单的实现了读取嵌入式系统中按键状态的功能。
-
fd_key1=open("/dev/gecBt",O_RDONLY);
:这行代码打开了名为"/dev/gecBt"的设备文件,该设备文件用于读取按键状态。它返回一个文件描述符(file descriptor),如果打开失败,则文件描述符为负值。 -
if(fd_key1<0)
:检查文件描述符是否有效。如果文件描述符小于0,则说明打开失败,输出错误消息。 -
notifier = new QSocketNotifier(fd_key1,QSocketNotifier::Read,this);
:创建一个QSocketNotifier对象,用于监听文件描述符fd_key1的读取事件。这样,当有数据可读取时,就会触发信号activated(int)。 -
connect(notifier,SIGNAL(activated(int)),this,SLOT(key_get()));
:将notifier的activated(int)信号连接到key_get()槽函数。这意味着当文件描述符fd_key1上有数据可读取时,将调用key_get()函数。 -
void DHT11_KEY::key_get()
:key_get()函数是一个槽函数,用于处理文件描述符上的数据读取事件。它从文件描述符fd_key1中读取按键状态,并根据按键状态执行相应的操作。 -
char buttonValue[4];
:定义一个大小为4的字符数组,用于存储按键状态。 -
::read(fd_key1, buttonValue, sizeof(buttonValue));
:从文件描述符fd_key1中读取4个字节的数据,即按键状态,并将其存储到buttonValue数组中。 -
for(int i=0;i < (int)sizeof(buttonValue); i++)
:遍历buttonValue数组中的每个元素,以检查每个按键的状态。 -
switch(i)
:根据当前迭代的索引值,选择不同的按键进行处理。 -
case 0:
:处理第一个按键(key1)的状态。 -
case 1:
:处理第二个按键(key2)的状态。 -
case 2:
:处理第三个按键(key3)的状态。 -
case 3:
:处理第四个按键(key4)的状态。
在每种情况下,根据按键的状态执行相应的操作,例如更改状态变量或输出调试信息。
六、蜂鸣器
#define BUZZER_IOCTL_SET_FREQ 1
#define BUZZER_IOCTL_STOP 0
//---------------pwm----------------
beep_fd = ::open("/dev/pwm", O_RDWR);
if ( beep_fd < 0 )
printf("open /dev/pwm failed\n");
if(get_data[0]>25&&beep_state==1)
{
::ioctl(beep_fd, BUZZER_IOCTL_SET_FREQ , freq );
}
else
{
::ioctl(beep_fd , BUZZER_IOCTL_STOP , freq);
}
七、主类的完整代码
#include "dht11_key.h"
#include "ui_dht11_key.h"
int state=0;
int beep_fd = -1;
int freq = 3000;
DHT11_KEY::DHT11_KEY(QWidget *parent) :
QWidget(parent),
ui(new Ui::DHT11_KEY)
{
ui->setupUi(this);
//---------------key-------
fd_key1=open("/dev/gecBt",O_RDONLY);
if(fd_key1<0)
{
printf("open buttons fail!\n");
}
notifier = new QSocketNotifier(fd_key1,QSocketNotifier::Read,this);
connect(notifier,SIGNAL(activated(int)),this,SLOT(key_get()));
//-------------led------------------
Led_Init();
//---------------pwm----------------
beep_fd = ::open("/dev/pwm", O_RDWR);
if ( beep_fd < 0 )
printf("open /dev/pwm failed\n");
//-------DHT11--------------//
my_Timer = new QTimer;
connect(my_Timer,SIGNAL(timeout()),this,SLOT(Main_Function()));
my_Timer->setTimerType(Qt::PreciseTimer);
my_Timer->start(500);
}
DHT11_KEY::~DHT11_KEY()
{
delete ui;
if(beep_fd>0)
{
::close(beep_fd);
}
if(fd_key1>0)
{
::close(fd_key1);
}
}
//------------------------key----------
// 延时函数
void delay(unsigned value)
{
while(value--);
}
int beep_state=1;
int led_state=1;
void DHT11_KEY::key_get()
{
char buttonValue[4];
memset(buttonValue, 0, 4);
::read( fd_key1, buttonValue, sizeof(buttonValue));
for(int i=0;i < (int)sizeof(buttonValue); i++)
{
switch(i)
{
case 0://key1
if(buttonValue[i]=='1')
{
state=1;
printf("KEY1\n");
}
break;
case 1://key2
if(buttonValue[i]=='1')
{
state=0;
printf("KEY2\n");
}
break;
case 2://key4
if(buttonValue[i]=='1')
{
beep_state=!beep_state;//反转
printf("KEY3 press beep_state=%d\n",beep_state);
}
break;
case 3://key4
if(buttonValue[i]=='1')
{
led_state=!led_state;
printf("KEY4 press led_state=%d\n",led_state);
}
break;
}
}
Main_Function();
}
//-----------------------main----------------
void DHT11_KEY::Main_Function()
{
if(state == 1)
{
ui->Collect_State->setText(QString("open"));
ui->Collect_State->setAlignment(Qt::AlignCenter);
dht11_get_data();
ui->humidity_data->setText(QString::number(get_data[1],10));
ui->temperature_data->setText(QString::number(get_data[0],10));
}
else
{
ui->Collect_State->setText(QString("close"));
ui->Collect_State->setAlignment(Qt::AlignCenter);
}
if(get_data[0]>25&&beep_state==1)
{
::ioctl(beep_fd, BUZZER_IOCTL_SET_FREQ , freq );
}
else
{
::ioctl(beep_fd , BUZZER_IOCTL_STOP , freq);
}
if(get_data[1]>5&&led_state==1)
{
Led2_open();
Led1_open();
// Led3_open();
// Led4_open();
}
else
{
Led2_close();
Led1_close();
// Led3_close();
// Led4_close();
}
}
本文中涉及的工程代码在我的github中可以进行下载03-DHT11简单版
升级版可以对数据以表格的形式展示,两个UI界面可以来回切换
地址:QT开发之两个UI界面切换与表格显示DHT11数据