ESP32-C3入门教程 IoT篇②——阿里云 物联网平台 EspAliYun RGB LED 实战之ESP32固件端源码解析

81 篇文章 552 订阅 ¥59.90 ¥99.00
该教程介绍了如何使用ESP32-C3通过阿里云物联网平台控制RGB LED。内容涵盖系统架构、初始化流程、WiFi和MQTT任务、按键扫描及固件烧录运行。源码已在Gitee开源。
摘要由CSDN通过智能技术生成

一、前言

本文基于VS Code IDE进行编程、编译、下载、运行等操作
基础入门章节请查阅:ESP32-C3入门教程 基础篇①——基于VS Code构建Hello World
教程目录大纲请查阅:ESP32-C3入门教程——导读

ESP32-C3入门教程 IoT篇①——阿里云 物联网平台 EspAliYun RGB LED 实战
ESP32-C3入门教程 IoT篇②——阿里云 物联网平台 EspAliYun RGB LED 实战之ESP32固件端源码解析
ESP32-C3入门教程 IoT篇③——阿里云 物联网平台 EspAliYun RGB LED 实战之Android端源码解析
ESP32-C3入门教程 IoT篇④——阿里云 物联网平台 EspAliYun RGB LED 实战之微信小程序端源码解析
ESP32-C3入门教程 IoT篇⑤——阿里云 物联网平台 EspAliYun RGB LED 实战之设备生产流程
ESP32-C3入门教程 IoT篇⑥——阿里云 物联网平台 EspAliYun RGB LED 实战之设备批量生产工具

ESP32固件端源码已经全部开源:小康师兄 / EspAliYun (gitee地址)

二、系统架构

2.1 系统架构

app_main
button
rgb_led
mqtt_solo
driver/gpio
common_components/led_strip
components/esp-aliyun
conn_mgr
iotkit-embedded
wrappers

2.2 组件component

两个外部组件component,分别通过两种方式依赖进来。
在这里插入图片描述

三、软件流程

3.1 初始化流程

app_main button rgb_led conn_mgr button_init() gpio配置 创建按键轮询线程 rgb_led_init() install ws2812 driver Clear LED strip conn_mgr_init() esp_event_loop_init(...) esp_wifi_init(&cfg) esp_wifi_set_storage(WIFI_STORAGE_RAM) esp_wifi_set_mode(WIFI_MODE_STA) esp_wifi_start() conn_mgr_register_wifi_event(wifi_event_handle) conn_mgr_set_wifi_config_ext(...) conn_mgr_start() app_main button rgb_led conn_mgr

3.2 WiFi任务回调流程

WiFi任务 app_main mqtt_solo wrappers iotkit-embedded SYSTEM_EVENT_STA_GOT_IP 创建mqtt线程 HAL_GetProductKey(...) 从nvs中获取productKey HAL_GetDeviceName(...) 从nvs中获取deviceName HAL_GetDeviceSecret(...) 从nvs中获取deviceSecret IOT_MQTT_Construct(...) example_subscribe(...) example_publish(...) while(...) WiFi任务 app_main mqtt_solo wrappers iotkit-embedded

3.3 MQTT订阅接收消息流程

MQTT任务 mqtt_solo rgb_led example_message_arrive cJSON解析 rgb_led_update() example_publish() MQTT任务 mqtt_solo rgb_led

3.4 按键扫描执行流程

button 按键扫描线程 rgb_led mqtt_solo 按键扫描线程 轮询 按键短按,Led开关 rgb_led_update() example_publish() 按键长按,Led颜色渐变 rgb_led_update() example_publish() button 按键扫描线程 rgb_led mqtt_solo

四、button

//按键扫描
void read_button()
{
    if(gpio_get_level(GPIO_INPUT_IO_0)==0){
        uint32_t tick1 = xTaskGetTickCount();
        uint32_t tick2 = xTaskGetTickCount();
        while(gpio_get_level(GPIO_INPUT_IO_0)==0){
            vTaskDelay(10 / portTICK_RATE_MS);
            if(xTaskGetTickCount()>tick1+100){
                tick1 = xTaskGetTickCount();
                ESP_LOGI(TAG, "按键长按\n");
                rgb_led.red*=1.1;
                rgb_led.green*=1.1;
                rgb_led.blue*=1.1;

                rgb_led.red=rgb_led.red>255?255:rgb_led.red;
                rgb_led.green=rgb_led.green>255?255:rgb_led.green;
                rgb_led.blue=rgb_led.blue>255?255:rgb_led.blue;

                rgb_led_update();
                example_publish();
            }
        }
        if(xTaskGetTickCount()>tick2 && xTaskGetTickCount()<tick2+100){
            ESP_LOGI(TAG, "按键短按\n");
            if(rgb_led.led_switch)
            {
                rgb_led.led_switch = 0;
            }else{
                rgb_led.led_switch = 1;
                if(rgb_led.red==0&&rgb_led.green==0&&rgb_led.blue==0){
                    rgb_led.red=100;
                    rgb_led.green=100;
                    rgb_led.blue=100;
                }
            }
            rgb_led_update();
            example_publish();
        }
    }
}

