打印
[USB芯片]

【CH32X035评估板测评】+ 教你使用PIOC端口驱动WS2812

[复制链接]
2830|2
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 袁胜富 于 2023-9-11 20:11 编辑

#申请原创# #有奖活动# #技术资源# #申请开发板#@21小管家
file:///C:/Users/hasee/AppData/Local/Temp/msohtmlclip1/01/clip_image001.png

一、概述  
         
CH32X035的PIOC是其众多MCU产品中的一个亮点,它可以做很多事情。引用手册:CH32X035 芯片内嵌了一个可编程协议 I/O 微控制器,该微控制器基于单时钟周期的专用精简指令集 RISC 内核,运行于系统主频,具有 2K 指令的程序 ROM 和 49 个 SFR 寄存器及 PWM 定时/计数器,支持 2 个 I/O 引脚的协议控制。从手册描述来看PIOC的结构就是一个定时器,可以输出PWM也可以捕获。在手册中没有关于PIOC的原理框图和相关寄存器说明,但是官方的SDK包里有关于PIOC的SFR.h头文件以及关于PIOC驱动WS2812和DS1820的例程。
本人就WS2812例程进行了二次封装,并且发现一些BUG,于是乎就有了本篇文章。


二、原理
           
从标准库文件来看PIOC外设挂载在AHB总线,使用系统时钟最大48Mz,PIOC在驱动WS2812时,如果使用48MHz,则需要56分频,约等于1.16us。如果使用24MHz,则需要28分频,约等于1.16us,也就是PIOC每发1bit数据需要1.16us周期。系统的时钟选择在system_ch32x035.c文件中选择,以下代码就是选择48MHz。//#define SYSCLK_FREQ_8MHz_HSI   8000000
//#define SYSCLK_FREQ_12MHz_HSI  12000000
//#define SYSCLK_FREQ_16MHz_HSI  16000000
//#define SYSCLK_FREQ_24MHz_HSI  24000000
#define SYSCLK_FREQ_48MHz_HSI  HSI_VALUE
因为PIOC复用了系统20KB的4KBSRAM,所以需要在Link.ld文件中修改一下,具体修改如图1所示。

图1
从手册来看,PIOC拥有两个IO口,分别是IO0和IO1,IO0连接PC18引脚,IO1连接在PC19引脚(复用在PC7引脚)。因为PC18和PC19分别是SWDIO和SWCLK下载引脚,所以感觉有点不太OK,会占用下载接口。
在初始化PC18作为IO0是,需要使用GPIO_PinRemapConfig(GPIO_Remap_SWJ_Disable, ENABLE);//禁用下载功能
禁用下载功能。
从例程中知道PIOC的RAM占3KB字节数据,也就是3072字节。
通过阅读WS2812的资料我们得知一个灯的数据由24bit组成,GRB中G占8位,R占8位,B占8位,G代表绿色,R代表红色,B代表蓝色,通过三种颜色可以显示出我们要的颜色。GRB顾名思义就是绿色占最低8位,红色占中间位,蓝色占最高8位,一颗灯珠驱动需要24bit数据,也就是3个字节,从PIOC来看RAM来看,3072/3=1024,意味着PIOC可以同时驱动1024个灯珠。
总结如下:PIOC要驱动WS2812需要按以下步骤进行配置和操作
将Link.ld文件的SRAM修改为16K;
修改系统时钟为24MHz(原因是48MHz第一个灯珠不亮).
因为PIOC的IO0占用下载口的SWDIO,需要使用USB下载。

三、代码
           
