WS2812驱动
这里只是把数据手册中使用到的重要部分摘取出来,完整版请看ws2812,这只是这个项目中的一个驱动代码,后续继续更新项目代码。项目实现功能请先看,智能门锁专栏 / 智能门锁功能实现这篇文章,里面介绍了实现的功能,后续将更新详细项目介绍
一. 简介
-
每个像素点的三基色颜色可实现256级亮度显示,完成16777216种颜色的全真色彩显示。
-
串行级联接口,能通过一根信号线完成数据的接收与解码。
-
数据协议采用单线归零码的通讯方式,像素点在上电复位以后,DIN端接受从控制器传输过来的数据,首先
送过来的24bit数据被第一个像素点提取后,送到像素点内部的数据锁存器,剩余的数据经过内部整形处理电路整
形放大后通过DO端口开始转发输出给下一个级联的像素点,每经过一个像素点的传输,信号减少24bit;像素点
采用自动整形转发技术,使得该像素点的级联个数不受信号传送的限制,仅受限信号传输速度要求;
-
引脚说明
序号 符号 管脚名 功能描述 1 DO 数据输出 控制数据信号输出 2 GND 地 信号接地和电源接地 3 DI 数据输入 控制数据信号输入 4 VDD 电源 供电管脚
二. 关键参数
-
时序格式
时序表名称
Timeline name最小值
Min.典型值
Typical value最大值
Max.单位
UnitT/码元周期 0.89 --- --- μs TOH/0码, 高电平时间 0.2 0.295 0.35 μs TOL/0码, 低电平时间 0.55 0.595 1.2 μs T1H/1码, 高电平时间 0.55 0.595 1.2 μs T1L/1码, 低电平时间 0.2 0.295 0.35 μs TRST/Reset码, 低电平时间 80 --- --- μs 注意 1. 写程序时,码元周期最低要求为 0.9us;
2. 0 码、1 码的高电平时间需按照上表的规定范围,0 码、1 码的低电平时间要求小于 15us;
-
时序波形图

-
数据传输方式

- esp32可以使用RMT或SPI控制时序波形。后面使用RMT控制
三. 代码
这里用两种方法实现了WS2812的时序,一种是用官方组件库,另一种是调用库函数实现。因为正好也是学习一下esp32,所以就把两种方法都写了一下。官方组件库其实也是调用的库函数,只是把它又封装一层,省去自己写驱动的过程,直接使用封装好的函数即可。
组件库地址espressif/led_strip • v3.0.1~1 • ESP Component Registry

把这段代码复制到vscode的esp-idf插件的终端,回车,就会自动下载组件。