五、rgb_led

  • rgb_led_update(),更新彩色灯状态
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include "esp_log.h"
#include "driver/rmt.h"
#include "led_strip.h"
#include "rgb_led.h"


#define RMT_TX_CHANNEL RMT_CHANNEL_0
#define EXAMPLE_RMT_TX_GPIO 8
#define EXAMPLE_STRIP_LED_NUMBER 1

static const char *TAG = "rgb_led";

led_strip_t *strip;
rgb_led_t rgb_led;

void rgb_led_update(void)
{
    ESP_LOGI(TAG, "rgb_led_update led_switch: %d, red: %d, green: %d, blue: %d", rgb_led.led_switch, rgb_led.red, rgb_led.green, rgb_led.blue);
    if(rgb_led.led_switch){
        strip->set_pixel(strip, 0, rgb_led.red, rgb_led.green, rgb_led.blue);
    }else{
        strip->set_pixel(strip, 0, 0, 0, 0);
    }
    strip->refresh(strip, 50);
}
  • rgb_led_init(),初始化彩色灯
void rgb_led_init(void)
{
    rmt_config_t config = RMT_DEFAULT_CONFIG_TX(EXAMPLE_RMT_TX_GPIO, RMT_TX_CHANNEL);
    // set counter clock to 40MHz
    config.clk_div = 2;

    ESP_ERROR_CHECK(rmt_config(&config));
    ESP_ERROR_CHECK(rmt_driver_install(config.channel, 0, 0));

    // install ws2812 driver
    led_strip_config_t strip_config = LED_STRIP_DEFAULT_CONFIG(EXAMPLE_STRIP_LED_NUMBER, (led_strip_dev_t)config.channel);
    strip = led_strip_new_rmt_ws2812(&strip_config);
    if (!strip) {
        ESP_LOGE(TAG, "install WS2812 driver failed");
    }
    // Clear LED strip (turn off all LEDs)
    ESP_ERROR_CHECK(strip->clear(strip, 100));
    // Show simple rainbow chasing pattern
    ESP_LOGI(TAG, "LED Rainbow Chase Start");
}

六、mqtt_solo

6.1 mqtt订阅

int example_subscribe(void *handle)
{
    int res = 0;
    const char *fmt = "/sys/%s/%s/thing/service/property/set";
    char *topic = NULL;
    int topic_len = 0;

    topic_len = strlen(fmt) + strlen(DEMO_PRODUCT_KEY) + strlen(DEMO_DEVICE_NAME) + 1;
    topic = HAL_Malloc(topic_len);
    if (topic == NULL) {
        EXAMPLE_TRACE("memory not enough");
        return -1;
    }
    memset(topic, 0, topic_len);
    HAL_Snprintf(topic, topic_len, fmt, DEMO_PRODUCT_KEY, DEMO_DEVICE_NAME);

    res = IOT_MQTT_Subscribe(handle, topic, IOTX_MQTT_QOS0, example_message_arrive, NULL);
    if (res < 0) {
        EXAMPLE_TRACE("subscribe failed");
        HAL_Free(topic);
        return -1;
    }

    HAL_Free(topic);
    return 0;
}

6.2 mqtt发布

