mirror of
https://gitee.com/beecue/fastbee.git
synced 2025-12-20 01:45:55 +08:00
添加智能灯固件代码
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
# The following lines of boilerplate have to be in your project's CMakeLists
|
||||
# in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(led_strip)
|
||||
@@ -0,0 +1,8 @@
|
||||
#
|
||||
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
|
||||
# project subdirectory.
|
||||
#
|
||||
|
||||
PROJECT_NAME := led_strip
|
||||
|
||||
include $(IDF_PATH)/make/project.mk
|
||||
@@ -0,0 +1,52 @@
|
||||
# RMT Transmit Example -- LED Strip
|
||||
|
||||
(See the README.md file in the upper level 'examples' directory for more information about examples.)
|
||||
|
||||
Although RMT peripheral is mainly designed for infrared remote applications, it can also support other generic protocols thanks to its flexible data format. [WS2812](http://www.world-semi.com/Certifications/WS2812B.html) is a digital RGB LED which integrates a driver circuit and a single control wire. The protocol data format defined in WS2812 is compatible to that in RMT peripheral. This example will illustrate how to drive an WS2812 LED strip based on the RMT driver.
|
||||
|
||||
## How to Use Example
|
||||
|
||||
### Hardware Required
|
||||
|
||||
* A development board with ESP32 SoC (e.g., ESP32-DevKitC, ESP-WROVER-KIT, etc.)
|
||||
* A USB cable for Power supply and programming
|
||||
* A WS2812 LED strip
|
||||
|
||||
Connection :
|
||||
|
||||
```
|
||||
--- 5V
|
||||
|
|
||||
+
|
||||
GPIO18 +-----------------+---|>| (WS2812)
|
||||
DI +
|
||||
|
|
||||
--- GND
|
||||
```
|
||||
|
||||
### Configure the Project
|
||||
|
||||
Open the project configuration menu (`idf.py menuconfig`).
|
||||
|
||||
In the `Example Connection Configuration` menu:
|
||||
|
||||
* Set the GPIO number used for transmitting the IR signal under `RMT TX GPIO` optin.
|
||||
* Set the number of LEDs in a strip under `Number of LEDS in a strip` option.
|
||||
|
||||
### Build and Flash
|
||||
|
||||
Run `idf.py -p PORT flash monitor` to build, flash and monitor the project.
|
||||
|
||||
(To exit the serial monitor, type ``Ctrl-]``.)
|
||||
|
||||
See the [Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/index.html) for full steps to configure and use ESP-IDF to build projects.
|
||||
|
||||
## Example Output
|
||||
|
||||
Connect the `DI` signal of WS2812 LED strip to the GPIO you set in menuconfig.
|
||||
|
||||
Run the example, you will see a rainbow chasing demonstration effect. To change the chasing speed, you can update the `EXAMPLE_CHASE_SPEED_MS` value in `led_strip_main.c` file.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
For any technical queries, please open an [issue] (https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you soon.
|
||||
@@ -0,0 +1,8 @@
|
||||
set(component_srcs "src/led_strip_rmt_ws2812.c")
|
||||
|
||||
idf_component_register(SRCS "${component_srcs}"
|
||||
INCLUDE_DIRS "include"
|
||||
PRIV_INCLUDE_DIRS ""
|
||||
PRIV_REQUIRES "driver"
|
||||
REQUIRES "")
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
COMPONENT_ADD_INCLUDEDIRS := include
|
||||
|
||||
COMPONENT_SRCDIRS := src
|
||||
@@ -0,0 +1,126 @@
|
||||
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "esp_err.h"
|
||||
|
||||
/**
|
||||
* @brief LED Strip Type
|
||||
*
|
||||
*/
|
||||
typedef struct led_strip_s led_strip_t;
|
||||
|
||||
/**
|
||||
* @brief LED Strip Device Type
|
||||
*
|
||||
*/
|
||||
typedef void *led_strip_dev_t;
|
||||
|
||||
/**
|
||||
* @brief Declare of LED Strip Type
|
||||
*
|
||||
*/
|
||||
struct led_strip_s {
|
||||
/**
|
||||
* @brief Set RGB for a specific pixel
|
||||
*
|
||||
* @param strip: LED strip
|
||||
* @param index: index of pixel to set
|
||||
* @param red: red part of color
|
||||
* @param green: green part of color
|
||||
* @param blue: blue part of color
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: Set RGB for a specific pixel successfully
|
||||
* - ESP_ERR_INVALID_ARG: Set RGB for a specific pixel failed because of invalid parameters
|
||||
* - ESP_FAIL: Set RGB for a specific pixel failed because other error occurred
|
||||
*/
|
||||
esp_err_t (*set_pixel)(led_strip_t *strip, uint32_t index, uint32_t red, uint32_t green, uint32_t blue);
|
||||
|
||||
/**
|
||||
* @brief Refresh memory colors to LEDs
|
||||
*
|
||||
* @param strip: LED strip
|
||||
* @param timeout_ms: timeout value for refreshing task
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: Refresh successfully
|
||||
* - ESP_ERR_TIMEOUT: Refresh failed because of timeout
|
||||
* - ESP_FAIL: Refresh failed because some other error occurred
|
||||
*
|
||||
* @note:
|
||||
* After updating the LED colors in the memory, a following invocation of this API is needed to flush colors to strip.
|
||||
*/
|
||||
esp_err_t (*refresh)(led_strip_t *strip, uint32_t timeout_ms);
|
||||
|
||||
/**
|
||||
* @brief Clear LED strip (turn off all LEDs)
|
||||
*
|
||||
* @param strip: LED strip
|
||||
* @param timeout_ms: timeout value for clearing task
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: Clear LEDs successfully
|
||||
* - ESP_ERR_TIMEOUT: Clear LEDs failed because of timeout
|
||||
* - ESP_FAIL: Clear LEDs failed because some other error occurred
|
||||
*/
|
||||
esp_err_t (*clear)(led_strip_t *strip, uint32_t timeout_ms);
|
||||
|
||||
/**
|
||||
* @brief Free LED strip resources
|
||||
*
|
||||
* @param strip: LED strip
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: Free resources successfully
|
||||
* - ESP_FAIL: Free resources failed because error occurred
|
||||
*/
|
||||
esp_err_t (*del)(led_strip_t *strip);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief LED Strip Configuration Type
|
||||
*
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t max_leds; /*!< Maximum LEDs in a single strip */
|
||||
led_strip_dev_t dev; /*!< LED strip device (e.g. RMT channel, PWM channel, etc) */
|
||||
} led_strip_config_t;
|
||||
|
||||
/**
|
||||
* @brief Default configuration for LED strip
|
||||
*
|
||||
*/
|
||||
#define LED_STRIP_DEFAULT_CONFIG(number, dev_hdl) \
|
||||
{ \
|
||||
.max_leds = number, \
|
||||
.dev = dev_hdl, \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Install a new ws2812 driver (based on RMT peripheral)
|
||||
*
|
||||
* @param config: LED strip configuration
|
||||
* @return
|
||||
* LED strip instance or NULL
|
||||
*/
|
||||
led_strip_t *led_strip_new_rmt_ws2812(const led_strip_config_t *config);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,171 @@
|
||||
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/cdefs.h>
|
||||
#include "esp_log.h"
|
||||
#include "esp_attr.h"
|
||||
#include "led_strip.h"
|
||||
#include "driver/rmt.h"
|
||||
|
||||
static const char *TAG = "ws2812";
|
||||
#define STRIP_CHECK(a, str, goto_tag, ret_value, ...) \
|
||||
do \
|
||||
{ \
|
||||
if (!(a)) \
|
||||
{ \
|
||||
ESP_LOGE(TAG, "%s(%d): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
|
||||
ret = ret_value; \
|
||||
goto goto_tag; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define WS2812_T0H_NS (300)
|
||||
#define WS2812_T0L_NS (1090)
|
||||
#define WS2812_T1H_NS (1090)
|
||||
#define WS2812_T1L_NS (320)
|
||||
#define WS2812_RESET_US (400)
|
||||
|
||||
static uint32_t ws2812_t0h_ticks = 0;
|
||||
static uint32_t ws2812_t1h_ticks = 0;
|
||||
static uint32_t ws2812_t0l_ticks = 0;
|
||||
static uint32_t ws2812_t1l_ticks = 0;
|
||||
|
||||
typedef struct {
|
||||
led_strip_t parent;
|
||||
rmt_channel_t rmt_channel;
|
||||
uint32_t strip_len;
|
||||
uint8_t buffer[0];
|
||||
} ws2812_t;
|
||||
|
||||
/**
|
||||
* @brief Conver RGB data to RMT format.
|
||||
*
|
||||
* @note For WS2812, R,G,B each contains 256 different choices (i.e. uint8_t)
|
||||
*
|
||||
* @param[in] src: source data, to converted to RMT format
|
||||
* @param[in] dest: place where to store the convert result
|
||||
* @param[in] src_size: size of source data
|
||||
* @param[in] wanted_num: number of RMT items that want to get
|
||||
* @param[out] translated_size: number of source data that got converted
|
||||
* @param[out] item_num: number of RMT items which are converted from source data
|
||||
*/
|
||||
static void IRAM_ATTR ws2812_rmt_adapter(const void *src, rmt_item32_t *dest, size_t src_size,
|
||||
size_t wanted_num, size_t *translated_size, size_t *item_num)
|
||||
{
|
||||
if (src == NULL || dest == NULL) {
|
||||
*translated_size = 0;
|
||||
*item_num = 0;
|
||||
return;
|
||||
}
|
||||
const rmt_item32_t bit0 = {{{ ws2812_t0h_ticks, 1, ws2812_t0l_ticks, 0 }}}; //Logical 0
|
||||
const rmt_item32_t bit1 = {{{ ws2812_t1h_ticks, 1, ws2812_t1l_ticks, 0 }}}; //Logical 1
|
||||
size_t size = 0;
|
||||
size_t num = 0;
|
||||
uint8_t *psrc = (uint8_t *)src;
|
||||
rmt_item32_t *pdest = dest;
|
||||
while (size < src_size && num < wanted_num) {
|
||||
for (int i = 0; i < 8; i++) {
|
||||
// MSB first
|
||||
if (*psrc & (1 << (7 - i))) {
|
||||
pdest->val = bit1.val;
|
||||
} else {
|
||||
pdest->val = bit0.val;
|
||||
}
|
||||
num++;
|
||||
pdest++;
|
||||
}
|
||||
size++;
|
||||
psrc++;
|
||||
}
|
||||
*translated_size = size;
|
||||
*item_num = num;
|
||||
}
|
||||
|
||||
static esp_err_t ws2812_set_pixel(led_strip_t *strip, uint32_t index, uint32_t red, uint32_t green, uint32_t blue)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
ws2812_t *ws2812 = __containerof(strip, ws2812_t, parent);
|
||||
STRIP_CHECK(index < ws2812->strip_len, "index out of the maximum number of leds", err, ESP_ERR_INVALID_ARG);
|
||||
uint32_t start = index * 3;
|
||||
// In thr order of GRB
|
||||
ws2812->buffer[start + 0] = green & 0xFF;
|
||||
ws2812->buffer[start + 1] = red & 0xFF;
|
||||
ws2812->buffer[start + 2] = blue & 0xFF;
|
||||
return ESP_OK;
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static esp_err_t ws2812_refresh(led_strip_t *strip, uint32_t timeout_ms)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
ws2812_t *ws2812 = __containerof(strip, ws2812_t, parent);
|
||||
STRIP_CHECK(rmt_write_sample(ws2812->rmt_channel, ws2812->buffer, ws2812->strip_len * 3, true) == ESP_OK,
|
||||
"transmit RMT samples failed", err, ESP_FAIL);
|
||||
return rmt_wait_tx_done(ws2812->rmt_channel, pdMS_TO_TICKS(timeout_ms));
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static esp_err_t ws2812_clear(led_strip_t *strip, uint32_t timeout_ms)
|
||||
{
|
||||
ws2812_t *ws2812 = __containerof(strip, ws2812_t, parent);
|
||||
// Write zero to turn off all leds
|
||||
memset(ws2812->buffer, 0, ws2812->strip_len * 3);
|
||||
return ws2812_refresh(strip, timeout_ms);
|
||||
}
|
||||
|
||||
static esp_err_t ws2812_del(led_strip_t *strip)
|
||||
{
|
||||
ws2812_t *ws2812 = __containerof(strip, ws2812_t, parent);
|
||||
free(ws2812);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
led_strip_t *led_strip_new_rmt_ws2812(const led_strip_config_t *config)
|
||||
{
|
||||
led_strip_t *ret = NULL;
|
||||
STRIP_CHECK(config, "configuration can't be null", err, NULL);
|
||||
|
||||
// 24 bits per led
|
||||
uint32_t ws2812_size = sizeof(ws2812_t) + config->max_leds * 3;
|
||||
ws2812_t *ws2812 = calloc(1, ws2812_size);
|
||||
STRIP_CHECK(ws2812, "request memory for ws2812 failed", err, NULL);
|
||||
|
||||
uint32_t counter_clk_hz = 0;
|
||||
STRIP_CHECK(rmt_get_counter_clock((rmt_channel_t)config->dev, &counter_clk_hz) == ESP_OK,
|
||||
"get rmt counter clock failed", err, NULL);
|
||||
// ns -> ticks
|
||||
float ratio = (float)counter_clk_hz / 1e9;
|
||||
ws2812_t0h_ticks = (uint32_t)(ratio * WS2812_T0H_NS);
|
||||
ws2812_t0l_ticks = (uint32_t)(ratio * WS2812_T0L_NS);
|
||||
ws2812_t1h_ticks = (uint32_t)(ratio * WS2812_T1H_NS);
|
||||
ws2812_t1l_ticks = (uint32_t)(ratio * WS2812_T1L_NS);
|
||||
|
||||
// set ws2812 to rmt adapter
|
||||
rmt_translator_init((rmt_channel_t)config->dev, ws2812_rmt_adapter);
|
||||
|
||||
ws2812->rmt_channel = (rmt_channel_t)config->dev;
|
||||
ws2812->strip_len = config->max_leds;
|
||||
|
||||
ws2812->parent.set_pixel = ws2812_set_pixel;
|
||||
ws2812->parent.refresh = ws2812_refresh;
|
||||
ws2812->parent.clear = ws2812_clear;
|
||||
ws2812->parent.del = ws2812_del;
|
||||
|
||||
return &ws2812->parent;
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
idf_component_register(SRCS "led_strip_main.c"
|
||||
INCLUDE_DIRS ".")
|
||||
@@ -0,0 +1,13 @@
|
||||
menu "Example Configuration"
|
||||
config EXAMPLE_RMT_TX_GPIO
|
||||
int "RMT TX GPIO"
|
||||
default 18
|
||||
help
|
||||
Set the GPIO number used for transmitting the RMT signal.
|
||||
|
||||
config EXAMPLE_STRIP_LED_NUMBER
|
||||
int "Number of LEDS in a strip"
|
||||
default 24
|
||||
help
|
||||
A single RGB strip contains several LEDs.
|
||||
endmenu
|
||||
@@ -0,0 +1,4 @@
|
||||
#
|
||||
# Main Makefile. This is basically the same as a component makefile.
|
||||
#
|
||||
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
|
||||
@@ -0,0 +1,116 @@
|
||||
/* RMT example -- RGB LED Strip
|
||||
|
||||
This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||
|
||||
Unless required by applicable law or agreed to in writing, this
|
||||
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied.
|
||||
*/
|
||||
#include "sdkconfig.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_log.h"
|
||||
#include "driver/rmt.h"
|
||||
#include "led_strip.h"
|
||||
|
||||
static const char *TAG = "example";
|
||||
|
||||
#define RMT_TX_CHANNEL RMT_CHANNEL_0
|
||||
|
||||
#define EXAMPLE_CHASE_SPEED_MS (10)
|
||||
|
||||
/**
|
||||
* @brief Simple helper function, converting HSV color space to RGB color space
|
||||
*
|
||||
* Wiki: https://en.wikipedia.org/wiki/HSL_and_HSV
|
||||
*
|
||||
*/
|
||||
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]
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
uint32_t red = 0;
|
||||
uint32_t green = 0;
|
||||
uint32_t blue = 0;
|
||||
uint16_t hue = 0;
|
||||
uint16_t start_rgb = 0;
|
||||
|
||||
rmt_config_t config = RMT_DEFAULT_CONFIG_TX(CONFIG_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(CONFIG_EXAMPLE_STRIP_LED_NUMBER, (led_strip_dev_t)config.channel);
|
||||
led_strip_t *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");
|
||||
while (true) {
|
||||
for (int i = 0; i < 3; i++) {
|
||||
for (int j = i; j < CONFIG_EXAMPLE_STRIP_LED_NUMBER; j += 3) {
|
||||
// Build RGB values
|
||||
hue = j * 360 / CONFIG_EXAMPLE_STRIP_LED_NUMBER + start_rgb;
|
||||
led_strip_hsv2rgb(hue, 100, 100, &red, &green, &blue);
|
||||
// Write RGB values to strip driver
|
||||
ESP_ERROR_CHECK(strip->set_pixel(strip, j, red, green, blue));
|
||||
}
|
||||
// Flush RGB values to LEDs
|
||||
ESP_ERROR_CHECK(strip->refresh(strip, 100));
|
||||
vTaskDelay(pdMS_TO_TICKS(EXAMPLE_CHASE_SPEED_MS));
|
||||
strip->clear(strip, 50);
|
||||
vTaskDelay(pdMS_TO_TICKS(EXAMPLE_CHASE_SPEED_MS));
|
||||
}
|
||||
start_rgb += 60;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user