1
电子说
WS2812B是一款全彩LED控制IC,单总线控制,何为单总线我的理解就是数据线在一根线上传输的控制方式就是单总线。其实要把灯点亮仅有一根线是不行的,还需要电源线和地线给其供电。
就是一颗灯珠串联另外一个灯珠,信号通过一根数据线相连起来控制等的亮灭就是在这根信号线上发送数据。
在说数据格式之前先来补充一下关于色彩的知识点,就是三原色,红绿蓝,也就是我们常说的RGB,R就是RED,G就是GREEN,B就是BLUE,一个彩色可以用这三种颜色的比例来混合出来。
为什么是红绿蓝?
三原色的原理不是出于物理原因,而是由于生理原因造成的。人的眼睛内有几种辨别颜色的锥形感光细胞,到的刺激略大于辨别绿色的细胞,人的感觉是黄色;如果辨别黄绿色的细胞受到的刺激大大高于辨别绿色的细胞,人的感觉是红色。虽然三种细胞并不是分别对红色、绿色和蓝色最敏感,但这三种光可以分别对三种锥形细胞产生刺激。
既然“三原色的原理不是出于物理原因,而是由于生理原因造成的”,那么前段所说的“用三种原色的光以不同的比例加合到一起,形成各种颜色的光”显然就不大合适。使用三原色并不足以重现所有的色彩,准确的说法应该是“将三原色光以不同的比例复合后,对人的眼睛可以形成与各种频率的可见光等效的色觉。”只有那些在三原色的色度所定义的颜色三角内的颜色,才可以利用三原色的光以非负量相加混合得到。
例如,红光与绿光按某种比例复合,对三种锥状细胞刺激后产生的色觉可与眼睛对单纯的黄光的色觉等效。但绝不能认为红光与绿光按某种比例复合后生成黄光,或黄光是由红光和绿光复合而成的。
24bit数据如何构造?
既然是24bit数据代表三种颜色,我们就要首先知道一个bit的意义是什么,我们传统意义上来说1个bit代表一个数据位,但是对于数据位bit的理解好像就是“1”或者“0”在数电里我们很容易把高低电平跟逻辑1和逻辑0对应起来,但是表示灯珠的逻辑电平不是简单的高低电平。
在数值上0xFFFFFF就是24bit的1,0x000000就是24bit的0.这里有8个bit代表颜色G分量,G7G6G5G4G3G2G1G0,有8个bit代表R分量R7R6R5R4R3R2R1R0,有8个bit代表B分量B7B6B5B4B3B2B1B0,当不同分量组合时候就会有不同的数据产生,这个数据背后其实是逻辑电平,这里要说明的是彩灯的逻辑“1”并不是简简单单的高电平,彩灯的逻辑“0”也不是简简单单的低电平。
由上图可知“0”码和“1”码都是既有高电平又有低电平不过高电平和低电平的比例不同,这点很好理解,重点是分析一下它的特点,首先直观的特点就是编码“0”的电平高电平时间短一些低电平时间长一些,这也恰好符合我们的逻辑毕竟它还是低电平多一些的,编码“1”的电平高电平时间就长一些,而低电平就短一些。
但是不管是高电平还是低电平他们占用整个时间长度是一样的,这里还有一个很长的低电平这个代表复位信号。
这里涉及到严格的数学描述了,长一点是多长?短一点是多短?这个肯定是有标准或者是约束的
理论上来说,高电平时长和低电平时长加起来应该是0.4us+0.85us或者0.85us+0.4us也就是说总共要占用1.25us的时间才可以编码出来一个“0”或者“1”出来。复位是要求50us以上,显然是要比编码的0或者1占用的时间要多的。
当然既然是电路的高低电平时长就会引入误差这个在误差允许的范围内我们可以接受,这个范围就是上下不超过150ns这里是ns比us还要小的时间,这个其实时间要求还是很严格的。
如何编程实现?
这里我选用我手上一个正点原子开发板,网上基于这种方式有很多驱动方案,有直接驱动也有PWM驱动也有SPI驱动,还有PWM+DMA驱动,还有用一些开源库进行驱动的,我感觉各种驱动方式各有优缺点,我先来尝试我认为最容易想到的方式(不一定是最好的或者最合适的)玩一下,后面会根据这些方式的特点进行一个总结,在相对应的需求下选用合适的方案是我们应该重点考虑的。
实现us级别延时
硬件延时NOP实现
滴答定时器中断实现
普通定时器实现
先用nop实现个us延时我手上的板子是精英板主控芯片是STM32F103ZET6系统频率是72M,一个NOP的周期就是1/72M单位是s = 1/72=单位是us,换句话说也就是72个NOP浪费的时间是1us,0.4us就是0.4*72=28.8个NOP取整数29,0.2个NOP的误差,因为一个NOP是1/72 1000 个约等于是13.88个ns 所以0.2个NOP引起的误差在150ns以内可以接受。
0.8572=61.2NOP同样取整数61个NOP,这样组合一下编码0的波形和编码1的波形就有了,实现一个 us函数 50us的低电平也可以产生复位信号,理论分析完毕咱直接上代码测试。
void RGB_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //使能PA,PD端口时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12; //LED0-- >PA.8 端口配置
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz
GPIO_Init(GPIOB, &GPIO_InitStructure); //根据设定参数初始化GPIOA.8
GPIO_ResetBits(GPIOB,GPIO_Pin_12); //PD.2 输出高
}
void Bit_0(void)
{
GPIO_SetBits(GPIOB,GPIO_Pin_12); //PB12 输出高
Delay_L();
GPIO_ResetBits(GPIOB,GPIO_Pin_12); //PB12 输出高
Delay_H();
}
void Bit_1(void)
{
GPIO_ResetBits(GPIOB,GPIO_Pin_12); //PB12 输出高
Delay_H();
GPIO_SetBits(GPIOB,GPIO_Pin_12); //PB12 输出高
Delay_L();
}
void RGB_Set(void)
{
for(uint8_t i = 0;i< 8;i++)
{
Bit_1();
}
for(uint8_t i = 0;i< 8;i++)
{
Bit_0();
}
for(uint8_t i = 0;i< 8;i++)
{
Bit_1();
}
// for(uint8_t i = 0;i< 24;i++)
// {
// delay_us(100);
// }
}
void Delay_L(void)
{
__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
}
void Delay_H(void)
{
__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
__nop();
}
全部0条评论
快来发表一下你的评论吧 !