int example_publish(void)
{
    int             res = 0;
    char           *topic = NULL;
    const char     *topic_fmt = "/sys/%s/%s/thing/event/property/post";
    int             topic_len = 0;
    char           *payload = NULL; 
    const char     *payload_fmt = "{ \
                        \"version\": \"1.0\", \
                        \"params\": { \
                            \"RGBColor\": { \
                                \"value\": %s, \
                            },\
                            \"LEDSwitch\": { \
                                \"value\": %d, \
                            }\
                        },\
                        \"method\": \"thing.event.property.post\"  \      
                    }";
    int             payload_len = 0;
    cJSON          *rgb =  cJSON_CreateObject();

    topic_len = strlen(topic_fmt) + strlen(DEMO_PRODUCT_KEY) + strlen(DEMO_DEVICE_NAME) + 1;
    topic = HAL_Malloc(topic_len);
    if (topic == NULL) {
        EXAMPLE_TRACE("memory not enough");
        return -1;
    }
    memset(topic, 0, topic_len);
    HAL_Snprintf(topic, topic_len, topic_fmt, DEMO_PRODUCT_KEY, DEMO_DEVICE_NAME);

    cJSON_AddItemToObject(rgb, "Red", cJSON_CreateNumber(rgb_led.red));
    cJSON_AddItemToObject(rgb, "Green", cJSON_CreateNumber(rgb_led.green));
    cJSON_AddItemToObject(rgb, "Blue", cJSON_CreateNumber(rgb_led.blue));    
    payload_len = strlen(payload_fmt) + strlen(cJSON_Print(rgb)) + 1 + 1;
    payload = HAL_Malloc(payload_len);
    if (payload == NULL) {
        EXAMPLE_TRACE("memory not enough");
        return -1;
    }
    memset(payload, 0, payload_len);
    HAL_Snprintf(payload, payload_len, payload_fmt, cJSON_Print(rgb), rgb_led.led_switch);
    EXAMPLE_TRACE("publish %s", payload);

    res = IOT_MQTT_Publish_Simple(0, topic, IOTX_MQTT_QOS0, payload, strlen(payload));
    if (res < 0) {
        EXAMPLE_TRACE("publish failed, res = %d", res);
        HAL_Free(topic);
        return -1;
    }

    HAL_Free(topic);
    return 0;
}

6.3 mqtt接收处理消息

void example_message_arrive(void *pcontext, void *pclient, iotx_mqtt_event_msg_pt msg)
{
    cJSON * root = NULL;
    cJSON * params = NULL;
    cJSON * rgb_color = NULL;

    iotx_mqtt_topic_info_t     *topic_info = (iotx_mqtt_topic_info_pt) msg->msg;

    switch (msg->event_type) {
        case IOTX_MQTT_EVENT_PUBLISH_RECEIVED:
            /* print topic name and topic message */
            EXAMPLE_TRACE("Message Arrived:");
            EXAMPLE_TRACE("Topic  : %.*s", topic_info->topic_len, topic_info->ptopic);
            EXAMPLE_TRACE("Payload: %.*s", topic_info->payload_len, topic_info->payload);
            EXAMPLE_TRACE("\n");
            root = cJSON_Parse(topic_info->payload);     
            params = cJSON_GetObjectItem(root, "params");
            rgb_color = cJSON_GetObjectItem(params, "RGBColor");
            rgb_led.led_switch = (int)cJSON_GetNumberValue(cJSON_GetObjectItem(params, "LEDSwitch"));
            rgb_led.red = (int)cJSON_GetNumberValue(cJSON_GetObjectItem(rgb_color, "Red"));
            rgb_led.green = (int)cJSON_GetNumberValue(cJSON_GetObjectItem(rgb_color, "Green"));
            rgb_led.blue = (int)cJSON_GetNumberValue(cJSON_GetObjectItem(rgb_color, "Blue"));
            rgb_led_update();
            example_publish();
            break;
        default:
            break;
    }
}

6.4 mqtt启动

