• STM32 HAL WS2812B PWM+DMA控制


    在这里插入图片描述
    由上图可知 T0H+T0LT1H+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);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    一个函数,简简单单就实现了上面的功能,示波器采集到的数据也对应得上
    在这里插入图片描述

    
    /**
     * @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;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57

    后续把WS2812B的驱动代码补上(如果我还记得的话。。。)

  • 相关阅读:
    进程和任务管理计划
    si446使用记录(二):使用WDS3生成头文件
    CentOS安装Elasticsearch集群
    Tomcat context.xml配置详解
    gpg: keyserver receive failed: Cannot assign requested address
    SpringSecurity6从入门到上天系列第七篇:讲明白SpringBoot的自动装配完善上篇文章中的结论
    在Spring项目启动时处理事情的几种实现方式
    12-分频器 -偶分频
    【LeetCode-中等题】116. 填充每个节点的下一个右侧节点指针
    L848字母位移
  • 原文地址:https://blog.csdn.net/weixin_43808708/article/details/127694125