- #include "debug.h"
 
- #include "tos_k.h"
 
 
- #define MQTT_TASK_STK_SIZE          2048
 
- k_task_t mqtt_task;
 
- __aligned(8) uint8_t mqtt_task_stk[MQTT_TASK_STK_SIZE];
 
 
- #define CONTROL_TASK_STK_SIZE       4096
 
- k_task_t control_task;
 
- __aligned(8) uint8_t control_task_stk[CONTROL_TASK_STK_SIZE];
 
 
- #define DATA_COLLECT_TASK_STK_SIZE       4096
 
- k_task_t data_collect_task;
 
- __aligned(8) uint8_t data_collect_task_stk[DATA_COLLECT_TASK_STK_SIZE];
 
 
- extern void mqtt_entry(void *arg);
 
- extern void control_entry(void *arg);
 
- extern void data_collect_entry(void *arg);
 
 
- k_msg_q_t msg_q;
 
- uint8_t DataMsgPool[100];
 
 
- int main(void)
 
- {
 
-     Delay_Init();
 
-     USART_Printf_Init(115200);
 
-     printf("SystemClk:%d\r\n",SystemCoreClock);
 
 
-     printf("Welcome to TencentOS tiny(%s)\r\n", TOS_VERSION);
 
 
-     tos_knl_init();
 
-     tos_msg_q_create(&msg_q, DataMsgPool, 100);
 
-     tos_task_create(&mqtt_task, "mqtt_task", mqtt_entry, NULL, 4, mqtt_task_stk, MQTT_TASK_STK_SIZE, 0);
 
-     tos_task_create(&control_task, "control_task", control_entry, NULL, 5, control_task_stk, CONTROL_TASK_STK_SIZE, 0);
 
-     tos_task_create(&data_collect_task, "data_collect_task", data_collect_entry, NULL, 6, data_collect_task_stk, DATA_COLLECT_TASK_STK_SIZE, 0);
 
-     tos_knl_start();
 
 
-     printf("should not run at here!\r\n");
 
-     while(1);
 
- }
 
数据采集线程实现对SGP30、SHT40传感器的初始化,定时将采集数据放入消息队列:
- void data_collect_entry(void *arg)
 
- {
 
-     uint16_t TVOC = 0, CO2 = 0;
 
-     uint8_t ID[6]={0};
 
-     while(sgp30_init() < 0)
 
-    {
 
-        printf(" sgp30 init error\r\n");
 
-        tos_sleep_ms(1000);
 
-    }
 
 
-    if(sgp30_get_serial_id(ID) < 0)
 
-    {
 
-        printf(" sgp30 read serial id error\r\n");
 
-    }else
 
-    {
 
-        printf("SGP30 Serial number: ");
 
-        for(int i = 0; i < 6; i++)  printf("%02X", ID[i]);
 
-        printf("\r\n");
 
-    }
 
-    // SGP30模块开机需要一定时间初始化,在初始化阶段读取的CO2浓度为400ppm,TVOC为0ppd且恒定不变。
 
-    printf("wait for sgp30 init");
 
-    fflush (stdout);
 
-    do
 
-    {
 
-         if(sgp30_read(&CO2, &TVOC) < 0)
 
-         {
 
-            printf("spg30 read error\r\n");
 
-         }
 
-         else
 
-         {
 
-            printf("-");
 
-            fflush (stdout);
 
-         }
 
-         tos_sleep_ms(500);
 
-    }while(TVOC == 0 && CO2 == 400);
 
 
-    printf("sgp30 init ok\r\n");
 
 
-    int16_t error = 0;
 
-    sensirion_i2c_hal_init();
 
-    uint32_t serial_number;
 
-    int32_t temperature;
 
-    int32_t humidity;
 
 
-    error = sht4x_serial_number(&serial_number);
 
-    if (error)
 
-    {
 
-        printf("Error executing sht4x_serial_number(): %i\r\n", error);
 
-    }
 
-    else
 
-    {
 
-        printf("SHT40 Serial number: %u\r\n", serial_number);
 
-    }
 
 
-    msg_t msg={0};
 
 
-    while (1)
 
-    {
 
-        if(sgp30_read(&CO2, &TVOC) < 0)
 
-        {
 
-            printf(" sgp30 read error\r\n");
 
-        }
 
-        else
 
-        {
 
-            printf("CO2:%5dppm TVOC:%5dppb\r\n", CO2, TVOC);
 
-        }
 
-        error = sht4x_measure_high_precision(&temperature, &humidity);
 
-        if (error)
 
-        {
 
-            printf("Error executing sht4x_measure_high_precision(): %i\n",error);
 
-        }
 
-        else
 
-        {
 
-            msg.tvoc = TVOC;
 
-            msg.co2 = CO2;
 
-            msg.tem = temperature / 1000.0f;
 
-            msg.hum = humidity / 1000.0f;
 
-            tos_msg_q_post(&msg_q,(void*)&msg);
 
-            printf("Temperature:%0.2f℃,Humidity:%0.2f %%RH\n",temperature / 1000.0f, humidity / 1000.0f);
 
-        }
 
-        tos_sleep_ms(3000);
 
-    }
 
- }
对接云平台,修改mqtt_iot_explorer.c文件开头的三元组信息产品 ID(ProductId)、设备名(DeviceName)、设备密钥(DeviceSecret)其中设备密钥由平台生成:
- #define PRODUCT_ID              "test"
 