PIOC_WS2812.h
#ifndefWS2812_PIOC_WS2812_H_
#define WS2812_PIOC_WS2812_H_
#ifndef __SPI_DMA_WS2812_H
#define __SPI_DMA_WS2812_H
#include"ch32x035.h"
#include"PIOC_SFR.h"
#define USE_24MHZHSI  1
//RGB灯的数量
#define PIXEL_NUM1  2                                                          //灯带1灯数(组数)
#define PIXEL_NUM2  2                                                          //灯带2灯数(组数)
#define PIXEL_NUM3  2                                                          //灯带3灯数(组数)
#define PIXEL_NUM4  2                                                          //灯带4灯数(组数)
#define PIXEL_NUM  (PIXEL_NUM1+PIXEL_NUM2+PIXEL_NUM3+PIXEL_NUM4)//灯数统计
#define GRB  24   //3*8 //Red8位 Green8位 Blue8位加起来24位
#define     RGB1W_SFR_ADDR  ((uint8_t *)&(PIOC->D8_DATA_REG0))  //RGB1W特殊功能寄存器模式的数据缓冲器起始地址详见"PIOC_SFR.h"的PIOC_TypeDef结构体
#define     RGB1W_SFR_SIZE  32                                  //RGB1W特殊功能寄存器模式的数据缓冲器起始地址宽度
#define     RGB1W_RAM_ADDR  ((uint8_t *)(PIOC_SRAM_BASE+0x400)) //RGB1W随机访问存储器模式的数据缓冲器起始地址
#define     RGB1W_RAM_SIZE  ((uint8_t *)(PIOC_SRAM_BASE+0x1000)-RGB1W_RAM_ADDR) // RGB1W随机访问存储器模式的数据缓冲器起始地址宽度   3KB大小复用了4KB的系统SRAM
#define     RGB1W_FREQ_CFG  (0x000C*2)  //RGB1W的系统频率配置
#define     RGB1W_CYC_48M   56      //位周期系统频率48MHZ ,约等于1.16us每个周期
#define     RGB1W_CYC_24M   28      //位周期系统频率24MHZ ,约等于1.16us每个周期
#define     RGB1W_CMD_RAM   0x80    //通知PIOC从RAM发送数据
#define     RGB1W_COMMAND   (PIOC->D8_CTRL_WR)  //输入指令
// 1~RGB1W_SFR_SIZE: RGB SFR mode, 0x01-0x20: RGB with short data in SFR, low 7bits is total byte
// > RGB1W_CMD_RAM:  RGB RAM mode, 0x88-0xFC: RGB with long data in code RAM, low 7bits is RGB1W_CYC_*, bit7 is RGB1W_CMD_RAM
// 0x41: start temperature convert
// 0x42: get temperature data
// 0x43: start temperature convert then get data
#define     CMD_T_START     0x41    // start temperature convert
#define     CMD_T_GET       0x42    // get temperature data
#define     CMD_T_STA_GET   0x43    // start temperature convert then get data
#define     RGB1W_ERR_OK    0       // error code for success
#define     RGB1W_ERR_CMD   1       // error code for command error
#define     RGB1W_ERR_PARA  2       // error code for parameter error
#define     RGB1W_ERR_OUTH  4       // error code for pin high at the end
#define     RGB1W_ERR_PINH  6       // error code for pin high at the start
extern  __IO    uint8_t     stat;
externconstunsignedchar PIOC_1W_CODE[] __attribute__((aligned (4)));
voidPIOC_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
/*
      R      G      B
红: 255     0      0
黄: 255    255     0
绿:  0     255     0
青:  0     255    255
蓝:  0      0     255
紫: 255     0     255
白: 255    255    255
*/
typedefunion_rgbPixelBuffer
{
struct
    {
uint8_tPixelBuffer1[PIXEL_NUM1][GRB/8];
uint8_tPixelBuffer2[PIXEL_NUM2][GRB/8];
uint8_tPixelBuffer3[PIXEL_NUM3][GRB/8];
uint8_tPixelBuffer4[PIXEL_NUM4][GRB/8];
    }buff;
uint8_tBuffer[PIXEL_NUM][GRB/8];
uint8_tAll_Buffer[PIXEL_NUM*(GRB/8)];
}RGB_PixelBuffer;
externRGB_PixelBufferRGB_Buffer;
voidRGB1W_SendSFR( uint16_ttotal_bytes, uint8_t *p_source_addr );  //SFR mode for 1~32 bytes data
voidRGB1W_SendRAM( uint16_ttotal_bytes, uint8_t *p_source_addr );  //RAM mode for 1~3072 bytes data
uint8_tRGB1W_SendSFR_Wait( uint16_ttotal_bytes, uint8_t *p_source_addr );  //SFR mode for 1~32 bytes data
uint8_tRGB1W_SendRAM_Wait( uint16_ttotal_bytes, uint8_t *p_source_addr );  //RAM mode for 1~3072 bytes data
voidRGB1W_Halt( void );  //halt/sleep PIOC
voidWS281x_Init(void);
voidWS281x_CloseAll(void);
uint32_tWS281x_Color(uint8_t red, uint8_t green, uint8_t blue);
voidWS281x_SetPixelColor(uint16_t n, uint32_tGRBColor);
voidWS281x_SetPixelRGB(uint16_t n ,uint8_t red, uint8_t green, uint8_t blue);
voidWS281x_Show(void);
voidWS281x_RainbowCycle(uint8_t wait);
voidWS281x_TheaterChase(uint32_t c, uint8_t wait);
voidWS281x_ColorWipe(uint32_t c, uint8_t wait);
voidWS281x_Rainbow(uint8_t wait);
voidWS281x_TheaterChaseRainbow(uint8_t wait);
voidRGB_DEBUG_TEST(void);
#endif
#endif/* WS2812_PIOC_WS2812_H_ */
PIOC_WS2812.c
/*
* PIOC_WS2812.c
*
*  Created on: 2023年9月10日
*      Author: hasee
*/
#include"PIOC_WS2812.h"
#include<string.h>
#include"system_ch32x035.h"
RGB_PixelBufferRGB_Buffer;
__IO    uint8_t     stat;
voidPIOC_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
/*********************************************************************
* @fnPIOC_IRQHandler
*
* @brief   This function handles PIOC exception.
*
* @return  none
*/
voidPIOC_IRQHandler( void )
{
//  uint8_t stat;
    stat = PIOC->D8_CTRL_RD;//auto remove interrupt request after reading
//  if ( stat == RGB1W_ERR_OK ) printf("1-wire finished\r\n");
//  else printf("1-wire error %02x\r\n", stat);
//  temper = PIOC->D16_DATA_REG0_1;//for DS1820 only
}
constunsignedchar PIOC_1W_CODE[] ={
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x16,0x60,0x00,0x00,0x00,0x00,0x00,0x00,   /* .........`...... */
    0x00,0x00,0x0A,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,   /* ...p............ */
    0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x00,0x00,0x1C,0x5E,0x1C,0x47,   /* ......0......^.G */
    0x1C,0x5D,0x16,0x60,0x1C,0x47,0x1E,0x02,0x09,0x10,0x31,0xC1,0x3E,0xC2,0x34,0xC3,   /* .].`.G....1.>.4. */
    0x2F,0x80,0x20,0x2F,0x41,0x38,0x87,0x2F,0x2F,0x38,0xFC,0x2F,0x93,0x38,0x00,0x00,   /* ....A8...8...8.. */
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x28,   /* ...............( */
    0x8E,0x60,0x00,0x00,0x2C,0x71,0x8E,0x60,0x00,0x00,0x2C,0x71,0x8E,0x30,0x4B,0x24,   /* .`..,q.`..,q.0K$ */
    0x28,0x22,0xE9,0x70,0x04,0x15,0x39,0x30,0x09,0x15,0x38,0x30,0x00,0x00,0x38,0x71,   /* (".p..90..80..8q */
    0x8E,0x60,0x00,0x00,0x08,0x01,0x0B,0x40,0x0A,0x48,0x0C,0x01,0x06,0x28,0x0B,0x54,   /* .`.....@.H...(.T */
0x8E,0x60,0x09,0x02,0x04,0x10,0x20,0x24,0x00,0x00,0x0B,0x48,0x0B,0x70,0x01,0x5F,   /* .`.....$...H.p._ */
    0x0B,0x40,0x08,0x70,0x0B,0x40,0x0A,0x70,0x0B,0x48,0x0B,0x70,0x01,0x5E,0x0B,0x40,   /* .@.p.@.p.H.p.^.@ */
    0x08,0x70,0x0B,0x40,0x0A,0x70,0x0B,0x48,0x0B,0x70,0x01,0x5D,0x0B,0x40,0x08,0x70,   /* .p.@.p.H.p.].@.p */
    0x0B,0x40,0x0A,0x70,0x0B,0x48,0x0B,0x70,0x01,0x5C,0x0B,0x40,0x08,0x70,0x0B,0x40,   /* .@.p.H.p.\.@.p.@ */
    0x0A,0x70,0x0B,0x48,0x0B,0x70,0x01,0x5B,0x0B,0x40,0x08,0x70,0x0B,0x40,0x0A,0x70,   /* .p.H.p.[.@.p.@.p */
    0x0B,0x48,0x0B,0x70,0x01,0x5A,0x0B,0x40,0x08,0x70,0x0B,0x40,0x0A,0x70,0x0B,0x48,   /* .H.p.Z.@.p.@.p.H */
    0x0B,0x70,0x01,0x59,0x0B,0x40,0x08,0x70,0x0B,0x40,0x0A,0x70,0x0B,0x48,0x0B,0x70,   /* .p.Y.@.p.@.p.H.p */
    0x01,0x58,0x0B,0x40,0x09,0x70,0x01,0x02,0x0B,0x40,0x0D,0x70,0x04,0x15,0x4D,0x30,   /* .X.@.p...@.p..M0 */
    0x1E,0x28,0xEE,0x70,0xEE,0x70,0x04,0x00,0x0B,0x54,0x04,0x28,0x1D,0x10,0x1C,0x4F,   /* .(.p.p...T.(...O */
    0x16,0x60,0x02,0x28,0x8E,0x60,0x00,0x00,0x08,0x01,0x0B,0x40,0x80,0x28,0x0C,0x10,   /* .`.(.`.....@.(.. */
    0x20,0x02,0x21,0x0A,0x91,0x34,0x0A,0x48,0x09,0x47,0x3E,0x01,0x04,0x01,0x06,0x28,   /* ..!..4.H.G>....( */
    0x0B,0x54,0x8E,0x60,0x02,0x28,0x3F,0x10,0x18,0x00,0x1F,0x10,0x80,0x29,0x09,0x0A,   /* .T.`.(?......).. */
    0x00,0x00,0x08,0x10,0x13,0x00,0xAE,0x00,0x13,0x00,0xAD,0x00,0x13,0x00,0xAC,0x00,   /* ................ */
    0x13,0x00,0xAB,0x00,0x13,0x00,0xAA,0x00,0x13,0x00,0x20,0x15,0x20,0x04,0x03,0x52,   /* ...............R */
    0x21,0x15,0xA9,0x00,0x13,0x00,0x20,0x02,0x21,0x0A,0xE3,0x34,0xA8,0x00,0x13,0x00,   /* !.......!..4.... */
    0x04,0x02,0x1F,0x10,0xAF,0x00,0x13,0x00,0xAE,0x00,0x13,0x00,0xAD,0x00,0x13,0x00,   /* ................ */
    0xAC,0x00,0x13,0x00,0x20,0x15,0x20,0x04,0x03,0x52,0x21,0x15,0xAB,0x00,0x13,0x00,   /* .........R!..... */
    0x3E,0x14,0x03,0x52,0x3F,0x14,0xAA,0x00,0x13,0x00,0x3E,0x02,0x04,0x10,0xA9,0x00,   /* >..R?.....>..... */
    0x13,0x00,0x20,0x02,0x21,0x0A,0xE3,0x34,0x3F,0x02,0xA8,0x00,0x13,0x00,0x18,0x00,   /* ....!..4?....... */
    0x1F,0x10,0xAF,0x00,0xAA,0x60,0xA8,0x00,0x12,0x00,0x13,0x00,0x12,0x00,0x08,0x01,   /* .....`.......... */
    0x88,0x60,0xFA,0x28,0xEE,0x60,0x41,0x28,0xEE,0x60,0x02,0x28,0x0D,0x70,0x00,0x00,   /* .`.(.`A(.`.(.p.. */
    0x0D,0x70,0x00,0x00,0x0D,0x70,0x00,0x00,0x0D,0x70,0x00,0x00,0xFF,0x2C,0x00,0x00,   /* .p...p...p...,.. */
    0xEE,0x30,0x30,0x00,0x0A,0x40,0x08,0x01,0x0C,0x01,0x05,0x28,0xEE,0x70,0x0B,0x40,   /* .00..@.....(.p.@ */
    0x0A,0x48,0xE9,0x70,0xE9,0x70,0x0A,0x40,0xEB,0x70,0x09,0x01,0x0B,0x54,0x04,0x24,   /* .H.p.p.@.p...T.$ */
    0xE9,0x70,0x09,0x02,0x30,0x00,0x09,0x10,0x08,0x22,0x0B,0x40,0x0A,0x48,0xED,0x70,   /* .p..0....".@.H.p */
    0x09,0x50,0x0A,0x40,0xEB,0x70,0x0A,0x40,0x05,0x28,0x09,0x58,0xEE,0x70,0x09,0x1F,   /* .P.@.p.@.(.X.p.. */
    0x04,0x15,0x0D,0x31,0x30,0x00,0x08,0x22,0x0B,0x40,0x0A,0x48,0xED,0x70,0x0A,0x40,   /* ...10..".@.H.p.@ */
    0x0A,0x28,0xEE,0x70,0x09,0x1F,0x09,0x47,0x0B,0x54,0x09,0x4F,0x37,0x28,0xEE,0x70,   /* .(.p...G.T.O7(.p */
    0x04,0x15,0x1C,0x31,0x09,0x02,0x30,0x00,0xFA,0x70,0x37,0x31,0xCC,0x28,0x0B,0x71,   /* ...1..0..p71.(.q */
    0x44,0x28,0x0B,0x71,0x1C,0x5C,0x36,0x61,0x0B,0x48,0x0A,0x48,0x04,0x00,0x30,0x00,   /* D(.q.\6a.H.H..0. */
    0xFA,0x70,0x43,0x31,0xCC,0x28,0x0B,0x71,0xBE,0x28,0x0B,0x71,0x1B,0x71,0x20,0x10,   /* .pC1.(.q.(.q.q.. */
    0x1B,0x71,0x21,0x10,0xFA,0x70,0x30,0x00,0x00,0x00};    /* .q!..p0... */