硬件抽象层
HAL_rmt.c
#include "HAL_rmt.h"
#if LED_STRIP_INIT
/* 全部led灯带句柄 */
static led_strip_handle_t g_xled_strip_handler;
/**
* @brief 初始化rmt
*
* @param 无
*
* @return 无
*/
void rmt_Init(void)
{
/* 配置WS2812灯带 */
led_strip_config_t led_strip_config =
{
.color_component_format = LED_STRIP_COLOR_COMPONENT_FMT_GRB,/* 颜色格式RGB */
.flags.invert_out = false, /* 输出不反转 */
.led_model = LED_MODEL_WS2812, /* 灯的类型WS2812 */
.max_leds = RMT_LED_NUM, /* 最大灯珠数量12 */
.strip_gpio_num = RMT_DATA_GPIO, /* gpio引脚 */
};
/* 配置 rmt 通道 */
led_strip_rmt_config_t led_strip_rmt_config =
{
.clk_src = RMT_CLK_SRC_DEFAULT, /* 默认时钟源APB */
.flags.with_dma = false, /* 不使用DMA */
.mem_block_symbols = 64, /* 最大RMT符号数 */
.resolution_hz = RMT_TX_CHANNEL_RESOLUTION, /* 分辨率10MHz */
};
led_strip_new_rmt_device(&led_strip_config,
&led_strip_rmt_config,
&g_xled_strip_handler); /* 初始化rmt通道 */
}
/**
* @brief rmt 发送数据
*
* @param rmt_tx_buff: 发送缓冲区
* @param rmt_tx_buff_len: 发送缓冲区大小
*
* @return 无
*/
void rmt_send_data(uint8_t *rmt_tx_buff,uint8_t rmt_tx_buff_len)
{
uint8_t i = 0;
for(i = 0; i < rmt_tx_buff_len / 3; i++)
{
/* 设置灯带颜色 */
led_strip_set_pixel(g_xled_strip_handler,
i,
rmt_tx_buff[i * 3],
rmt_tx_buff[i * 3 + 1],
rmt_tx_buff[i * 3 + 2]);
}
/* 刷新缓存 */
led_strip_refresh(g_xled_strip_handler);
}
#elif RMT_INIT
/* RMT 通道句柄 */
static rmt_channel_handle_t g_xrmt_channel_handler;
/* RMT 编码器句柄*/
static rmt_encoder_handle_t g_xrmt_encoder_handler;
/**
* @brief 初始化rmt
*
* @param 无
*
* @return 无
*/
void rmt_Init(void)
{
/* 创建RMT通道 */
rmt_tx_channel_config_t rmt_tx_channel_config =
{
.clk_src = RMT_CLK_SRC_DEFAULT, /* 使用默认时钟源 */
.gpio_num = RMT_DATA_GPIO, /* GPIO引脚 */
.mem_block_symbols = 64, /* RMT符号最大数量 */
.resolution_hz = RMT_TX_CHANNEL_RESOLUTION, /* 分辨率10MHz */
.trans_queue_depth = 6, /* 队列深度 */
};
rmt_new_tx_channel(&rmt_tx_channel_config,
&g_xrmt_channel_handler);
/* 创建 rmt字节编码器 */
rmt_bytes_encoder_config_t rmt_byter_encoder_config =
{
.bit0 = /* 发送 0 */
{
.level0 = 1, /* 首先高电平 */
.duration0 = 0.3 * RMT_TX_CHANNEL_RESOLUTION / 1000000, /* 时间 0.3us */
.level1 = 0, /* 再低电平 */
.duration1 = 0.9 * RMT_TX_CHANNEL_RESOLUTION / 1000000, /* 时间 0.9us */
},
.bit1 =
{
.level0 = 1, /* 首先高电平 */
.duration0 = 0.9 * RMT_TX_CHANNEL_RESOLUTION / 1000000, /* 时间 0.9us */
.level1 = 0, /* 再低电平 */
.duration1 = 0.3 * RMT_TX_CHANNEL_RESOLUTION / 1000000, /* 时间 0.3us */
},
.flags.msb_first = 1, /* 高位先行 */
};
rmt_new_bytes_encoder(&rmt_byter_encoder_config,
&g_xrmt_encoder_handler);
/* 使能RMT */
rmt_enable(g_xrmt_channel_handler);
}
/**
* @brief rmt 发送数据
*
* @param rmt_tx_buff: 发送缓冲区
* @param rmt_tx_buff_len: 发送缓冲区大小
*
* @return 无
*/
void rmt_send_data(uint8_t *rmt_tx_buff,uint8_t rmt_tx_buff_len)
{
rmt_transmit_config_t rmt_transmit_config =
{
.loop_count = false, /* 不使用循环发送 */
.flags =
{
.eot_level = 0, /* 结束低电平 */
.queue_nonblocking = 1, /* 队列满返回不阻塞 */
}
};
rmt_transmit(g_xrmt_channel_handler,
g_xrmt_encoder_handler,
rmt_tx_buff,
rmt_tx_buff_len,
&rmt_transmit_config); /* 发送数据 */
rmt_tx_wait_all_done(g_xrmt_channel_handler,
portMAX_DELAY); /* 等待发送完成 */
}
#endif
HAL_rmt.h
#ifndef HAL_RMT_H
#define HAL_RMT_H
#define RMT_INIT 0
#define LED_STRIP_INIT 1
#include <stdio.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "driver/gpio.h"
#if LED_STRIP_INIT
#include "../../managed_components/espressif__led_strip/include/led_strip.h"
#elif RMT_INIT
#include "driver/rmt_tx.h"
#include "driver/rmt_encoder.h"
#include "esp_err.h"
#endif
#define RMT_TX_CHANNEL_RESOLUTION 10000000 /* 发送通道分辨率 10Mhz 0.1us */
/* rmt GPIO 引脚 */
#define RMT_DATA_GPIO GPIO_NUM_6
/* 灯珠数量 */
#define RMT_LED_NUM 12
/**
* @brief 初始化rmt
*
* @param 无
*
* @return 无
*/
void rmt_Init(void);
/**
* @brief rmt 发送数据
*
* @param rmt_tx_buff: 发送缓冲区
* @param rmt_tx_buff_len: 发送缓冲区大小
*
* @return 无
*/
void rmt_send_data(uint8_t *rmt_tx_buff,uint8_t rmt_tx_buff_len);
#endif
驱动层
Dri_WS2812.c
#include "Dri_WS2812.h"
/* led灯颜色 */
uint8_t color_red[3] = {255, 0 , 0 };
uint8_t color_green[3] = {0 , 255, 0 };
uint8_t color_bule[3] = {0 , 0 , 255};
uint8_t color_white[3] = {255, 255, 255};
uint8_t color_black[3] = {0 , 0 , 0 };
/* RMT 发送缓冲区 */
static uint8_t g_rmt_tx_buff[36];
/**
* @brief 初始化WS2812
*
* @param 无
*
* @return 无
*/
void WS2812_Init(void)
{
WS2812_set_led_strip_allcolor(color_black);
}
/**
* @brief 设置WS2812灯带颜色
*
* @param led_num: 灯珠号
* @param color_data: 颜色
*
* @return 无
*/
void WS2812_set_led_strip_color(uint8_t led_num, uint8_t color_data[])
{
memset(&g_rmt_tx_buff[led_num * 3], 0, 3); /* 清空对应数组数据 */
memcpy(&g_rmt_tx_buff[led_num * 3], color_data, 3); /* 设置灯珠颜色 */
/* rmt 发送数据 */
rmt_send_data(g_rmt_tx_buff,sizeof(g_rmt_tx_buff));
}
/**
* @brief 设置WS2812灯带全部颜色
*
* @param color_data: 颜色
*
* @return 无
*/
void WS2812_set_led_strip_allcolor(uint8_t color_data[])
{
uint8_t i = 0;
memset(g_rmt_tx_buff,0,sizeof(g_rmt_tx_buff)); /* 清空数组 */
for(i = 0; i < WS2812_LED_NUM; i++)
{
memcpy(&g_rmt_tx_buff[i * 3], color_data, 3); /* 设置灯珠颜色 */
}
/* rmt 发送数据 */
rmt_send_data(g_rmt_tx_buff,sizeof(g_rmt_tx_buff));
}
Dri_WS2812.h
#ifndef HAL_WS2812_H
#define HAL_WS2812_H
#include <stdio.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "HAL_rmt.h"
#include "Dri_SC12B.h"
/* 灯珠数量 */
#define WS2812_LED_NUM 12
/* led灯颜色 */
extern uint8_t color_red[3];
extern uint8_t color_green[3];
extern uint8_t color_bule[3];
extern uint8_t color_white[3];
extern uint8_t color_black[3];
/**
* @brief 初始化WS2812
*
* @param 无
*
* @return 无
*/
void WS2812_Init(void);
/**
* @brief 设置WS2812灯带颜色
*
* @param led_num: 灯珠号
* @param color_data: 颜色
*
* @return 无
*/
void WS2812_set_led_strip_color(uint8_t led_num,uint8_t color_data[]);
/**
* @brief 设置WS2812灯带全部颜色
*
* @param color_data: 颜色
*
* @return 无
*/
void WS2812_set_led_strip_allcolor(uint8_t color_data[]);
#endif

浙公网安备 33010602011771号