ONENET物联网平台的mqtt订阅、上报。基于ESP32S3

张开发
2026/4/13 1:13:27 15 分钟阅读

分享文章

ONENET物联网平台的mqtt订阅、上报。基于ESP32S3
一、_ONENET_DM_H_#ifndef _ONENET_DM_H_ #define _ONENET_DM_H_ #include cJSON.h void onenet_dm_init(void); void onenet_property_handle(cJSON* property); cJSON* onenet_property_upload(void); #endif#include onenet_dm.h #include led_ws2812.h #include driver/gpio.h #include driver/ledc.h #include string.h static ws2812_strip_handle_t ws2812_handle NULL; static int led_brightness 0; static int led_statue 0; static int ws2812_red 0; static int ws2812_green 0; static int ws2812_blue0; void onenet_dm_init(void) { ws2812_init(GPIO_NUM_18, 3, ws2812_handle); ledc_timer_config_t ledc_timer { .duty_resolution LEDC_TIMER_12_BIT, .timer_num LEDC_TIMER_0, .freq_hz 5000, // Set output frequency at 4 kHz .clk_cfg LEDC_AUTO_CLK }; ledc_timer_config(ledc_timer); ledc_channel_config_t ledc_channel { .timer_sel LEDC_TIMER_0, .intr_type LEDC_INTR_DISABLE, .gpio_num GPIO_NUM_15, .duty 0, // Set duty to 0% .channel LEDC_CHANNEL_0, }; ledc_channel_config(ledc_channel); ledc_fade_func_install(0); } void onenet_property_handle(cJSON* property) { /* { id: 123, version: 1.0, params: { Brightness: 50, LightSwitch: ture, RGBColor: { Red: 100, Green: 100, Blue: 100, } } } */ cJSON* param_js cJSON_GetObjectItem(property, params);//把cjson的params整个成员取到了param_js if(param_js) { cJSON* name_js param_js-child;//指向的第一个成员就是“Brightness” while(name_js) { if(strcmp(name_js-string, Brightness ) 0)//对应的是键值对的键名 { led_brightness cJSON_GetNumberValue(name_js); int duty led_brightness * 4095 / 100; ledc_set_duty_and_update(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, duty, 0); } else if (strcmp(name_js-string, LightSwitch ) 0) { if(cJSON_IsTrue(name_js)) { led_statue 1; led_brightness 50; int duty 50 * 4095 / 100; ledc_set_duty_and_update(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, duty, 0); } else { led_statue 0; led_brightness 0; ledc_set_duty_and_update(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, 0, 0); } } else if (strcmp(name_js-string, RGBColor ) 0) { ws2812_red cJSON_GetNumberValue(cJSON_GetObjectItem(name_js,Red)); ws2812_green cJSON_GetNumberValue(cJSON_GetObjectItem(name_js,Green)); ws2812_blue cJSON_GetNumberValue(cJSON_GetObjectItem(name_js,Blue)); } for(int i 0; i 3; i) { ws2812_write(ws2812_handle , i, ws2812_red, ws2812_green, ws2812_blue ); } name_js name_js-next; } } } cJSON* onenet_property_upload(void) { /* { id: 123, version: 1.0, params: { Brightness: { value:50 }, LightSwitch: { value:true }, RGBColor: { value: { Red: 100, Green: 100, Blue: 100, } } } } */ cJSON* root cJSON_CreateObject(); cJSON_AddStringToObject(root, id, 123); cJSON_AddStringToObject(root, version, 1.0); cJSON* param_js cJSON_AddObjectToObject(root,params);//这是一个嵌套对象所以要接收 //亮度 cJSON* brightness_js cJSON_AddObjectToObject(param_js,Brightness); cJSON_AddBoolToObject(brightness_js, value, led_brightness); //开关 cJSON* lightness_js cJSON_AddObjectToObject(param_js,LightSwitch); cJSON_AddNumberToObject(lightness_js, value, led_statue); //RGB值 cJSON* color_js cJSON_AddObjectToObject(param_js,RGBColor); cJSON* color_value_js cJSON_AddObjectToObject(color_js,value); cJSON_AddNumberToObject(color_value_js, Red, ws2812_red); cJSON_AddNumberToObject(color_value_js, Green, ws2812_green); cJSON_AddNumberToObject(color_value_js, Blue, ws2812_blue); return root; }二、onenet_mqtt.h#ifndef _ONENET_MQTT_H_ #define _ONENET_MQTT_H_ #include esp_err.h //产品ID #define ONENET_PRODUCT_ID yUvsasb4rmci5 //产品密钥 #define ONENET_PRODUCT_ACCESS_KEY IRc3sadasxXd60tg53Nq6O3IYU73/vLvT3Nk3GDq1Op10c\\自己的产品密钥 #define ONENET_DEVICE_NAME esp32led02 esp_err_t onenet_start(void); esp_err_t onenet_post_property_data(const char* data); #endif#include onenet_mqtt.h #include mqtt5_client.h #include esp_log.h #include stdio.h #include stdint.h #include string.h #include onenet_token.h #include cJSON.h #include onenet_dm.h #define TAG onenet #define ONENET_EXPIRE_TIME 1799999999 // 过期时间 static esp_mqtt_client_handle_t client NULL; static void onenet_property_ack(const char* id, int code, char *msg); static void onenet_subscribe(void); static void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data) { ESP_LOGD(TAG, Event dispatched from event loop base%s, event_id% PRIi32 , base, event_id); esp_mqtt_event_handle_t event event_data; esp_mqtt_client_handle_t client event-client; int msg_id; switch ((esp_mqtt_event_id_t)event_id) { case MQTT_EVENT_CONNECTED: ESP_LOGI(TAG, MQTT_EVENT_CONNECTED); onenet_subscribe();//连接成功订阅主题 cJSON* property_js onenet_property_upload();//上报一包所有数据为了数据同步 char* data cJSON_PrintUnformatted(property_js); onenet_post_property_data(data); cJSON_free(data); cJSON_Delete(property_js); break; case MQTT_EVENT_DISCONNECTED: ESP_LOGI(TAG, MQTT_EVENT_DISCONNECTED); break; case MQTT_EVENT_SUBSCRIBED: ESP_LOGI(TAG, MQTT_EVENT_SUBSCRIBED, msg_id%d, event-msg_id); break; case MQTT_EVENT_UNSUBSCRIBED: ESP_LOGI(TAG, MQTT_EVENT_UNSUBSCRIBED, msg_id%d, event-msg_id); break; case MQTT_EVENT_PUBLISHED: ESP_LOGI(TAG, MQTT_EVENT_PUBLISHED, msg_id%d, event-msg_id); break; case MQTT_EVENT_DATA: ESP_LOGI(TAG, MQTT_EVENT_DATA); printf(TOPIC%.*s\r\n, event-topic_len, event-topic); printf(DATA%.*s\r\n, event-data_len, event-data); if(strstr(event-topic,property/set)) { cJSON* property cJSON_Parse(event-data); cJSON* id_js cJSON_GetObjectItem(property,id); onenet_property_handle(property); onenet_property_ack(cJSON_GetStringValue(id_js),200,success); cJSON_Delete(property); } break; case MQTT_EVENT_ERROR: ESP_LOGI(TAG, MQTT_EVENT_ERROR); break; default: ESP_LOGI(TAG, Other event id:%d, event-event_id); break; } } esp_err_t onenet_start(void) { esp_mqtt_client_config_t mqtt_cfg ; memset(mqtt_cfg, 0, sizeof(esp_mqtt_client_config_t)); mqtt_cfg.broker.address.uri mqtt://mqtts.heclouds.com:1883; mqtt_cfg.broker.address.port 1883; mqtt_cfg.credentials.client_id ONENET_DEVICE_NAME; mqtt_cfg.credentials.username ONENET_PRODUCT_ID ; static char token[256]; dev_token_generate(token, SIG_METHOD_SHA256,ONENET_EXPIRE_TIME, ONENET_PRODUCT_ID, ONENET_DEVICE_NAME, ONENET_PRODUCT_ACCESS_KEY); mqtt_cfg.credentials.authentication.password token; client esp_mqtt_client_init(mqtt_cfg); esp_mqtt_client_register_event(client, ESP_EVENT_ANY_ID, mqtt_event_handler, NULL); return esp_mqtt_client_start(client); } // static void onenet_property_ack(const char* id, int code, char *msg) { char topic[128]; snprintf(topic, 128, $sys/%s/%s/thing/property/set_reply,ONENET_PRODUCT_ID, ONENET_DEVICE_NAME); cJSON* reply_js cJSON_CreateObject(); cJSON_AddStringToObject(reply_js,id , id); cJSON_AddNumberToObject(reply_js,code, code); cJSON_AddStringToObject(reply_js,msg , msg); char* data cJSON_PrintUnformatted(reply_js); esp_mqtt_client_publish(client,topic,data,strlen(data), 1, 0); cJSON_free(data); cJSON_Delete(reply_js); } static void onenet_subscribe(void) { char topic[128]; //订阅上报回复主题 snprintf(topic, 128, $sys/%s/%s/thing/property/reply,ONENET_PRODUCT_ID, ONENET_DEVICE_NAME); esp_mqtt_client_subscribe_single(client,topic,1); //下行 snprintf(topic, 128, $sys/%s/%s/thing/property/set,ONENET_PRODUCT_ID, ONENET_DEVICE_NAME); esp_mqtt_client_subscribe_single(client,topic,1); } esp_err_t onenet_post_property_data(const char* data) { char topic[128]; snprintf(topic, 128, $sys/%s/%s/thing/property/post,ONENET_PRODUCT_ID, ONENET_DEVICE_NAME); ESP_LOGI(TAG, upload topic : %s, payload:%s,topic, data); return esp_mqtt_client_publish(client,topic,data,strlen(data), 1, 0); }三、wifi_manager.h#ifndef _WIFI_MANAGER_H_ #define _WIFI_MANAGER_H_ #include esp_err.h #include esp_wifi.h typedef enum { WIFI_STATE_CONNECTED, WIFI_STATE_DISCONNECTED, }WIFI_STATE; //wifi状态变化回调函数 typedef void(*p_wifi_state_callback)(WIFI_STATE state); /** 初始化wifi默认进入STA模式 * param f wifi状态变化回调函数 * return 无 */ void wifi_manager_init(p_wifi_state_callback f); /** 连接wifi * param ssid * param password * return 成功/失败 */ esp_err_t wifi_manager_connect(const char* ssid,const char* password); #endif#include wifi_manager.h #include stdio.h #include esp_log.h #include string.h #include esp_netif.h #include esp_wifi.h #include esp_event.h #define TAG wifi_manager //重连次数 #define MAX_CONNECT_RETRY 6 static int sta_connect_count 0; //回调函数 static p_wifi_state_callback wifi_state_cb NULL; //当前sta连接状态 static bool is_sta_connected false; /** 事件回调函数 * param arg 用户传递的参数 * param event_base 事件类别 * param event_id 事件ID * param event_data 事件携带的数据 * return 无 */ static void event_handler(void* arg, esp_event_base_t event_base,int32_t event_id, void* event_data) { if(event_base WIFI_EVENT) { switch (event_id) { case WIFI_EVENT_STA_START: //WIFI以STA模式启动后触发此事件 { wifi_mode_t mode; esp_wifi_get_mode(mode); if(mode WIFI_MODE_STA) esp_wifi_connect(); //启动WIFI连接 break; } case WIFI_EVENT_STA_CONNECTED: //WIFI连上路由器后触发此事件 ESP_LOGI(TAG, Connected to AP); break; case WIFI_EVENT_STA_DISCONNECTED: //WIFI从路由器断开连接后触发此事件 if(is_sta_connected) { if(wifi_state_cb) wifi_state_cb(WIFI_STATE_DISCONNECTED); is_sta_connected false; } if(sta_connect_count MAX_CONNECT_RETRY) { wifi_mode_t mode; esp_wifi_get_mode(mode); if(mode WIFI_MODE_STA) esp_wifi_connect(); //继续重连 sta_connect_count; } ESP_LOGI(TAG,connect to the AP fail,retry now); break; default: break; } } if(event_base IP_EVENT) //IP相关事件 { switch(event_id) { case IP_EVENT_STA_GOT_IP: //只有获取到路由器分配的IP才认为是连上了路由器 ESP_LOGI(TAG,Get ip address); is_sta_connected true; if(wifi_state_cb) wifi_state_cb(WIFI_STATE_CONNECTED); break; default:break; } } } /** 初始化wifi默认进入STA模式 * param 无 * return 无 */ void wifi_manager_init(p_wifi_state_callback f) { ESP_ERROR_CHECK(esp_netif_init()); //用于初始化tcpip协议栈 ESP_ERROR_CHECK(esp_event_loop_create_default()); //创建一个默认系统事件调度循环之后可以注册回调函数来处理系统的一些事件 esp_netif_create_default_wifi_sta(); //使用默认配置创建STA对象 //初始化WIFI wifi_init_config_t cfg WIFI_INIT_CONFIG_DEFAULT(); ESP_ERROR_CHECK(esp_wifi_init(cfg)); //注册事件 ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT,ESP_EVENT_ANY_ID,event_handler,NULL)); ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT,IP_EVENT_STA_GOT_IP,event_handler,NULL)); wifi_state_cb f; //启动WIFI ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA) ); //设置工作模式为STA ESP_ERROR_CHECK(esp_wifi_start() ); //启动WIFI ESP_LOGI(TAG, wifi_init finished.); } /** 连接wifi * param ssid * param password * return 成功/失败 */ esp_err_t wifi_manager_connect(const char* ssid,const char* password) { sta_connect_count 0; wifi_config_t wifi_config { .sta { .threshold.authmode WIFI_AUTH_WPA2_PSK, //加密方式 }, }; snprintf((char*)wifi_config.sta.ssid,31,%s,ssid); snprintf((char*)wifi_config.sta.password,63,%s,password); ESP_ERROR_CHECK(esp_wifi_disconnect()); wifi_mode_t mode; esp_wifi_get_mode(mode); if(mode ! WIFI_MODE_STA) { ESP_ERROR_CHECK(esp_wifi_stop()); ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA)); ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, wifi_config)); esp_wifi_start(); } else { ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, wifi_config)); esp_wifi_connect(); } return ESP_OK; }四、led_ws2812.h/* * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ #pragma once #include stdint.h #include driver/rmt_encoder.h #ifdef __cplusplus extern C { #endif typedef struct ws2812_strip_t *ws2812_strip_handle_t; /** 初始化WS2812外设 * param gpio 控制WS2812的管脚 * param maxled 控制WS2812的个数 * param led_handle 返回的控制句柄 * return ESP_OK or ESP_FAIL */ esp_err_t ws2812_init(gpio_num_t gpio,int maxled,ws2812_strip_handle_t* led_handle); /** 反初始化WS2812外设 * param handle 初始化的句柄 * return ESP_OK or ESP_FAIL */ esp_err_t ws2812_deinit(ws2812_strip_handle_t handle); /** 向某个WS2812写入RGB数据 * param handle 句柄 * param index 第几个WS28120开始 * param r,g,b RGB数据 * return ESP_OK or ESP_FAIL */ esp_err_t ws2812_write(ws2812_strip_handle_t handle,uint32_t index,uint32_t r,uint32_t g,uint32_t b); /** 设置某个WS2812亮度 * param handle 句柄 * param index 第几个WS28120开始 * param brightness 亮度 (0-100) * return ESP_OK or ESP_FAIL */ esp_err_t ws2812_set_brightness(ws2812_strip_handle_t handle,uint32_t index,uint32_t brightness); /** 获取某个WS2812亮度 * param handle 句柄 * param index 第几个WS28120开始 * return 亮度值 */ uint32_t ws2812_get_brightness(ws2812_strip_handle_t handle,uint32_t index); #ifdef __cplusplus } #endif/* * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ #include esp_check.h #include led_ws2812.h #include driver/rmt_tx.h #include math.h static const char *TAG led_encoder; #define LED_STRIP_RESOLUTION_HZ 10000000 // 10MHz 分辨率, 也就是1tick 0.1us也就是可以控制的最小时间单元低于0.1us的脉冲无法产生 //WS2812驱动的描述符 struct ws2812_strip_t { rmt_channel_handle_t led_chan; //rmt通道 rmt_encoder_handle_t led_encoder; //rmt编码器 uint8_t *led_buffer; //rgb数据 int led_num; //led个数 }; //自定义编码器 typedef struct { rmt_encoder_t base; //编码器里面包含三个需要用户实现的回调函数encode,del,ret rmt_encoder_t *bytes_encoder; //字节编码器调用rmt_new_bytes_encoder函数后创建 rmt_encoder_t *copy_encoder; //拷贝编码器调用rmt_new_copy_encoder函数后创建 int state; //状态控制 rmt_symbol_word_t reset_code; //结束位的时序 } rmt_led_strip_encoder_t; /* 发送WS2812数据的函数调用顺序如下 * 1、调用rmt_transmit需传入RMT通道、发送的数据、编码器参数 * 2、调用编码器的encode函数在本例程中就是调用rmt_encode_led_strip函数 * 3、调用由rmt_new_bytes_encoder创建的字节编码器编码函数bytes_encoder-encode将用户数据编码成rmt_symbol_word_t RMT符号 * 4、调用由rmt_new_copy_encoder创建的拷贝编码器编码函数copy_encoder-encode将复位信号安装既定的电平时间进行编码 * 5、rmt_encode_led_strip函数返回在底层将信号发送出去本质上是操作IO管脚高低电平 */ /** HSV转RGB * param h:色调(0-360) s饱和度(0-100) v亮度(0-100) * param rgb * return 无 */ static void led_strip_hsv2rgb(uint32_t h, uint32_t s, uint32_t v, uint32_t *r, uint32_t *g, uint32_t *b) { h % 360; // h - [0,360] if(v 100) v 100; uint32_t rgb_max v * 2.55f; uint32_t rgb_min rgb_max * (100 - s) / 100.0f; uint32_t i h / 60; uint32_t diff h % 60; // RGB adjustment amount by hue uint32_t rgb_adj (rgb_max - rgb_min) * diff / 60; switch (i) { case 0: *r rgb_max; *g rgb_min rgb_adj; *b rgb_min; break; case 1: *r rgb_max - rgb_adj; *g rgb_max; *b rgb_min; break; case 2: *r rgb_min; *g rgb_max; *b rgb_min rgb_adj; break; case 3: *r rgb_min; *g rgb_max - rgb_adj; *b rgb_max; break; case 4: *r rgb_min rgb_adj; *g rgb_min; *b rgb_max; break; default: *r rgb_max; *g rgb_min; *b rgb_max - rgb_adj; break; } } /** RGB转HSV * param rgb 传入的RGB值 * param hsv 传出的RGB值 * return 无 */ static void led_strip_rgb2hsv(uint32_t r, uint32_t g, uint32_t b, uint32_t *h, uint32_t *s, uint32_t *v) { // 归一化到 [0.0, 1.0] 范围 float rf r / 255.0f; float gf g / 255.0f; float bf b / 255.0f; float max_val fmaxf(rf, fmaxf(gf, bf)); // 最大分量 float min_val fminf(rf, fminf(gf, bf)); // 最小分量 float delta max_val - min_val; // 色差 // 计算 Value (V) - 转换为 [0, 100] *v (int)(max_val * 100.0f 0.5f); // 0.5f 用于四舍五入 // 计算 Saturation (S) - 转换为 [0, 100] if (max_val 0.0f) { *s 0; // V为0时S定义为0黑色 } else { *s (int)((delta / max_val) * 100.0f 0.5f); // 0.5f 用于四舍五入 } // 计算 Hue (H) - 转换为 [0, 360) if (delta 0.0f) { *h 0; // S为0时H无定义通常设为0 } else { if (max_val rf) { // 红色扇区 *h (int)(60.0f * fmodf(((gf - bf) / delta), 6.0f) 0.5f); } else if (max_val gf) { // 绿色扇区 *h (int)(60.0f * (((bf - rf) / delta) 2.0f) 0.5f); } else { // max_val bf // 蓝色扇区 *h (int)(60.0f * (((rf - gf) / delta) 4.0f) 0.5f); } // 确保 h 在 [0, 360) 范围内 if (*h 0) { *h 360; } else if (*h 360) { *h - 360; } } } /** 编码回调函数 * param encoder 编码器 * param channel RMT通道 * param primary_data 待编码用户数据 * param data_size 待编码用户数据长度 * param ret_state 编码状态 * return RMT符号个数 */ static size_t rmt_encode_led_strip(rmt_encoder_t *encoder, rmt_channel_handle_t channel, const void *primary_data, size_t data_size, rmt_encode_state_t *ret_state) { /* __containerof宏的作用: 通过结构的成员来访问这个结构的地址 在这个函数中传入参数encoder是rmt_led_strip_encoder_t结构体中的base成员 __containerof宏通过encoder的地址根据rmt_led_strip_encoder_t的内存排布找到rmt_led_strip_encoder_t* 的首地址 */ rmt_led_strip_encoder_t *led_encoder __containerof(encoder, rmt_led_strip_encoder_t, base); rmt_encoder_handle_t bytes_encoder led_encoder-bytes_encoder; //取出字节编码器 rmt_encoder_handle_t copy_encoder led_encoder-copy_encoder; //取出拷贝编码器 rmt_encode_state_t session_state RMT_ENCODING_RESET; rmt_encode_state_t state RMT_ENCODING_RESET; size_t encoded_symbols 0; switch (led_encoder-state) { //led_encoder-state是自定义的状态这里只有两种值0是发送RGB数据1是发送复位码 case 0: // send RGB data encoded_symbols bytes_encoder-encode(bytes_encoder, channel, primary_data, data_size, session_state); if (session_state RMT_ENCODING_COMPLETE) { //字节编码完成 led_encoder-state 1; // switch to next state when current encoding session finished } if (session_state RMT_ENCODING_MEM_FULL) { //缓存不足本次退出 state | RMT_ENCODING_MEM_FULL; goto out; // yield if theres no free space for encoding artifacts } // fall-through case 1: // send reset code encoded_symbols copy_encoder-encode(copy_encoder, channel, led_encoder-reset_code, sizeof(led_encoder-reset_code), session_state); if (session_state RMT_ENCODING_COMPLETE) { led_encoder-state RMT_ENCODING_RESET; // back to the initial encoding session state | RMT_ENCODING_COMPLETE; } if (session_state RMT_ENCODING_MEM_FULL) { state | RMT_ENCODING_MEM_FULL; goto out; // yield if theres no free space for encoding artifacts } } out: *ret_state state; return encoded_symbols; } static esp_err_t rmt_del_led_strip_encoder(rmt_encoder_t *encoder) { rmt_led_strip_encoder_t *led_encoder __containerof(encoder, rmt_led_strip_encoder_t, base); rmt_del_encoder(led_encoder-bytes_encoder); rmt_del_encoder(led_encoder-copy_encoder); free(led_encoder); return ESP_OK; } static esp_err_t rmt_led_strip_encoder_reset(rmt_encoder_t *encoder) { rmt_led_strip_encoder_t *led_encoder __containerof(encoder, rmt_led_strip_encoder_t, base); rmt_encoder_reset(led_encoder-bytes_encoder); rmt_encoder_reset(led_encoder-copy_encoder); led_encoder-state RMT_ENCODING_RESET; return ESP_OK; } /** 创建一个基于WS2812时序的编码器 * param ret_encoder 返回的编码器这个编码器在使用rmt_transmit函数传输时会用到 * return ESP_OK or ESP_FAIL */ esp_err_t rmt_new_led_strip_encoder(rmt_encoder_handle_t *ret_encoder) { esp_err_t ret ESP_OK; //创建一个自定义的编码器结构体用于控制发送编码的流程 rmt_led_strip_encoder_t *led_encoder NULL; led_encoder calloc(1, sizeof(rmt_led_strip_encoder_t)); ESP_GOTO_ON_FALSE(led_encoder, ESP_ERR_NO_MEM, err, TAG, no mem for led strip encoder); led_encoder-base.encode rmt_encode_led_strip; //这个函数会在rmt发送数据的时候被调用我们可以在这个函数增加额外代码进行控制 led_encoder-base.del rmt_del_led_strip_encoder; //这个函数在卸载rmt时被调用 led_encoder-base.reset rmt_led_strip_encoder_reset; //这个函数在复位rmt时被调用 //新建一个编码器配置(0,1位持续时间参考芯片手册) rmt_bytes_encoder_config_t bytes_encoder_config { .bit0 { .level0 1, .duration0 0.3 * LED_STRIP_RESOLUTION_HZ / 1000000, // T0H0.3us .level1 0, .duration1 0.9 * LED_STRIP_RESOLUTION_HZ / 1000000, // T0L0.9us }, .bit1 { .level0 1, .duration0 0.9 * LED_STRIP_RESOLUTION_HZ / 1000000, // T1H0.9us .level1 0, .duration1 0.3 * LED_STRIP_RESOLUTION_HZ / 1000000, // T1L0.3us }, .flags.msb_first 1 //高位先传输 }; //传入编码器配置获得数据编码器操作句柄 rmt_new_bytes_encoder(bytes_encoder_config, led_encoder-bytes_encoder); //新建一个拷贝编码器配置拷贝编码器一般用于传输恒定的字符数据比如说结束位 rmt_copy_encoder_config_t copy_encoder_config {}; rmt_new_copy_encoder(copy_encoder_config, led_encoder-copy_encoder); //设定结束位时序 uint32_t reset_ticks LED_STRIP_RESOLUTION_HZ / 1000000 * 50 / 2; //分辨率/1M每个ticks所需的us然后乘以50就得出50us所需的ticks led_encoder-reset_code (rmt_symbol_word_t) { .level0 0, .duration0 reset_ticks, .level1 0, .duration1 reset_ticks, }; //返回编码器 *ret_encoder led_encoder-base; return ESP_OK; err: if (led_encoder) { if (led_encoder-bytes_encoder) { rmt_del_encoder(led_encoder-bytes_encoder); } if (led_encoder-copy_encoder) { rmt_del_encoder(led_encoder-copy_encoder); } free(led_encoder); } return ret; } /** 初始化WS2812外设 * param gpio 控制WS2812的管脚 * param maxled 控制WS2812的个数 * param led_handle 返回的控制句柄 * return ESP_OK or ESP_FAIL */ esp_err_t ws2812_init(gpio_num_t gpio,int maxled,ws2812_strip_handle_t* handle) { struct ws2812_strip_t* led_handle NULL; //新增一个WS2812驱动描述 led_handle calloc(1, sizeof(struct ws2812_strip_t)); assert(led_handle); //按照led个数来分配RGB缓存数据 led_handle-led_buffer calloc(1,maxled*3); assert(led_handle-led_buffer); //设置LED个数 led_handle-led_num maxled; //定义一个RMT发送通道配置 rmt_tx_channel_config_t tx_chan_config { .clk_src RMT_CLK_SRC_DEFAULT, //默认时钟源 .gpio_num gpio, //GPIO管脚 .mem_block_symbols 64, //内存块大小即 64 * 4 256 字节 .resolution_hz LED_STRIP_RESOLUTION_HZ, //RMT通道的分辨率10000000hz0.1us也就是可以控制的最小时间单元 .trans_queue_depth 4, //底层后台发送的队列深度 }; //创建一个RMT发送通道 ESP_ERROR_CHECK(rmt_new_tx_channel(tx_chan_config, led_handle-led_chan)); //创建自定义编码器重点函数所谓编码就是发射红外时加入我们的时序控制 ESP_ERROR_CHECK(rmt_new_led_strip_encoder(led_handle-led_encoder)); //使能RMT通道 ESP_ERROR_CHECK(rmt_enable(led_handle-led_chan)); //返回WS2812操作句柄 *handle led_handle; return ESP_OK; } /** 反初始化WS2812外设 * param handle 初始化的句柄 * return ESP_OK or ESP_FAIL */ esp_err_t ws2812_deinit(ws2812_strip_handle_t handle) { if(!handle) return ESP_OK; rmt_del_encoder(handle-led_encoder); if(handle-led_buffer) free(handle-led_buffer); free(handle); return ESP_OK; } /** 向某个WS2812写入RGB数据 * param handle 句柄 * param index 第几个WS28120开始 * param r,g,b RGB数据 * return ESP_OK or ESP_FAIL */ esp_err_t ws2812_write(ws2812_strip_handle_t handle,uint32_t index,uint32_t r,uint32_t g,uint32_t b) { rmt_transmit_config_t tx_config { .loop_count 0, //不循环发送 }; if(index handle-led_num) return ESP_FAIL; uint32_t start index*3; handle-led_buffer[start0] g 0xff; //注意WS2812的数据顺序时GRB handle-led_buffer[start1] r 0xff; handle-led_buffer[start2] b 0xff; return rmt_transmit(handle-led_chan, handle-led_encoder, handle-led_buffer, handle-led_num*3, tx_config); } /** 设置某个WS2812亮度 * param handle 句柄 * param index 第几个WS28120开始 * param brightness 亮度 (0-100) * return ESP_OK or ESP_FAIL */ esp_err_t ws2812_set_brightness(ws2812_strip_handle_t handle,uint32_t index,uint32_t brightness) { if(index handle-led_num) return ESP_FAIL; uint32_t start index*3; uint32_t h,s,v; uint32_t r,g,b; //注意WS2812的数据顺序时GRB r handle-led_buffer[start1] ; g handle-led_buffer[start0]; b handle-led_buffer[start2]; led_strip_rgb2hsv(r,g,b,h,s,v); v brightness; led_strip_hsv2rgb(h,s,v,r,g,b); return ws2812_write(handle,index,r,g,b); } /** 获取某个WS2812亮度 * param handle 句柄 * param index 第几个WS28120开始 * return 亮度值 */ uint32_t ws2812_get_brightness(ws2812_strip_handle_t handle,uint32_t index) { if(index handle-led_num) return 0; uint32_t start index*3; uint32_t h,s,v; uint32_t r,g,b; r handle-led_buffer[start1] ; g handle-led_buffer[start0]; b handle-led_buffer[start2]; led_strip_rgb2hsv(r,g,b,h,s,v); return v; }

更多文章