普冉PY32系列(十三) SPI驱动WS2812全彩LED
目录
- 普冉PY32系列(一) PY32F0系列32位Cortex M0+ MCU简介
- 普冉PY32系列(二) Ubuntu GCC Toolchain和VSCode开发环境
- 普冉PY32系列(三) PY32F002A资源实测 - 这个型号不简单
- 普冉PY32系列(四) PY32F002A/003/030的时钟设置
- 普冉PY32系列(五) 使用JLink RTT代替串口输出日志
- 普冉PY32系列(六) 通过I2C接口驱动PCF8574扩展的1602LCD
- 普冉PY32系列(七) SOP8,SOP10,SOP16封装的PY32F002A/PY32F003管脚复用
- 普冉PY32系列(八) GPIO模拟和硬件SPI方式驱动无线收发芯片XN297LBW
- 普冉PY32系列(九) GPIO模拟和硬件SPI方式驱动无线收发芯片XL2400
- 普冉PY32系列(十) 基于PY32F002A的6+1通道遥控小车I - 综述篇
- 普冉PY32系列(十一) 基于PY32F002A的6+1通道遥控小车II - 控制篇
- 普冉PY32系列(十二) 基于PY32F002A的6+1通道遥控小车III - 驱动篇
- 普冉PY32系列(十三) SPI驱动WS2812全彩LED
WS2812/WS2812B

WS2812 是一种集成了控制器的全彩LED, 常见单体尺寸为50mm * 50mm, 4个PIN, 分别是 VCC, GND, DIN, DOUT, 工作电压3.7V-5.3V, 电流16mA. 市面上出售的大都是制作成条状, 环状或矩阵的成品. 供电电压有5V和12V两种, 前者因为电压低, 如果长度较长, 每隔两三百颗需要外接电源补电.
WS2812的特点就是全彩并且是单线串行接口, 只需要一个IO就可以对彩灯实现全部控制.
接口通信格式
WS2812/WS2812B LED 使用 24 bit 数据调节 RGB 色彩, 每个 bit 都是通过(一个高电平 + 一个低电平)表示的.

