一、项目背景
通过农业物联网产品为6000万大棚种植户节省30%人工,提升20%收益。中国是世界上最大的大棚种植国家,但种植方式还停留在纯人工的传统模式上,尤其控温类操作,极其耗时。随着大棚种植规模的扩大,高频耗时的控温类操作,已经成为农户扩大生产的最大阻力。如果有智能云端温湿度监控系统,帮助农户节省人工,精准控温,让作物生长周期缩短,坐果率提升,作物品相提升,年收益提升。
二、作品简介
本系统温湿度采集使用DHT11模块,实时读取温湿度数据。然后将数据先OLED屏幕上显示,并将数据上传到阿里云物联网平台。DHT11是一款有已校准数字信号输出的温湿度传感器。 其精度湿度±5%RH, 温度±2℃,量程湿度5~95%RH, 温度-20~+60℃。连接WIFI模块使用联盛德W800芯片,W800芯片采用40纳米工艺,芯片封装尺寸4mm*4mm,业界最小。芯片采用平头哥玄铁804(32位)CPU内核,最高主频达到240MHz;内置TEE安全引擎,为芯片提供了高性能的核心处理能力及安全可信的执行环境;内置DSP与浮点运算单元,支持2.4G IEEE802.11b/g/n Wi-Fi 标准协议,支持 BT/BLE4.2 蓝牙协议;支持丰富的MCU数字接口。
三、系统框图
四、各部分功能说明和解析
1,DHT11温度采集模块。
DHT11 的技术参数如下:
程序代码:
#include <aos/aos.h>
#include "aos/cli.h"
#include "dht11.h"
#ifndef TAG
#define TAG "app"
#endif
uint8_t H_inte = 0;
uint8_t H_frac = 0;
uint8_t T_inte = 0;
uint8_t T_frac = 0;
static csi_gpio_pin_t pin_dht11;
void delay_ms(unsigned char n)
{
udelay(n * 1000);
}
void delay_us(unsigned char n)
{
udelay(n);
}
/*DHT11复位和检测响应函数,返回值:1-检测到响应信号;0-未检测到响应信号*/
u8 DHT11RstAndCheck(void)
{
u8 timer = 0;
csi_gpio_pin_dir(&pin_dht11, GPIO_DIRECTION_OUTPUT);
csi_gpio_pin_write(&pin_dht11, GPIO_PIN_LOW); //输出低电平
delay_ms(20); //拉低至少18ms
csi_gpio_pin_write(&pin_dht11, GPIO_PIN_HIGH); //输出高电平
delay_us(30); //拉高20~40us
csi_gpio_pin_dir(&pin_dht11, GPIO_DIRECTION_INPUT);
while (!csi_gpio_pin_read(&pin_dht11)) //等待总线拉低,DHT11会拉低40~80us作为响应信号
{
timer++; //总线拉低时计数
delay_us(10);
}
if (timer>10 || timer<2) //判断响应时间
{
return 0;
}
timer = 0;
while (csi_gpio_pin_read(&pin_dht11)) //等待DHT11释放总线,持续时间40~80us
{
timer++; //总线拉高时计数
delay_us(10);
}
if (timer>10 || timer<2) //检测响应信号之后的高电平
{
return 0;
}
return 1;
}
/*读取一字节数据,返回值-读到的数据*/
u8 DHT11ReadByte(void)
{
u8 i;
u8 byt = 0;
csi_gpio_pin_dir(&pin_dht11, GPIO_DIRECTION_INPUT);
for (i=0; i<8; i++)
{
while (csi_gpio_pin_read(&pin_dht11)); //等待低电平,数据位前都有50us低电平时隙
while (!csi_gpio_pin_read(&pin_dht11)); //等待高电平,开始传输数据位
delay_us(40);
byt <<= 1; //因高位在前,所以左移byt,最低位补0
if (csi_gpio_pin_read(&pin_dht11)) //将总线电平值读取到byt最低位中
{
byt |= 0x01;
}
}
return byt;
}
/*读取一次数据,返回参数:Humi-湿度,Temp-温度;返回值: 0-成功,1-失败*/
u8 DHT11ReadData(u8 *H_inte, u8 *H_frac, u8 *T_inte, u8 *T_frac)
{
s8 sta = 0;
u8 i;
u8 buf[5];
// u8 H_inte = 0;
// u8 H_frac = 0;
// u8 T_inte = 0;
// u8 T_frac = 0;
if (DHT11RstAndCheck()) //检测响应信号
{
for(i=0;i<5;i++) //读取40位数据
{
buf=DHT11ReadByte(); //读取1字节数据
}
if(buf[0]+buf[1]+buf[2]+buf[3] == buf[4]) //校验成功
{
*H_inte = buf[0]; //湿度整数部分数据
*H_frac = buf[1]; //湿度小数部分数据
*T_inte = buf[2]; //温度整数部分数据
*T_frac = buf[3]; //温度小数部分数据
// LOGD("zyd", "temp:%d.%d",*T_inte,*T_frac);
// LOGD("zyd", "humi:%d.%d",*H_inte,*H_frac);
// char tmp1[8], tmp2[8];
// sprintf(tmp1, "%d.%d",H_inte,H_frac);
// sscanf(tmp1, "%f", Humi);
// sprintf(tmp2, "%d.%d",T_inte,T_frac);
// sscanf(tmp2, "%f", Temp);
}
sta = 0;
}
else //响应失败返回-1
{
*H_inte = 0; //湿度整数部分数据
*H_frac = 0; //湿度小数部分数据
*T_inte = 0; //温度整数部分数据
*T_frac = 0; //温度小数部分数据
sta = 1;
}
return sta;
}
/*DHT11初始化函数*/
u8 DHT11Init(void)
{
csi_pin_set_mux(PA7, PIN_FUNC_GPIO);
csi_gpio_pin_init(&pin_dht11, PA7);
csi_gpio_pin_dir(&pin_dht11, GPIO_DIRECTION_OUTPUT);
return DHT11RstAndCheck(); //返回DHT11状态
}
2,LVGL显示。
LVGL的作者是来自匈牙利的Gabor Kiss-Vamosikisvegabor,LVGL用C语言编写,以实现最大的兼容性(与C ++兼容),模拟器可在没有嵌入式硬件的PC上启动嵌入式GUI设计,同时LVGL作为一个图形库,它自带着接近三十多种小工具可以供开发者使用。这些强大的构建块按钮搭配上带有非常丝滑的动画以及可以做到平滑滚动的高级图形,同时兼具着不高的配置要求以及开源属性,显著的优势使得LVGL蔚然成风,成为广大开发者在选择GUI时的第一选择。
显示程序代码:
#include <aos/aos.h>
#include "aos/cli.h"
#include <stdlib.h>
#include <string.h>
#include "display.h"
#include "dht11.h"
#ifndef TAG
#define TAG "app"
#endif
lv_obj_t *temp;
lv_obj_t *humi;
//float Humi;
//float Temp;
void gui_main_menu_create(void)
{
lv_obj_t *p0 = lv_label_create(lv_scr_act(), NULL);
lv_label_set_long_mode(p0, LV_LABEL_ALIGN_CENTER);
lv_label_set_align(p0, LV_LABEL_ALIGN_CENTER);
lv_obj_set_pos(p0, 0, 4);
lv_obj_set_size(p0, 60, 10);
lv_label_set_text(p0, "TEMP:");//\nGUI\nDEMO
temp = lv_label_create(lv_scr_act(), NULL);
lv_label_set_long_mode(temp, LV_LABEL_ALIGN_CENTER);
lv_label_set_align(temp, LV_LABEL_ALIGN_CENTER);
lv_obj_set_pos(temp, 64, 4);
lv_obj_set_size(temp, 60, 10);
lv_label_set_text(temp, "22");//\nGUI\nDEMO
lv_obj_t *p2 = lv_label_create(lv_scr_act(), NULL);
lv_label_set_long_mode(p2, LV_LABEL_ALIGN_CENTER);
lv_label_set_align(p2, LV_LABEL_ALIGN_CENTER);
lv_obj_set_pos(p2, 0, 32);
lv_obj_set_size(p2, 60, 10);
lv_label_set_text(p2, "HUMI:");//\nGUI\nDEMO
humi = lv_label_create(lv_scr_act(), NULL);
lv_label_set_long_mode(humi, LV_LABEL_ALIGN_CENTER);
lv_label_set_align(humi, LV_LABEL_ALIGN_CENTER);
lv_obj_set_pos(humi, 64, 32);
lv_obj_set_size(humi, 60, 10);
lv_label_set_text(humi, "42%");//\nGUI\nDEMO
}
void set_label_temp_value(uint16_t value)
{
lv_label_set_text_fmt(temp, "%d.%d C",value,value%10);
}
void set_label_humi_value(uint16_t value)
{
lv_label_set_text_fmt(humi, "%d.%d %%",value/10,value%10);
}
void set_label_temp_float_value(uint8_t inte , uint8_t frac)
{
lv_label_set_text_fmt(temp, "%d.%d C",inte,frac);
}
void set_label_humi_float_value(uint8_t inte , uint8_t frac)
{
lv_label_set_text_fmt(humi, "%d.%d %%",inte,frac);
}
void gui_lvgl_task(void *arg)
{
uint16_t i=0;
lv_init();
/*Initialize for LittlevGL*/
oled_init();
DHT11Init();
/*Select display 1*/
// demo_create();
// gui_label_create();
gui_main_menu_create();
while (1) {
/* Periodically call the lv_task handler.
* It could be done in a timer interrupt or an OS task too.*/
lv_task_handler();
i++;
if(i>100)
{
i=0;
//num = DHT11ReadData(&dht11_temp, &dht11_humi);
DHT11ReadData(&H_inte,&H_frac,&T_inte, &T_frac);
set_label_temp_float_value(T_inte,T_frac);
set_label_humi_float_value(H_inte,H_frac);
//LOGD(TAG, "Hello world! YoC");
}
aos_msleep(5); //zyd; long time will make error
lv_tick_inc(1);
}
}
3,WIFI连接。
RVB2601 内置了联盛德公司高性能&安全的 WiFi4 芯片 W800,W800 通过 SPI 口与 CH2601 连接。W800 已经默认烧录基于 AT 的 WiFi 透传固件,开发者可基于 AT 网络指令,快速实现联网的应用场景。
代码程序:
/* * Copyright (C) 2019-2020 Alibaba Group Holding Limited */ #include <stdlib.h> #include <string.h> #include <aos/list.h> #include <aos/debug.h> #include <drv/gpio.h> #include <drv/gpio_pin.h> #include <drv/pin.h> #include <uservice/uservice.h> #include <uservice/eventid.h> #include <yoc/sysinfo.h> #include <board.h> #include <yoc/at_port.h> #include <yoc/netmgr.h> #include <devices/w800.h> //#include "player_demo.h" #include "cJSON.h" #include "w800_api.h" //#include "thp_get.h" #include "wifi.h" #include "dht11.h" #define TAG "APP" //extern Result_S res_data; int iot_con_flag = 0; netmgr_hdl_t app_netmgr_hdl; //extern int w800_living_wjap(const char *myssid,const char *mypassword); //extern int w800_living_idmau(const char *mykey,const char *myname,const char *mysecret,const char *mypsecretconst); //extern int w800_living_idmcon(void); //extern int w800_living_idmpp(const char *dev_id, const char *msg, int *packet_id); static csi_gpio_pin_t g; void led_pin_init() { csi_pin_set_mux(PA25, PIN_FUNC_GPIO); csi_gpio_pin_init(&g, PA25); csi_gpio_pin_dir(&g, GPIO_DIRECTION_OUTPUT); csi_gpio_pin_write(&g, GPIO_PIN_HIGH); } void led_refreshed(int sw_led) { if (sw_led == 1) { csi_gpio_pin_write(&g, GPIO_PIN_LOW); } else { csi_gpio_pin_write(&g, GPIO_PIN_HIGH); } } unsigned char buff_accept[68]; cJSON *str_json, *str_value; //初始化json结构体指针 static int net_reset_err_times = 0; void app_exception_event(uint32_t event_id) { switch(event_id) { case EVENT_NETMGR_NET_DISCON: LOGD(TAG, "EVENT_NETMGR_NET_DISCON"); net_reset_err_times++; if (net_reset_err_times >= MAX_NET_RESET_ERR_TIMES) { LOGD(TAG, "Net Reset times %d, reboot", net_reset_err_times); //do reboot aos_reboot(); } else { LOGD(TAG, "Net Reset after %d second", NET_RESET_DELAY_TIME); netmgr_reset(app_netmgr_hdl, NET_RESET_DELAY_TIME); } break; case EVENT_NETMGR_GOT_IP: net_reset_err_times = 0; break; } } void connect_tcp_server(char *server_ip, uint16_t port) { char ssid[32]; int bssid[6]; int channel; int rssi; w800_ap_info( ssid, bssid , &channel, &rssi); printf("ssid: %s\r\n", ssid); printf("channel: %d\r\n", channel); printf("rssi: %d\r\n", rssi); w800_connect_remote(0, NET_TYPE_TCP_CLIENT, server_ip, port); } static void network_event(uint32_t event_id, const void *param, void *context) { switch(event_id) { case EVENT_NETMGR_GOT_IP: LOGD(TAG, "net got ip"); // connect_tcp_server("192.168.2.226",1111); break; case EVENT_NETMGR_NET_DISCON: LOGD(TAG, "net disconnect"); break; } /*do exception process */ app_exception_event(event_id); } // int iot_apply(char *strbuff) { strcpy((char *)buff_accept,strbuff); str_json = cJSON_Parse((char *)buff_accept); //创建JSON解析对象,返回JSON格式是否正确 if(str_json == NULL) { LOGI(TAG"error:%s;\r\n",cJSON_GetErrorPtr()); cJSON_Delete(str_json);//释放内存 return -1; } else { cJSON *str_value = cJSON_GetObjectItem(str_json, "led"); LOGI(TAG,"led powerstate:%d;\r\n",str_value->valueint); //led_refreshed(str_value->valueint); //res_data.led = str_value->valueint; cJSON_Delete(str_json);//释放内存 return 1; } } int iot_connect_dome(void) { //char *my_ssid = "TP-LINK_AF26";//2.4GHZ WiFi ssidTP-LINK_678C14 //char *my_password = "20190213";//2.4GHZ WiFi password // char *my_ssid = "dong123";//2.4GHZ WiFi ssid // char *my_password = "donghae12";//2.4GHZ WiFi password char *my_ssid = "zyd";//2.4GHZ WiFi ssid char *my_password = "12345678";//2.4GHZ WiFi password char *my_key = "a1QNjTo9nGU";//ProductKey char *my_name = "RVB2601";//DeviceName char *my_secret = "ec7d6db43764c9a480e332bf269db138";//DeviceSecret char *my_p_secret = "o9EvLXL7szMFH95H";//Product Secret int ret1 = -1; int ret2 = -1; int ret3 = -1; ret1 = w800_living_wjap(my_ssid,my_password); if (ret1 == 0){ printf("AT+WJAP:OK!\n"); } else{ printf("AT+WJAP:ERROR!\n"); } ret2 = w800_living_idmau(my_key,my_name,my_secret,my_p_secret); if (ret2 == 0){ printf("AT+IDMAU:OK!\n"); } else{ printf("AT+IDMAU:ERROR!\n"); } ret3 = w800_living_idmcon(); if (ret3 == 0){ printf("AT+IDMCON:OK!\n"); } else{ printf("AT+IDMCON:ERROR!\n"); } if(ret1 == 0 && ret2 == 0 && ret3 == 0){ return 0; }else{ return -1; } } static void network_init() { w800_wifi_param_t w800_param; /* init wifi driver and network */ w800_param.reset_pin = PA21; w800_param.baud = 1*1000000; w800_param.cs_pin = PA15; w800_param.wakeup_pin = PA25; w800_param.int_pin = PA22; w800_param.channel_id = 0; w800_param.buffer_size = 4*1024; wifi_w800_register(NULL, &w800_param); app_netmgr_hdl = netmgr_dev_wifi_init(); if (app_netmgr_hdl) { utask_t *task = utask_new("netmgr", 2 * 1024, QUEUE_MSG_COUNT, AOS_DEFAULT_APP_PRI); netmgr_service_init(task); // netmgr_config_wifi(app_netmgr_hdl, "@PHICOMM_20", 11, "12345678", 8); // w800_packet_input_cb_register(&w800_data_receive_callback); netmgr_start(app_netmgr_hdl); // /* Subscribe */ event_subscribe(EVENT_NETMGR_GOT_IP, network_event, NULL); event_subscribe(EVENT_NETMGR_NET_DISCON, network_event, NULL); } } void wifi_task(void *arg) { int ret = -1; char report_buf[80]; const char *dev_id = "0"; int pkt_id = 0; char tmp1[8]; char tmp2[8]; float CurrentTemperature=0; float CurrentHumidity=0; // int len = sizeof(report_buf); // int timeout=120; event_service_init(NULL); //ulog_init(); aos_set_log_level(AOS_LL_DEBUG); network_init(); // event_subscribe(EVENT_NETMGR_GOT_IP, network_event, NULL); // event_subscribe(EVENT_NETMGR_NET_DISCON, network_event, NULL); // ret = iot_connect_dome(); // /* Subscribe */ if (ret == 0){ printf("connect iot success\n"); }else{ printf("connect iot error\n"); } while (1) { // snprintf(report_buf,len,pdata,sht20Info.humidity,sht20Info.tempreture); // w800_send_data(report_buf, len, timeout); sprintf(tmp1, "%d.%d",H_inte,H_frac); sscanf(tmp1, "%f", &CurrentHumidity); sprintf(tmp2, "%d.%d",T_inte,T_frac); sscanf(tmp2, "%f", &CurrentTemperature); snprintf(report_buf,80,"{\\\"CurrentTemperature\\\":%.1f,\\\"CurrentHumidity\\\":%.1f}",CurrentTemperature,CurrentHumidity); LOGD("zyd", "temp:%.1f",CurrentTemperature); LOGD("zyd", "humi:%.1f",CurrentHumidity); //snprintf(report_buf,80,"{\\\"CurrentTemperature\\\":%.1f,\\\"CurrentHumidity\\\":%.1f}",sht20Info.tempreture,sht20Info.humidity); //printf( "==> start attribute upload\n"); w800_living_idmpp(dev_id, report_buf, &pkt_id); aos_msleep(2000); } }
五、作品源码
https://download.eeworld.com.cn/detail/zhengyad/623786
六、视频演示
七、项目总结
疫情之下,缺芯严重,给国产芯片一个难得的机会,国产替代进口大势所趋。想通过这个项目了解下国产芯片,参考很多网友的例程,自己简单整合了一下,因为自己时间比较少,项目比较简陋。总的来说,芯片功能很强大,库文件很多,但是编辑器确实还有待提高,经常出现不明所以的问题,希望国产品牌越做越好。
【平头哥RVB2601创意应用开发】学习笔记1——开发环境搭建及新建工程 https://bbs.eeworld.com.cn/thread-1199346-1-1.html
【平头哥RVB2601创意应用开发】RVB2601之启动流程 https://bbs.eeworld.com.cn/thread-1200744-1-1.html
【平头哥RVB2601创意应用开发】飞燕平台产品创建 https://bbs.eeworld.com.cn/thread-1204380-1-1.html
【平头哥RVB2601创意应用开发】RVB2601开发板——W800模块更新固件方法 https://bbs.eeworld.com.cn/thread-1205616-1-1.html