本帖最后由 阿源玩电子 于 2024-12-27 10:30 编辑
#申请原创# #有奖活动# #申请开发板# 一、硬件介绍
1. WS2812B通常由多个LED组成,每个LED都可以独立控制,常见的连接方式如下:
- 电源(VCC和GND):WS2812B需要一个稳定的5V电源供电。为了保证色环稳定运行,电源应该足够强大,这里我使用额外的电源对色环进行供电。
- 控制线:根据开发板的I/O资源,可以选择任意一个GPIO口来控制WS2812B。
2. WS2812B 使用一种基于时间的协议来传输数据。数据通过单线传输,每个数据包包含一个 LED 的颜色信息,数据格式是逐位传输,每个 LED 需要 24 位数据。
- 每个 LED:需要 24 位数据,分为 3 个字节(8 位每个),对应颜色通道:红色 (R)、绿色 (G)、蓝色 (B),数据顺序为:GRB。
- 1 个 LED 数据格式:G:8 bits (字节) R:8 bits (字节) B:8 bits (字节)
3. 数据位:WS2812B 的每个数据位都有严格的时序要求,特别是高电平和低电平的时间。
数据的传输基于如下的时序规则
- 逻辑 1 (高电平):
- 高电平持续约 0.65 微秒
- 低电平持续约 1.15 微秒
- 逻辑 0 (低电平):
- 高电平持续约 0.20 微秒
- 低电平持续约 0.55 微秒
通过这种方式,控制信号可以传递 0 和 1,1 和 0 的组合来表示数据。
二、驱动介绍
1. 我准备直接使用PC5,进行翻转来模拟WS2812B时序,定义一个数组用来储存灯珠数据
#define Flow_led_num 26 // 流动LED灯的数量
#define led_data_lenght 24 // WS2812的数据长度
uint8_t Flow_led_buffer[Flow_led_num * led_data_lenght] = {0};
2.初始化GPIOC_5
void Flow_led_init(void)
{
CLOCK_SYS_ConfigModuleClock(PMC_CLK, NULL);
PINS_SetMuxModeSel(PMC, 5U, PM_MUX_AS_GPIO);
PINS_SetPinIntSel(PMC, 5U, PM_DMA_INT_DISABLED);
PINS_SetPins(GPIOC, 1U << 5U);
PINS_SetPinDir(GPIOC, 5U, 1U);
}
3.延时函数以及数据发送函数void delay(uint32_t time) {
// 精确延时函数,替代 __NOP(),根据系统时钟来控制延时
for (uint32_t i = 0; i < time; i++) {
__NOP();
}
}
void Flow_led_send(void) {
// 遍历 Flow_led_buffer
for (int i = 0; i < sizeof(Flow_led_buffer); i++) {
if (Flow_led_buffer[i]) {
// 发送 '1'
GPIOC->PLLOS.reg = 1U << 5U; // 设置高电平
delay(9); // 延时,调节延时以满足硬件时序要求
GPIOC->PLLOC.reg = 1U << 5U; // 设置低电平
delay(3); // 延时
} else {
// 发送 '0'
GPIOC->PLLOS.reg = 1U << 5U; // 设置高电平
delay(3); // 延时,调节延时以满足硬件时序要求
GPIOC->PLLOC.reg = 1U << 5U; // 设置低电平
delay(9); // 延时
}
}
}
4.HSV转RGB算法void hsv_to_rgb(float hue, float saturation, float value, uint8_t *r, uint8_t *g, uint8_t *b) {
float c = value * saturation; // Chroma
float x = c * (1 - fabs(fmod(hue / 60.0, 2) - 1));
float m = value - c;
float r_prime, g_prime, b_prime;
if (hue >= 0 && hue < 60) {
r_prime = c, g_prime = x, b_prime = 0;
} else if (hue >= 60 && hue < 120) {
r_prime = x, g_prime = c, b_prime = 0;
} else if (hue >= 120 && hue < 180) {
r_prime = 0, g_prime = c, b_prime = x;
} else if (hue >= 180 && hue < 240) {
r_prime = 0, g_prime = x, b_prime = c;
} else if (hue >= 240 && hue < 300) {
r_prime = x, g_prime = 0, b_prime = c;
} else {
r_prime = c, g_prime = 0, b_prime = x;
}
*r = (uint8_t)((r_prime + m) * 255);
*g = (uint8_t)((g_prime + m) * 255);
*b = (uint8_t)((b_prime + m) * 255);
}
5.色环驱动函数
uint16_t i,j;
uint8_t Colorful_gradient(uint8_t ledNum, uint8_t brightness, uint8_t speed_flow) {
static float Hue = 0;
static const float Saturation = 1.0f;
float Value = brightness / 255.0f;
static uint32_t time = 0;
static uint8_t R, G, B;
static uint32_t RGB;
static uint8_t num;
Hue += 0.1f;
if (Hue >= 360.0f) {
Hue -= 360.0f;
}
time+=100;
if (time >= 7000) {
time = 0;
Hue = 0;
num++;
}
for ( i = 0; i < ledNum; i++) {
float ledHue = Hue + (float)(i * 360.0f / ledNum) + (float)time / 20.0f;
if (ledHue >= 360.0f) {
ledHue -= 360.0f;
}
hsv_to_rgb(ledHue, Saturation, Value, &R, &G, &B);
RGB = ((uint32_t)R << 16) | ((uint32_t)G << 8) | B;
ws2812_set_index_brightness(RGB, i);
}
return 0;
}
6.主函数
int main(void)
{
SystemCoreClockConfigure(); /* Configure system core clock */
SystemCoreClockUpdate(); /* Update system core clock info */
SysTick_Init();
Flow_led_init();
while(1)
{
Flow_led_send();
Colorful_gradient(26,10,1);
SysTick_Delay(10);
}
}
三、效果
四、总结
直接使用IO口驱动,本来效果是七彩旋转,结果视频放不上去,没办法展示。
|