首先是WS2812引脚初始化代码,这点和其他配置GPIO代码相同
void WS2812_PinInit(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOB,&GPIO_InitStructure);
WS2812_Reset();
}
其次是要向WS2812发送数据,我们看一下WS2812时序要求
可以看到WS2812对时间要求比较严格,我们来操作GPIO
首先如果直接调用库函数中的GPIO_SetBits()和GPIO_ResetBits()函数
我们来试一下
int main(void)
{
WS2812_PinInit();
while(1)
{
GPIO_SetBits(GPIOB,GPIO_Pin_11);
GPIO_ResetBits(GPIOB,GPIO_Pin_11);
}
}
可以看到,单片机主频72MHz才堪堪达到要求,如果更换其他型号主频较低的单片机,可能就达不到要求了
我们打开GPIO_SetBits()和GPIO_ResetBits()函数
void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
{
assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
assert_param(IS_GPIO_PIN(GPIO_Pin));
GPIOx->BSRR = GPIO_Pin;
}
void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
{
assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
assert_param(IS_GPIO_PIN(GPIO_Pin));
GPIOx->BRR = GPIO_Pin;
}
其中,assert_param()函数在这里的作用是检查GPIO_SetBits库函数传入的参数是否为真,如果为真,就什么也不执行,如果为假,就会在源程序编译的时候报错!
而GPIOx->BSRR = GPIO_Pin;就是操作GPIO引脚设置高电平
GPIOx->BRR = GPIO_Pin; 就是操作GPIO引脚设置低电平
那么,具体怎么操作呢
int main(void)
{
WS2812_PinInit();
while(1)
{
GPIOB->BSRR = GPIO_Pin_11; //拉高PB11
GPIOB->BRR = GPIO_Pin_11; //拉低PB11
}
}
可以看到,高电平时间由原来的约160us变为了现在的约40us
接下来就开始向WS2812发送 ‘0’ 码
int main(void)
{
WS2812_PinInit();
while(1)
{
GPIOB->BSRR = GPIO_Pin_11;//拉高PB11
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
GPIOB->BRR = GPIO_Pin_11;//拉低PB11
}
}
可以看到,在添加12个nop函数后,高电平时序大概能满足要求了
接下来就是满足低电平的时间
int main(void)
{
WS2812_PinInit();
while(1)
{
GPIOB->BSRR = GPIO_Pin_11;//拉高PB11
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
GPIOB->BRR = GPIO_Pin_11;//拉低PB11
__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();
}
}
低电平延时大概30个nop
接下来就是 ‘1’ 码
int main(void)
{
WS2812_PinInit();
while(1)
{
GPIOB->BSRR = GPIO_Pin_11;//拉高PB11
__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();
GPIOB->BRR = GPIO_Pin_11;//拉低PB11
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
}
}
因为要合并两个函数,所以预留了一点时间
接下来合并函数
void WS2812_SendBit(uint8_t Bit);
int main(void)
{
WS2812_PinInit();
while(1)
{
WS2812_SendBit(1);
WS2812_SendBit(0);
}
}
void WS2812_SendBit(uint8_t Bit)
{
GPIOB->BSRR = GPIO_Pin_11;//拉高PB11
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
if(Bit != 0)
GPIOB->BRR = GPIO_Pin_11;//拉低PB11
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
GPIOB->BRR = GPIO_Pin_11;//拉低PB11
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
}
可以看到,波形是可以满足时序要求的
接下来就是向WS2812发送 3 字节的RGB数据
需要注意的是,WS2812数据发送顺序是G R B,也就是绿色在前,然后是红色,蓝色。而不是红色,绿色,蓝色
void WS2812_SendRGB(uint8_t R,uint8_t G,uint8_t B);
int main(void)
{
WS2812_PinInit();
WS2812_SendRGB(50,0,0);
while(1)
{
}
}
void WS2812_SendRGB(uint8_t R,uint8_t G,uint8_t B)
{
for(int i = 0;i < 8;i ++) //发送8位绿色数据
{
GPIOB->BSRR = GPIO_Pin_11;//拉高PB11
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
if((G & (0x80 >> i)) == 0)
GPIOB->BRR = GPIO_Pin_11;//拉低PB11
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
GPIOB->BRR = GPIO_Pin_11;//拉低PB11
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
}
for(int i = 0;i < 8;i ++) //发送8位红色数据
{
GPIOB->BSRR = GPIO_Pin_11;//拉高PB11
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
if((R & (0x80 >> i)) == 0)
GPIOB->BRR = GPIO_Pin_11;//拉低PB11
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
GPIOB->BRR = GPIO_Pin_11;//拉低PB11
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
}
for(int i = 0;i < 8;i ++) //发送8位蓝色数据
{
GPIOB->BSRR = GPIO_Pin_11;//拉高PB11
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
if((B & (0x80 >> i)) == 0)
GPIOB->BRR = GPIO_Pin_11;//拉低PB11
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
GPIOB->BRR = GPIO_Pin_11;//拉低PB11
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
}
}
可以看到,这颗灯珠已经可以被点亮了
|