使用f031的SPI单引脚(MOSI)+DMA实现WS2812B三色灯的级联控制

WS2812B是一种集成了电流控制芯片的低功耗的RGB三色灯,
关于这个灯的一些硬件分析我就不多说,百度一堆一堆的;
今天主要讲讲使用SPI的MOSI+DMA实现控制的方式;
主MCU:灵动微的 MMF031,关于这个MCU就是直接仿造的ST同系列的,可直接百度吧;
主频:#define SYSCLK_HSI_48MHz 48000000
思路:利用SPI发送不同的byte实现WS2812B规格书需求的高低电平;
基础实现高低电平如下:

void LED_SPI_SendBits(uint8_t bits)
{
    int zero = 0X1F00;//0x0700;  	//0001 1111 0000 0000
    int one = 0XFFC0;//0x07E0;    //1111 1111 1100 0000
    int i = 0x00;
    for (i = 0x80; i >= 0x01; i >>= 1)
    {
        LED_SPI_WriteByte((bits & i) ? one : zero);
    }
}

实现RGB三个字段共计24BIT的代码如下(这里需要定义一个结构体实现数据转存):

struct Pixel {
    uint8_t red;
    uint8_t green;
    uint8_t blue;
};
void LED_SPI_SendPixel(struct Pixel pixel)
{
    LED_SPI_SendBits(pixel.green);
    LED_SPI_SendBits(pixel.red);
    LED_SPI_SendBits(pixel.blue);
}

需要一个实现发送的代码,传参length 是WS2812级联的个数:

ErrorStatus LED_SPI_Update(struct Pixel buffer[], uint32_t length)
{
    uint8_t i = 0;
	uint16_t delay_break = 0 ;
    if(DMA_GetCurrDataCounter(DMA1_Channel3) == 0)//检查DMA是否完成传输任务
    {
        for (i = 0; i < length; i++)
        {
            LED_SPI_SendPixel(buffer[i]);///一个buffer 一个灯
        }
        PixelPointer = 0;
				DMA1_Channel3->CNDTR = TX_RX_LEN;
				DMA1_Channel3->CMAR =	(uint32_t)PixelBuffer;
				DMA_ClearFlag(DMA1_FLAG_TC3);//清除通道3数据传输完成标志位 
				SPI_DMACmd(SPI1,SPI_DMAReq_EN,ENABLE);//使能SPI DMA	
				DMA_Cmd(DMA1_Channel3, ENABLE);  //使能SPI TX DMA1 所指示的通道 
				SPI_Cmd(SPI1, ENABLE); 		//Enables the specified SPI peripheral SPI使能、主机模式 8位数据模式 SPI 的波特率	
				while(!DMA_GetFlagStatus(DMA1_FLAG_TC3))  
				{//通道3数据发送传输完成标志位
					delay_break ++ ;
					if(delay_break >2000)
						break ;
				}
				DMA_ClearFlag(DMA1_FLAG_TC3);//清除通道3数据传输完成标志位 
        return SUCCESS;
    }
    else
    {
        return ERROR;
    }
}

这里一个例子是5个数据的代码(实现2+2+1的亮法)可根据实际应用更改了:

void PixelRound_color(u8 left_r ,u8 left_g ,u8 left_b ,u8 right_r,u8 right_g,u8 right_b, u8 front_r,u8 front_g,u8 front_b )//RGB????
{
		LEDPixel[0].red = left_r;///红
		LEDPixel[0].blue = left_g;	
		LEDPixel[0].green = left_b;	
		LEDPixel[1].red = left_r;
		LEDPixel[1].blue= left_g;	
		LEDPixel[1].green = left_b;//绿		
		LEDPixel[2].red = right_r;//蓝
		LEDPixel[2].blue= right_g;	
		LEDPixel[2].green = right_b;	
		LEDPixel[3].red = right_r;///黄
		LEDPixel[3].blue= right_g;	
		LEDPixel[3].green = right_b;	
		LEDPixel[4].red = front_r;///青
		LEDPixel[4].blue= front_g;	
		LEDPixel[4].green = front_b;	
		LEDPixel[5].red = 0;///紫
		LEDPixel[5].blue= 0;	
		LEDPixel[5].green = 0;	
		LED_SPI_Update(LEDPixel,5);
}

