【WS2812驱动ch582板】基于CH582使用IO模拟时序驱动WS2812,实现红绿蓝切换
【WS2812驱动ch582板】基于CH582使用IO模拟时序驱动WS2812,实现红绿蓝切换
1.背景
选择IO口驱动WS2812实属无奈,事情是这样的,本来想使用TIM PWM+DMA的方式,但是画板子的时候选择了CH582的第14pin,即PB7 PWM9模式,按理说PWM模式没有DMA问题也不大嘛,但是事情不是这样的,因为这个PWM模式,他的周期只能选择如下几种;
typedef enum
{
PWMX_Cycle_256 = 0, // 256 个PWMX周期
PWMX_Cycle_255, // 255 个PWMX周期
PWMX_Cycle_128, // 128 个PWMX周期
PWMX_Cycle_127, // 127 个PWMX周期
PWMX_Cycle_64, // 64 个PWMX周期
PWMX_Cycle_63, // 63 个PWMX周期
PWMX_Cycle_32, // 32 个PWMX周期
PWMX_Cycle_31, // 31 个PWMX周期
} PWMX_CycleTypeDef;
并且我们的主频是60M,选择分频系数为1不分频,最后算出来1码没有达到800K,尝试了好几种配置,能点亮红色,绿色,蓝色不亮;
2. WS2812B驱动原理
通过阅读规格书,如下图所示,可以知道WS2812B的数据刷新率为800K,
再有时序定义如下:0码由T0H和T0L组成,1码也差不多,RESET码是断帧码,断帧就是第几个灯珠停止,点亮几颗灯的意思;
最后是数据结构,如下,一个灯珠的数据由24bit的GRB组成,N个24bit的GRB点亮N个灯珠,最后Reset断帧,其中1个bit如果是二进制的1,那么时序对应的是1码,反之是0码;
3. 代码实现:
这里我们直接上代码,其中Set0Code和Set1Code是基于1码和0码的时序用示波器调出来的,这里就介绍方法不介绍过程了;方法是直接调用SendOneFrame(0xFF);全发1码驱动1码,确定0码是发SendOneFrame(0x00),看高低电平即可;
/********************************** (C) COPYRIGHT *******************************
* File Name : Main.c
* Author : Li
* Version : V1.0
* Date : 2022/09/07
* Description : IO驱动WS281X彩灯功能演示
* Copyright (c) 2022 Guangzhou Liandun Electronic Technology Co., LTD.
* SPDX-License-Identifier: Apache-2.0
*******************************************************************************/
#include "CH58x_common.h"
#define SNUM 1//灯珠数量
//缓存区
unsigned char buf[SNUM][3]={
0
};
//发0码
void Set0Code(void) {
GPIOB_SetBits(GPIO_Pin_7);
__nop();
__nop();
GPIOB_ResetBits(GPIO_Pin_7);
// NOP();
}
//发1码
void Set1Code(void) {
GPIOB_SetBits(GPIO_Pin_7);
__nop();
__nop();
__nop();
__nop();
__nop();
__nop();
__nop();
__nop();
GPIOB_ResetBits(GPIO_Pin_7);
}
//发一个像素
void SendOnePix(unsigned char *ptr) {
unsigned char i, j;
unsigned char temp;
for (j = 0; j < 3; j++) {
temp = ptr[j];
for (i = 0; i < 8; i++) {
if (temp & 0x80) //从高位开始发送
{
Set1Code();
} else //发送“0”码
{
Set0Code();
}
temp = (temp << 1); //左移位
}
}
}
//发一帧数据
void SendOneFrame(unsigned char *ptr) {
uint16_t k;
// PWM_RGB=0;//发送帧复位信号
// DelayMs(1);
for (k = 0; k < SNUM; k++) //发送一帧数据,SNUM是板子LED的个数
{
SendOnePix(&ptr[(3 * k)]);
}
GPIOB_ResetBits(GPIO_Pin_7); //发送帧复位信号
}
/*********************************************************************
* @fn main
*
* @brief 主函数
*
* @return none
*/
int main() {
SetSysClock(CLK_SOURCE_PLL_60MHz);
/* 配置GPIO */
GPIOB_ModeCfg(GPIO_Pin_7, GPIO_ModeOut_PP_20mA); // PB7 - PWM9
while(1)
{
//Red
buf[0][0]=0xFF;
buf[0][1]=0x00;
buf[0][2]=0x00;
SendOneFrame(buf);
DelayMs(1000);
//Green
buf[0][0]=0x00;
buf[0][1]=0xFF;
buf[0][2]=0x00;
SendOneFrame(buf);
DelayMs(1000);
//Blue
buf[0][0]=0x00;
buf[0][1]=0x00;
buf[0][2]=0xFF;
SendOneFrame(buf);
DelayMs(1000);
}
}
4.下载验证:
可以看到RGB大约1ms切换;