【腾讯连连IoT开发大赛】基于TencentOS Tiny的智能甲醛探测与云打印系统

2021-01-13 10:25:45 浏览数 (1)

1、产品介绍

达特甲醛探测仪是基于英国达特公司设计开发的WZ-S型甲醛检测模组设计开发的,它可以用于检测环境中甲醛的浓度,以提示用户运用科学有效的方法降低甲醛污染,进而使环境的空气质量变得更加清新,也进一步提高用户的健康意识以及对生活品质的追求。

基于TencentOS tiny智能达特甲醛探测系统基于TencentOS tiny智能达特甲醛探测系统

项目开源地址:https://gitee.com/morixinguan/smart-dart-detect

2、产品主要功能视频演示

基于TencentOS tiny智能达特探测系统

3、产品亮点

  • 支持使用腾讯连连小程序扫描设备上的二维码
  • 支持腾讯连连小程序实时查看动态甲醛浓度数据
  • 支持腾讯云平台IoT explorer实时查看动态甲醛浓度数据
  • 支持外部串口调试,系统可动态匹配用户下发的指令灵活做出回应
  • 可供用户设置参数(密码权限管理、单位显示、声光报警、数据上传)
  • 支持设备状态实时查看(工作状态、网络状态、用户权限、SD卡容量)
  • 支持甲醛浓度数据SD卡实时存储,并可以通过SD卡进行数据导出查看
  • 支持设备恢复出厂设置功能,确保设备在出厂前所有的默认设置参数一致
  • 支持腾讯云平台IoT explorer实时下发字符串,设备实时通过热敏打印机实时打印字符串内容,并且可控制外设

4、产品硬件平台

4.1、智能达特甲醛探测系统硬件组成架构

智能达特甲醛探测系统组成智能达特甲醛探测系统组成

该系统由小熊派开发板、达特甲醛模组、ESP8266模块、热敏打印机模组构成。

4.2、小熊派开发板简介

小熊派BearPi开发板是南京厚德物联网有限公司为着力于开发者打造的一款简单、丰富、低成本、可扩展、支持多种IoT通信的物联网开发板,可广泛应用于智能家居、智慧农业、智慧城市等等领域。

小熊派开发板功能硬件外设功能示意小熊派开发板功能硬件外设功能示意
小熊派开发板硬件系统框图小熊派开发板硬件系统框图
小熊派开发板硬件资源描述小熊派开发板硬件资源描述

4.3、达特甲醛模组简介

达特甲醛模组采用的是英国达特WZ-S型甲醛模组,它可以用于将环境中甲醛的含量转换成浓度值,然后进行标准化数字输出,也便于系统集成。

英国达特甲醛探测模组特点英国达特甲醛探测模组特点
英国达特甲醛探测模组常见的应用场景英国达特甲醛探测模组常见的应用场景

该模组的硬件接口为腾讯团队定制的符合物联网俱乐部定义的标准E53接口,如下硬件原理图所示:

标准E53接口硬件原理图标准E53接口硬件原理图

4.4、ESP8266模块简介

ESP8266模块小熊派开发板套件提供的用于通过Wi-Fi传输数据的通信扩展板,该拓展板采用的是乐鑫ESP8266 Wi-Fi通信模组,支持常见的IPv4/TCP/UDP/HTTP/FTP等通信协议。

ESP8266引脚定义描述ESP8266引脚定义描述

该模组的硬件接口为小熊派定制的符合物联网俱乐部定义的标准WAN接口,如下硬件原理图所示:

标准WAN接口硬件原理图标准WAN接口硬件原理图

4.5、热敏打印机模组

热敏打印机模组采用的是深圳市荔璟科技有限公司的MC-EH205嵌入式小票打印机,该模组主要应用于各种仪器仪表打印相关凭证及检测数据明细,可广泛应用于邮政快递行业、仓储服务行业、安防安检行业、警用军工行业等等。

MC-EH205小票打印机模组外观MC-EH205小票打印机模组外观

该模组支持串口TTL或者USB接口通讯,采用开关电源或主板供电,工作电压为5-9V,工作电流0.5~1.5A,瞬间电流约等于2A。

MC-EH205小票打印机模组引脚功能MC-EH205小票打印机模组引脚功能

