看了一下程序,不是独立的,是顺序的,三路的那个,除了第一路比较正常,其它路不正常,学习了

点赞  2020-1-19 20:45

里面有一些地方理解不了

prescaler=0,这个占空比这里设置为0

但纵观整个程序,没有看到有其它设置占空比的地方,除非这个:

DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)TIM4_CCR1_Address;    // physical address of Timer 3 CCR1

如果是这个的话,它是怎么改变的呢?

 

点赞  2020-1-21 10:52

image-20200320195604-1.png 这里发送的(50,25)是如何计算出来的?

点赞  2020-3-20 19:56

谢谢指教

点赞  2020-4-4 21:58
引用: n_m 发表于 2020-3-20 19:56 这里发送的(50,25)是如何计算出来的?

根据WS2812驱动波形近似出来的一个比例数,具体看一下驱动原理就明白了

点赞  2020-4-16 10:46

楼主我有个疑惑,为什么非要用DMA呢?我用F4的板子还需要用DMA吗?

点赞  2020-4-23 13:57
引用: Heart丶。 发表于 2020-4-23 13:57 楼主我有个疑惑,为什么非要用DMA呢?我用F4的板子还需要用DMA吗?

用DMA是为了给MCU留出更多的时间去处理别的事情,

如果MCU只是用来点个灯,可以不用DMA方式

点赞  2020-4-25 00:24
引用: 通宵敲代码 发表于 2020-4-25 00:24 用DMA是为了给MCU留出更多的时间去处理别的事情, 如果MCU只是用来点个灯,可以不用DMA方式

楼主我自己用PWM模式控制,灯一直以很高的频率在闪完全不受控制。我又按照你的驱动改了一份F4的DMA+PWM的,还是一直闪不受控制。看了好几天了感觉代码写的确实是没有问题,能不能麻烦你帮我看看到底哪里出了问题?

 

#define TIMING_ONE  70
#define TIMING_ZERO 30
 uint16_t LED_BYTE_Buffer[300];
 
DMA_HandleTypeDef  TIM3xDMA_Handler;   
TIM_HandleTypeDef  TIM3_Handler;         //定时器3PWM句柄 
TIM_OC_InitTypeDef TIM3_CH4Handler;        //定时器3通道4句柄
//TIM3 PWM部分初始化 
//PWM输出初始化
//arr:自动重装值
//psc:时钟预分频数
void TIM3_PWM_Init()

    TIM3_Handler.Instance=TIM3;            //定时器3
    TIM3_Handler.Init.Prescaler=0;       //定时器分频
    TIM3_Handler.Init.CounterMode=TIM_COUNTERMODE_UP;//向上计数模式
    TIM3_Handler.Init.Period=100-1;          //自动重装载值
    TIM3_Handler.Init.ClockDivision=0;
    HAL_TIM_PWM_Init(&TIM3_Handler);       //初始化PWM
    
    TIM3_CH4Handler.OCMode=TIM_OCMODE_PWM1; //模式选择PWM1
    TIM3_CH4Handler.Pulse=0;            //设置比较值,此值用来确定占空比,默认比较值为自动重装载值的一半,即占空比为50%
    TIM3_CH4Handler.OCPolarity=TIM_OCPOLARITY_HIGH; //输出比较极性为高
    HAL_TIM_PWM_ConfigChannel(&TIM3_Handler,&TIM3_CH4Handler,TIM_CHANNEL_4);//配置TIM3通道4
    
    HAL_TIM_PWM_Start(&TIM3_Handler,TIM_CHANNEL_4);//开启PWM通道4
}


//定时器底层驱动,时钟使能,引脚配置
//此函数会被HAL_TIM_PWM_Init()调用
//htim:定时器句柄
void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim)
{
    GPIO_InitTypeDef GPIO_Initure;
    __HAL_RCC_TIM3_CLK_ENABLE();            //使能定时器3
    __HAL_RCC_GPIOB_CLK_ENABLE();            //开启GPIOB时钟
    
    GPIO_Initure.Pin=GPIO_PIN_1;               //PB1
    GPIO_Initure.Mode=GPIO_MODE_AF_PP;      //复用推挽输出
    GPIO_Initure.Pull=GPIO_PULLUP;          //上拉
    GPIO_Initure.Speed=GPIO_SPEED_HIGH;     //高速
    GPIO_Initure.Alternate= GPIO_AF2_TIM3;    //PB1复用为TIM3_CH4
    HAL_GPIO_Init(GPIOB,&GPIO_Initure);
}


