看了一下程序,不是独立的,是顺序的,三路的那个,除了第一路比较正常,其它路不正常,学习了
里面有一些地方理解不了
prescaler=0,这个占空比这里设置为0
但纵观整个程序,没有看到有其它设置占空比的地方,除非这个:
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)TIM4_CCR1_Address; // physical address of Timer 3 CCR1
如果是这个的话,它是怎么改变的呢?
引用: n_m 发表于 2020-3-20 19:56 这里发送的(50,25)是如何计算出来的?
根据WS2812驱动波形近似出来的一个比例数,具体看一下驱动原理就明白了
引用: Heart丶。 发表于 2020-4-23 13:57 楼主我有个疑惑,为什么非要用DMA呢?我用F4的板子还需要用DMA吗?
用DMA是为了给MCU留出更多的时间去处理别的事情,
如果MCU只是用来点个灯,可以不用DMA方式
引用: 通宵敲代码 发表于 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-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);
}
楼主我用示波器测了,波形是正常的,说明代码是没问题的,但是每一段时间内就会有一个小的高电平脉冲,所以导致了灯各种颜色一直闪,找来找去发现我在初始化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来试试
引用: Heart丶。 发表于 2020-4-29 08:32 楼主我用示波器测了,波形是正常的,说明代码是没问题的,但是每一段时间内就会有一个小的高电平脉冲,所以 ...
多尝试尝试吧,有问题得慢慢追
引用: 通宵敲代码 发表于 2018-5-6 22:49 定义了三个数组,主函数里写个三色循环呼吸灯看看效果。 附上相关程序 这个是用TIM2_CH1实 ...
老哥,这个4路灯的代码,里面的TIM5初始化应该是有些问题的,初始化TIM5后会进断言
引用: Anonymous_W 发表于 2020-5-22 15:02 老哥,这个4路灯的代码,里面的TIM5初始化应该是有些问题的,初始化TIM5后会进断言
哈哈,问题找到了,我的问题,没仔细看手册。
引用: Anonymous_W 发表于 2020-5-22 15:40 哈哈,问题找到了,我的问题,没仔细看手册。
同时使用CH1 CH2和CH3的时候怎么数据不一致了,只用其中一个通道就OK了;LZ之前碰到这种现象吗
引用: 1235678900 发表于 2020-6-1 15:07 同时使用CH1 CH2和CH3的时候怎么数据不一致了,只用其中一个通道就OK了;LZ之前碰到这种现象吗
同时使用时不使能TIM_DMA_Update;使能TIM_DMA_CC1/2/3/4;同时各个通道的使能预装载寄存器
引用: 通宵敲代码 发表于 2020-4-16 10:46 根据WS2812驱动波形近似出来的一个比例数,具体看一下驱动原理就明白了
好的,谢谢,DMA触发方式,各个通道,当只有这个触发TIMx_up的时候,才有效?这个怎么理解?
引用: vickyinhere 发表于 2018-12-25 18:08 我也是这样,只有8个,请问你解决了吗,还是说要使用三路LED的代码
修改下main函数 ws2812_send(rgbx,24)
引用: qw845253793 发表于 2019-4-24 16:31 请问为什么我一个灯条60颗灯,只能点亮48颗灯,如果设置为大于48,就全都不亮
对,我也是,最高48颗灯,应该是时序的问题,但是还没检查出来哪有问题