99久久全国免费观看_国产一区二区三区四区五区VM_久久www人成免费看片中文_国产高清在线a视频大全_深夜福利www_日韩一级成人av

一個IO控制很多個LED,這個技能你get到了嗎

實現目標

  • 每隔一秒,點亮模塊上的一個LED
  • 點亮模塊上的所有LED

所需工具及環境

  • Keil 5
  • STM32F103RET6核心板(本平臺自制專用核心板,隨便找一個開發板亦可)
  • 8位 圓形 WS2812B LED模塊

本文源碼

簡介

電壓:DC4~7V

多位(幾個LED就是幾位)通過引腳級聯接一個到另一個的輸出引腳,通過這種級聯的方式,只需要使用一個IO口(單片機引腳)就能控制盡可能多的LED,每個LED都集成了一顆驅動芯片在里面,讓我們的LED變得智能和尋址,每一個內部都有恒流驅動,所以LED顏色非常一致,即使電壓有小幅抖動,電壓變化也是一樣的。

不需要外部電阻——限流電阻使LED燈的布局設計變得簡單。

單線通信,能夠最大限度的減少單片機IO口的壓力,另外這款RGB燈使用了WS2812B驅動芯片,讓外圍電路只需要一顆電容就能夠滿足電路需求,從而最大可能的讓電路變得簡單優美。

特點

  1. 智能反接保護,電源反接不會損壞IC;
  2. IC控制電路與LED點光源公用一個電源;
  3. 控制電路與RGB芯片集成在一個5050封裝的元器件中,構成一個外控像素點;
  4. 內置信號整形電路,任何一個像素點收到信號后經過波形整形再輸出,保證線路波形畸變不會累加;
  5. 內置上電復位和掉電復位電路;
  6. 每個像素點的三基色顏色可實現256級亮度顯示,完成16777216種顏色的全真色彩顯示,掃描頻率不低于400Hz;
  7. 串行級聯接口,能通過一根信號線完成數據的接收與解碼;
  8. 任意兩點傳輸距離在不超過5米時,無需增加額外電路;
  9. 當刷新速率30幀/秒時,級聯數不小于1024點;
  10. 數據發送速度可達800Kbps;
  11. 光的顏色高度一致,性價比高。

注意: 800Kbps,相當于1.25us傳輸一比特數據。

引腳圖

引腳功能描述:

NO.Symbol功能描述1VDDLED的供電電源,Vdd 范圍 +3.5~+5.3 V2DOUT控制信號數據輸出引腳3VSS地4DIN控制信號數據輸入引腳

典型電路

串聯方法

原理圖

除了燈珠以外只需要額外增加一個0.1uF的電容即可。

硬件連接

STM32F103RET6核心板WS2812B模塊PA6DINVCC+5VGNDGND

驅動原理

數據協議采用單線歸零碼的通訊方式,像素點在上電復位以后,DIN端接受從控制器傳輸過來的數據,首先送過來的24bit數據被第一個像素點提取后,送到像素點內部的數據鎖存器,剩余的數據經過內部整形處理電路整形放大后通過DOUT端口開始轉發輸出給下一個級聯的像素點,每經過一個像素點的傳輸,信號減少24bit。

像素點采用自動整形轉發技術,使得該像素點的級聯個數不受信號傳送的限制,僅僅受限信號傳輸速度要求。

因為數據被內部鎖存,所以只要不改變顏色值(模塊持續供電),顏色是不會發生改變的,設置顏色的脈沖也不需要持續提供(單片機發生復位也無影響),只需要在修改顏色值的時候,發送一遍即可。

0和1的區分

Treset:復位時間

由上圖可知,我們要發送 ‘0’ ,需要將GPIO引腳置高并持續0.4 us(400 ns),然后GPIO置低并持續0.85 us(850 ns),此過程即完成0 code的發送,具體代碼實現如下:

void send_0(void)
{
	IN_H;
	Wait400ns;
	IN_L;
	Wait850ns;
}

我們要發送 ‘1’ ,需要將GPIO引腳置高并持續0.85 us(850 ns),然后GPIO置低并持續0.4 us(400 ns),此過程即完成1 code的發送,具體代碼實現如下:

void send_1(void)
{
	IN_H;
	Wait850ns;
	IN_L;
	Wait400ns;
}

所以本程序的難點即是求取400 ns 和 850 ns 相對精確的延時時間。

延時函數的實現

單片機里的延時函數一般通過執行一些無意義的循環進行延時,比如定義如下函數:

void delay(unsigned char i)
{
  while(--i);
}