voidRGB1W_Init ( void )
{
GPIO_InitTypeDefGPIO_InitStructure = {0};
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOC, ENABLE);
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_IO2W, ENABLE);
#if 1  //PC18
GPIO_PinRemapConfig(GPIO_Remap_SWJ_Disable, ENABLE);//禁用下载功能
GPIO_SetBits(GPIOC, GPIO_Pin_18);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_18;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC, &GPIO_InitStructure);
#else//PC7
GPIO_PinRemapConfig(GPIO_Remap_PIOC, ENABLE);
GPIO_SetBits(GPIOC, GPIO_Pin_7);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC, &GPIO_InitStructure);
#endif
//  PIOC->D8_SYS_CFG = 0;//停止
    PIOC->D8_SYS_CFG = RB_MST_RESET | RB_MST_IO_EN0;    //复位PIOC并且使能IO0
memcpy( (uint8_t *)(PIOC_SRAM_BASE), PIOC_1W_CODE, sizeof( PIOC_1W_CODE ) );// PIOC装载代码
#ifUSE_24MHZHSI
    RGB1W_COMMAND = RGB1W_CYC_24M | RGB1W_CMD_RAM;// set bit cycle and PIOC start send
#else// default is 48MHz
    RGB1W_COMMAND = RGB1W_CYC_48M | RGB1W_CMD_RAM;// set bit cycle and PIOC start send
