本帖最后由 anny 于 2017-6-14 13:07 编辑 5 e+ {, I; |" H 其实社区有朋友发帖子用STM32驱动WS2811灯带了,他们用的是硬件SPI,其实也可以用PWM。 今天我的驱动方式不是用单片机外设来驱动,而是用最古老的延时方式,这种方式不适合地方你们自己想了,优点是灵活,想在哪个IO口驱动随便换。 E4 V* c' I4 ~% E3 H( @7 r2 b 还有,我这个驱动方式可以兼容UCS1903、SM16703等等这些灯带。 a3 I9 b# K. S+ m- e# c- P2 r 驱动芯片:STM32F103RBT6 频率:72M 说明:为了保护单片机我用了块74HC245来隔离,也算是做了电压转换,从3.3V变成了5V 好吧,上程序:6 @; ?' [! y$ J2 j void WS2811_SendByte(u8 dat)//发送1BIT的数据7 Z4 P$ \3 t! | { u8 i;4 f3 S. b1 Q! ^' _9 W$ L6 N for(i=0;i<8;i++)) F1 a/ W4 M a& I1 \ {* A( t% T5 d# m/ p if(dat & 0x80) //发送数据1 { Light_SDA=1;, ^( Z Z; }$ w/ w* G4 } delay_us(1); Light_SDA=0; __nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop(); } J$ u$ u4 A4 d" R% S! v( k! C else //发送数据0* {& |# P. r2 t$ d5 c1 c Z5 A6 W { Light_SDA=1;//0 __nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop(); Light_SDA=0; delay_us(1); } dat <<= 1; } } u4 k0 } z; e, l 1 b V- ^, d/ a) \, H, S) Z " K. f) c+ P J4 `* L void Reset(void) 7 ~# b g9 W, y) n& Q) d { 4 _* F F! o9 k; d. @ Light_SDA=0; delay_ms(30); Q+ {* Q/ Y2 b5 A/ O* I" F } b# a2 p6 @3 f- Z9 {& E! M 基本的发数据程序就这样了8 Z$ S+ v4 H- M7 B+ R void send_data(u8 R,u8 G,u8 B) {2 v8 Y3 ]/ Z3 s+ H u8 i;7 X. W! P7 S8 G; T% D* ] for(i=0;i<led_size;i++) { WS2811_SendByte(G); WS2811_SendByte(R); WS2811_SendByte(B); }* R9 ^5 Q; A! g4 D* ?" ~ }0 a, p Reset(); } void ls_mode(void)3 k+ I& z% ^" Y { u8 i=0,ys=0,yz=0; for(i=led_size;i>0;i--)2 A! _1 d2 {0 W- y { if(i<=ls_t)8 G! W! Z8 O# \/ J" Y6 Y8 u { if(ys<ls_t)3 M) {$ I9 K5 T4 t { ys++; } else ys=0;. U5 p* n7 y2 [) ?) M9 C WS2811_SendByte(LED_data[45-(ys%45)][1]); WS2811_SendByte(LED_data[45-(ys%45)][0]); WS2811_SendByte(LED_data[45-(ys%45)][2]);$ T2 ]0 `1 z6 P } else {1 S" q. y; }+ H, g" J8 I( k if(yz>0)+ S, X0 B4 e4 h7 z- B$ `( C: ~ { yz--; } else yz=led_size-ls_t;; N" j0 J9 ]% R+ W8 I0 m WS2811_SendByte(LED_data[yz%45][1]);: g* {. j' {3 T+ `3 ~' a- H* i WS2811_SendByte(LED_data[yz%45][0]); WS2811_SendByte(LED_data[yz%45][2]); }+ ?8 K, r$ R. I/ x/ x# X Y6 R D }' `; x: [* W W7 d: @7 J' i, @: g1 l+ b Reset();% |7 K, [5 i3 z2 f1 E K% [ }4 D9 b7 ~& m- H; N% b' i" j 0 S3 p# w8 t! h1 f8 P9 e 0 q1 O% m" O# I4 M5 B6 k5 T 这是应用程序,其实就是PLAY一个数组,我刚刚开始的方法是完全用FOR来实现,发现哪样做每种流水方式都要重新写,太痛苦了。PLAY数组里面的内容相对会方便很多,当然也可以在函数名上加指针用来实现PLAY哪个数组,这个就自行改善吧! const u8 LED_data[45][3]={ o" M% I4 d/ }: @2 E- s% S) R0 ^ {55,0,255},//G,R,B+ f8 |! s' Q8 G {100,0,200}, {155,0,155}, {200,0,100},3 y1 K- `) f6 m7 n( ]' Z: D4 Z {255,0,55},//5 {255,0,0},1 }: }# F4 E, Q/ B' u, P; T. I {255,0,0}, {255,0,0}, {255,0,0},: \3 F' _/ d1 @& {, A {255,0,0}, {255,0,0},0 I* q; R+ t& w" R+ T% q {255,0,0}," @& c1 C0 g" s' H$ W0 s" P {255,0,0}, {255,0,0}, {255,0,0},//15 {255,55,0}, {200,100,0}, {155,155,0},# D8 `- E7 O- i, w4 n {100,200,0}, {55,255,0},//209 A; ]$ k+ q% O8 V; u {0,255,0},//G,R,B {0,255,0},0 }6 Q! O- N. k) S5 y* ]2 p {0,255,0},9 e( [, R1 v) r" U A2 l- Q {0,255,0},0 `, }% l ^0 e {0,255,0},& F2 d! Q' ?! c5 i3 H. v! m {0,255,0}, i+ w$ o' B6 s) X {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},' I. Q' B, O( b& r) R' ~5 H6 U {0,100,200}, {0,55,255}, {0,0,255},//35 {0,0,255}, {0,0,255},8 ~; {1 }4 H) I. j, l) d7 y* ~+ L {0,0,255},( `# a, V" A: @; A {0,0,255}, {0,0,255}, {0,0,255},8 d6 ?) t( B1 W3 f/ } x" w3 F( R# f {0,0,255}, {0,0,255},# s b! t0 i' A! L# @/ |1 ` {0,0,255}//45/ i* P& o& e$ K; C }; % s) F& f; D8 L' ~8 D: c 3 u/ b+ s! g$ T: W' M2 U 这是要PLAY的数组,这次实现的是流水灯,在颜色链接的地方加上了渐变,这样更好看。当然也可以换上其它的方式9 N5 k7 a0 x5 T) f- ]( n1 ` 单单上面的程序流水灯是流不起来的,在定时中断用变量++来驱动:! T9 a; u6 q9 y9 P void TIM2_IRQHandler(void) // 1s enter { if (TIM_GetITStatus(TIM2, TIM_IT_CC1) != RESET)4 C. \7 ~) [0 `8 k {- O* `8 o) G% {) d. e. G // ls_mode12();6 u( v9 H0 x5 X% a( W if(++t2>=ls_speed)9 ?6 N8 l( U) g9 S, r8 N& L {. s+ ?+ K& p6 \- c, K t2=0; if(++ls_t>=led_size) //注意!!6 }2 C# u; A% {5 O+ w { ls_t=0; }- x: ~& X) n0 y2 _! B }+ R* ^' r% u. j9 g/ ^9 _. Q" l TIM_ClearITPendingBit(TIM2, TIM_IT_CC1 ); 3 h! L5 I3 F# a. d1 x* ] F } }0 W* Q$ o" `& e$ O0 `2 S 5 f& n' ~! m2 j$ N, \3 ^- _ 这样在main函数调用ls_mode()灯就流起来了!! Q. W: ]9 w3 h 漂亮的东西怎么没有视频: 6 {: }0 n$ x* } |
参与人数 4 | ST金币 +11 | 收起 理由 |
---|---|---|
勿忘初心ºº¹ | + 1 | 赞一个! |
pythonworld | + 2 | 很给力! |
shaoziyang | + 5 | 很给力! |
MrJiu | + 3 | 赞一个! |
思路就是用MOSI脚驱动,然后直接发送数据,用逻辑分析仪看高低电平的时间,然后做调整,比如发SPI发送0xE0,其实就是发送了3个1,5个0,这样低电平的时间就肯定长,然后自己看着来调整就行了。
请问您这边有思路吗,我也是想只使用定时器的PWM实现,补寄有的单片机没有DMA控制器
是72M的