4.6、STM32CubeMX配置

STM32CubeMX配置STM32CubeMX配置

5、产品方案设计

5.1 产品整体架构图

智能达特甲醛探测系统主要是基于TencentOS tiny物联网操作系统进行开发,整体架构图如下:

TencentOS tiny物联网操作系统架构图TencentOS tiny物联网操作系统架构图

达特智能系统主要包括硬件组成部分、驱动组成部分、操作系统(TencentOS tiny物联网操作系统)组成部分以及应用逻辑交互部分等,其整体产品架构设计如下:

产品架构设计产品架构设计

其中,界面交互部分是整个产品最核心的部分,主要由以下逻辑构成:

智能甲醛探测系统整体界面交互逻辑智能甲醛探测系统整体界面交互逻辑

5.2 产品核心软件框架说明

5.2.1 产品界面框架设计

关于界面交互,依赖于核心的软件框架,主要是基于事件驱动的方式来实现:

核心软件UI界面操作框架核心软件UI界面操作框架
5.2.2 操作系统任务分配与功能设计

关于产品的操作系统启动流程由以下流程图构成:

系统启动与任务分配系统启动与任务分配

(1)默认任务设计与功能实现

功能实现:

  • 创建用于任务间、中断和任务间通信的队列、信号量,/*默认任务处理*/
  • 创建按键任务、状态栏任务、数据上传任务、传感器任务、串口接口任务。 软件逻辑实现:
代码语言:txt复制
void default_task(void *pdata)
{
    tos_knl_sched_lock();
    /*创建队列,用于接收传感器数据*/
    tos_msg_q_create(&sensor_data_msg, sensor_msg_pool, SENSOR_U3_BUFFER_SIZE);
    tos_msg_q_create(&uploader_data_msg, uploader_msg_pool, NETWORK_BUF);
    tos_msg_q_create(&recv_data_msg, recv_msg_pool, CMD_STR_SIZE);
    /*创建按键任务*/
    osThreadCreate(osThread(KeyTask), NULL);
    /*创建状态栏任务*/
    osThreadCreate(osThread(Status_Task), NULL);
    /*创建数据上传任务*/
    osThreadCreate(osThread(uploader_task), NULL);
    /*创建传感器数据任务*/
    osThreadCreate(osThread(Sensor_Task), NULL);
    /*创建串口接收任务*/
    osThreadCreate(osThread(UartCmdTask), NULL);
    tos_knl_sched_unlock();
}

(2)按键任务设计与功能实现

功能实现:

  • 获取按键事件并转换为具体的事件值
  • 根据当前界面的游标以及菜单实现界面切换

软件逻辑实现:

代码语言:txt复制
void KeyTask(void *argument)
{
    __IO uint8_t KeyCode = 255;

    while(1)
    {
        /*获取键值*/
        GetKey(&KeyCode);

        if(255 != KeyCode)
        {
            Menu_Select_Item(Flow_Cursor.flow_cursor, KeyCode);
            KeyCode = 255 ;
        }

        tos_sleep_ms(5);
    }
}

(3)状态栏任务设计与功能实现

功能实现:

  • 获取系统RTC时钟日期和时间
  • 当系统位于主页面时,1s钟存储一条甲醛数据
  • 实现根据当前系统设置及状态刷新状态栏所有图标显示
  • 当配置报警选项将功能打开时,当浓度超过国标规定参数时,设备能够自动闪烁LED灯进行报警,否则关闭LED灯

软件逻辑实现:

