WS2812灯带 PWM+DMA驱动

WS2812灯带

主控芯片GD32F303

一、ws2812灯带

1、产品特点

  • 数据发送速度可达800Kbps
  • 串行级联接口, 能通过一根信号线完成数据的接收与解码
  • 任意两点传传输距离在不超过3米时无需增加任何电路。
  • 内置信号整形电路, 任何一个像素点收到信号后经过波形整形再输出, 保证线路波形畸变不会累加
  • 内置上电复位和掉电复位电路

2、确定编码格式

在这里插入图片描述

1)BIT0

​ 周期 :T0H + T0L = 1/800k = 1.25μs

​ 波形占空比 :T0H /1.25 *100% = 32%

2)BIT1

​ 周期 : T1H + T1L = 1/800k = 1.25μs ,

​ 波形占空比 : T1L / 1.25 * 100% = 1-32% = 78%

3、数据传输

在这里插入图片描述
在这里插入图片描述

二、采用DMA+PWM的方式驱动

1、timer配置

  • 根据定时器的时钟频率,设置相应的预分频系数及重装载值

    本文定时器时钟频率:112M、预分频系数:1、自动重装载值:69 ;

    频率 = 时钟频率/(预分频系数+1)/(自动重装载值+1) = 112/2/70 =0.8M = 800K

    周期 = 1/频率 = 1.25μs

  • 周期为1.25μs 的PWM输出,开启DMA

/********************************************************************************************
* Function Name  : bsp_timerPwm_led_init
* Description    : 定时器pwm   timer4_ch1
* Input          : void
* Output         : void
* Return         : none
********************************************************************************************/

void bsp_timerPwm_lights(void)
{
    #define TIM_PWM  TIMER4
    timer_oc_parameter_struct timer_ocintpara;
    timer_parameter_struct timer_initpara;
    
    //clock
    rcu_periph_clock_enable(RCU_GPIOA);
    rcu_periph_clock_enable(RCU_TIMER4);
    rcu_periph_clock_enable(RCU_AF);
    
    //GPIO
    gpio_init(GPIOA,GPIO_MODE_AF_PP,GPIO_OSPEED_50MHZ,GPIO_PIN_1);
    // gpio_init(GPIOA,GPIO_MODE_AF_PP,GPIO_OSPEED_50MHZ,GPIO_PIN_2);
    //  gpio_init(GPIOA,GPIO_MODE_AF_PP,GPIO_OSPEED_50MHZ,GPIO_PIN_3);

    //TIMER
    timer_deinit(TIM_PWM);
   
    timer_initpara.prescaler         = 1;
    timer_initpara.alignedmode       = TIMER_COUNTER_EDGE;
    timer_initpara.counterdirection  = TIMER_COUNTER_UP;
    timer_initpara.period            = 69;
    timer_initpara.clockdivision     = TIMER_CKDIV_DIV1;
    timer_initpara.repetitioncounter = 0;
    timer_init(TIM_PWM, &timer_initpara);   
    timer_ocintpara.outputstate  = TIMER_CCX_ENABLE;
    timer_ocintpara.outputnstate = TIMER_CCXN_DISABLE;
    timer_ocintpara.ocpolarity   = TIMER_OC_POLARITY_HIGH;
    timer_ocintpara.ocnpolarity  = TIMER_OCN_POLARITY_HIGH;
    timer_ocintpara.ocidlestate  = TIMER_OC_IDLE_STATE_HIGH;
    timer_ocintpara.ocnidlestate = TIMER_OCN_IDLE_STATE_LOW;    
    timer_channel_output_config(TIM_PWM, TIMER_CH_1, &timer_ocintpara); 
    timer_channel_output_pulse_value_config(TIM_PWM, TIMER_CH_1, 0);
    timer_channel_output_mode_config(TIM_PWM, TIMER_CH_1, TIMER_OC_MODE_PWM0);
    timer_channel_output_shadow_config(TIM_PWM, TIMER_CH_1, TIMER_OC_SHADOW_DISABLE);   
    timer_dma_enable(TIM_PWM,TIMER_DMA_CH1D);

    timer_channel_dma_request_source_select( TIMER4,TIMER_DMAREQUEST_UPDATEEVENT);
    /* auto-reload preload enable */
    timer_auto_reload_shadow_enable(TIM_PWM);
    /* auto-reload preload enable */
    timer_enable(TIM_PWM);
}

2、DMA配置

/********************************************************************************************
* Function Name  : dma1_ch3_config
* Description    : DMA1_CH3 配置---Timer4_ch1
* Input          : void
* Output         : void
* Return         : none
********************************************************************************************/
void dma1_ch3_config(void)
{
    dma_parameter_struct dma_init_struct; 
    //clock
    rcu_periph_clock_enable(RCU_DMA1); 
    //DMA
    dma_deinit(DMA1, DMA_CH3);
    dma_init_struct.direction     = DMA_MEMORY_TO_PERIPHERAL;
    dma_init_struct.memory_addr   = (uint32_t)(ws2812_rgb_buf);
    dma_init_struct.memory_inc    = DMA_MEMORY_INCREASE_ENABLE;
    dma_init_struct.memory_width  = DMA_MEMORY_WIDTH_8BIT;
    dma_init_struct.number        = (WS2812_NUM+20)*24;
    dma_init_struct.periph_addr   = (uint32_t)(&TIMER_CH1CV(TIMER4));
    dma_init_struct.periph_inc    = DMA_PERIPH_INCREASE_DISABLE;
    dma_init_struct.periph_width  = DMA_PERIPHERAL_WIDTH_16BIT;
    dma_init_struct.priority      = DMA_PRIORITY_ULTRA_HIGH;
    dma_init(DMA1, DMA_CH3, &dma_init_struct);
    /* configure DMA mode */
    dma_circulation_enable(DMA1, DMA_CH3);      
    /* enable DMA channel */
    dma_channel_enable(DMA1, DMA_CH3); 
}

