STM32用PWM +DMA驱动 WS2812

参考的代码:

------------------------------------WS2812B.c------------------------------------
#include "WS2812B.h"
/* Buffer that holds one complete DMA transmission
 * 
 * Ensure that this buffer is big enough to hold
 * all data bytes that need to be sent
 * 
 * The buffer size can be calculated as follows:
 * number of LEDs * 24 bytes + 42 bytes
 * 
 * This leaves us with a maximum string length of
 * (2^16 bytes per DMA stream - 42 bytes)/24 bytes per LED = 2728 LEDs
 */
#define TIM3_CCR3_Address 0x4000043c 	// physical memory address of Timer 3 CCR1 register
//#define TIM3_CCR1_Address 0x40000434	// physical memory address of Timer 3 CCR1 register
//#define TIM2_CCR4_Address 0x40000040
	
#define TIMING_ONE  61
#define TIMING_ZERO 29
 uint16_t LED_BYTE_Buffer[300];
 uint16_t testcount = 0;
  uint16_t testcount1 = 0;
//---------------------------------------------------------------//

void Timer2_init(void)
{
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
  TIM_OCInitTypeDef  TIM_OCInitStructure;
  GPIO_InitTypeDef GPIO_InitStructure;
  DMA_InitTypeDef DMA_InitStructure;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);
	/* GPIOA Configuration: TIM2 Channel 1 as alternate function push-pull */
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
  
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
	/* Compute the prescaler value */
	//PrescalerValue = (uint16_t) (SystemCoreClock / 24000000) - 1;
	/* Time base configuration */
	TIM_TimeBaseStructure.TIM_Period = 90-1; // 800kHz 
	TIM_TimeBaseStructure.TIM_Prescaler = 0;
	TIM_TimeBaseStructure.TIM_ClockDivision = 0;
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);

	/* PWM1 Mode configuration: Channel1 */
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
	TIM_OCInitStructure.TIM_Pulse = 0;
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
	TIM_OC1Init(TIM2, &TIM_OCInitStructure);
  TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Enable);
//  TIM_ARRPreloadConfig(TIM3, ENABLE);
	//GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3,ENABLE);	
	/* configure DMA */
	/* DMA clock enable */
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
	
	/* DMA1 Channel6 Config */
	DMA_DeInit(DMA1_Channel2);

	DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&TIM2->CCR1);	// physical address of Timer 3 CCR1
	DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)LED_BYTE_Buffer;		// this is the buffer memory 
	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;						// data shifted from memory to peripheral
	DMA_InitStructure.DMA_BufferSize = 42;
	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;					// automatically increase buffer index
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
	DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;							// stop DMA feed after buffer size is reached
	DMA_InitStructure.DMA_Priority = DMA_Priority_High;
	DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
	
	DMA_Init(DMA1_Channel2, &DMA_InitStructure);

		/* TIM3 CC1 DMA Request enable */
	TIM_DMACmd(TIM2, TIM_DMA_Update, ENABLE);
}

/* This function sends data bytes out to a string of WS2812s
 * The first argument is a pointer to the first RGB triplet to be sent
 * The seconds argument is the number of LEDs in the chain
 * 
 * This will result in the RGB triplet passed by argument 1 being sent to 
 * the LED that is the furthest away from the controller (the point where
 * data is injected into the chain)
 */
void WS2812_send(uint8_t (*color)[3], uint16_t len)
{
	uint8_t i;
	uint16_t memaddr;
	uint16_t buffersize;
	buffersize = (len*24)+10;	// 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++;
		}

		DMA_SetCurrDataCounter(DMA1_Channel2, memaddr); 	// load number of bytes to be transferred
		
    DMA_Cmd(DMA1_Channel2, ENABLE); 			// enable DMA channel 6
		TIM_Cmd(TIM2, ENABLE); 						// enable Timer 3

		while(!DMA_GetFlagStatus(DMA1_FLAG_TC2)) 
    {
//      testcount1 = DMA_GetCurrDataCounter(DMA1_Channel2);
//      if(DMA_GetFlagStatus(DMA1_FLAG_TE2))
//      {
//        testcount++;
//      }
    }; 	// wait until transfer complete
//	  testcount++;	
    TIM_Cmd(TIM2, DISABLE); 	// disable Timer 3
		DMA_Cmd(DMA1_Channel2, DISABLE); 			// disable DMA channel 6
		DMA_ClearFlag(DMA1_FLAG_TC2); 				// clear DMA1 Channel 6 transfer complete flag
}


----------------------------------------Main.c---------------------------------------------
uint8_t r[][3] = {255,0,0};
uint8_t g[][3] = {0,255,0};
uint8_t b[][3] = {0,0,255};
uint8_t cheng[][3] = {255,128,0};
uint8_t huang[][3] = {255,255,0};
uint8_t qing[][3] = {0,255,255};
uint8_t zi[][3] = {128,0,255};
uint32_t testt = (uint32_t)(&TIM3->CCR3);


 int main(void)
 {	
    //RCC_Configuration();
   
    delay_init();	    //延时函数初始化	  
    //LED_Init();		  //初始化与LED连接的硬件接口
    Timer2_init();
	while(1)
	{
		WS2812_send(r,8);
		delay_ms(1000);
		WS2812_send(g,8);
		delay_ms(1000);
		WS2812_send(b,8);
		delay_ms(1000);
    WS2812_send(cheng,8);
		delay_ms(1000);
		WS2812_send(huang,8);
		delay_ms(1000);
		WS2812_send(qing,8);
		delay_ms(1000);
    WS2812_send(zi,8);
		delay_ms(1000);
	}
 }

需要注意以下几点:

1)采用的是TIM2->CH1,用的是TIM_DMA_Update触发,如果改用其他的通道需要更改触发方式

2)代码中---bug:最后一个周期波形不知道为什么全是高电平,故增加一个波形

    可以注销此句代码,主要是  buffersize = (len*24)+10;不知道为什么需要加上10,加上1就不行,不知道什么原因,那位知道可以探讨下。

这是在网上下载,用其他通道采用的方式链接:

https://pan.baidu.com/s/13qcHDSr5CIW4fb1YVQO15w 
提取码:tegt 

  • 9
    点赞
  • 76
    收藏
    觉得还不错? 一键收藏
  • 13
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值