代码语言:txt复制
void Status_Task(void *argument)
{
    LCD_Fill_Para status_bar_fill_para = {0, 240, 0, 27, WHITE} ;
    lcd_model.lcd_driver->lcd_fill(status_bar_fill_para);
    display_runing_time_font(1);

    while(1)
    {
        Get_Date_Time();

        if(0 == plot_handler.plot_mode)
        {
            sprintf(DateTime_Handler_Info.DisPlay_DateBuf, "d:d:d", 
                    DateTime_Handler_Info.hour, DateTime_Handler_Info.minute, DateTime_Handler_Info.sec);
            lcd_model.lcd_driver->lcd_show_ascii_str(datatime_display_para);

            if(MAIN_PAGE == Flow_Cursor.flow_cursor)
                display_runing_time(DateTime_Handler_Info.hour, DateTime_Handler_Info.minute, DateTime_Handler_Info.sec, 1);
        }

        if(MAIN_PAGE == Flow_Cursor.flow_cursor)
        {
            tos_knl_sched_lock();
            save_record_to_flash();
            tos_knl_sched_unlock();
        }

        if(1 == User_Memory_Para.alarm)
        {
            /*如果大于0.062ppm,则报警灯闪烁,否则熄灭*/
            if(0 == User_Memory_Para.unit)
            {
                if(Formaldehyde_Sensor_interface.Formaldehyde_Value > 0.062)
                    HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
                else
                    HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET);
            }
            /*如果大于0.062*0.74666mg/m3,则报警灯闪烁,否则熄灭*/
            else
            {
                if(Formaldehyde_Sensor_interface.Formaldehyde_Value > 0.046)
                    HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
                else
                    HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET);
            }
        }
        else
        {
            HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET);
        }

        /*刷新WIFI连接状态*/
        if(0 == wifi_connect_flag)
            display_signal_status(0);
        else
            display_signal_status(4);

        /*刷新服务器连接状态*/
        if(0 == server_connect_flag)
            display_server_status(0);
        else
            display_server_status(1);

        /*刷新上传状态*/
        if(0 == User_Memory_Para.upload_flag)
            display_upload_status(0);
        else
            display_upload_status(1);

        /*刷新设备密码状态*/
        if(1 == User_Memory_Para.password_enable_flag)
            display_passwd_icon(0);
        else
            display_passwd_icon(1);

        /*刷新SD卡状态*/
        refresh_sd_card_status();
        tos_sleep_ms(1000);
    }
}

(4)数据上传任务设计与功能实现

功能实现:(注意,需要腾讯云固件支持,后续章节讲解)

  • 完成产品与腾讯云IoT explorer平台的对接
  • 接收腾讯云IoT explorer平台下发的指令和字符串,控制打印机打印
  • 根据系统配置实时上传当前甲醛浓度值,并通过IoT explorer和腾讯连连小程序展示

软件逻辑实现:(mqtt_demo_task代码过长,此处省略,详细请看代码)

代码语言:txt复制
void uploader_task(void *arg)
{
    mqtt_demo_task();
    while (1)
    {
        printf("This is a mqtt demo!rn");
        tos_task_delay(1000);
    }
}

(5)传感器任务设计与功能实现

功能实现:

  • 传感器注册(完成串口接收配置)
  • 获取传感器数据并进行解析(根据传感器手册进行数据解析)
  • 当浓度超过国标规定参数时,设备能够让数值显示自动飘红,提醒用户注意阈值超出
  • 根据数值开关,选择是否在界面上显示最大值和最小值,当打开则显示,关闭则不显示最大最小值
  • 根据传感器数据实时显示当前的工作状态和传感器数值,并能根据设置单位选项随意切换浓度匹配算法
  • 当网络上传功能打开时,发送信号量通知数据上传任务将传感器浓度值上传到腾讯云IoT explorer平台

软件逻辑实现:

代码语言:txt复制
void Sensor_Task(void  *argument)
{
    char ch20_data[20] = {0};
    /*传感器注册*/
    Sensor_Register(&Formaldehyde_Sensor_interface);
    while(1)
    {
        /*获取传感器数据*/
        Formaldehyde_Sensor_interface.get_Formaldehyde_Value(&Formaldehyde_Sensor_interface);

        /*处理传感器数据展示*/
        if(MAIN_PAGE == Flow_Cursor.flow_cursor)
        {
            display_work_status(Formaldehyde_Sensor_interface.Formaldehyde_Value, 1);

            //PPM
            if(0 == User_Memory_Para.unit)
            {
                /* 正常解析之后通过队列发送 */
                memset(ch20_data, 0, 20);

                if(Formaldehyde_Sensor_interface.Formaldehyde_Value > 2)
                {
                    Formaldehyde_Sensor_interface.Formaldehyde_Value = 2 ;
                    sprintf(ch20_data, "ppm:%.3f", Formaldehyde_Sensor_interface.Formaldehyde_Value);
                }
                else
                    sprintf(ch20_data, "ppm:%.3f", Formaldehyde_Sensor_interface.Formaldehyde_Value);

                /*如果网络功能开的状态下才会进行队列发送*/
                if(1 == User_Memory_Para.upload_flag && 1 == wifi_connect_flag && 1 == server_connect_flag)
                    tos_msg_q_post(&uploader_data_msg, ch20_data);

                if(Formaldehyde_Sensor_interface.Formaldehyde_Value > 2)
                {
                    ch20_ppm_value_printf = 2;
                    display_hcho_value(ch20_ppm_value_printf, RED, 1);

                    if(1 == User_Memory_Para.value)
                    {
                        display_hcho_max_value(ch20_ppm_value_printf, GREEN, 1);
                        display_hcho_min_value(ch20_ppm_value_printf, GREEN, 1);
                    }
                    else
                    {
                        display_hcho_max_value(ch20_ppm_value_printf, BLACK, 0);
                        display_hcho_max_value(ch20_ppm_value_printf, BLACK, 0);
                    }
                }
                else
                {
                    if(Formaldehyde_Sensor_interface.Formaldehyde_Value > 0.062)
                    {
                        ch20_ppm_value_printf = Formaldehyde_Sensor_interface.Formaldehyde_Value;
                        display_hcho_value(Formaldehyde_Sensor_interface.Formaldehyde_Value, RED, 1);

                        if(1 == User_Memory_Para.value)
                        {
                            display_hcho_max_value(Formaldehyde_Sensor_interface.Formaldehyde_Max_Value, GREEN, 1);
                            display_hcho_min_value(Formaldehyde_Sensor_interface.Formaldehyde_Min_Value, GREEN, 1);
                        }
                        else
                        {
                            display_hcho_max_value(ch20_ppm_value_printf, BLACK, 0);
                            display_hcho_max_value(ch20_ppm_value_printf, BLACK, 0);
                        }
                    }
                    else
                    {
                        ch20_ppm_value_printf = Formaldehyde_Sensor_interface.Formaldehyde_Value;
                        display_hcho_value(Formaldehyde_Sensor_interface.Formaldehyde_Value, GREEN, 1);

                        if(1 == User_Memory_Para.value)
                        {
                            display_hcho_max_value(Formaldehyde_Sensor_interface.Formaldehyde_Max_Value, GREEN, 1);
                            display_hcho_min_value(Formaldehyde_Sensor_interface.Formaldehyde_Min_Value, GREEN, 1);
                        }
                        else
                        {
                            display_hcho_max_value(ch20_ppm_value_printf, BLACK, 0);
                            display_hcho_max_value(ch20_ppm_value_printf, BLACK, 0);
                        }
                    }
                }
            }
            //mg/m3
            else
            {
                /* 正常解析之后通过队列发送 */
                memset(ch20_data, 0, 20);

                if(Formaldehyde_Sensor_interface.Formaldehyde_Value > 0.046)
                {
                    Formaldehyde_Sensor_interface.Formaldehyde_Value = 0.046 ;
                    sprintf(ch20_data, "mgm3:%.3f", Formaldehyde_Sensor_interface.Formaldehyde_Value);
                }
                else
                    sprintf(ch20_data, "mgm3:%.3f", Formaldehyde_Sensor_interface.Formaldehyde_Value);

                /*如果网络功能开的状态下才会进行队列发送*/
                if(1 == User_Memory_Para.upload_flag && 1 == wifi_connect_flag && 1 == server_connect_flag)
                    tos_msg_q_post(&uploader_data_msg, ch20_data);

                if(Formaldehyde_Sensor_interface.Formaldehyde_Value > 1.493)		//2 * 0.74666
                {
                    ch20_ppm_value_printf = 1.493;
                    display_hcho_value(ch20_ppm_value_printf, RED, 1);

                    if(1 == User_Memory_Para.value)
                    {
                        display_hcho_max_value(ch20_ppm_value_printf, GREEN, 1);
                        display_hcho_min_value(ch20_ppm_value_printf, GREEN, 1);
                    }
                    else
                    {
                        display_hcho_max_value(ch20_ppm_value_printf, BLACK, 0);
                        display_hcho_max_value(ch20_ppm_value_printf, BLACK, 0);
                    }
                }
                else
                {
                    if(Formaldehyde_Sensor_interface.Formaldehyde_Value > 0.046)
                    {
                        ch20_ppm_value_printf = Formaldehyde_Sensor_interface.Formaldehyde_Value;
                        display_hcho_value(ch20_ppm_value_printf, RED, 1);

                        if(1 == User_Memory_Para.value)
                        {
                            display_hcho_max_value(ch20_ppm_value_printf, GREEN, 1);
                            display_hcho_min_value(ch20_ppm_value_printf, GREEN, 1);
                        }
                        else
                        {
                            display_hcho_max_value(ch20_ppm_value_printf, BLACK, 0);
                            display_hcho_max_value(ch20_ppm_value_printf, BLACK, 0);
                        }
                    }
                    else
                    {
                        ch20_ppm_value_printf = Formaldehyde_Sensor_interface.Formaldehyde_Value;
                        display_hcho_value(ch20_ppm_value_printf, GREEN, 1);

                        if(1 == User_Memory_Para.value)
                        {
                            display_hcho_max_value(ch20_ppm_value_printf, GREEN, 1);
                            display_hcho_min_value(ch20_ppm_value_printf, GREEN, 1);
                        }
                        else
                        {
                            display_hcho_max_value(ch20_ppm_value_printf, BLACK, 0);
                            display_hcho_max_value(ch20_ppm_value_printf, BLACK, 0);
                        }
                    }
                }
            }
        }
    }
}

