
本帖最后由 anny 于 2017-6-14 13:07 编辑 其实社区有朋友发帖子用STM32驱动WS2811灯带了,他们用的是硬件SPI,其实也可以用PWM。 今天我的驱动方式不是用单片机外设来驱动,而是用最古老的延时方式,这种方式不适合地方你们自己想了 ![]() 还有,我这个驱动方式可以兼容UCS1903、SM16703等等这些灯带。 驱动芯片:STM32F103RBT6 频率:72M 说明:为了保护单片机我用了块74HC245来隔离,也算是做了电压转换,从3.3V变成了5V 好吧,上程序: void WS2811_SendByte(u8 dat)//发送1BIT的数据 { u8 i; for(i=0;i<8;i++) { if(dat & 0x80) //发送数据1 { Light_SDA=1; delay_us(1); Light_SDA=0; __nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop(); } else //发送数据0 { Light_SDA=1;//0 __nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop(); Light_SDA=0; delay_us(1); } dat <<= 1; } } void Reset(void) { Light_SDA=0; delay_ms(30); } 基本的发数据程序就这样了 void send_data(u8 R,u8 G,u8 B) { u8 i; for(i=0;i<led_size;i++) { WS2811_SendByte(G); WS2811_SendByte(R); WS2811_SendByte(B); } Reset(); } void ls_mode(void) { u8 i=0,ys=0,yz=0; for(i=led_size;i>0;i--) { if(i<=ls_t) { if(ys<ls_t) { ys++; } else ys=0; WS2811_SendByte(LED_data[45-(ys%45)][1]); WS2811_SendByte(LED_data[45-(ys%45)][0]); WS2811_SendByte(LED_data[45-(ys%45)][2]); } else { if(yz>0) { yz--; } else yz=led_size-ls_t; WS2811_SendByte(LED_data[yz%45][1]); WS2811_SendByte(LED_data[yz%45][0]); WS2811_SendByte(LED_data[yz%45][2]); } } Reset(); } 这是应用程序,其实就是PLAY一个数组,我刚刚开始的方法是完全用FOR来实现,发现哪样做每种流水方式都要重新写,太痛苦了。PLAY数组里面的内容相对会方便很多,当然也可以在函数名上加指针用来实现PLAY哪个数组,这个就自行改善吧! const u8 LED_data[45][3]={ {55,0,255},//G,R,B {100,0,200}, {155,0,155}, {200,0,100}, {255,0,55},//5 {255,0,0}, {255,0,0}, {255,0,0}, {255,0,0}, {255,0,0}, {255,0,0}, {255,0,0}, {255,0,0}, {255,0,0}, {255,0,0},//15 {255,55,0}, {200,100,0}, {155,155,0}, {100,200,0}, {55,255,0},//20 {0,255,0},//G,R,B {0,255,0}, {0,255,0}, {0,255,0}, {0,255,0}, {0,255,0}, {0,255,0}, {0,255,0}, {0,255,0}, {0,255,0},//30 {0,255,55},//G,R,B {0,200,100}, {0,155,155}, {0,100,200}, {0,55,255}, {0,0,255},//35 {0,0,255}, {0,0,255}, {0,0,255}, {0,0,255}, {0,0,255}, {0,0,255}, {0,0,255}, {0,0,255}, {0,0,255}//45 }; 这是要PLAY的数组,这次实现的是流水灯,在颜色链接的地方加上了渐变,这样更好看。当然也可以换上其它的方式 单单上面的程序流水灯是流不起来的,在定时中断用变量++来驱动: void TIM2_IRQHandler(void) // 1s enter { if (TIM_GetITStatus(TIM2, TIM_IT_CC1) != RESET) { // ls_mode12(); if(++t2>=ls_speed) { t2=0; if(++ls_t>=led_size) //注意!! { ls_t=0; } } TIM_ClearITPendingBit(TIM2, TIM_IT_CC1 ); } } 这样在main函数调用ls_mode()灯就流起来了!! 漂亮的东西怎么没有视频: ![]() |
参与人数 4 | ST金币 +11 | 收起 理由 |
---|---|---|
|
+ 1 | 赞一个! |
|
+ 2 | 很给力! |
|
+ 5 | 很给力! |
|
+ 3 | 赞一个! |
思路就是用MOSI脚驱动,然后直接发送数据,用逻辑分析仪看高低电平的时间,然后做调整,比如发SPI发送0xE0,其实就是发送了3个1,5个0,这样低电平的时间就肯定长,然后自己看着来调整就行了。
请问您这边有思路吗,我也是想只使用定时器的PWM实现,补寄有的单片机没有DMA控制器
是72M的