////设置TIM通道4的占空比
////compare:比较值
//void TIM_SetTIM3Compare4(u32 compare)
//{
//    TIM3->CCR4=compare; 
//}
void MYDMA_Config(DMA_Stream_TypeDef *DMA_Streamx,u32 chx)

    __HAL_RCC_DMA1_CLK_ENABLE();
    __HAL_LINKDMA(&TIM3_Handler,hdma[TIM_DMA_ID_CC4],TIM3xDMA_Handler);
    
    
     HAL_DMA_DeInit(&TIM3xDMA_Handler);
     TIM3xDMA_Handler.Instance=DMA1_Stream2;
     TIM3xDMA_Handler.Init.Channel=DMA_CHANNEL_5;
     TIM3xDMA_Handler.Init.Direction=DMA_MEMORY_TO_PERIPH;
     TIM3xDMA_Handler.Init.FIFOMode=DMA_FIFOMODE_DISABLE;
     TIM3xDMA_Handler.Init.FIFOThreshold=DMA_FIFO_THRESHOLD_FULL;
     TIM3xDMA_Handler.Init.MemBurst=DMA_MBURST_SINGLE;
     TIM3xDMA_Handler.Init.PeriphBurst=DMA_PBURST_SINGLE;
     TIM3xDMA_Handler.Init.MemDataAlignment=DMA_MDATAALIGN_HALFWORD;
     TIM3xDMA_Handler.Init.PeriphDataAlignment=DMA_PDATAALIGN_HALFWORD;
     TIM3xDMA_Handler.Init.MemInc=DMA_MINC_ENABLE;
     TIM3xDMA_Handler.Init.PeriphInc=DMA_PINC_DISABLE;
     TIM3xDMA_Handler.Init.Mode=DMA_NORMAL; 
     TIM3xDMA_Handler.Init.Priority=DMA_PRIORITY_MEDIUM;
     HAL_DMA_Init(&TIM3xDMA_Handler);


void WS2812_send(uint8_t (*color)[3], uint16_t len)
{
    uint8_t i;
    uint16_t memaddr;
    uint16_t buffersize;
    buffersize = (len*24)+43;    // number of bytes needed is #LEDs * 24 bytes + 42 trailing bytes
    memaddr = 0;                // reset buffer memory index

    while (len)
    {    
        for(i=0; i<8; i++) // GREEN data
        {
            LED_BYTE_Buffer[memaddr] = ((color[0][1]<<i) & 0x0080) ? TIMING_ONE:TIMING_ZERO;
            memaddr++;
        }
        for(i=0; i<8; i++) // RED
        {
                LED_BYTE_Buffer[memaddr] = ((color[0][0]<<i) & 0x0080) ? TIMING_ONE:TIMING_ZERO;
                memaddr++;
        }
        for(i=0; i<8; i++) // BLUE
        {
                LED_BYTE_Buffer[memaddr] = ((color[0][2]<<i) & 0x0080) ? TIMING_ONE:TIMING_ZERO;
                memaddr++;
        }
        len--;
    }
//===================================================================//    
//bug:最后一个周期波形不知道为什么全是高电平,故增加一个波形
      LED_BYTE_Buffer[memaddr] = ((color[0][2]<<8) & 0x0080) ? TIMING_ONE:TIMING_ZERO;
//===================================================================//    
      memaddr++;    
        while(memaddr < buffersize)
        {
            LED_BYTE_Buffer[memaddr] = 0;
            memaddr++;
        }  

         HAL_TIM_PWM_Start_DMA(&TIM3_Handler, TIM_CHANNEL_4, (u32 *)&LED_BYTE_Buffer, buffersize);     // load number of bytes to be transferred
         while(!__HAL_DMA_GET_FLAG(&TIM3xDMA_Handler,DMA_FLAG_TCIF2_6));        
         HAL_TIM_PWM_Stop_DMA(&TIM3_Handler, TIM_CHANNEL_4);
        __HAL_DMA_CLEAR_FLAG(&TIM3xDMA_Handler,DMA_FLAG_TCIF2_6);
}
 

