【开发者成长激励计划-基于TencentOS Tiny 和腾讯云的环境监测系统】

2022-07-14 22:52:08 浏览数 (2)

1. 引言

本文设计了基于CH32V307和TencentOS Tiny的环境监测系统,通过DHT11传感器读取相关的数据,将温湿度数据显示在LCD上,并通过ESP8266实现下位机与腾讯云的连接,将该数据上传到腾讯云上,实现云端数据的监视。

2. 硬件介绍

整体架构

2.1 单片机

单片机采用CH32V307VCT6的芯片,CH32V307系列是基于32位RISC-V设计的互联型微控制器,配备了硬件堆栈区、快速中断入口,在标准RISC-V基础上大大提高了中断响应速度。加入单精度浮点指令集,扩充堆栈区,具有更高的运算性能。CH32V307是基于32位RISC-V设计的互联型微控制器,配备了硬件堆栈区、快速中断入口,在标准RISC-V基础上大大提高了中断响应速度。加入单精度浮点指令集,扩充堆栈区,具有更高的运算性能。扩展串口UART数量到8组,电机定时器到4组。提供USB2.0高速接口(480Mbps)并内置了PHY收发器,以太网MAC升级到千兆并集成了10M-PHY模块。

硬件使用的是 TencentOS Tiny CH32V_EVB RISC-V开发套件,板载Type-C接口WCH-LINK仿真器,板载esp8266 WiFi模组,支持腾讯云固件。

 TencentOS Tiny CH32V_EVB RISC-V开发套件 TencentOS Tiny CH32V_EVB RISC-V开发套件

2.2 温湿度传感器

DHT11是一款有已校准数字信号输出的温湿度传感器。 其精度湿度±5%RH, 温度±2℃,量程湿度5~95%RH, 温度-20~ 60℃。

DHT11DHT11

2.3 显示模块

LCD模块使用的是ST7789,一般是用于262K彩色TFT-LCD的单片控制器/驱动程序。它由960条源线和480条栅线驱动电路组成。ST7796S能够连接直接 Y为外部微处理器,接受8位/9位/16位/18位并行接口,spi和ST7796S也提供mipi接口。

这是官网提供的原理图。

2.4 通信模块

通信模块使用是ESP8266,可以直接烧录腾讯云的AT固件,连接腾讯云的物联网平台非常简单。ESP-12F是安信可用ESP8266EX芯片做的一款WiFi模组,这个模块已经把内部的电路设计好了。实际测试,ESP01和01s不如12f系列的稳定,经常出问题,要是长期使用还是建议使用12f系列。

2.5 效果图

3 程序设计

程序分为三个任务,分别为温湿度采集、数据显示、数据上传三个任务。

(1)创建任务

其中任务1为数据显示,任务2为温湿度采集,任务3为上传上传。

代码语言:javascript复制
 tos_mail_q_create(&mail_q, mail_pool, MAIL_MAX, sizeof(mail_t));
    tos_task_create(&task1, "task1", task1_entry, NULL, 3, task1_stk, TASK1_STK_SIZE, 0); // Create task1
    tos_task_create(&task2, "task2", task2_entry, NULL, 3, task2_stk, TASK2_STK_SIZE, 0);// Create task2
    tos_task_create(&task3, "task3", task3_entry, NULL, 2, task3_stk, TASK3_STK_SIZE, 0);// Create task3

(2)温湿度采集数据

温湿度采用的是DHT11采集环境信息,由于DHT11对延时要求比较高,所以该设计采用的是定时器实现延时。采用的是定时器3.

初始化定时器3,实现定时器分频。

代码语言:javascript复制
void TIM3_Init(void)
{
    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);  ///使能TIM3时钟
    TIM_TimeBaseInitStructure.TIM_Period    = 0xffff;  //自动重装载值
    TIM_TimeBaseInitStructure.TIM_Prescaler = 144-1;     //定时器分频
    TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up; //向上计数模式
    TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;
    TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStructure);//初始化TIM3
}

延时函数

代码语言:javascript复制
//微秒级延时
void TIM3_Delayus(u16 xus)
{
    TIM_Cmd(TIM3,ENABLE); //启动定时器
    while(TIM3->CNT < xus);
    TIM3->CNT = 0;
    TIM_Cmd(TIM3,DISABLE); //关闭定时器
}

任务函数

代码语言:javascript复制
void task2_entry(void *arg)
{
    u8 temperature=0;
    u8 humidity=0;
    mail_t mail;
    while (1) {

        DHT11_Read_Data(&temperature,&humidity);  //读取温湿度值
        mail.temp = temperature;
        mail.humi = humidity;
        tos_mail_q_post_all(&mail_q, &mail, sizeof(mail_t));
        tos_task_delay(5000);
    }
}

(2)该系统移植的是系统中自带的LCD模块驱动代码,这里我添加的是实现汉字和英文混合显示的功能。其代码如下所示

