当前位置:   article > 正文

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

esc32源码分析

一、前言

本文基于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();
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41

五、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);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 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");
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

六、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;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

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;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54

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;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

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;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130

七、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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 通过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
  • 1
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
  • 1

在这里插入图片描述

  • 烧写配置文件到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...
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

在这里插入图片描述

7.3 运行

在这里插入图片描述

八、其他

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

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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/煮酒与君饮/article/detail/850620
推荐阅读
相关标签
  

闽ICP备14008679号