点赞  2020-4-26 10:28
引用: 通宵敲代码 发表于 2020-4-25 00:24 用DMA是为了给MCU留出更多的时间去处理别的事情, 如果MCU只是用来点个灯,可以不用DMA方式

这一份PWM的逻辑就更简单了,我就在主函数调用WS2812_send(r,1),r这个数组我定义的是

r[][0]={255,0,0},理论上应该是红色,可是实际的效果是各种颜色已很高的频率不停的闪,因为用的是F4的板子,时钟是180MHZ的,TIM的时钟是90Mhz,arr给100-1,psc给0,理论上一个周期1.11us,感觉这里设定的也没有错

 

 

#define TIMING_ONE  70
#define TIMING_ZERO 30
 u16 LED_BYTE_Buffer[300];

TIM_HandleTypeDef TIM3_Handler;         //定时器3PWM句柄 
TIM_OC_InitTypeDef TIM3_CH4Handler;        //定时器3通道4句柄

//TIM3 PWM部分初始化 
//PWM输出初始化
//arr:自动重装值
//psc:时钟预分频数
void TIM3_PWM_Init(u16 arr,u16 psc)

    TIM3_Handler.Instance=TIM3;            //定时器3
    TIM3_Handler.Init.Prescaler=psc;       //定时器分频
    TIM3_Handler.Init.CounterMode=TIM_COUNTERMODE_UP;//向上计数模式
    TIM3_Handler.Init.Period=arr;          //自动重装载值
    TIM3_Handler.Init.ClockDivision=0;
    HAL_TIM_PWM_Init(&TIM3_Handler);        //初始化PWM
    
    TIM3_CH4Handler.OCMode=TIM_OCMODE_PWM1; //模式选择PWM1
    TIM3_CH4Handler.Pulse=0;            //设置比较值,此值用来确定占空比,默认比较值为自动重装载值的一半,即占空比为50%
    TIM3_CH4Handler.OCPolarity=TIM_OCPOLARITY_HIGH; //输出比较极性为高
    HAL_TIM_PWM_ConfigChannel(&TIM3_Handler,&TIM3_CH4Handler,TIM_CHANNEL_4);//配置TIM3通道4
    
    HAL_TIM_PWM_Start(&TIM3_Handler,TIM_CHANNEL_4);//开启PWM通道4
}


//定时器底层驱动,时钟使能,引脚配置
//此函数会被HAL_TIM_PWM_Init()调用
//htim:定时器句柄
void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim)
{
    GPIO_InitTypeDef GPIO_Initure;
    __HAL_RCC_TIM3_CLK_ENABLE();            //使能定时器3
    __HAL_RCC_GPIOB_CLK_ENABLE();            //开启GPIOB时钟
    
    GPIO_Initure.Pin=GPIO_PIN_1;               //PB1
    GPIO_Initure.Mode=GPIO_MODE_AF_PP;      //复用推挽输出
    GPIO_Initure.Pull=GPIO_PULLUP;          //上拉
    GPIO_Initure.Speed=GPIO_SPEED_HIGH;     //高速
    GPIO_Initure.Alternate= GPIO_AF2_TIM3;    //PB1复用为TIM3_CH4
    HAL_GPIO_Init(GPIOB,&GPIO_Initure);
}


//设置TIM通道4的占空比
//compare:比较值
void TIM_SetTIM3Compare4(u32 compare)
{
    TIM3->CCR4=compare; 
}

