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