int mqtt_main(void *paras)
{
    void                   *pclient = NULL;
    int                     res = 0;
    iotx_mqtt_param_t       mqtt_params;

    HAL_GetProductKey(DEMO_PRODUCT_KEY);
    HAL_GetDeviceName(DEMO_DEVICE_NAME);
    HAL_GetDeviceSecret(DEMO_DEVICE_SECRET);

    EXAMPLE_TRACE("mqtt example");

    /* Initialize MQTT parameter */
    /*
     * Note:
     *
     * If you did NOT set value for members of mqtt_params, SDK will use their default values
     * If you wish to customize some parameter, just un-comment value assigning expressions below
     *
     **/
    memset(&mqtt_params, 0x0, sizeof(mqtt_params));

    /**
     *
     *  MQTT connect hostname string
     *
     *  MQTT server's hostname can be customized here
     *
     *  default value is ${productKey}.iot-as-mqtt.cn-shanghai.aliyuncs.com
     */
    /* mqtt_params.host = "something.iot-as-mqtt.cn-shanghai.aliyuncs.com"; */

    /**
     *
     *  MQTT connect port number
     *
     *  TCP/TLS port which can be 443 or 1883 or 80 or etc, you can customize it here
     *
     *  default value is 1883 in TCP case, and 443 in TLS case
     */
    /* mqtt_params.port = 1883; */

    /**
     *
     * MQTT request timeout interval
     *
     * MQTT message request timeout for waiting ACK in MQTT Protocol
     *
     * default value is 2000ms.
     */
    /* mqtt_params.request_timeout_ms = 2000; */

    /**
     *
     * MQTT clean session flag
     *
     * If CleanSession is set to 0, the Server MUST resume communications with the Client based on state from
     * the current Session (as identified by the Client identifier).
     *
     * If CleanSession is set to 1, the Client and Server MUST discard any previous Session and Start a new one.
     *
     * default value is 0.
     */
    /* mqtt_params.clean_session = 0; */

    /**
     *
     * MQTT keepAlive interval
     *
     * KeepAlive is the maximum time interval that is permitted to elapse between the point at which
     * the Client finishes transmitting one Control Packet and the point it starts sending the next.
     *
     * default value is 60000.
     */
    /* mqtt_params.keepalive_interval_ms = 60000; */

    /**
     *
     * MQTT write buffer size
     *
     * Write buffer is allocated to place upstream MQTT messages, MQTT client will be limitted
     * to send packet no longer than this to Cloud
     *
     * default value is 1024.
     *
     */
    /* mqtt_params.write_buf_size = 1024; */

    /**
     *
     * MQTT read buffer size
     *
     * Write buffer is allocated to place downstream MQTT messages, MQTT client will be limitted
     * to recv packet no longer than this from Cloud
     *
     * default value is 1024.
     *
     */
    /* mqtt_params.read_buf_size = 1024; */

    /**
     *
     * MQTT event callback function
     *
     * Event callback function will be called by SDK when it want to notify user what is happening inside itself
     *
     * default value is NULL, which means PUB/SUB event won't be exposed.
     *
     */
    mqtt_params.handle_event.h_fp = example_event_handle;

    pclient = IOT_MQTT_Construct(&mqtt_params);
    if (NULL == pclient) {
        EXAMPLE_TRACE("MQTT construct failed");
        return -1;
    }

    res = example_subscribe(pclient);
    if (res < 0) {
        IOT_MQTT_Destroy(&pclient);
        return -1;
    }

    example_publish();
    while (1) {
        IOT_MQTT_Yield(pclient, 1000);
    }

    return 0;
}

七、Flash 烧录&运行

7.1 固件文件编译&下载

7.2 配置文件生成&烧写

  • 将从阿里云物联网平台获取的ProductKeyProductSecretDeviceNameDeviceSecret(第3.3章节),按照如下格式输入,保存成csv文件
key,type,encoding,value
aliyun-key,namespace,,
DeviceName,data,string,xxx1
DeviceSecret,data,string,xxx2
ProductKey,data,string,xxx3
ProductSecret,data,string,xxx4
  • 通过nvs_partition_gen.py ,转成配置文件bin文件
python $IDF_PATH/components/nvs_flash/nvs_partition_generator/nvs_partition_gen.py generate single_mfg_config.csv single_mfg.bin 0x4000
python C:\Espressif\frameworks\esp-idf-v4.4\components\nvs_flash\nvs_partition_generator\nvs_partition_gen.py generate single_mfg_config.csv single_mfg.bin 0x4000

在这里插入图片描述

  • 烧写配置文件到ESP32-C3
python C:\Espressif\frameworks\esp-idf-v4.4\components\esptool_py\esptool\esptool.py -p COM6 -b 460800 write_flash 0x210000 single_mfg.bin
esptool.py v3.2-dev
Serial port COM6
Connecting....
Detecting chip type... ESP32-C3
Chip is ESP32-C3 (revision 3)
Features: Wi-Fi
Crystal is 40MHz
MAC: 84:f7:03:08:4d:80
Uploading stub...
Running stub...
Stub running...
Changing baud rate to 460800
Changed.
Configuring flash size...
Flash will be erased from 0x00100000 to 0x00103fff...
Compressed 16384 bytes to 326...
Wrote 16384 bytes (326 compressed) at 0x00100000 in 0.2 seconds (effective 581.6 kbit/s)...
Hash of data verified.

Leaving...
Hard resetting via RTS pin...

在这里插入图片描述

7.3 运行

在这里插入图片描述

八、其他

文章中关于CJSON部分内容,同学们如有不了解的可以查阅:ESP32-C3入门教程 系统篇④——cJSON应用实例 | C语言中超轻量级JSON解析器

觉得好,就一键三连呗(点赞+收藏+关注)

  • 9
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 9
    评论
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小康师兄

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值