...
嵌入式 STC

STC8G驱动WS2812

技术名词解释

1t单片机

  • 1t可以说是相对传统51单片机来说的,理论上比传统51单片机快12倍。并且该型号频率可以达到33mhz。如果以普通的51单片机来类比,当传统51单片机晶振为12mhz时,一条nop();指令的时间为1us,而stc8g就是1/12us,约等于0.083us。
  • 为了更好模拟准确的时序,我们在下载时把内部时钟设置为 24mhz ,这样一条 nop(); 指令的时间为1/24us约等于 0.0417us(即41.7ns),三条就刚好约为125ns

ws2812

  • WS2812B-V5是一个集控制电路与发光电路于一体的智能外控LED光源。其外型与一个5050LED灯珠相同, 每个元件即为一个像素点。像素点内部包含了智能数字接口数据锁存信号整形放大驱动电路,还包含有高精度的 内部振荡器和可编程定电流控制部分,有效保证了像素点光的颜色高度一致。 数据协议采用单线归零码的通讯方式,像素点在上电复位以后,DIN端接受从控制器传输过来的数据,首先送过 来的24bit数据被第一个像素点提取后,送到像素点内部的数据锁存器,剩余的数据经过内部整形处理电路整形放 大后通过DO端口开始转发输出给下一个级联的像素点,每经过一个像素点的传输,信号减少24bit。像素点采用 自动整形转发技术,使得该像素点的级联个数不受信号传送的限制,仅受限信号传输速度要求。

ws2812详细数据协议
WS2812通过rgb三种颜色来产生理论上255x255x255种颜色,其通信方式如下所示:

所以我们只要模拟出上图的时序就能控制ws2812了,但要注意他的数据顺序是G->R->B

为了更好模拟准确的时序,我们在下载时把内部时钟设置为 24mhz ,这样一条 nop(); 指令的时间为1/24us约等于 0.0417,三条就刚好约为125ns。

Keil工程的设置

Keil需要选择对应的单片机型号

设置为24Mhz

关闭优化功能为Level0(避免编译器过度优化,导致时序不正确)

代码编程

  • 需要#include “stc8.h”
  • 使用nop()函数前,需要#include “intrins.h”
  • 根据主时钟频率,调整延时函数的数量
  • – STC8G1K08A最高支持35MHz
  • – 这里使用24MHz
  • 使用下载时,注意选择型号并配置时钟频率 (如下图)

看代码

main.c

#include <STC8G.H>
#include "WS2812.h"

void main(void)
{   
    while(1)
    {
        WS2812_SendData(255,0,0);
    }
}

WS2812.h

#ifndef WS2812_H
#define WS2812_H

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

#define WS28_PIN P33 // 引脚定义
#define WS28_NUM 4

// 初始化引脚
void WS28_Init();

// 模块写入一组数据
void WS28_SetRGB(unsigned char r_data,  // 红色
                 unsigned char g_data,  // 绿色
                 unsigned char b_data); // 蓝色

#endif // WS2812_H

WS2812.c

#include "WS2812.h"

// 初始化引脚
void WS28_Init()
{
    // 引脚P33初始化为输出
    P3M0 |= 0x08;
    P3M1 &= 0xF7;
}

// 模块写入一组数据
void WS28_SetRGB(unsigned char r_data, // 红色
                 unsigned char g_data, // 绿色
                 unsigned char b_data) // 蓝色
{
    unsigned char temp[3];
    unsigned char n, j;
    unsigned char dat;

    // 注意顺序,按照数据手册为grb顺序排列
    temp[0] = g_data;
    temp[1] = r_data;
    temp[2] = b_data;

    for (n = 0; n < 3; n++) // 循环3次(发送一组 rgb 颜色数据)
    {
        dat = temp[n];
        for (j = 0; j < WS28_NUM; j++) // 循环WS28_NUM次(发送1byte数据)
        {
            if (dat & (0x80>>i)) // 写入数据1
            {
                // 上面说了:为了更好模拟准确的时序,我们在下载时把内部时钟设置为 24mhz ,这样一条 nop(); 指令的时间为1/24us约等于 0.0417,三条就刚好约为125ns。
                // ws2812写1的时候 H->580ns~1us L->220ns~420ns
                // 此处20个nop一个41.7ns  20*41.7ns≈834ns符合写1 T1H 580ns~1us
                WS28_PIN = 1;
                _nop_();_nop_();_nop_();_nop_();_nop_();//_nop_();    delay 41ns
                _nop_();_nop_();_nop_();_nop_();_nop_();
                _nop_();_nop_();_nop_();_nop_();_nop_();
                _nop_();_nop_();_nop_();_nop_();_nop_();
                // 此处7个nop一个41.7ns  7*41.7ns≈291ns符合写1 T1L 220ns~420ns
                WS28_PIN = 0;
                _nop_();_nop_();_nop_();_nop_();_nop_();
                _nop_();_nop_();
            }
            else // 写入数据0
            {
                // 上面说了:为了更好模拟准确的时序,我们在下载时把内部时钟设置为 24mhz ,这样一条 nop(); 指令的时间为1/24us约等于 0.0417,三条就刚好约为125ns。
                // 此处正好相反
                WS28_PIN = 1;
                _nop_();_nop_();_nop_();_nop_();_nop_();
                _nop_();_nop_();
                WS28_PIN = 0;
                _nop_();_nop_();_nop_();_nop_();_nop_();//_nop_();    delay 41ns
                _nop_();_nop_();_nop_();_nop_();_nop_();
                _nop_();_nop_();_nop_();_nop_();_nop_();
                _nop_();_nop_();_nop_();_nop_();_nop_();
            }
        }
    }
}

参考:
https://blog.csdn.net/Xhw3f586/article/details/132295552
https://blog.csdn.net/github_38203983/article/details/142327258
https://blog.csdn.net/qq_61688416/article/details/132503077

STC8G使用串口打印调试 HID 报告描述详解
biu biu biu
frp搭建免费的内网穿透 分享几个免费的内网穿透解决方案 美国/香港便宜VPS云服务器优惠码,12块一个月的国外服务器~ electron-builder 在打包时编译sqlite3下载nsis winCodeSign超时问题 nodejs 使用 SQLite3 基本教程