赞
踩
WS2812 内部集成了处理芯片和3颗不同颜色的led灯(红,绿,蓝),通过单总线协议分别控制三个灯的亮度强弱,达到全彩的效果。
T0H | 0码,高电平时间 | 220ns~380ns |
T1H | 1码,高电平时间 | 580ns~1us |
T0L | 0码,低电平时间 | 580ns~1us |
T1L | 1码,低电平时间 | 220ns~420ns |
RES | 帧单位,低电平时间 | 280us以上 |
每一个灯需要 8 bits(1 byte) 的数据 (8个1时最亮、8个0时不亮),所以一颗 ws2812 共需要24 bits(3 bytes) **(24个1时最亮、24个0时不亮)**的数据。
注:高位先发,按照 GRB 的顺序发送数据
G7 | G6 | G5 | G4 | G3 | G2 | G1 | G0 | R7 | R6 | R5 | R4 | R3 | R2 | R1 | R0 | B7 | B6 | B5 | B4 | B3 | B2 | B1 | B0 |
---|
绿色
1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
---|
红色
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
---|
蓝色
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
---|
1、使用 延时函数
直接翻转IO口产生时序,这种方式最为简单易用,只需要控制延时的时间,就可以从产生0和1码,它需要占用系统资源。
使用 SPI 数据传输产生时序
2、通过SPI控制
只需要控制在合适的波特率,在传输不同数据的时候,可以产生符合要求的0和1码,这种方式需要等同于使用了一个SPI设备
3、使用 DMA+Timer 产生时序
这种方式需要使用一个定时器,其中一个通道固定产生一个周期1.25us的PWM,占空比2/3,接着需要另一个通道,在周期的1/3处搬运数据到IO口,若为1,PWM不变,若为0,PWM则为0码,这种方式有更大的局限性,由于DMA只能搬运至少一个字节,所以每次会同时改变8个IO口的高低电平,或许使用位带操作可以解决这问题
4、使用 Timer+PWM+DMA 产生时序
本文讨论的实现方案,这种方案有2种驱动的方式,一种是直接建立一个大的数组,存放所有灯珠的数据,然后启动DMA传输,第二种是建立2个灯组数据大小的数组,当DMA传输一个灯珠数据时,改变另一个灯组数据,通过不断改变数组的方式,节约内存,相比较而言,第一种方式较为直观,第二种方式则可以解决灯珠较多的情况,本文讨论第一种的原理和程序的实现。
定时器 TIM 用以产生一个固定周期的PWM,DMA用以改变PWM 的占空比:
如图,DMA通过不断的搬运数据到定时器调节占空比的CCR寄存器,实现ws2812时序的产生,在STM32中,通过配置外设可实现:定时器每产生一次溢出事件(即计数完成),就请求一次DMA搬运一个数据(长度:字节/半字/字可选),所以用户只需要将数据排列在数组里,就可以产生所需要的时序。
1、选择芯片 STM32F103C8T6
2、选择下载方式
3、配置系统时钟
4、时钟树配置
5、生成工程配置
6、生成工程配置
7、定时器配置
8、DMA配置
9、选择TIM3_CH1/TRIG
10、选择Normal Byte Byte
11、GENERATE CODE生产代码
12、打开工程
13、编译成功
新建一个.c和.h文件
#include "ws2812.h" WS28xx_TypeStruct WS28xx; void __show() { HAL_TIM_PWM_Start_DMA(&WS28xx_PWM_hTIMER,WS28xx_PWM_Chaneel,(uint32_t *)(&WS28xx.WS28xx_Data),sizeof(WS28xx.WS28xx_Data)); } //设置index的颜色 void __SetPixelColor_RGB(unsigned short int index,unsigned char r,unsigned char g,unsigned char b) { unsigned char j; if(index > WS28xx.Pixel_size) return; for(j = 0; j < 8; j++) { WS28xx.WS28xx_Data.ColorRealData [24 * index + j] = (g & (0x80 >> j)) ? BIT_1 : BIT_0; //G 将高位先发 WS28xx.WS28xx_Data.ColorRealData [24 * index + j + 8] = (r & (0x80 >> j)) ? BIT_1 : BIT_0; //R将高位先发 WS28xx.WS28xx_Data.ColorRealData [24 * index + j + 16] = (b & (0x80 >> j)) ? BIT_1 : BIT_0; //B将高位先发 } } //获取某个位置的RGB void __GetPixelColor_RGB(unsigned short int index,unsigned char *r,unsigned char *g,unsigned char *b) { unsigned char j; *r=0; *g=0; *b=0; if(index > WS28xx.Pixel_size) return; for(j = 0; j <8; j++) { (*g)|=((WS28xx.WS28xx_Data.ColorRealData [24 * index + j] >=BIT_1)? 0x80>>j:0); //G (*r)|=((WS28xx.WS28xx_Data.ColorRealData [24 * index + j + 8] >=BIT_1)? 0x80>>j:0); //R (*b)|=((WS28xx.WS28xx_Data.ColorRealData [24 * index + j + 16]>=BIT_1)? 0x80>>j:0); //B } } void __SetPixelColor_From_RGB_Buffer( unsigned short int pixelIndex,unsigned char pRGB_Buffer[][3],unsigned short int DataCount) { unsigned short int Index,j=0; for(Index=pixelIndex;Index < WS28xx.Pixel_size; Index++) { WS28xx.SetPixelColor_RGB(Index,pRGB_Buffer[j][0],pRGB_Buffer[j][1],pRGB_Buffer[j][2]); j++; if(j>DataCount) return; } } //设置所有颜色 void __SetALLColor_RGB(unsigned char r,unsigned char g,unsigned char b) { unsigned short int Index; for(Index=0;Index < WS28xx.Pixel_size; Index++) { WS28xx.SetPixelColor_RGB(Index,r,g,b); } } void WS28xx_TypeStructInit() { WS28xx.Pixel_size=PIXEL_SIZE; WS28xx.GetPixelColor_RGB=__GetPixelColor_RGB; WS28xx.SetPixelColor_From_RGB_Buffer=__SetPixelColor_From_RGB_Buffer; WS28xx.SetPixelColor_RGB=__SetPixelColor_RGB; WS28xx.SetALLColor_RGB=__SetALLColor_RGB; WS28xx.show=__show; }
#ifndef MYLIB_WS28XX #define MYLIB_WS28XX #include "tim.h" /**************************************** *Config ****************************************/ #define BIT_1 61 //1码比较值为61-->850us #define BIT_0 28 //0码比较值为28-->400us #define PIXEL_SIZE 8 //灯的数量 #define WS28xx_PWM_hTIMER htim3 //定时器3 #define WS28xx_PWM_Chaneel TIM_CHANNEL_1 //通道1 //整个WS28xx_DataTypeStruct结构体将被以PWM方式发送 typedef struct { unsigned char ColorStartData[3]; //3个0等待PWM稳定 unsigned char ColorRealData[24*PIXEL_SIZE];//实际GRB数据(已经转换为PWM对应的值) unsigned char ColorEndData; //结束位为0 }WS28xx_DataTypeStruct; /**************************************** *对象化编程 ****************************************/ typedef struct { //实际发送的数据 WS28xx_DataTypeStruct WS28xx_Data; //灯数量 unsigned short int Pixel_size; //单独设置index的RGB颜色 void (*SetPixelColor_RGB)(unsigned short int index,unsigned char r,unsigned char g,unsigned char b); //从RGB数据读出:设置index的RGB颜色 void (*SetPixelColor_From_RGB_Buffer)( unsigned short int pixelIndex,unsigned char pRGB_Buffer[][3],unsigned short int DataCount); //设置所有为RGB颜色 void (*SetALLColor_RGB)(unsigned char r,unsigned char g,unsigned char b); //获取某个位置的RGB void (*GetPixelColor_RGB)(unsigned short int index,unsigned char *r,unsigned char *g,unsigned char *b); //显示(发出数据) void (*show)(void); }WS28xx_TypeStruct; extern WS28xx_TypeStruct WS28xx; void WS28xx_TypeStructInit(void); #endif
注:记得在main.c中加上初始化函数 WS28xx_TypeStructInit
WS28xx.SetALLColor_RGB (255,0,0);//整体红色 WS28xx.show (); HAL_Delay (200); WS28xx.SetALLColor_RGB (0,255,0);//整体绿色 WS28xx.show (); HAL_Delay (200); WS28xx.SetALLColor_RGB (0,0,255);//整体蓝色 WS28xx.show (); HAL_Delay (200); WS28xx.SetALLColor_RGB (0,0,0); //集体熄灭 WS28xx.show (); WS28xx.SetPixelColor_RGB(0,0,0,255);//第一个亮蓝灯 WS28xx.show (); HAL_Delay (200); WS28xx.SetALLColor_RGB (0,0,0); WS28xx.SetPixelColor_RGB(1,0,0,255);//第二个亮绿灯 WS28xx.show (); HAL_Delay (200); WS28xx.SetALLColor_RGB (0,0,0); WS28xx.SetPixelColor_RGB(2,0,0,255);//第三个亮蓝灯 WS28xx.show (); HAL_Delay (200); WS28xx.SetALLColor_RGB (0,0,0); WS28xx.SetPixelColor_RGB(2,0,0,255);//第四个亮蓝灯 WS28xx.show (); HAL_Delay (200); WS28xx.SetALLColor_RGB (0,0,0); WS28xx.SetPixelColor_RGB(4,0,0,255);//第五个亮蓝灯 WS28xx.show (); HAL_Delay (200); WS28xx.SetALLColor_RGB (0,0,0); WS28xx.SetPixelColor_RGB(5,0,0,255);//第六个亮蓝灯 WS28xx.show (); HAL_Delay (200); WS28xx.SetALLColor_RGB (0,0,0); WS28xx.SetPixelColor_RGB(6,0,0,255);//第七个亮蓝灯 WS28xx.show (); HAL_Delay (200); WS28xx.SetALLColor_RGB (0,0,0); WS28xx.SetPixelColor_RGB(7,0,0,255);//第八个亮蓝灯 WS28xx.show (); HAL_Delay (200);
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。