代码语言:javascript复制
void LCD_ShowStringCn(u16 x,u16 y,u8 *s,u16 fc,u16 bc,u8 sizey,u8 mode)
{
    while(*s!='')
    {
        if(*s<128){
            LCD_ShowChar(x,y,*s,fc,bc,sizey,mode);
            x =sizey/2;
            s  ;
        }
        else{
            if(sizey==12) LCD_ShowChinese12x12(x,y,s,fc,bc,sizey,mode);
            else if(sizey==16) LCD_ShowChinese16x16(x,y,s,fc,bc,sizey,mode);
            else if(sizey==24) LCD_ShowChinese24x24(x,y,s,fc,bc,sizey,mode);
            else if(sizey==32) LCD_ShowChinese32x32(x,y,s,fc,bc,sizey,mode);
            else return;
            s =2;
            x =sizey;
        }
    }
}

这里需要自己取字模,字模的格式如下

创建的显示任务代码

代码语言:javascript复制
void task1_entry(void *arg)
{
    k_err_t err;
    mail_t mail;
    size_t mail_size;
    u8 s_temp[128];
    LCD_ShowString(0,0,"Welcome TencentOS",WHITE,BLACK,16,0);
    while (1) {

        err = tos_mail_q_pend(&mail_q, &mail, &mail_size, TOS_TIME_FOREVER);
        if (err == K_ERR_NONE) {
            TOS_ASSERT(mail_size == sizeof(mail_t));
            printf("温度: %d, 湿度:%d n", mail.temp, mail.humi);
            sprintf(s_temp,"温度: %d, 湿度:%d   ",mail.temp, mail.humi);
            LCD_ShowStringCn(0,32,s_temp,GREEN,BLACK,16,0);
        }
    }
}

(3)创建上传任务代码

代码语言:javascript复制
#define QOS0 0
void task3_entry(void *arg)
{
    k_err_t err;
    mail_t mail;
    size_t mail_size;
        char payload[256] = {0};
        u8 temperature=0;
        u8 humidity=0;
        mqtt_state_t state;

        char *product_id = "0G95XV3IEP";
        char *device_name = "isnt0";
        char *key = "C8CJeD69bCFvwsD13gnyBA==";

        device_info_t dev_info;
        memset(&dev_info, 0, sizeof(device_info_t));
        esp8266_tencent_firmware_sal_init(HAL_UART_PORT_2);
        esp8266_tencent_firmware_join_ap("TP-LINK_XXXX", "11112222");

        strncpy(dev_info.product_id, product_id, PRODUCT_ID_MAX_SIZE);
        strncpy(dev_info.device_name, device_name, DEVICE_NAME_MAX_SIZE);
        strncpy(dev_info.device_serc, key, DEVICE_SERC_MAX_SIZE);
        tos_tf_module_info_set(&dev_info, TLS_MODE_PSK);

        mqtt_param_t init_params = DEFAULT_MQTT_PARAMS;
        if (tos_tf_module_mqtt_conn(init_params) != 0) {
            printf("module mqtt conn failn");
        } else {
            printf("module mqtt conn successn");
        }

        if (tos_tf_module_mqtt_state_get(&state) != -1) {
            printf("MQTT: %sn", state == MQTT_STATE_CONNECTED ? "CONNECTED" : "DISCONNECTED");
        }

        static char topic_name[TOPIC_NAME_MAX_SIZE] = {0};
        static char topic_name_sub[TOPIC_NAME_MAX_SIZE] = {0};
        int size = snprintf(topic_name, TOPIC_NAME_MAX_SIZE, "$thing/up/property/%s/%s", product_id, device_name);

        if (size < 0 || size > sizeof(topic_name) - 1) {
            printf("topic content length not enough! content size:%d  buf size:%d", size, (int)sizeof(topic_name));
        }
        size = snprintf(topic_name_sub, TOPIC_NAME_MAX_SIZE, "$thing/down/property/%s/%s", product_id, device_name);
                if (size < 0 || size > sizeof(topic_name) - 1) {
                    printf("topic content length not enough! content size:%d  buf size:%d", size, (int)sizeof(topic_name));
                }
        if (tos_tf_module_mqtt_sub(topic_name_sub, QOS0, default_message_handler) != 0) {
            printf("module mqtt sub failn");
        } else {
            printf("module mqtt sub successn");
        }
        while (1) {
            /* use AT PUB AT command */
            memset(payload, 0, sizeof(payload));
            sprintf(payload, "{\"method\":\"report\"\,\"clientToken\":\"123\"\,\"params\":{\"temp\":%d\,\"humi\":%d}}",temperature,humidity);
            printf("message publish: %sn", payload);
            if (tos_tf_module_mqtt_pub(topic_name, QOS0, payload) != 0) {
                printf("module mqtt pub failn");
                break;
            } else {
                printf("module mqtt pub successn");
            }
            err = tos_mail_q_pend(&mail_q, &mail, &mail_size, TOS_TIME_FOREVER);
            if (err == K_ERR_NONE) {
                TOS_ASSERT(mail_size == sizeof(mail_t));
                temperature = mail.temp ;
                humidity=  mail.humi ;
            }

        }

}

4 云平台设计

(1)物模型的搭建

(2)数据显示

这是完整的代码,在TencentOS-tiny-masterboard替换TencentOS_Tiny_CH32V307_EVB文件夹即可。 TencentOS_Tiny_CH32V307_EVB.rar

0 人点赞