- #define DEVICE_NAME             "test"
 
- #define DEVICE_KEY              "test"
然后修改要接入WIFI的名称和密码:
- esp8266_tencent_firmware_join_ap("ssid", "passwd");
mqtt线程首先完成esp8266初始化、wifi协议栈初始化、mqtt订阅主题等功能。当接收到消息后,将采集数据依据消息发布使用的物模型Topic打包,然后通过MQTT发送出去。属性上报主题格式如下所示:
$thing/up/property/${deviceID}/${deviceName}
根据腾讯云平台配置的物模型将数据打包为json格式上传,消息体json格式如下:
- #define REPORT_DATA_TEMPLATE    "{\\"method\\":\\"report\\"\\,\\"clientToken\\":\\"00000001\\"\\,\\"params\\":{\\"tvoc\\":%d\\,\\"co2\\":%d\\,\\"fan\\":%d\\,\\"sleep\\":%d\\,\\"temperature\\":%0.1f\\,\\"humidity\\":%0.1f\\}}"
-     memset(report_topic_name, 0, sizeof(report_topic_name));
 
-     size = snprintf(report_topic_name, TOPIC_NAME_MAX_SIZE, "$thing/up/property/%s/%s", product_id, device_name);
-         memset(payload, 0, sizeof(payload));
 
-         snprintf(payload, sizeof(payload), REPORT_DATA_TEMPLATE, tvoc,co2,0,0,tem,hum);
- tos_tf_module_mqtt_pub(report_topic_name, QOS0, payload)
推送传感器数据到腾讯云物联网开发平台IoT Explorer的mqtt线程如下:
- void mqtt_demo_task(void)
 
- {
 
-     int ret = 0;
 
-     int size = 0;
 
 
-     mqtt_state_t state;
 
 
-     char *product_id = PRODUCT_ID;
 
-     char *device_name = DEVICE_NAME;
 
-     char *key = DEVICE_KEY;
 
 
-     device_info_t dev_info;
 
-     memset(&dev_info, 0, sizeof(device_info_t));
 
 
-     /**
 
-      * Please Choose your AT Port first, default is HAL_UART_2(USART2)
 
-     */
 
-     ret = esp8266_tencent_firmware_sal_init(HAL_UART_PORT_2);
 
 
-     if (ret < 0) {
 
-         printf("esp8266 tencent firmware sal init fail, ret is %d\r\n", ret);
 
-     }
 
 
-     esp8266_tencent_firmware_join_ap("HUAWEI-DQL", "dql8837150");
 
 
-     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 fail\n");
 
-     } else {
 
-         printf("module mqtt conn success\n");
 
-     }
 
 
-     if (tos_tf_module_mqtt_state_get(&state) != -1) {
 
-         printf("MQTT: %s\n", state == MQTT_STATE_CONNECTED ? "CONNECTED" : "DISCONNECTED");
 
-     }
 
 
-     size = snprintf(report_reply_topic_name, TOPIC_NAME_MAX_SIZE, "$thing/down/property/%s/%s", product_id, device_name);
 
 
-     if (size < 0 || size > sizeof(report_reply_topic_name) - 1) {
 
-         printf("sub topic content length not enough! content size:%d  buf size:%d", size, (int)sizeof(report_reply_topic_name));
 
-     }
 
