WS2812内置IC通过一根数据线即可控制多个灯珠的RGB颜色变化,时序如下图
通常驱动都是手动控制IO电平和延时,或者借助SPI外设,但是在Ai-M61-32S所用的BL616上有一种更简单的驱动方法
这个芯片的GPIO有一种可编程输出模式,看用户文档的描述很适合用来驱动WS2812
可惜官方没提供这个模式的例程,论坛和网上也没搜到,不过在我的尝试下成功驱动了WS2812
Ai-M61-32S默认的时钟是40M,一个时钟周期是0.025us,ws2812的0码高电平0.3us低电平0.6us,1码高电平0.6us低电平0.3us
cr_code0_high_time=0.3/0.025=12
cr_code1_high_time=0.6/0.025=24
cr_code_total_time=36
设置高电平先发送,空闲低电平,GPIO初始化代码如下
- #define WS2812PIN GLB_GPIO_PIN_0
- void ws2812_gpio_init(void)
- {
- GLB_GPIO_Cfg_Type gpio_cfg;
- GLB_GPIO_FIFO_CFG_Type gpio_fifo_cfg;
- gpio_cfg.drive = 0;
- gpio_cfg.smtCtrl = 0;
- gpio_cfg.outputMode = GPIO_DMA_OUTPUT_VALUE_MODE;
- gpio_cfg.gpioMode = GPIO_MODE_OUTPUT;
- gpio_cfg.pullType = GPIO_PULL_NONE;
- gpio_cfg.gpioPin = WS2812PIN;
- gpio_cfg.gpioFun = GPIO_FUN_GPIO;
- GLB_GPIO_Init(&gpio_cfg);
- gpio_fifo_cfg.code0FirstTime = 12;
- gpio_fifo_cfg.code1FirstTime = 24;
- gpio_fifo_cfg.codeTotalTime = 36;
- gpio_fifo_cfg.code0Phase = GPIO_FIFO_PHASE_FIRST_HIGH;
- gpio_fifo_cfg.code1Phase = GPIO_FIFO_PHASE_FIRST_HIGH;
- gpio_fifo_cfg.idle = GPIO_FIFO_IDLE_LOW;
- gpio_fifo_cfg.latch = GPIO_FIFO_LATCH_WRITE;
- GLB_GPIO_Fifo_Init(&gpio_fifo_cfg);
- }
复制代码 BL616提供了128x16bits的缓冲区向GPIO写入数据,每16个GPIO为1组,例如IO0~IO15为1组IO16~IO31为1组,IO0和IO16都对应第0位,对应bit是1发送逻辑1码否则发送逻辑0码,写入缓冲区后开启发送并等待发送完成,实现发送代码如下
- void ws2812_write_byte(uint8_t byte)
- {
- uint16_t bits[8];
- uint8_t i = 0;
- while (i < 8)
- {
- if(byte&0x80)
- bits[i] = 1<<(WS2812PIN%16);
- else
- bits[i] = 0;
- byte <<= 1;
- i += 1;
- }
- GLB_GPIO_Fifo_Clear();
- GLB_GPIO_Fifo_Push(bits,8);
- GLB_GPIO_Fifo_Enable();
- while (GLB_GPIO_Fifo_GetCount()!=128);
- }
- void ws2812_reset()
- {
- bflb_mtimer_delay_us(80);
- }
- void ws2812_write_rgb(uint8_t r,uint8_t g,uint8_t b)
- {
- ws2812_write_byte(g);
- ws2812_write_byte(r);
- ws2812_write_byte(b);
- }
复制代码 测试代码
- int main(void)
- {
- board_init();
- gpio = bflb_device_get_by_name("gpio");
- bflb_gpio_init(gpio, GPIO_PIN_12, GPIO_OUTPUT | GPIO_FLOAT | GPIO_SMT_EN | GPIO_DRV_0);
-
- ws2812_gpio_init();
- ws2812_write_rgb(25,0,0);
- ws2812_write_rgb(0,25,0);
- ws2812_write_rgb(0,0,25);
- ws2812_write_rgb(25,0,25);
- ws2812_reset();
- while (1) {
- bflb_gpio_set(gpio, GPIO_PIN_12);
- bflb_mtimer_delay_ms(1000);
- bflb_gpio_reset(gpio, GPIO_PIN_12);
- bflb_mtimer_delay_ms(1000);
- }
- }
复制代码 运行效果
|