(6)串口接收任务设计与功能实现

功能实现:

  • 命令解析器注册
  • 接收来自串口调试助手发送的字符串
  • 通过命令解析器对接收的字符串进行匹配执行对应的命令 主要会执行如下命令,分别是: 命令1:开灯/关灯 命令2:获取当前传感器浓度数据 命令3:获取当前系统版本 命令4:系统复位 命令5:获取系统参数并通过打印机打印出来

软件逻辑实现如下:

代码语言:txt复制
/*注册命令*/
REGISTER_CMD(reset, cpu_reset_process);
REGISTER_CMD(led_on, led_on_process);
REGISTER_CMD(led_off, led_off_process);
REGISTER_CMD(get_sensor_data, get_sensor_data);
REGISTER_CMD(get_system_para, get_system_para);
REGISTER_CMD(get_system_version, get_system_version);
void UartCmdTask(void  *argument)
{
    k_err_t err;
    void *msg_received;
    uint8_t uart_recv_buf[CMD_STR_SIZE] = {0};
    /*命令初始化*/
    cmd_init();
    HAL_UART_Receive_IT(&huart1, (uint8_t *)&cmd_parse_typedef.Res, 1);
    while(1)
    {
        err = tos_msg_q_pend(&recv_data_msg, &msg_received, TOS_TIME_FOREVER);

        if (err == K_ERR_NONE)
        {
            memcpy(uart_recv_buf, msg_received, CMD_STR_SIZE);
            cmd_parsing((char *)uart_recv_buf);
            memset(&cmd_parse_typedef, 0, sizeof(cmd_parse_typedef));
        }
    }
}

6、产品与腾讯云IoT explorer平台和腾讯连连对接设计

6.1、为ESP8266模块烧写腾讯云定制固件

(1)下载腾讯云官方提供的ESP8266固件

https://github.com/tencentyun/qcloud-iot-esp-wifi

要烧录的腾讯云固件要烧录的腾讯云固件

(2)下载烧录工具

使用乐鑫官方下载工具ESPFlashDownloadTool,下载链接如下:

https://www.espressif.com/zh-hans/support/download/other-tools

(3)操作步骤

1、确保硬件连接正确,上电即能进入ESP8266烧录模式

烧录模式硬件连接烧录模式硬件连接

2、打开烧录工具

打开烧录工具打开烧录工具

选择开发者模式

开发者模式选项开发者模式选项

选择ESP8266下载工具

ESP8266下载工具选项ESP8266下载工具选项

配置烧录界面面板参数

烧录界面面板参数配置烧录界面面板参数配置