-     if (tos_tf_module_mqtt_sub(report_reply_topic_name, QOS0, default_message_handler) != 0) {
 
-         printf("module mqtt sub fail\n");
 
-     } else {
 
-         printf("module mqtt sub success\n");
 
-     }
 
 
-     memset(report_topic_name, 0, sizeof(report_topic_name));
 
-     size = snprintf(report_topic_name, TOPIC_NAME_MAX_SIZE, "$thing/up/property/%s/%s", product_id, device_name);
 
 
-     if (size < 0 || size > sizeof(report_topic_name) - 1)
 
-     {
 
-         printf("pub topic content length not enough! content size:%d  buf size:%d", size, (int)sizeof(report_topic_name));
 
-     }
 
-     void *MsgRecv;
 
-     msg_t msg;
 
-     int tvoc;
 
-     int co2;
 
-     float tem;
 
-     float hum;
 
-     while (1)
 
-     {
 
-         //GPIO_SetBits(GPIOE,GPIO_Pin_5);
 
-         //tos_sleep_ms(2000);
 
-         //GPIO_ResetBits(GPIOE,GPIO_Pin_5);
 
 
-         tos_msg_q_pend(&msg_q, &MsgRecv, TOS_TIME_FOREVER);
 
-         memcpy(&msg,MsgRecv,sizeof(msg_t));
 
-         tos_mutex_pend(&mutex);
 
-         printf("tvoc:%d co2:%d temp:%d hum:%d\r\n",msg.tvoc,msg.co2,msg.tem,msg.hum);
 
-         tos_mutex_post(&mutex);
 
-         /* use AT+PUB AT command */
 
 
-         tvoc = msg.tvoc;
 
-         co2 = msg.co2;
 
-         tem = msg.tem;
 
-         hum = msg.hum;
 
 
-         memset(payload, 0, sizeof(payload));
 
-         snprintf(payload, sizeof(payload), REPORT_DATA_TEMPLATE, tvoc,co2,0,0,tem,hum);
 
-         if (tos_tf_module_mqtt_pub(report_topic_name, QOS0, payload) != 0)
 
-         {
 
-             printf("module mqtt pub fail\n");
 
-             break;
 
-         }
 
-         else
 
-         {
 
-             printf("module mqtt pub success\n");
 
-         }
 
-     }
 
- }
程序运行正常的情况下,在云平台调试界面就可以看到设备发送的数据:
 
进入腾讯连连小程序连接设备后也能看到之前设计的小程序界面:
小程序收到超标告警消息:
 
六、视频演示
【CH32V307&tencentos-tiny接入腾讯云平台小程序数据采集展示】 https://www.bilibili.com/video/BV1xD4y177yd/?share_source=copy_web&vd_source=4b9c499d8564e7ad9169a2c39fa19a17
 
七、总结通过本项目体验了国产MCU、国产RTOS、国产IDE生态,了解了沁恒RISC-V内核微控制器 CH32V307VCT6应用、了解了国产物联网操作系统TencentOS-tiny和国产集成开发工具MounRiver Studio,感受到了国货的崛起。
由于本人能力水平不足,文章写的有误或者不清楚的地方敬请见谅。
八、工程源码由于大小限制,替换TencentOS-tiny\board\TencentOS_Tiny_CH32V307_EVB即可。