【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,

image

再有时序定义如下:0码由T0H和T0L组成,1码也差不多,RESET码是断帧码,断帧就是第几个灯珠停止,点亮几颗灯的意思;

image

最后是数据结构,如下,一个灯珠的数据由24bit的GRB组成,N个24bit的GRB点亮N个灯珠,最后Reset断帧,其中1个bit如果是二进制的1,那么时序对应的是1码,反之是0码;

image

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切换;

posted @ 2022-09-08 21:12  LiJin_hh  阅读(1356)  评论(0编辑  收藏  举报