点击START查看模组信息:

查看模组信息查看模组信息
模组信息模组信息

导入要下载的固件,设置地址从0x000开始

导入要下载的固件导入要下载的固件

重新点击START下载腾讯云固件

下载腾讯云固件下载腾讯云固件

如图所示看见完成即固件更新成功。

将ESP8266硬件恢复为正常模式,也就是将那些线全部用烙铁取掉,将ESP8266模块插在小熊派开发板上,如下图所示,切换开关为AT PC模式:

image.pngimage.png

发送模组信息读取命令查看当前模组信息:

上电发送模组信息读取命令上电发送模组信息读取命令

如果能打印和文档描述信息则表示固件更新正确。

6.2、腾讯云IoT explorer与腾讯连连小程序配置

(1)打开腾讯云官网,提前登录成功后,选择物联网开发平台选项

选择物联网开发平台选择物联网开发平台
物联网开发平台IoT explorer入口物联网开发平台IoT explorer入口

然后点击立即进入。

(2)根据腾讯云开发文档指示创建项目并配置好参数

达特甲醛探测仪达特甲醛探测仪

详细配置流程请参考:TencentOS官方公众号文章

https://mp.weixin.qq.com/s/t8iVaypA1BtZwt7EEkAWyw

(3)根据腾讯云开发文档指示配置腾讯连连小程序面板

腾讯连连小程序面板腾讯连连小程序面板

详细配置流程请参考:TencentOS官方公众号文章

https://mp.weixin.qq.com/s/t8iVaypA1BtZwt7EEkAWyw

(4)程序连连小程序操作步骤

  • 1.添加家庭 手机端在【微信】搜索【腾讯连连】小程序,首次使用需要进入后点击【我的】->【家庭管理】,添加一个你喜欢的名称即可。
  • 2.添加调试设备 返回【首页】,点击右上角“加号”图标:
添加调试设备添加调试设备
  • 3.添加产品二维码
添加产品二维码添加产品二维码

位于腾讯IoT explorer物联网开发平台的设备调试页面,有一个二维码的选项,点击扫码添加,结果如下图所示:

添加设备成功添加设备成功

最后,在确保硬件正常连接的情况下,设备能够按操作视频所述正常工作,部分现象如下图所示:

设备对接腾讯云IoT explorer平台成功设备对接腾讯云IoT explorer平台成功
腾讯云IoT explorer平台数据实时显示腾讯云IoT explorer平台数据实时显示
腾讯连连小程序数据实时显示腾讯连连小程序数据实时显示
通过腾讯云端下发指令给硬件平台并打印出来通过腾讯云端下发指令给硬件平台并打印出来

7、使用腾讯云IoT explorer平台和腾讯连连的感受

(1)操作简单,技术支持到位

腾讯云IoT explorer致力于让用户快速将设备联网接入,完善的官方操作指引以及简单的操作界面,用户很快就能学习并应用到实际的产品开发中去,其次是腾讯云IoT explorer拥有强大的售后技术支持团队,致力于解决用户使用过程中的任何疑难杂症,保证用户能够简单,高效,快速完成腾讯云平台的对接。

(2)完善的开发者解决方案

腾讯云IoT explorer还提供多个解决方案,通过提供简单的API给用户,用户通过简单调用就可以轻松接入,完善的解决方案注定腾讯云IoT explorer未来能够引领物联网行业走向,促进物联网生态快速发展。

(3)移动端快速资源整合

腾讯云Iot explorer与腾讯连连小程序的默契配合,将物联网网页端平台展现的数据也可以通过手机等移动端随时随地的展示,十分迎合当下信息化时代的发展以及用户需求,该小程序还支持用户二次开发和定制,让用户设备可以有更多的展示空间。

8、本次活动收获

本次参加腾讯连连IoT开发大赛,让我全方位的学习了TencetOS tiny操作系统的使用、腾讯云IoT物联网平台的配置和使用以及腾讯小程序腾讯连连的配置和使用,加深了我对物联网产品开发的理解,同时也让我收获了基于腾讯云物联网设备的开发流程和步骤,经过本次的学习和实践,未来在物联网产品的开发上,优先考虑本次实践的方案。

0 人点赞