我們這里需要的延時周期很小,才1.25us,因為函數的調用,需要入棧和出棧,所以如果使用上面的延時函數的方式的話,那么一進一出就接近幾百ns的時間就沒了,所以為了精確控制,我們這里延時函數的定義如下:

#define    Wait10nop        {__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();}
#define    Wait250ns        {__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();}
#define    Wait400ns        {Wait250ns;Wait10nop;}    //388
#define    Wait850ns        {Wait250ns;Wait10nop;Wait10nop;Wait10nop;Wait10nop;__NOP();__NOP();__NOP();__NOP();__NOP();}    //860

我們在main函數中使用如下方式測試這個延時函數:

while(1)
{
	IN_H;
	//Wait250ns;
	Wait850ns;
	IN_L;
	//Wait250ns;
	Wait850ns;
}

然后用示波器觀察與模塊DIN引腳相連的GPIO輸出的脈沖信號,查看其高電平是否與咱們預定義的一致,如果不一致,增加或減少空指令進行調整。

注意一個 __NOP(); 空指令的耗時大約:1000/72 ≈ 14 ns 的時間,自己可以在上面定義的基礎上,根據需要隨意增加或者減少 __NOP(); 空指令的個數。

注意空指令前面是兩個“_”。

經過示波器測量,不斷調整,上面定義的 Wait250ns 宏定義的耗時如下圖所示。

經過示波器測試,上面的 Wait400ns 耗時為 388 ns , Wait850ns 耗時為 860 ns,滿足上面"0"和"1"的時間區間范圍。

24 bit數據的組成

注意: 數據傳輸順序按GRB順序傳輸,并且高位在前。

void ws2812_rgb(u8 ws_num,u8 ws_r,u8 ws_g,u8 ws_b)	
{
	ws_data[(ws_num-1)*3]=ws_g;
	ws_data[(ws_num-1)*3+1]=ws_r;
	ws_data[(ws_num-1)*3+2]=ws_b;
}

ws_data[] 數組中用于記錄待傳輸的RGB數據,每一個燈珠的顏色占用三個字節,因為數據傳輸順序按GRB的順序傳輸,所以賦值的時候注意先后順序,上面函數是設置某一個燈珠的顏色值。

ws_data[] 數組中顏色值設置完畢之后,就要把這個數組的數據發送到模塊中,具體的實現函數如下:

void ws2812_refresh(u8 ws_count)
{
	u8 ws_ri=0;
    
	for(;ws_ri<ws_count*3;ws_ri++)
	{
		if((ws_data[ws_ri]&0x80)==0)	send_0();	else send_1();
		if((ws_data[ws_ri]&0x40)==0)	send_0();	else send_1();
		if((ws_data[ws_ri]&0x20)==0)	send_0();	else send_1();
		if((ws_data[ws_ri]&0x10)==0)	send_0();	else send_1();
		if((ws_data[ws_ri]&0x08)==0)	send_0();	else send_1();
		if((ws_data[ws_ri]&0x04)==0)	send_0();	else send_1();
		if((ws_data[ws_ri]&0x02)==0)	send_0();	else send_1();
		if((ws_data[ws_ri]&0x01)==0)	send_0();	else send_1();
	}
    
    //延時一段時間
	ws2812_reset();
}

ws_data[] 數組中的每一個字節按位判斷發送,因為高位在前,所以先發送每個字節的高位,獲取最高位的值的方法為:ws_data[ws_ri]&0x80 。

數據傳輸方法

N位的模塊,一次就要發送 N * 3 字節的數據。

注意: D1的數據是通過單片機發送,D2,D3,D4通過像素內重塑放大傳輸。

main函數調用

main函數中,每隔1S,點亮一個LED,當8個LED都點亮一次之后,所有LED點亮一次,然后再開啟下一次循環。

main函數的具體實現如下所示:

int main(void)  
{ 
	int times = 0; 
    
	//初始化
	//延時函數初始化 	 
	delay_init();
		  
	uart_init(115200);	 		//串口1:Debug,初始化為115200 

    ws2812_init();
    
	printf("System Init OK ...\r\n");
	
	while(1) 
	{		
		times++;	

        if(times > 8)
            times = 0;
        
        switch(times)
        {
            case 0:
                ws2812_rgb(1, WS_RED);
                ws2812_rgb(2, WS_GREEN);
                ws2812_rgb(3, WS_BLUE);
                ws2812_rgb(4, WS_WHITE);
                ws2812_rgb(5, WS_PURPLE);
                ws2812_rgb(6, WS_YELLOW);
                ws2812_rgb(7, WS_BROWN);
                ws2812_rgb(8, WS_BLUE);
                ws2812_refresh(8);
                break;
            case 1:
                memset(ws_data,0,WS_ARRAY_SIZE*sizeof(u8)); 
                ws2812_rgb(1, WS_RED);
                ws2812_refresh(8);
                break;
            case 2:
                memset(ws_data,0,WS_ARRAY_SIZE*sizeof(u8)); 
                ws2812_rgb(2, WS_GREEN);
                ws2812_refresh(8);
                break;
            case 3:
                memset(ws_data,0,WS_ARRAY_SIZE*sizeof(u8)); 
                ws2812_rgb(3, WS_BLUE);
                ws2812_refresh(8);
                break;
            case 4:
                memset(ws_data,0,WS_ARRAY_SIZE*sizeof(u8)); 
                ws2812_rgb(4, WS_WHITE);
                ws2812_refresh(8);
                break;
            case 5:
                memset(ws_data,0,WS_ARRAY_SIZE*sizeof(u8)); 
                ws2812_rgb(5, WS_PURPLE);
                ws2812_refresh(8);
                break;
            case 6:
                memset(ws_data,0,WS_ARRAY_SIZE*sizeof(u8)); 
                ws2812_rgb(6, WS_YELLOW);
                ws2812_refresh(8);
                break;
            case 7:
                memset(ws_data,0,WS_ARRAY_SIZE*sizeof(u8)); 
                ws2812_rgb(7, WS_BROWN);
                ws2812_refresh(8);
                break;
            case 8:
                memset(ws_data,0,WS_ARRAY_SIZE*sizeof(u8)); 
                ws2812_rgb(8, WS_BLUE);
                ws2812_refresh(8);
                break;
        }
        
        delay_ms(1000);        
	}  
}

顏色RGB值查詢

顏色的RGB值和名稱可以參考下面鏈接:

https://code.ziqiangxuetang.com/try/color.py

程序中顏色預定義如下:

#define WS_DARK 	0,0,0
#define WS_WHITE 	255,255,255
#define WS_RED 		255,0,0
#define WS_GREEN 	0,255,0
#define WS_BLUE 	0,0,255
#define WS_YELLOW 	255,255,0
#define WS_PURPLE   255,0,255
#define WS_CYAN 	0,255,255
#define WS_BROWN    165,42,42

大家可以根據自己的喜歡,隨意替換顏色。

結果展示

聲明:本內容為作者獨立觀點,不代表電子星球立場。未經允許不得轉載。授權事宜與稿件投訴,請聯系:editor@netbroad.com
本篇所含全部資料,點擊此處留下郵箱我會發給你
資料明細:文中對應WS2812B模塊資料、數據手冊及工程源碼。
覺得內容不錯的朋友,別忘了一鍵三連哦!
贊 4
收藏 5
關注 69
成為作者 賺取收益
全部留言
0/200
  • dy-geKbk8iH 02-12 11:48
    謝謝!作者提供的詳細資料作為一個職教學院的老師,對作者的無私幫助表示感謝 20****@****.com
    回復 1條回復
  • oysliang 2021-01-22 17:55
    老師,能不能發我一下資料,謝謝! 10****@****.com
    回復 1條回復
主站蜘蛛池模板: 男人添女人下身视频高清 | 日本护士体内SHE精2╳╳╳ | 91精品论坛 | 亚洲一区二区三区不卡国产欧美 | 西西最大胆日本无码视频 | 人人妻人人澡人人爽人人精品AV | 精品国产青草久久久久96 | 欧美aaaaaabbbbb | 日韩爱爱片 | 91肥熟| wwwwwww黄| 一区二区三区日韩一区二区中文 | 欧美国产精品久久久 | japan高清日本乱xxxxx | 久久久女人视频 | 男女啪啪做爰高潮无遮挡 | 在线国产精品一区 | 桃子视频在线观看高清免费视频 | 国产免费国产 | 国产精品无套内射迪丽热巴 | 动漫无码3d在线观看 | 飘雪影院免费版在线观看视频 | 99久久ER热在这里只有精品99 | 18禁黄久久久AAA片 | 视频一区视频二区视频三区视频四区国产 | www在线免费观看欧美黄 | 亚洲综合啪啪 | 扒开双腿猛进入喷水高潮视频 | 在线不卡视频 | 国产精品人妻无码久久久郑州天气网 | 无码国产69精品久久久久 | 嫩草av91| 国产精品99久久久久久久 | 日本一级待黄大片 | 成人性生交大片免费看中文 | 国产免费一区二区三区在线观看 | 在线视频麻豆 | 成人福利一区 | 大尺度做爰黄9996片视频 | 日韩免费视频播放 | 精品国产乱码久久久久久久 |