目录
简单的喷淋实验(2):
(1)根据土壤湿度自动控制喷淋开关;
(2)根据光照强度控制风扇以及灯的开关---嵌入式实训
任务 2 :
在所给的 irrigate-1 文件夹中创建一个main.c 完成以下内容:
(1)根据土壤湿度自动控制喷淋开关
(2)根据光照强度控制风扇以及灯的开关
参考:
cpp
#include <stdio.h>
#include <unistd.h>
#include "mqtt.h"
#include "parse_config.h"
#define SUB_TOPIC "1703161172612/AIOTSIM2APP" //定阅的主题
#define PUB_TOPIC "1703161172612/APP2AIOTSIM" //发布主题
#define IRRIGATED_ON "{\"irrigated\":true}"
#define IRRIGATED_OFF "{\"irrigated\":false}"
#define FAN_ON "{\"fan\":true}"
#define FAN_OFF "{\"fan\":false}"
#define LAMP_ON "{\"lamp\":true}"
#define LAMP_OFF "{\"lamp\":false}"
#define ALARM_ON "{\"alarm\":true}"
#define ALARM_OFF "{\"alarm\":false}"
int main(int argc, const char *argv[])
{
ENV msg_env={};
//1.初始化mqtt协议
if(mqtt_init()!=0)
{
printf("mqtt init err.\n");
return -1;
}
//订阅别人发布的消息
if(mqtt_subscribe(SUB_TOPIC) < 0)
{
printf("sub err.\n");
return -1;
}
//循环获取温湿度
//当大于阈值关闭灌溉,小于就打开
while(1)
{
sleep(1);
//获取值
msg_env=get_virtual_env();
if(msg_env.ill < 20000)
{
mqtt_publish(PUB_TOPIC,FAN_OFF);
mqtt_publish(PUB_TOPIC,LAMP_ON);
}else if(msg_env.ill > 50000)
{
mqtt_publish(PUB_TOPIC,FAN_ON);
mqtt_publish(PUB_TOPIC,LAMP_OFF);
}
printf("ill:%f\n",msg_env.ill);
if(msg_env.soil < 30)
{
mqtt_publish(PUB_TOPIC,IRRIGATED_ON);
}else if(msg_env.soil > 50)
{
mqtt_publish(PUB_TOPIC,IRRIGATED_OFF);
}
printf("soilhum:%f\n",msg_env.soil);
// if(msg_env.infrared == 1)
// {
// mqtt_publish(PUB_TOPIC,ALARM_ON);
// }else {
// mqtt_publish(PUB_TOPIC,ALARM_OFF);
// }
// printf("infrared:%d\n",msg_env.infrared);
}
exit_mqtt();
return 0;
}
具体过程:
所用的头文件:
data_global.h
cpp
#ifndef __DATA_GLOBAL__H__
#define __DATA_GLOBAL__H__
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <time.h>
#include <termios.h>
#include <signal.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include <stdbool.h>
struct env_info
{
float soil; //土壤湿度
float light; //光照强度
float temp; //空气温度
uint8_t gas; //有害气体
};
extern struct env_info env_msg;
//设备编号
#define FAN 0x00
#define BEEP 0x10
#define LED 0x20
#define PUMP 0X30
#define DATA_ARRIVE SIGUSR1 //数据到达信号
//订阅、发布主题
#define ENV_PUB_TOPIC "FS_VRJJ/control"
//虚拟仿真硬件协议
#define LAMP_ON "{\"lamp\":true}"
#define LAMP_OFF "{\"lamp\":false}"
#define ALARM_ON "{\"alarm\":true}"
#define ALARM_OFF "{\"alarm\":false}"
#define SUNSHADE_FOR "{\"sunshade\":\"forward\"}"
#define SUNSHADE_REV "{\"sunshade\":\"reverse\"}"
#define SUNSHADE_STOP "{\"sunshade\":\"stop\"}"
#define VIR_FAN_ON "{\"fan\":true}"
#define VIR_FAN_OFF "{\"fan\":false}"
#define IRRIGATED_OFF "{\"irrigated\":false}"
#define IRRIGATED_ON "{\"irrigated\":true}"
#endif
mqtt.h
cpp
#ifndef __MQTT_SMART_H_
#define __MQTT_SMART_H_
typedef struct env
{
float soil;//土壤湿度
float ill;//光照
int smog;//烟雾
int infrared;//人体红外
}ENV;
int mqtt_init();
void exit_mqtt();
int mqtt_subscribe(const char*topic);
int mqtt_publish(const char *topic, char *msg);
ENV get_virtual_env();
#endif
主程序:mian.c
cpp
#include<stdio.h>
#include"mqtt.h"
#include<unistd.h>
#include"data_global.h"
#define subscribe "1703503856299/AIOTSIM2APP"
#define publish "1703503856299/APP2AIOTSIM"
int main(int argc, char *argv[]){
//1-连接服务器
mqtt_init();
//2-订阅元宇宙平台主题,获得数据串
//通过目标节点的发布主题,才能的得到发布的内容
mqtt_subscribe(subscribe);
//4.循环获取数据,下发控制指令
while (1){
sleep(1);
ENV env= get_virtual_env();
if (env.soil>60){
mqtt_publish(publish, IRRIGATED_OFF);
printf("关闭喷淋。。。。\n");
}
else if (env.soil<30){
mqtt_publish(publish, IRRIGATED_ON);
printf("打开喷淋\n");
}
printf("当前土壤湿度:%.2f\n", env.soil);
if (env.ill>27000)
{
mqtt_publish(publish, VIR_FAN_ON);
mqtt_publish(publish, LAMP_OFF);
printf("打开风扇,关闭灯。。。。\n");
}
else if (env.ill<25000)
{
mqtt_publish(publish, VIR_FAN_OFF);
mqtt_publish(publish, LAMP_ON);
printf("关闭风扇,打开灯。。。。。。\n");
}
sleep(1);
printf("当前光照强度:%.2f\n", env.ill);
printf("++++++++++++++++++++++++++++\n");
}
exit_mqtt();
return 0;
}
运行结果:
元宇宙未运行时:
元宇宙运行后:
运行过程视频:
嵌入式实训2023-12-25 20-19-53
上述程序存在问题:
初步破局:
在元宇宙实验平台还没开始运行时,各种数据都是0,就会导致程序通过if、else if判断语句来控制各种机器运作,这是不正确的。为了避免这种情况,可以添加一些额外的判断来解决这个问题。
首先,我们可以在while循环之前添加一个延时等待,让实验平台有足够的时间来获取和发送数据。例如,我们可以使用sleep函数来等待5秒钟:
cpp
sleep(5); // 等待5秒钟,让实验平台有足够的时间来获取和发送数据
然后,我们可以在if、else if判断语句之前添加一个判断,检查所需的数据是否已经被正确地获取。例如,我们可以检查土壤湿度是否为0来确定是否成功获取了土壤湿度数据:
cpp
ENV env= get_virtual_env();
if (env.soil == 0) {
printf("未成功获取到土壤湿度数据,等待下一次获取...\n");
sleep(1);
continue; // 跳过本次循环,等待下一次循环
}
// 在此之后添加if、else if判断语句进行控制
同样,我们可以添加类似的判断来检查光照强度等数据是否已经被正确获取。这样做可以避免在数据未准备好时误操作机器,保证程序的正确性。
完整代码:
cpp
#include<stdio.h>
#include"mqtt.h"
#include<unistd.h>
#include"data_global.h"
#define subscribe "1703503856299/AIOTSIM2APP"
#define publish "1703503856299/APP2AIOTSIM"
int main(int argc, char *argv[]){
//1-连接服务器
mqtt_init();
//2-订阅元宇宙平台主题,获得数据串
//通过目标节点的发布主题,才能的得到发布的内容
mqtt_subscribe(subscribe);
//3.等待数据准备就绪
printf("等待数据准备就绪...\n");
sleep(5); // 等待5秒钟,让实验平台有足够的时间来获取和发送数据
//4.循环获取数据,下发控制指令
while (1){
ENV env= get_virtual_env();
if (env.soil == 0) {
printf("未成功获取到土壤湿度数据,等待下一次获取...\n");
sleep(1);
continue; // 跳过本次循环,等待下一次循环
}
if (env.soil>60){
mqtt_publish(publish, IRRIGATED_OFF);
printf("关闭喷淋。。。。\n");
}
else if (env.soil<30){
mqtt_publish(publish, IRRIGATED_ON);
printf("打开喷淋\n");
}
printf("当前土壤湿度:%.2f\n", env.soil);
if (env.ill == 0) {
printf("未成功获取到光照强度数据,等待下一次获取...\n");
sleep(1);
continue; // 跳过本次循环,等待下一次循环
}
if (env.ill>27000)
{
mqtt_publish(publish, VIR_FAN_ON);
mqtt_publish(publish, LAMP_OFF);
printf("打开风扇,关闭灯。。。。\n");
}
else if (env.ill<25000)
{
mqtt_publish(publish, VIR_FAN_OFF);
mqtt_publish(publish, LAMP_ON);
printf("关闭风扇,打开灯。。。。。。\n");
}
printf("当前光照强度:%.2f\n", env.ill);
printf("++++++++++++++++++++++++++++\n");
sleep(1);
}
exit_mqtt();
return 0;
}
继续探讨:
还是有点问题,如果等待5秒后,实验平台运行了,但是土壤湿度和光照强度又恰好是0呢?这样是没有错误的呀
上述提出了一个很好的问题。确实,在等待5秒后,如果土壤湿度和光照强度仍然是0,那么程序就会继续执行,而不会等待数据准备就绪。为了解决这个问题,可以使用一个循环来判断数据是否已经准备就绪,并设置一个最大等待时间。
下面是修改后的代码示例:
cpp
#include<stdio.h>
#include"mqtt.h"
#include<unistd.h>
#include"data_global.h"
#define subscribe "1703503856299/AIOTSIM2APP"
#define publish "1703503856299/APP2AIOTSIM"
int main(int argc, char *argv[]){
//1.连接服务器
mqtt_init();
//2.订阅元宇宙平台主题,获得数据串
//通过目标节点的发布主题,才能的得到发布的内容
mqtt_subscribe(subscribe);
//3.等待数据准备就绪
printf("等待数据准备就绪...\n");
int max_wait_time = 10; // 最大等待时间为10秒
int wait_time = 0; // 已等待的时间
ENV env;
while (1){
env= get_virtual_env();
if (env.soil != 0 && env.ill != 0) {
break; // 数据已准备就绪,跳出循环
}
sleep(1);
wait_time++;
if(wait_time >= max_wait_time){
printf("超过最大等待时间,未成功获取到数据!\n");
exit_mqtt();
return 0;
}
}
//4.循环获取数据,下发控制指令
while (1){
if (env.soil>60){
mqtt_publish(publish, IRRIGATED_OFF);
printf("关闭喷淋。。。。\n");
}
else if (env.soil<30){
mqtt_publish(publish, IRRIGATED_ON);
printf("打开喷淋\n");
}
printf("当前土壤湿度:%.2f\n", env.soil);
if (env.ill>27000)
{
mqtt_publish(publish, VIR_FAN_ON);
mqtt_publish(publish, LAMP_OFF);
printf("打开风扇,关闭灯。。。。\n");
}
else if (env.ill<25000)
{
mqtt_publish(publish, VIR_FAN_OFF);
mqtt_publish(publish, LAMP_ON);
printf("关闭风扇,打开灯。。。。。。\n");
}
printf("当前光照强度:%.2f\n", env.ill);
printf("++++++++++++++++++++++++++++\n");
sleep(1);
}
exit_mqtt();
return 0;
}