void WS2812_send(u8 *rgb[3], u16 len)
{    u16 j;
    u8 i;
    u16 memaddr;
    u16 buffersize;
    buffersize = (len*24)+43;    // number of bytes needed is #LEDs * 24 bytes + 42 trailing bytes
    memaddr = 0;                // reset buffer memory index

    while (len)
    {    
        for(i=0; i<8; i++) //  GREEN
        {
            LED_BYTE_Buffer[memaddr] = ((rgb[0][1]<<i) & 0x0080) ?   TIMING_ONE:TIMING_ZERO;
            memaddr++;
                
        }
        for(i=0; i<8; i++) // RED
        {
                LED_BYTE_Buffer[memaddr] = ((rgb[0][0]<<i) & 0x0080) ?  TIMING_ONE:TIMING_ZERO;
                memaddr++;
        
        }
        for(i=0; i<8; i++) // BLUE
        {
                LED_BYTE_Buffer[memaddr] = ((rgb[0][2]<<i) & 0x0080) ?  TIMING_ONE:TIMING_ZERO;
                memaddr++;
            
        }
        len--;
          
    }

    for(j=0;j<300;j++){
        
        
        TIM_SetTIM3Compare4(LED_BYTE_Buffer[j]);
        
        
        
                      }
    
        HAL_TIM_PWM_Stop(&TIM3_Handler,TIM_CHANNEL_4);        
                      
}

点赞  2020-4-26 10:36

楼主我用示波器测了,波形是正常的,说明代码是没问题的,但是每一段时间内就会有一个小的高电平脉冲,所以导致了灯各种颜色一直闪,找来找去发现我在初始化HAL_TIM_PWM_Start(&TIM3_Handler,TIM_CHANNEL_4);和HAL_TIM_PWM_Start_DMA(&TIM3_Handler, TIM_CHANNEL_4, (u32 *)&LED_BYTE_Buffer, buffersize); 这两句,只要有初始化就会有一个高电平脉冲,可是这两句都是放在while循环里的,就会一直执行导致了会有断断续续的高电平影响整个信号,这个bug我还没找到解决方法,打算先用您第三章的SPI+DMA来试试

点赞  2020-4-29 08:32
引用: Heart丶。 发表于 2020-4-29 08:32 楼主我用示波器测了,波形是正常的,说明代码是没问题的,但是每一段时间内就会有一个小的高电平脉冲,所以 ...

多尝试尝试吧,有问题得慢慢追

点赞  2020-4-29 08:36
引用: 通宵敲代码 发表于 2018-5-6 22:49 定义了三个数组,主函数里写个三色循环呼吸灯看看效果。 附上相关程序 这个是用TIM2_CH1实 ...

老哥,这个4路灯的代码,里面的TIM5初始化应该是有些问题的,初始化TIM5后会进断言

点赞  2020-5-22 15:02
引用: Anonymous_W 发表于 2020-5-22 15:02 老哥,这个4路灯的代码,里面的TIM5初始化应该是有些问题的,初始化TIM5后会进断言

哈哈,问题找到了,我的问题,没仔细看手册。

点赞  2020-5-22 15:40
引用: Anonymous_W 发表于 2020-5-22 15:40 哈哈,问题找到了,我的问题,没仔细看手册。

点赞  2020-5-23 00:37

同时使用CH1 CH2和CH3的时候怎么数据不一致了,只用其中一个通道就OK了;LZ之前碰到这种现象吗

点赞  2020-6-1 15:07
引用: 1235678900 发表于 2020-6-1 15:07 同时使用CH1 CH2和CH3的时候怎么数据不一致了,只用其中一个通道就OK了;LZ之前碰到这种现象吗

同时使用时不使能TIM_DMA_Update;使能TIM_DMA_CC1/2/3/4;同时各个通道的使能预装载寄存器

点赞  2020-6-2 19:21
引用: 通宵敲代码 发表于 2020-4-16 10:46 根据WS2812驱动波形近似出来的一个比例数,具体看一下驱动原理就明白了

好的,谢谢,DMA触发方式,各个通道,当只有这个触发TIMx_up的时候,才有效?这个怎么理解?

点赞  2020-6-6 16:37
引用: vickyinhere 发表于 2018-12-25 18:08 我也是这样,只有8个,请问你解决了吗,还是说要使用三路LED的代码

修改下main函数 ws2812_send(rgbx,24)

点赞  2020-8-15 21:28

真的干货,谢谢分享!!!!

点赞  2020-11-16 14:11
引用: qw845253793 发表于 2019-4-24 16:31 请问为什么我一个灯条60颗灯,只能点亮48颗灯,如果设置为大于48,就全都不亮

对,我也是,最高48颗灯,应该是时序的问题,但是还没检查出来哪有问题

点赞  2021-1-8 16:06
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复