硬件平台:STM32L431RCT6
软件版本:RT-Thread Studio 2.2.8,STM32CubeMX 6.12.0
RT-Thread版本:4.1.0
言:之前写过一篇WS2812B的教程,但是最近扒出来用发现不能单独点亮或者熄灭特定位置的灯珠,只能从第一个节点开始,项目需求要单独控制,没办法,只能从头捣鼓。经过一整天的努力终于完工了,效果还不错,赶紧写篇笔记加深一下印象。
一.创建工程
二.STM32CubeMX配置
选48M
由于WS2812不会向SPI主机发送数据,所以选择主机模式只发送就行,PA7就是SPI1的MOSI,只需要把WS2812B的数据引脚连在PA7就行。
完事,直接生成代码,然后关闭cubemx
三.RT-Thread Studio setting设置
打开spi驱动框架,点一下就行,不要点多,双击会取消选中,记得保存!!!
四.board.h修改
#define BSP_USING_SPI1
#define BSP_SPI1_TX_USING_DMA
五.将驱动文件拖入工程内
ws2812b.c:
#include "ws2812b.h"volatile uint8_t RGB_BIT_Buffer[RGB_BIT];
volatile uint8_t buffer[RGB_BIT * LED_NUMS];
struct rt_spi_device *spi;static int rt_hw_spi_ws2812_init(void)
{rt_hw_spi_device_attach("spi1", "spi10", GPIOB, GPIO_PIN_12);ws2812_init();ws2812_clear_rgb_to_all();return RT_EOK;
}
/* 导出到自动初始化 */
INIT_COMPONENT_EXPORT(rt_hw_spi_ws2812_init);int ws2812_init(void)
{spi = (struct rt_spi_device *)rt_device_find("spi10");if (spi == RT_NULL){rt_kprintf("Error: SPI device not found.\n");return -1;}// 配置 spistruct rt_spi_configuration ws2812_spi_config;ws2812_spi_config.mode = RT_SPI_MASTER | RT_SPI_MODE_3 | RT_SPI_MSB;ws2812_spi_config.max_hz = 6 * 1000 * 1000;ws2812_spi_config.data_width = 8;rt_spi_configure((struct rt_spi_device *)spi, &ws2812_spi_config);memset((void *)buffer, WS2812_0, sizeof(buffer));memset((void *)RGB_BIT_Buffer, WS2812_0, sizeof(RGB_BIT_Buffer));return 0;
}void ws2812_update()
{rt_spi_send(spi, buffer, RGB_BIT * LED_NUMS);
}static void ws2812_creat_data(uint8_t R, uint8_t G, uint8_t B)
{uint8_t temp[RGB_BIT] = {0};for (uint8_t i = 0; i < 8; i++){temp[7 - i] = (G & 0x01) ? WS2812_1 : WS2812_0;G = G >> 1;}for (uint8_t i = 0; i < 8; i++){temp[15 - i] = (R & 0x01) ? WS2812_1 : WS2812_0;R = R >> 1;}for (uint8_t i = 0; i < 8; i++){temp[23 - i] = (B & 0x01) ? WS2812_1 : WS2812_0;B = B >> 1;}memcpy((void *)RGB_BIT_Buffer, temp, RGB_BIT);
}static void ws2812_write_rgb_to_node(uint32_t color, uint16_t Pos)
{uint8_t R, G, B;uint16_t i;R = (color >> 16) & 0x00FF;G = (color >> 8) & 0x0000FF;B = (color) & 0x0000FF;ws2812_creat_data(R, G, B);if (Pos < LED_NUMS && Pos >= 0){memcpy((void *)(buffer + RGB_BIT * Pos), (void *)RGB_BIT_Buffer, RGB_BIT);}else{rt_kprintf("Error: Pos is out of range.\n");}
}void ws2812_clear_rgb_to_node(uint16_t Pos)
{if (Pos < LED_NUMS && Pos >= 0){memset((void *)(buffer + RGB_BIT * Pos), WS2812_0, RGB_BIT);}
}void ws2812_clear_rgb_to_all()
{for (uint16_t i = 0; i < LED_NUMS; i++){ws2812_clear_rgb_to_node(i);}ws2812_update();
}static void cmd_rgb_control(int argc, char **argv)
{if (argc != 4){rt_kprintf("Usage: %s <node> <on/off> <color>\n", argv[0]);return;}int node = atoi(argv[1]) - 1; // 将第一个参数转换成整数作为节点编号int on_off = atoi(argv[2]); // 将第二个参数转换成整数作为开关int color = atoi(argv[3]); // 将第三个参数转换成整数作为颜色代码// 检查传入的参数是否有效if (on_off != 0 && on_off != 1){rt_kprintf("Invalid switch value. Use 1 for on and 0 for off.\n");return;}// 根据开关值执行相应的操作if (on_off == 1){// 打开RGB灯,并设置颜色switch (color){case 1:ws2812_write_rgb_to_node(red_0, node); // 使用指定的节点编号和颜色break;case 2:ws2812_write_rgb_to_node(brown_30, node); // 使用指定的节点编号和颜色break;case 3:ws2812_write_rgb_to_node(yellow_60, node); // 使用指定的节点编号和颜色break;case 4:ws2812_write_rgb_to_node(Dark_green_90, node); // 使用指定的节点编号和颜色break;default:break;}}else if (on_off == 0){// 关闭RGB灯ws2812_clear_rgb_to_node(node);}ws2812_update();
}// 注册命令到 MSH
MSH_CMD_EXPORT(cmd_rgb_control, control the specified rgb LED with node on / off and color parameters);
ws2812b.h
#ifndef WS2812_H
#define WS2812_H#include <stdint.h>
#include <string.h>
#include "rtthread.h"
#include "rtdevice.h"
#include "board.h"
#include "stm32l431xx.h"
#include <msh.h>
#include "libraries\STM32L4xx_HAL_Driver\Inc\stm32l4xx_hal_gpio.h"#define WS2812_0 0xC0
#define WS2812_1 0xF0
#define WS2812_RST 0x00
#define LED_NUMS 10
#define RGB_BIT 24// 以下编码准寻· 光学色相环(RGB模型)-12色
#define red_0 0xFF0000 // 红
#define brown_30 0xFF7F00 // 棕色
#define yellow_60 0xFFFF00 // 黄色
#define Dark_green_90 0x7FFF00 // 深绿色
#define Medium_green_120 0x00FF00 // 中绿色
#define Light_green_150 0x00FF7F // 浅绿色
#define Baby_blue_180 0x00FFFF // 浅蓝色
#define Medium_blue_210 0x007FFF // 中蓝色
#define Dark_blue_240 0x0000FF // 深蓝色
#define modena_270 0x7F00FF // 深紫色
#define Medium_purple_300 0xFF00FF // 中紫色
#define lilac_330 0xFF007F // 浅紫色#define white_360 0xFFFFFF // 白色
#define off_390 0x000000 // 熄灯typedef struct
{uint8_t R;uint8_t G;uint8_t B;
} LEDType;/**
turn off all leds
*/
int ws2812_init(void);#endif
六.使用MSH命令验证功能
比如发送cmd_rgb_control 1 1 1 ,表示第一个灯亮红色
cmd_rgb_control 2 1 3代表第二个灯亮黄色
cmd_rgb_control 1 0 1代表关闭第一个灯
功能验证通过,文章到此结束
参考文章:【STM32】硬件SPI+DMA驱动WS2812灯珠,基于HAL库_stm32 ws2812-CSDN博客