根据手册
- 0 表示为一个短的(0.35 µs)高电平加一个长的(0.90 µs)低电平
- 1 表示为一个长的(0.90 µs)高电平加一个短的(0.35 µs)低电平
- 单个 bit 信号周期, 高低电平时长合计为 1.25 µs
- 发送超过 24 bit 信号后, 之前输入的信号会依次传递给串行的下一个 WS2812 LED
- 控制器发送数据前需要保持低电平超过 50 µs(又称为 RESET), 用于通知 WS2812 开始接收数据.
根据上面的信息, 对单颗LED发送数据, 需要的时间为
\(24 × 1.25 µs + 50 µs = 80 µs\)
对于8颗LED, 需要的时间为
\(8 × 24 × 1.25 µs + 50 µs = 290 µs\)
实际的通信时间间隔要求
当传输信号时, 高低电平时间间隔如果不符合手册要求, 差距较大时LED会不工作(不亮), 在间隔接近但是不完全满足时, LED会出现显示错乱, 色彩乱跳等.
Tim “cpldcpu” 做过一系列实验 https://cpldcpu.wordpress.com/2014/01/14/light_ws2812-library-v2-0-part-i-understanding-the-ws2812/ 验证过时间间隔的边界, 发现这些要求实际上相当宽松:
- 触发RESET只需要 9 µs (比手册要求的 50 µs 小很多)
- 一个 bit 的周期至少需要 1.25 µs, 但是不能超过 9 µs, 因为这样容易触发RESET
- 0 的高电平时间, 手册要求是 0.35 µs, 实际上可以短至 62.5 ns , 但是不能长于 0.50 µs
- 1 的高电平时间, 手册要求是 0.65 µs, 实际上长度可以几乎跨越整个 bit 周期, 但是不能短于 0.625 µs
SPI驱动时的bit数选择
对于输出固定长度的电平组合, SPI是最简单的方式. 可以使用 SPI, 通过控制其中的数据值与 WS2812 通信, 而时间间隔控制则需要通过控制 SPI 的时钟以及每次发送的 bit 数量实现, 根据Controlling WS2812(B) leds using STM32 HAL SPI 的计算, 通过对比多种 bit 数的时间要求, 发现使用 bit 数越多, 兼容性越好, MCU越容易实现. 因此可以使用默认的 8bit SPI 通信.
对于 PY32F002A/PY32F003/PY32F030, 因为最高频率是48MHz, 所以当SPI分频为8, 16时, 分别对应 6MHz, 3MHz, 在工作范围内; 对于 PY32F040/PY32F071/PY32F072, 最高频率是72MHz, 当SPI分频为8, 16, 32时, 分别对应 9MHz, 4.5MHz, 2.25MHz, 都在工作范围内.
SPI 驱动 WS2812
对应不同的LED数量, 需要调整下面代码中WS2812_NUM_LEDS的值, 这里使用的是一个8x8的点阵, 因此设为64. 注意这个ws2812_buffer实际上非常占内存, 对于数量超过64的LED灯带(矩阵), 需要考虑其它的实现.
头文件 ws2812_spi.h
#include "main.h"
#define WS2812_NUM_LEDS 64
#define WS2812_SPI_HANDLE Spi1Handle
#define WS2812_RESET_PULSE 60
#define WS2812_BUFFER_SIZE (WS2812_NUM_LEDS * 24 + WS2812_RESET_PULSE)
extern SPI_HandleTypeDef WS2812_SPI_HANDLE;
extern uint8_t ws2812_buffer[];
void ws2812_init(void);
void ws2812_send_spi(void);
void ws2812_pixel(uint16_t led_no, uint8_t r, uint8_t g, uint8_t b);
void ws2812_pixel_all(uint8_t r, uint8_t g, uint8_t b);
函数实现 ws2812_spi.c
#include <string.h>
#include "ws2812_spi.h"
#define WS2812_FILL_BUFFER(COLOR) \
for( uint8_t mask = 0x80; mask; mask >>= 1 ) { \
if( COLOR & mask ) { *ptr++ = 0xfc; } \
else { *ptr++ = 0x80; }}
uint8_t ws2812_buffer[WS2812_BUFFER_SIZE];
void ws2812_init(void) {
memset(ws2812_buffer, 0, WS2812_BUFFER_SIZE);
ws2812_send_spi();
}
void ws2812_send_spi(void) {
HAL_SPI_Transmit(&WS2812_SPI_HANDLE, ws2812_buffer, WS2812_BUFFER_SIZE, HAL_MAX_DELAY);
}
void ws2812_pixel(uint16_t led_no, uint8_t r, uint8_t g, uint8_t b) {
uint8_t * ptr = &ws2812_buffer[24 * led_no];
WS2812_FILL_BUFFER(g);
WS2812_FILL_BUFFER(r);
WS2812_FILL_BUFFER(b);
}
void ws2812_pixel_all(uint8_t r, uint8_t g, uint8_t b) {
uint8_t * ptr = ws2812_buffer;
for( uint16_t i = 0; i < WS2812_NUM_LEDS; ++i) {
WS2812_FILL_BUFFER(g);
WS2812_FILL_BUFFER(r);
WS2812_FILL_BUFFER(b);
}
}
使用 PY32F0 驱动 WS2812
具体的SPI初始化可以参考文章结尾的示例代码, 根据各自环境的工作频率不同, 需要控制SPI的时钟周期在工作范围之内
对于开启PLL运行在48MHz的PY32F002A/003/030, 使用8分频
static void APP_SPIConfig(void)
{
LL_SPI_InitTypeDef SPI_InitStruct = {0};
LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
//...
/* The frequency after prescaler should be below 8.25MHz */
SPI_InitStruct.BaudRate = LL_SPI_BAUDRATEPRESCALER_DIV8;
//...
}
对于 PY32F040/071/072, 工作在HSI 24MHz, 使用4分频
static void APP_SPI_Config(void)
{
Spi1Handle.Instance = SPI1;
/* The frequency after prescale should be below 8.25MHz */
Spi1Handle.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4;
//...
}
示例代码中, 通过循环依次修改像素点的RGB值演示LED全彩效果
ws2812_pixel_all(r, g, b);
ws2812_send_spi();
while (1)
{
i = (i + 1) % WS2812_NUM_LEDS;
ws2812_pixel(i, r++, g++, b++);
ws2812_send_spi();
LL_mDelay(20);
}
完整的示例代码通过以下链接查看
- PY32F002A/PY32F003/PY32F030 https://github.com/IOsetting/py32f0-template/tree/main/Examples/PY32F0xx/LL/SPI/WS2812_LED
- PY32F040/PY32F071/PY32F072 https://github.com/IOsetting/py32f0-template/tree/main/Examples/PY32F07x/HAL/SPI/WS2812_LED
注意事项
要注意自己使用的 WS2812 的供电电压是 5V 还是 12V, 不要和 PY32F0 的供电混在一起. WS2812 数量多了之后电流是很大的, 对 5V 8x8 的矩阵实测工作电流在 500mA 以上, 如果是 16x16 的矩阵, 电流会超过 2A. 这么大的电流最好单独供电.
参考
普冉PY32系列(十三) SPI驱动WS2812全彩LED的更多相关文章
- 玩转X-CTR100 l STM32F4 l WS2812全彩LED灯
更多塔克创新资讯欢迎登陆[塔克社区 www.xtark.cn ][塔克博客 www.cnblogs.com/xtark/ ] WS2812B RGB全彩LED灯珠,只需通过一根信号线控制多个 ...
- 普冉PY32系列(六) 通过I2C接口驱动PCF8574扩展的1602LCD
目录 普冉PY32系列(一) PY32F0系列32位Cortex M0+ MCU简介 普冉PY32系列(二) Ubuntu GCC Toolchain和VSCode开发环境 普冉PY32系列(三) P ...
- 普冉PY32系列(一) PY32F0系列32位Cortex M0+ MCU简介
目录 普冉PY32系列(一) PY32F0系列32位Cortex M0+ MCU简介 普冉PY32系列(二) Ubuntu GCC Toolchain和VSCode开发环境 PY32F0系列上市其实相 ...
- 普冉PY32系列(二) Ubuntu GCC Toolchain和VSCode开发环境
目录 普冉PY32系列(一) PY32F0系列32位Cortex M0+ MCU简介 普冉PY32系列(二) Ubuntu GCC Toolchain和VSCode开发环境 以下介绍PY32F0系列在 ...
- 普冉PY32系列(七) SOP8, SOP10和SOP16封装的PY32F003/PY32F002A管脚复用
目录 普冉PY32系列(一) PY32F0系列32位Cortex M0+ MCU简介 普冉PY32系列(二) Ubuntu GCC Toolchain和VSCode开发环境 普冉PY32系列(三) P ...
- 普冉PY32系列(三) PY32F002A资源实测 - 这个型号不简单
目录 普冉PY32系列(一) PY32F0系列32位Cortex M0+ MCU简介 普冉PY32系列(二) Ubuntu GCC Toolchain和VSCode开发环境 普冉PY32系列(三) P ...
- 普冉PY32系列(四) PY32F002/003/030的时钟设置
目录 普冉PY32系列(一) PY32F0系列32位Cortex M0+ MCU简介 普冉PY32系列(二) Ubuntu GCC Toolchain和VSCode开发环境 普冉PY32系列(三) P ...
- 普冉PY32系列(五) 使用JLink RTT代替串口输出日志
目录 普冉PY32系列(一) PY32F0系列32位Cortex M0+ MCU简介 普冉PY32系列(二) Ubuntu GCC Toolchain和VSCode开发环境 普冉PY32系列(三) P ...
- linux驱动基础系列--linux spi驱动框架分析
前言 主要是想对Linux 下spi驱动框架有一个整体的把控,因此会忽略某些细节,同时里面涉及到的一些驱动基础,比如平台驱动.设备模型等也不进行详细说明原理.如果有任何错误地方,请指出,谢谢! spi ...
- linux驱动基础系列--linux spi驱动框架分析(续)
前言 这篇文章是对linux驱动基础系列--linux spi驱动框架分析的补充,主要是添加了最新的linux内核里设备树相关内容. spi设备树相关信息 如之前的文章里所述,控制器的device和s ...
随机推荐
- 知识图谱(Knowledge Graph)- Neo4j 5.10.0 Desktop & GraphXR 连接自建数据库
#输入查看数据库连接 neo4j$ :server status 添加 远程连接,输入连接地址 Graph Apps 选择 GraphXR 打开 显示
- 当小白遇到FullGC
起初没有人在意这场GC,直到它影响到了每一天! 前言 本文记录了一次排查FullGC导致的TP99过高过程,介绍了一些排查时思路,线索以及工具的使用,希望能够帮助一些新手在排查问题没有很好的思路时,提 ...
- 三维模型OBJ格式轻量化压缩主要技术方法浅析
三维模型OBJ格式轻量化压缩主要技术方法浅析 OBJ格式是一种常用的三维模型文件格式,它以文本形式保存了模型的顶点.纹理坐标和法线信息.为了实现轻量化压缩,可以采用以下主要技术方法: 1.简化网格 ...
- 白话领域驱动设计DDD
容我找个借口先,日常工作太忙,写作略有荒废.一直想聊下领域驱动设计,以下简称DDD,之前也看过一些教程,公司今年两个项目--银行核心和信用卡核心,都深度运用DDD成功落地,有人说DDD挺难理解,在此讲 ...
- Python+Flask接口实现简单的ToKen功能
话不多说,上代码 from flask import request, jsonify from functools import wraps class TokenRequired: @classm ...
- Linux下Python环境安装
Linux通常都附带Python环境,但是Linux附带的大多数Python都是2.7.5版本.如果我们想使用Python3或者Anaconda3,最好安装一个新的Python3环境,但不要尝试删除P ...
- .NET使用quartz+topshelf实现定时执行任务调度服务
一.项目开发 1.新建控制台应用(.NET Framework) 2.配置新项目,自行修改项目名称.位置和框架(建议使用.NET Framework4.5以上版本) 创建好的项目目录如下: 3.右键引 ...
- salesforce零基础学习(一百三十一)Validation 一次的bypass设计
本篇参考: https://admin.salesforce.com/blog/2022/how-i-solved-it-bypass-validation-rules-in-flows 背景:作为系 ...
- 低功耗引擎 Cliptrix 有什么价值
在万物互联的时代,现代人已普遍接受电视.音箱等电器设备具备智能化能力,也是在这个趋势下,我们身边越来越多的iOT设备联网和交互成为刚需.但iot设备也面临到一些非常显著的痛点,例如iot设备的内存.处 ...
- DBeaver Ultimate 22.1.0 连接数据库(MySQL+Mongo+Clickhouse)
前言 继续书接上文 Docker Compose V2 安装常用数据库MySQL+Mongo,部署安装好之后我本来是找了一个web端的在线连接数据库的工具,但是使用过程中并不丝滑,最终还是选择了使用 ...