关键词:WS2812 ,STM32G030F6
说 明:本代码用于驱动 16 个RGB LED(WS2812 )模块,可以按16个预定颜色的流水显示,
使用RT-Thread RTOS 基于STM32G030F6 最小系统板的 ws2812 驱动工程。
WS2812是一个集控制电路与发光电路于一体的外控LED光源,外形一般为5050封装,每个LED灯珠为一个像素点,支持RGB无极调色,同时每颗灯珠内部集成有数字接口数据锁存信号整形放大驱动电路,还包含有高精度的内部振荡器和可编程定电流控制部分,整个 LED 模组只需要3条线即可驱动,VCC,GND,DATA, LED 模组上的所有LED都串在一条数据线上,所以只需要使用1条IO即可驱动。
驱动效果,彩色渐变循环显示
16位 WS2812 5050 RGB LED 智能全彩RGB灯环开发板
/*
* Copyright (c) 2006-2020, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* IO 直接数据输出模式控制 ws2812B
* 说明:本代码用于驱动 16 个RGB LED模块,可以按16个预定颜色的流水显示
*/
#include "user_cfg.h"
#define RGBLED_GPIOX GPIOA /* LED驱动IO */
#define RGBLED_PIN GPIO_PIN_3 /* LED驱动IO */
#define LED_NUM 16 /* LED数量 */
//#define RGBLED GET_PIN(A, 3)
/* STM32F103 系列 IO 输出控制,采用直接寄存器操作方法,这样可以做到IO的控制速度最大化 */
/*方式1:(72M主频)BSRR 只写寄存器:既能控制管脚为高电平,也能控制管脚为低电平。对寄存器高 16bit 写1 对应管脚为低电平,对寄存器低16bit写1对应管脚为高电平。写 0 ,无动作*/
//#define LED1(X) X? (GPIOB->BSRR |= (0X00000001<<7)):(GPIOB->BSRR |= (0X00000001<<23)) /* 控制 PB7 输出1 或者 0 ,最小脉宽 250ns*/
/*方式2:(72M主频)ODR寄存器可读可写:既能控制管脚为高电平,也能控制管脚为低电平。管脚对应位写1 gpio 管脚为高电平,写 0 为低电平*/
//#define LED1(X) X? (GPIOB->ODR |= (0X01<<7)):(GPIOB->ODR &=~ (0X01<<7)) /* 控制 PB7 输出1 或者 0 ,最小脉宽 250ns */
//#define LED1(X) X? (GPIOA->ODR |= (0X0001<<12)):(GPIOA->ODR &=~ (0X0001<<12)) /* 控制 PA12 输出1 或者 0 ,最小脉宽 250ns */
/* 方式2.1:(72M主频)以下是在方式2的基础上,直接用移位和取反的结果,省去了移位和取反的操作时间,示波器测量对比,IO的翻转时间和方式2没有明显变化 */
//#define RGBLED_1 GPIOA->ODR |= 0X08 /* 控制 PB3 输出1 或者 0 ,最小脉宽 243.6ns */
//#define RGBLED_0 GPIOA->ODR &= 0XF7
#define RGBLED_1 HAL_GPIO_WritePin(RGBLED_GPIOX,RGBLED_PIN, 1)
#define RGBLED_0 HAL_GPIO_WritePin(RGBLED_GPIOX,RGBLED_PIN, 0)
//#define RGBLED_1 LED1(1)
//#define RGBLED_0 LED1(0)
/*方式3:(72M主频)使用RT Thread 的 IO 控制函数,控制IO翻转的时间*/
//#define RGBLED_1 rt_pin_write(RGBLED, 1) /* 最小脉宽 3.1us */
//#define RGBLED_0 rt_pin_write(RGBLED, 0)
/* 定义LED要显示的16个颜色 */
char count = 0; /* 计数变量,用于旋转跑马灯计数用 */
char color_rgb[16][3] = {{255,182,193},\
{255, 20,147},\
{255, 0,255},\
{ 0, 0,255},\
{ 30,144,255},\
{ 0,255,255},\
{ 0,250,154},\
{ 50,205,50 },\
{255,255,0 },\
{255,165,0 },\
{255,140,0 },\
{255, 69,0 },\
{250,128,114},\
{255, 0,0 },\
{128, 0,0 },\
{255,255,255},\
};
void RGB_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOA_CLK_ENABLE();
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(RGBLED_GPIOX,RGBLED_PIN, GPIO_PIN_RESET);
/*Configure GPIO pin : PB0 */
GPIO_InitStruct.Pin = RGBLED_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(RGBLED_GPIOX, &GPIO_InitStruct);
}
/* 复位 80us低电平 */
void RGB_LEDReset()
{
RGBLED_0;
rt_hw_us_delay(80);
}
/* RGB写一个字节 */
void RGB_WriteByte(char dat)
{
char i;
for(i= 0;i<8;i++)
{
dat <<= i;
if(dat & 0x80) // 判断最高位
{
RGBLED_1;
RGBLED_1;
RGBLED_0;
}
else
{
RGBLED_1;
RGBLED_0;
RGBLED_0;
}
}
}
/* 输出LED数据 */
void RGB_ColorSet(char red,char green,char blue)
{
RGB_WriteByte(green);
RGB_WriteByte(red);
RGB_WriteByte(blue);
}
/* 设置 并输出 LED 数据*/
void RGB_RandomColor(uint8_t i)
{
char red,green,blue;
uint8_t j = 0;
j = count + i;
if (j >= LED_NUM)
{
j = j - (LED_NUM - 1);
}
red = color_rgb[j][0];
green = color_rgb[j][1];
blue = color_rgb[j][2];
RGB_ColorSet(red,green,blue); /*输出LED数据*/
}
/* 关闭 i 个 LED */
void RGB_RandomColor_off(void)
{
char red,green,blue;
red = 0;
green = 0;
blue = 0;
RGB_ColorSet(red,green,blue);
}
/* 点亮 i 个 LED */
void RGB_RandomColor4(uint8_t i)
{
for (uint8_t var = 0; var < i; ++var)
{
if (i)
{
RGB_RandomColor(var);
}
else
{
RGB_RandomColor_off();
}
}
RGB_LEDReset();
if (count < LED_NUM -1)
{
++count;
}
else
{
count = 0;
}
}
/* 线程 rgbled_test 的入口函数 */
static void rgbled_entry(void *param)
{
RGB_Init();
RGBLED_0;
while (1)
{
RGB_RandomColor4(LED_NUM);
rt_thread_mdelay(1000);
}
}
/*线程创建函数*/
int rgbled_test(void)
{
rt_thread_t tid1; /*创建线程控制块指针来接收线程创建函数的返回值,目的是通过返回值判断线程是否创建ok*/
/* 创建线程 1,名称是 rgbled_test,入口是 rgbled_entry*/
tid1 = rt_thread_create("rgbled_test", /*线程名称,系统打印线程时会显示这个线程的名字*/
rgbled_entry, /*线程入口函数,入口函数函数名*/
RT_NULL, /*入口参数*/
500, /*设置内存堆栈大小*/
9, /*设置优先级*/
500); /*时间片参数,时间片是在有多个相同优先级线程时,这个线程每次被执行多少个时间片*/
/* 如果获得线程控制块,启动这个线程 */
if (tid1 != RT_NULL)
rt_thread_startup(tid1);
return RT_EOK;
}
//INIT_APP_EXPORT(rgbled_test);
测试工程