#endif
NVIC_EnableIRQ(PIOC_IRQn);//enable interrupt
NVIC_SetPriority(PIOC_IRQn,0xf0);
}
/*********************************************************************
* @fn      RGB1W_SendSFR
*
* @brief   SFR mode for 1~32 bytes data.
*
* @paramtotal_bytes - total data number(byte).
*          p_source_addr - data.
*
* @return  none
*/
voidRGB1W_SendSFR( uint16_ttotal_bytes, uint8_t *p_source_addr ) {//SFR mode for 1~32 bytes data
// p_source_addr: point source data buffer start address, set NULL if copy into PIOC buffer already
if ( total_bytes > RGB1W_SFR_SIZE ) return;
    PIOC->D8_SYS_CFG = RB_MST_RESET | RB_MST_IO_EN0;//clear&halt PIOC
    PIOC->D8_SYS_CFG = RB_MST_CLK_GATE | RB_MST_IO_EN0;//run PIOC before write SFR
if ( p_source_addr ) memcpy( RGB1W_SFR_ADDR, p_source_addr, total_bytes );//copy source data to RGB1W SFR, @PIOC run
    RGB1W_COMMAND = (uint8_t)total_bytes;// PIOC start send
}
/*********************************************************************
* @fn      RGB1W_SendRAM
*
* @brief   RAM mode for 1~3072 bytes data.
*
* @paramtotal_bytes - total data number(byte).
*          p_source_addr - data.
*
* @return  none
*/
voidRGB1W_SendRAM( uint16_ttotal_bytes, uint8_t *p_source_addr ) {//RAM mode for 1~3072 bytes data
// p_source_addr: point source data buffer start address, set NULL if copy into PIOC buffer already
if ( total_bytes > RGB1W_RAM_SIZE ) return;
    PIOC->D8_SYS_CFG = RB_MST_RESET | RB_MST_IO_EN0;//clear&halt PIOC
if ( p_source_addr ) memcpy( RGB1W_RAM_ADDR, p_source_addr, total_bytes );//copy source data to PIOC SRAM, @PIOC halt
    PIOC->D8_SYS_CFG = RB_MST_CLK_GATE | RB_MST_IO_EN0;//run PIOC after load data in SRAM
    PIOC->D16_DATA_REG0_1 = total_bytes;// data size
#ifUSE_24MHZHSI
    RGB1W_COMMAND = RGB1W_CYC_24M | RGB1W_CMD_RAM;// set bit cycle and PIOC start send
#else// default is 48MHz
    RGB1W_COMMAND = RGB1W_CYC_48M | RGB1W_CMD_RAM;// set bit cycle and PIOC start send
#endif
}
/*********************************************************************
* @fn      RGB1W_SendSFR_Wait
*
* @brief   SFR mode for 1~3072 bytes data wait PIOC operate finish.
*
* @paramtotal_bytes - total data number(byte).
*          p_source_addr - data.
*
* @return  none
*/
uint8_tRGB1W_SendSFR_Wait( uint16_ttotal_bytes, uint8_t *p_source_addr ) {//SFR mode for 1~32 bytes data
// p_source_addr: point source data buffer start address, set NULL if copy into PIOC buffer already
if ( total_bytes == 0 || total_bytes > RGB1W_SFR_SIZE ) return( RGB1W_ERR_PARA );
    RGB1W_SendSFR( total_bytes, p_source_addr );
while ( ( PIOC->D8_SYS_CFG & RB_INT_REQ ) == 0 );//wait, PIOC request interrupt after finish
return( PIOC->D8_CTRL_RD );//auto remove interrupt request after reading
}
/*********************************************************************
* @fn      RGB1W_SendRAM_Wait
*
* @brief   RAM mode for 1~3072 bytes data wait PIOC operate finish.
*
* @paramtotal_bytes - total data number(byte).
*          p_source_addr - data.
*
* @return  none
*/
uint8_tRGB1W_SendRAM_Wait( uint16_ttotal_bytes, uint8_t *p_source_addr ) {//RAM mode for 1~3072 bytes data
// p_source_addr: point source data buffer start address, set NULL if copy into PIOC buffer already
if ( total_bytes == 0 || total_bytes > RGB1W_RAM_SIZE ) return( RGB1W_ERR_PARA );
    RGB1W_SendRAM( total_bytes, p_source_addr );
while ( ( PIOC->D8_SYS_CFG & RB_INT_REQ ) == 0 );//wait, PIOC request interrupt after finish
return( PIOC->D8_CTRL_RD );//auto remove interrupt request after reading
}
/*********************************************************************
* @fn      RGB1W_Halt
*
* @brief   halt/sleep PIOC .
*
* @return  none
*/
voidRGB1W_Halt( void ) {//halt/sleep PIOC
    PIOC->D8_SYS_CFG &= ~ RB_MST_CLK_GATE;
}
voidWS281x_Init(void)
{
    RGB1W_Init( );
    stat = 0x80;    //free
    WS281x_CloseAll();
}
#definetimer_to_run            1   // start by timer
voidWS281x_Show(void)
{
uint16_ttotal_bytes;
uint8_t* RGB_RAM;
total_bytes = sizeof(RGB_Buffer.All_Buffer);
    stat = 0x80;//free
if ( stat != 0xFF ) {//RGB1W completed
if ( stat < 0x80 ) {//got status in interrupt
if ( stat == RGB1W_ERR_OK ) printf("1-wire finished\r\n")/**/;
elseprintf("1-wire error %02x\r\n", stat)/* */;
            stat = 0x80;//free
        }
if ( stat == 0x80 && total_bytes && timer_to_run ) {//RAM mode for 1~3072 bytes data
            stat = 0xFF;//wait
            RGB_RAM = RGB_Buffer.All_Buffer;
            RGB1W_SendRAM( total_bytes, RGB_RAM );
total_bytes = 0;
        }
    }
if ( PIOC->D8_SYS_CFG & RB_INT_REQ ) {//query if disable interrupt
        stat = PIOC->D8_CTRL_RD;//auto remove interrupt request after reading
    }
}
//配置完成之后便可以构思底层控制函数了,为了方便多个LED灯珠的可控制首先要定义一个缓冲区pixelBuffer[PIXEL_NUM][24]\
通过设定颜色将数据填入缓冲区再通过更新函数将数据传入到LED灯珠上。
//关闭所有灯珠
voidWS281x_CloseAll(void)
{
uint16_ti;
for(i = 0; i < PIXEL_NUM*(GRB/8); ++i)
  {
RGB_Buffer.All_Buffer = 0X00;
  }
  WS281x_Show();
}
uint32_tWS281x_Color(uint8_t red, uint8_t green, uint8_t blue)
{
return green << 16 | red << 8 | blue;
}
voidWS281x_SetPixelColor(uint16_t n, uint32_tGRBColor)
{
RGB_Buffer.Buffer[n][0] = (GRBColor>>16)&0X000000FF;//绿色值
RGB_Buffer.Buffer[n][1] = (GRBColor>>8)&0X000000FF;//红色值
RGB_Buffer.Buffer[n][2] = (GRBColor)&0X000000FF;//蓝色值
}
voidWS281x_SetPixelRGB(uint16_t n ,uint8_t red, uint8_t green, uint8_t blue)
{
RGB_Buffer.Buffer[n][0] = green;//绿色值
RGB_Buffer.Buffer[n][1] = red;//红色值
RGB_Buffer.Buffer[n][2] = blue;//蓝色值
}
// Input a value 0 to 255 to get a color value.
// The colours are a transition r - g - b - back to r.
uint32_tWS281x_Wheel(uint8_twheelPos) {
wheelPos = 255 - wheelPos;
if(wheelPos < 85) {
return WS281x_Color(255 - wheelPos * 3, 0, wheelPos * 3);
  }
if(wheelPos < 170) {
wheelPos -= 85;
return WS281x_Color(0, wheelPos * 3, 255 - wheelPos * 3);
  }
wheelPos -= 170;
return WS281x_Color(wheelPos * 3, 255 - wheelPos * 3, 0);
}
// Fill the dots one after the other with a color
voidWS281x_ColorWipe(uint32_t c, uint8_t wait) {
for(uint16_ti=0; i<PIXEL_NUM; i++) {
    WS281x_SetPixelColor(i, c);
    WS281x_Show();
Delay_Ms(wait);
  }
}
voidWS281x_Rainbow(uint8_t wait) {
uint16_ti, j;
for(j=0; j<256; j++) {
for(i=0; i<PIXEL_NUM; i++) {
      WS281x_SetPixelColor(i, WS281x_Wheel((i+j) & 255));
    }
    WS281x_Show();
Delay_Ms(wait);
  }
}
// Slightly different, this makes the rainbow equally distributed throughout
voidWS281x_RainbowCycle(uint8_t wait) {
uint16_ti, j;
for(j=0; j<256*5; j++) { // 5 cycles of all colors on wheel
for(i=0; i< PIXEL_NUM; i++) {
      WS281x_SetPixelColor(i,WS281x_Wheel(((i * 256 / PIXEL_NUM) + j) & 255));
    }
    WS281x_Show();
Delay_Ms(wait);
  }
}
//Theatre-style crawling lights.
voidWS281x_TheaterChase(uint32_t c, uint8_t wait) {
for (int j=0; j<10; j++) {  //do 10 cycles of chasing
for (int q=0; q < 3; q++) {
for (uint16_ti=0; i < PIXEL_NUM; i=i+3) {
        WS281x_SetPixelColor(i+q, c);    //turn every third pixel on
      }
      WS281x_Show();
Delay_Ms(wait);
for (uint16_ti=0; i < PIXEL_NUM; i=i+3) {
        WS281x_SetPixelColor(i+q, 0);        //turn every third pixel off
      }
    }
  }
}
//Theatre-style crawling lights with rainbow effect
voidWS281x_TheaterChaseRainbow(uint8_t wait) {
for (int j=0; j < 256; j++) {     // cycle all 256 colors in the wheel
for (int q=0; q < 3; q++) {
for (uint16_ti=0; i < PIXEL_NUM; i=i+3) {
        WS281x_SetPixelColor(i+q, WS281x_Wheel( (i+j) % 255));    //turn every third pixel on
      }
      WS281x_Show();
Delay_Ms(wait);
for (uint16_ti=0; i < PIXEL_NUM; i=i+3) {
        WS281x_SetPixelColor(i+q, 0);        //turn every third pixel off
      }
    }
  }
}
// Slightly different, this makes the rainbow equally distributed throughout
voidWS2812_RainbowRotate(uint16_t wait) {
uint16_ti, j;
for (j = 0; j < 256 * 5; j++) { // 5 cycles of all colors on wheel
for (i = 0; i < PIXEL_NUM; i++) {
            WS281x_SetPixelColor(i,  WS281x_Wheel(((i * 256 / PIXEL_NUM) + j) & 255));
        }
        WS281x_Show();
Delay_Ms(wait);
    }
}
//hsv和rgb互相转
floatretmax(float a, float b, float c)                            //求最大值
{
float max = 0;
    max = a;
if (max < b)
        max = b;
if (max < c)
        max = c;
return max;
}
floatretmin(float a, float b, float c)                            //求最小值
{
float min = 0;
    min = a;
if (min > b)
        min = b;
if (min > c)
        min = c;
return min;
}
//R,G,B参数传入范围(0~100)
//转换结果h(0~360),s(0~100),v(0~100)
voidrgb_to_hsv(uint16_t *H, uint16_t *S, uint16_t *V, uint8_t r, uint8_t g, uint8_t b) {
float max = 0, min = 0;
float R = (float)r;
float G = (float)g;
float B = (float)b;
float h, s, v;
    R = R / 255.0;
    G = G / 255.0;
    B = B / 255.0;
    max = retmax(R, G, B);
    min = retmin(R, G, B);
    v = max;
if (max == 0)
        s = 0;
else
        s = 1 - (min / max);
if (max == min)
        h = 0;
elseif (max == R && G >= B)
        h = 60 * ((G - B) / (max - min));
elseif (max == R && G < B)
        h = 60 * ((G - B) / (max - min)) + 360;
elseif (max == G)
        h = 60 * ((B - R) / (max - min)) + 120;
elseif (max == B)
        h = 60 * ((R - G) / (max - min)) + 240;
    v = v * 100;
    s = s * 100;
    *H = (int) h;
    *S = (int) s;
    *V = (int) v;
}
//参数入参范围h(0~360),s(0~100),v(0~100),这里要注意,要把s,v缩放到0~1之间
//转换结果R(0~100),G(0~100),B(0~100),如需转换到0~255,只需把后面的乘100改成乘255
voidhsv_to_rgb(int h, int s, int v, uint8_t *r, uint8_t *g, uint8_t *b) {
float C = 0, X = 0, Y = 0, Z = 0;
inti = 0;
float H = (float) (h);
float S = (float) (s) / 100.0;
float V = (float) (v) / 100.0;
float R, G, B;
if (S == 0)
        R = G = B = V;
else {
        H = H / 60;
i = (int) H;
        C = H - i;
        X = V * (1 - S);
        Y = V * (1 - S * C);
        Z = V * (1 - S * (1 - C));
switch (i) {
case 0:
            R = V;
            G = Z;
            B = X;
break;
case 1:
            R = Y;
            G = V;
            B = X;
break;
case 2:
            R = X;
            G = V;
            B = Z;
break;
case 3:
            R = X;
            G = Y;
            B = V;
break;
case 4:
            R = Z;
            G = X;
            B = V;
break;
case 5:
            R = V;
            G = X;
            B = Y;
break;
        }
    }
    R = R * 255;
    G = G * 255;
    B = B * 255;
    *r = (int) R;
    *g = (int) G;
    *b = (int) B;
}
voidRGB_DEBUG_TEST(void)
{
inti,j;
for(i=0;i<3;i++)
    {
for(j=0;j<8;j++)
        {
if(i==0)
            {
                WS281x_ColorWipe(WS281x_Color(255, 0, 0), 2); // Red
            }
elseif(i==1)
            {
                WS281x_ColorWipe(WS281x_Color(0, 255, 0), 2); // Green
            }
else
            {
                WS281x_ColorWipe(WS281x_Color(0, 0, 0), 2); // Blue
            }
        }
    }
    WS2812_RainbowRotate(2);
// Some example procedures showing how to display to the pixels:
    WS281x_ColorWipe(WS281x_Color(255, 0, 0), 2); // Red
    WS281x_ColorWipe(WS281x_Color(0, 255, 0), 2); // Green
    WS281x_ColorWipe(WS281x_Color(0, 0, 255), 2); // Blue
    WS281x_TheaterChase(WS281x_Color(127, 127, 127), 2); // White
    WS281x_TheaterChase(WS281x_Color(127, 0, 0), 2); // Red
    WS281x_TheaterChase(WS281x_Color(0, 0, 127), 2); // Blue
    WS281x_Rainbow(2);
    WS281x_RainbowCycle(2);
    WS281x_TheaterChaseRainbow(2);
}
Main.c
#include"PIOC_WS2812.h"
/*********************************************************************
* @fn      main
*
* @brief   Main program.
*
* @return  none
*/
intmain(void)
{
    Delay_Init();
    Delay_Ms(1000);
    Delay_Ms(1000);
   USART_Printf_Init(115200);
   printf("SystemClk:%d\r\n", SystemCoreClock);
   printf( "ChipID:%08x\r\n", DBGMCU_GetCHIPID() );
    printf("PIOC WS2812 Test\r\n");
    WS281x_Init( );
    stat = 0x80;    //free
    while ( 1 )
    {
        WS281x_SetPixelRGB(0,0,255,0);//第一颗灯珠显示蓝色
        WS281x_Show();//显示
        Delay_Ms(200);
        RGB_DEBUG_TEST();//测试彩虹效果
        WS281x_ColorWipe(WS281x_Color(255, 0, 0), 2); // 全部显示红色
        Delay_Ms(1000);
        WS281x_ColorWipe(WS281x_Color(0, 255, 0), 2); // 全部显示绿色
        Delay_Ms(1000);
        WS281x_ColorWipe(WS281x_Color(0, 0, 255), 2); // 全部显示蓝色
        Delay_Ms(1000);
    }
}



四、展示
       BiliBili链接:【CH32X035C8T6PIOC外设驱动WS2812-哔哩哔哩】 https://b23.tv/2PHiz5b




五、心得与体会

    总的来看CH32X035的外设来看还是很丰富的,在PIOC这个外设来看,还是很有优势的,之前驱动WS2812的方案主要是PWM+DMASPI+DMA的。在今看来还多了一个PIOC驱动。
       其次就是WCH的芯片开发库函数基本的都是兼容的,不同系列的芯片相互移植还是非常快的。
       谢谢大家,如有不当之处,还望不吝赐教。
   

CH32X035C8T6_WS2812.zip

556.95 KB

使用特权

评论回复
沙发
LIzs6| | 2023-9-11 16:42 | 只看该作者
又一种新的驱动WS2812的方式,跟着学习一下

使用特权

评论回复
板凳
forgot| | 2023-9-14 08:48 | 只看该作者
赞一下,非常好的测评,我的板子也收到了,先来学习一下

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

29

主题

147

帖子

2

粉丝