这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 活动中心 » 板卡试用 » 【换逻辑分析仪】使用8051单片机驱动WS2812

共4条 1/1 1 跳转至

【换逻辑分析仪】使用8051单片机驱动WS2812

菜鸟
2024-12-01 03:00:01     打赏

简介



本文将带你了解如何用 STC 8H8K64U 单片机控制 WS2812 全彩 LED 灯珠。我们会先简单介绍 WS2812 的原理,再详细分析如何通过程序实现点亮效果。


WS2812 简单介绍




WS2812 是一种非常流行的全彩 RGB LED,它最大的特点是内置控制芯片,通过一根数据线就可以实现对灯珠颜色和亮度的精准控制。以下是它的一些关键特性:

  • 单线通信:通过一个数据线传输控制信号,级联多个灯珠时,后续灯珠从前一个灯珠的输出端获取数据。

  • 24 位颜色控制:每颗灯珠由红、绿、蓝三个颜色通道组成,每个通道占 8 位(0~255)。

  • 级联控制:支持多个灯珠串联,单片机只需要控制第一颗灯珠,后续灯珠会自动接收剩余数据。



image.png



实现步骤



首先,你需要以下材料:

  • 一块 STC 8H8K64U 单片机开发板。

  • 一颗或多颗 WS2812 灯珠。

  • 一根连接灯珠和单片机的数据线,以及电源(一般 5V)。

硬件连接示意:

  • WS2812 DIN 接单片机的 GPIO 口(如 P21)。

  • WS2812 VCC 接 5V 电源。

  • WS2812 GND 接地。


WS2812 通信协议




WS2812 使用单线协议,传输的每一位数据用高低电平来表示:

  • 逻辑 1:高电平持续约 0.7 µs,低电平持续约 0.6 µs。

  • 逻辑 0:高电平持续约 0.35 µs,低电平持续约 0.8 µs。

  • 复位信号:低电平保持至少 50 µs,表示一帧数据结束。

24 位数据的顺序为:绿色 8 位红色 8 位蓝色 8 位

(建议参考不同厂商的时序来确定高低电平的时间, 不同厂商的这个时间略有不同)


如下图所示

image.png

下图为典型的通讯时序。

image.png

所以即点亮单个LED的话, 需要发送的BIT数为24, 绿色先发, 然后是红色, 然后是蓝色。 每个颜色一共是2^8 即256(0-255),可以通过控制发送0码和1码来自由组合。


程序实现如下


由于采用的STC8H8H64U,它的单片机IO口的翻转速度可以满足上述的传输时序需要。因此我们可以使用逻辑分析仪等来帮助我们辅助分析0码和1码。如下图所示。

下图展示的为0码,如果顺序颠倒一下, 基本上等于1码

image.png


代码如下

#include <AI8H.H>
#include <intrins.h>

typedef unsigned char uint8_t; // 定义无符号字符类型为 uint8_t

// 定义 WS2812 LED 的逻辑 "0" 和 "1" 信号代码
#define ZERO_CODE() P21=1; NOP7(); P21=0; NOP14(); // 输出逻辑 "0"
#define ONE_CODE() P21=1; NOP14(); P21=0; NOP12(); // 输出逻辑 "1"

#define LED_NUMBER 2       // LED 的数量
#define BRIGHTNESS 2       // LED 亮度设置
#define MAX_BRIGHTNESS 255   // LED 最大亮度值

uint8_t led_states[3][3];  // 存储每个 LED 的颜色状态 [LED索引][颜色分量]

// 延时 55 微秒函数
void Delay55us(void)
{
    unsigned char i, j;
    _nop_(); // 插入一个空指令
    i = 2;
    j = 180;
    do {
        while (--j); // 内层延时
    } while (--i);   // 外层延时
}

// 延时 1000 毫秒函数
void Delay1000ms(void)
{
    unsigned char i, j, k;
    _nop_(); _nop_(); // 插入两个空指令
    i = 122;
    j = 193;
    k = 128;
    do {
        do {
            while (--k); // 最内层延时
        } while (--j);   // 中层延时
    } while (--i);       // 最外层延时
}

// 重置所有 LED 为关
void reset_all()
{
    uint8_t index;
    for (index = 0; index < 24 * LED_NUMBER; index++) {
        ZERO_CODE(); // 发送 0 信号
    }
    Delay55us(); // 延时 55 微秒,确保数据传输完成
}

// 设置指定 LED 的颜色
void set_led_color(uint8_t led_index, uint8_t green, uint8_t red, uint8_t blue)
{
    uint8_t i, mask, number;

    // 调整颜色值以应用亮度设置
    green = (green * BRIGHTNESS) / MAX_BRIGHTNESS;
    red = (red * BRIGHTNESS) / MAX_BRIGHTNESS;
    blue = (blue * BRIGHTNESS) / MAX_BRIGHTNESS;

    // 保存颜色值到状态数组
    led_states[led_index][0] = green;
    led_states[led_index][1] = red;
    led_states[led_index][2] = blue;

    // 遍历每个 LED,输出其颜色数据
    for (number = 0; number < LED_NUMBER; number++) {
        // 输出绿色分量数据
        for (i = 0; i < 8; i++) {
            mask = 0x80 >> i; // 获取当前位的掩码
            if (led_states[number][0] & mask) {
                ONE_CODE();  // 输出逻辑 "1"
            } else {
                ZERO_CODE(); // 输出逻辑 "0"
            }
        }
        // 输出红色分量数据
        for (i = 0; i < 8; i++) {
            mask = 0x80 >> i;
            if (led_states[number][1] & mask) {
                ONE_CODE();
            } else {
                ZERO_CODE();
            }
        }
        // 输出蓝色分量数据
        for (i = 0; i < 8; i++) {
            mask = 0x80 >> i;
            if (led_states[number][2] & mask) {
                ONE_CODE();
            } else {
                ZERO_CODE();
            }
        }
    }
    Delay55us(); // 延时确保数据传输完成
}

// 主函数
void main()
{
    // 设置 P21 引脚为推挽输出模式
    P2M0 |= 0x02;
    P2M1 &= ~0x02;

    reset_all(); // 初始化,关闭所有 LED
    set_led_color(0, 0, 255, 0); // 设置第一个 LED 为红色 (R=255, G=0, B=0)
    set_led_color(1, 255, 255, 0); // 设置第一个 LED 为红色 (R=255, G=0, B=0)
    while (1) {
       
    }
}


注意,上述程序可以正确的运行的主频为24M的单片机内。 如果需要移植到你的单片机上的话,(需要重新计算延时时间)只需要控制好0码和1码的生成。

下图为STC-ISP调整的主频截图。


image.png


运行效果


将程序烧录到单片机中并运行后:

  • 第一颗灯珠会显示红色;

  • 第二颗灯珠会显示绿色;

  • 如果有更多灯珠,会保持默认关闭状态。

51c45bcc9f0610e8729bd815f29bc3d.jpg


如果需要调整亮度的话, 可以修改BRIGHTNESS的定义.


总结


通过这篇教程,我们学习了 WS2812 的通信原理和具体实现方法。尽管 WS2812 的时序要求较高,但通过简单的逻辑分析和代码实现,我们可以轻松完成对灯珠的控制。你可以进一步尝试添加更多灯珠、动态变化颜色等更复杂的效果。



专家
2024-12-01 07:19:17     打赏
2楼

学习一下


专家
2024-12-01 13:58:40     打赏
3楼

有汇编实现代码吗?


专家
2024-12-01 19:00:41     打赏
4楼

学习


共4条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]