配置代码(有点混乱,没有时间整理,直接发出来了):

/********************************************************************************************************
**函数信息 :SPIM_Init(unsigned short spi_baud_div)            
**功能描述 :可修改参数初始化SPI
**输入参数 :spi_baud_div
**输出参数 :无
********************************************************************************************************/
void SPIM_Init(SPI_TypeDef* SPIx,unsigned short spi_baud_div)
{
	
//	SPI_InitTypeDef SPI_InitStructure;
	GPIO_InitTypeDef  GPIO_InitStructure;
	
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);  //SPI1 clk enable
	SPIM_CSHigh(SPIx);
	
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB|RCC_AHBPeriph_GPIOA, ENABLE); 
	
	GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_5;   //spi1_mosi PA7	  //spi1_sck  PA5 
	                                                                    
	                                                                    
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//GPIO_Mode_AF_PP; 	// 推免复用输出
	GPIO_Init(GPIOB, &GPIO_InitStructure);
	
//	GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_4;   	//spi1_cs   PA4
//	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
//	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//
//	GPIO_Init(GPIOA, &GPIO_InitStructure);	
// 
//	GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_6;  		//spi1_miso  PA6
//	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
//	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; 		//上拉输入   
//	GPIO_Init(GPIOA, &GPIO_InitStructure);

//  SPIM_CSHigh(SPI1);  //CS high

	GPIO_PinAFConfig(GPIOB,GPIO_PinSource5,GPIO_AF_0);           //开复用时钟
//	GPIO_PinAFConfig(GPIOA,GPIO_PinSource6,GPIO_AF_0);
//	GPIO_PinAFConfig(GPIOA,GPIO_PinSource7,GPIO_AF_0);
	
  SPI1->GCTL|=SPI_GCTL_MM;//主机模式
  SPI1->CCTL|=SPI_CCTL_SPILEN;//8位数据宽度
    
//	SPI1->GCTL|=	SPI_GCTL_DATA_SEL;//32 bit 有效
		
  SPI1->CCTL&=~SPI_CCTL_CPOL;//SPI_CPOL_Low    // //spi MODE0  CLK 空闲低电平  上升沿采样下降沿送数据
  SPI1->CCTL|=SPI_CCTL_CPHA;//SPI_CPHA_1Edge
    
  SPI1->GCTL&=~SPI_GCTL_NSS_SEL; //软件控制NSS
  SPI1->CCTL |=0x10;             //开启高速模式
  SPI1->SPBRG =spi_baud_div;//4分频,波特率应该为72M/4=18M
//  SPI1->CCTL&=~SPI_CCTL_LSBFE;//MSB
	SPIx->CCTL|=SPI_CCTL_LSBFE;    //LSB  
//		
	SPI1->EXTCTL = 0x10;               //16bit 数据长度

		
	SPIM_TXEn(SPI1);//SPI发送使能	
 	SPIM_RXEn(SPI1);//SPI接收使能		

//  SPI_Cmd(SPI1, ENABLE); 			//Enables the specified SPI peripheral SPI使能、从机模式 8位数据模式 SPI 的波特率

}


/********************************************************************************************************
**函数信息 :SPI_DMA_TX_Init            
**功能描述 : SPI发送DMA初始化
**输入参数 :
**输出参数 :无
********************************************************************************************************/
void SPI_DMA_TX_Init(u16 *TX_buffer)
{
	DMA_InitTypeDef  DMA_InitStructure;
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);	//使能DMA传输
	DMA_DeInit(DMA1_Channel3);
	DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&(SPI1->TXREG);//SPI发送数据寄存器
	DMA_InitStructure.DMA_MemoryBaseAddr =(uint32_t)&(*TX_buffer);
	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;//数据从memory到外设
	DMA_InitStructure.DMA_BufferSize = TX_RX_LEN;//发送数据个数
	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外设地址不改变
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//memory地址递增开启
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;//DMA_PeripheralDataSize_Byte;/内存地址增量(变化)
	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;//DMA_MemoryDataSize_Byte;/外设传输宽度(字节)
	DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;//普通模式
	DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
	DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
	DMA_Init(DMA1_Channel3, &DMA_InitStructure);//SPI TX为DMA通道3
}

工程代码过几天附上。

你可能感兴趣的:(LED相关)