由上图可知 T0H+T0L
和 T1H+T1L
的时间周期为 800ns ~ 1380ns
取一个中间值 1.25us
那么0码/1码的周期就是 1s / 1.25us = 800kHz
所以PWM的周期就是800KHz
1.配置PWM+DMA
我这里使用的是TIM2_CH1 总线上的时钟频率为 52M
52M / 800KHz = 65
分频系数为0
那么向上计数值为65-1
2.占空比设置
0码的高电平大概占1/3的时间,那么PWM的计数值为 65 * 1/3 = 22
1码的高电平大概占2/3的时间,那么PWM的计数值为65 * 2/3 = 43
上面理论的东西弄好了,接下来是怎么使用
如果你以前只是使用PWM来调节呼吸灯,那你可能很难理解
例如我想输出 8个码 0 0 1 0 1 0 1 1
这里需要解决两个问题,怎么控制
1.输出一个0后,如何快速输出一个1?
2.怎么精准控制输出8个脉冲后就停止了?
运用你以前的PWM的使用方法是无法做到上面这两点的,但是和DMA组合使用,就可以很方便地实现(一行代码就搞定)
#define NUM 9
uint16_t send_Buf[NUM] = {22, 22, 43, 22, 43, 22, 43, 43, 0};
void led_on(void)
{
send_Buf[NUM - 1] = 0; // 这个很重要,最后一个需要设为0,要不然DMA不会停下来
HAL_TIM_PWM_Start_DMA(&htim2, TIM_CHANNEL_1, (uint32_t *)send_Buf, NUM);
}
一个函数,简简单单就实现了上面的功能,示波器采集到的数据也对应得上
/**
* @brief :输入hsv 返回rgb值 转换函数
* @param {uint32_t} h:色调(0~360°)
* @param {uint32_t} s:饱和度(0~100%)
* @param {uint32_t} v:亮度(0~100%)
* @param {uint32_t} *r:
* @param {uint32_t} *g:
* @param {uint32_t} *b:
* @return {*}
**/
void led_strip_hsv2rgb(uint32_t h, uint32_t s, uint32_t v, uint32_t *r, uint32_t *g, uint32_t *b)
{
h %= 360; // h -> [0,360]
uint32_t rgb_max = v * 2.55f;
uint32_t rgb_min = rgb_max * (100 - s) / 100.0f;
uint32_t i = h / 60;
uint32_t diff = h % 60;
// RGB adjustment amount by hue
uint32_t rgb_adj = (rgb_max - rgb_min) * diff / 60;
switch (i)
{
case 0:
*r = rgb_max;
*g = rgb_min + rgb_adj;
*b = rgb_min;
break;
case 1:
*r = rgb_max - rgb_adj;
*g = rgb_max;
*b = rgb_min;
break;
case 2:
*r = rgb_min;
*g = rgb_max;
*b = rgb_min + rgb_adj;
break;
case 3:
*r = rgb_min;
*g = rgb_max - rgb_adj;
*b = rgb_max;
break;
case 4:
*r = rgb_min + rgb_adj;
*g = rgb_min;
*b = rgb_max;
break;
default:
*r = rgb_max;
*g = rgb_min;
*b = rgb_max - rgb_adj;
break;
}
}
后续把WS2812B的驱动代码补上(如果我还记得的话。。。)