三、灯效

1、点亮

#define WS2812_NUM   (100)
#define BIT0  23			/*23/70 = 32.86%*/
#define BIT1  47			/*47/70 = 67.14%*/
uint8_t ws2812_rgb_buf[WS2812_NUM+20][24];    //后10个二维数组用于更新锁存器,1.25μs*10*24 = 300μs
/**/


/********************************************************************************************
* Function Name  : clean_all_color
* Description    : 清除所有灯珠的颜色(关闭灯珠)
* Input          : None
* Output         : void
* Return         : none
********************************************************************************************/
static void clean_all_color(void)
{
    uint8_t i = 0, j = 0;
    for (i = 0; i < WS2812_NUM; i++) {
           for (j = 0; j < 8; j++)
                ws2812_rgb_buf[i+10][j] = (0x00 & (0x01 << (7 - j))) ? BIT_1 : BIT_0;
       }
    for (i = 0; i < WS2812_NUM; i++) {
           for (j = 0; j < 8; j++)
                ws2812_rgb_buf[i+10][j+8]  = (0x00 & (0x01 << (7 - j))) ? BIT_1 : BIT_0;
       }
    for (i = 0; i < WS2812_NUM; i++) {
           for (j = 0; j < 8; j++)
                ws2812_rgb_buf[i+10][j+16]  = (0x00 & (0x01 << (7 - j))) ? BIT_1 : BIT_0;
    }
}

/********************************************************************************************
* Function Name  : clean_one_color
* Description    : 清除某个灯珠的颜色(关闭灯珠)
* Input          : which   选择第几个灯珠
* Output         : void
* Return         : none
********************************************************************************************/
static void clean_one_color(uint8_t which)
{
    uint8_t i = 0;
        for (i = 0; i < 8; i++)
            ws2812_rgb_buf[which+10][i] = (0x00 & (0x01 << (7 - i))) ? BIT_1 : BIT_0;
        for (i = 0; i < 8; i++)
            ws2812_rgb_buf[which+10][i+8]  = (0x00 & (0x01 << (7 - i))) ? BIT_1 : BIT_0; 
        for (i = 0; i < 8; i++)
            ws2812_rgb_buf[which+10][i+16]  = (0x00 & (0x01 << (7 - i))) ? BIT_1 : BIT_0;
}


* Function Name  : set_ws2812_single_color
* Description    : 将所有灯珠设置为同一种颜色
* Input          : 
                   uint8_t red       
                   uint8_t green
                   uint8_t blue
* Output         : void
* Return         : none
********************************************************************************************/
static void set_ws2812_single_color( uint8_t red, uint8_t green, uint8_t blue)
{
    uint8_t i = 0, j = 0;
    memset(ws2812_rgb_buf, 0, sizeof(ws2812_rgb_buf));
    for (i = 0; i < WS2812_NUM ; i++) {
        for (j = 0; j < 8; j++)
            ws2812_rgb_buf[i+10][j] = (green & (0x01 << (7 - j))) ? BIT_1 : BIT_0;
    }
    for (i = 0; i < WS2812_NUM ; i++) {
        for (j = 0; j < 8; j++)
            ws2812_rgb_buf[i+10][j+8]  = (red & (0x01 << (7 - j))) ? BIT_1 : BIT_0;
    }
    for (i = 0; i < WS2812_NUM ; i++) {
        for (j = 0; j < 8; j++)
             ws2812_rgb_buf[i+10][j+16]  = (blue & (0x01 << (7 - j))) ? BIT_1 : BIT_0; 
    }
    // ws2812_enable();
}

/********************************************************************************************
* Function Name  : ws2812_process
* Description    : ws2812模块处理函数
* Input          : void 
* Output         : void
* Return         : none
********************************************************************************************/
void ws2812_process(void)
{
    static uint8_t firstFlag = 0;
    if(!firstFlag)
    {
        /******** 定时器配置PWM********/
        bsp_timerPwm_lights();
        /********DMA_CH3配置及使能********/
        dma1_ch3_config();
    }
     set_ws2812_single_color(255,255,255);
}

2、闪烁

3、流光

4、呼吸

  • 7
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
C语言中的随机数函数是rand()。它可以生成一个介于0和RAND_MAX之间的伪随机整数。要使用rand()函数之前,我们需要使用srand()函数设置种子。通常可以使用当前时间作为种子,以确保每次程序运行时都会生成不同的随机数序列。 为了生成0到N-1之间的随机数,我们可以使用rand() % N的方式。但需要注意的是,这种方式并不是完全随机的,因为rand()函数的伪随机性可能导致某些数值出现的概率更高。 下面是一个范例代码,演示了如何生成1到10之间的随机数: ```c #include <time.h> #include <stdlib.h> #include <stdio.h> int main() { int i, j; srand((unsigned)time(NULL)); for(i = 0; i < 10; i++) { j = 1 + (int)(10.0 * rand() / (RAND_MAX + 1.0)); printf("%d ", j); } return 0; } ``` 该代码首先使用srand()函数设置种子,然后使用rand()函数生成一个0到RAND_MAX之间的随机整数。接着,通过计算将其映射到1到10之间的范围,并将结果打印出来。由于种子是基于当前时间的,所以每次运行程序时都会得到不同的随机数序列。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [【C++】random随机数与【C++11】/rand()和srand()的用法](https://blog.csdn.net/Darlingqiang/article/details/119451672)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [C++随机数生成实例讲解](https://download.csdn.net/download/weixin_38609765/13781808)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [c++中的随机数rand()](https://blog.csdn.net/a13352912632/article/details/108555783)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值