WS2812B(矩阵LED)【10】

目录

1 WS2812B

1.1 简介

1.2 WS2812B原理

1.2.1 WS2812B内部结构         

1.2.2 数据传输方式

​2 基于8*8图像显示

2.1 思路

3 基于UART图像发送WS2812B显示 

3.1 思路

3.1.1 信号匿化模块 (param)

 3.1.2 UART发送

3.1.3 WS2812B模块

3.1.4 顶层TOP

1 WS2812B

1.1 简介

        AWC_C4 FPGA开发套件上板载8行8列共64个WS2812灯珠,构成一个8*8的LED点阵,主要用于静态或动态显示彩色数字、字符以及特效等。该部分电路由64个RGB三色发光二极管采用串行级联的方式组成,仅通过一根信号线即可完成数据的接收与 解码。RGB三色发光二极管采用的是WORLDSEMI公司的发光二极管,型号为WS2812C-2020。此外,由于信 号线IO电平标准为3.3V,为匹配RGB三色发光二极管的驱动电平要求(5V),采用TI公司的单位双电源 总线收发器芯片进行配置电压转换,型号为SN74LVC1T45DBVR。

1.2 WS2812B原理

1.2.1 WS2812B内部结构         

        WS2812 是将控制电路与发光电路集于一体的智能外控 LED 光源,外观和 5050 LED 灯珠一样,并且每个元件就是一个像素点。其像素点内部包含了智能数字接口、数据锁存、信号整形放大驱动电路,还有高精度的内部振荡器以及可编程定电流控制部分。这些内部电路模块协同工作,能有效确保像素点光的颜色高度一致,使得最终呈现出的灯光色彩效果更加均匀、准确。

1.2.2 数据传输方式

数据量与点亮方式:每个灯珠需要 24bit 数据来点亮,这意味着要精确控制每个灯珠所发出的颜色等显示状态,就需要向其准确传输特定的 24bit 数据组合。

数据传输协议:采用单线归零码的通讯方式。在像素点上电复位后,从控制器经 DIN 端传输过来的数据开始起作用。首先传输过来的 24bit 数据会被第一个像素点提取,然后送入其内部的数据锁存器,以确定该像素点的显示状态。而剩余的数据会经过内部整形处理电路进行整形放大,再通过 DO 端口转发输出给下一个级联的像素点,并且每经过一个像素点传输,信号就会相应减少 24bit,按照这样的规则依次向后传递,最终实现对整个串行连接的多个灯珠的分别控制,从而让整个 8×8 的 LED 点阵能够按预期显示出各种灯光图案或色彩组合等效果。

        像素点采用自动整形转发技术,使得该像素点的级联个数不受信号传送的限制,仅受 限信号传输速度要求。高达2KHz的端口扫描频率, 在高清摄像头的捕捉下都不会出现闪 烁现象,非常适合高速移动产品的使用。280μs以上的RESET时间,所以即使出现中断 也不会引起误复位,可以支持更低频率、价格便宜的MCU。LED具有低电压驱动、环保节 能、亮度高、散射角度大、一致性好、超低功率及超长寿命等优点。将控制电路集成于 LED 上面,电路变得更加简单,体积小。每个LED灯珠有4个引脚,见下表。

        FPGA 驱动WS2812 灯珠点亮,是通过DIN引脚以串行的方式输入单bit数据(0或1), 需要遵循WS2812的通信时序,每驱动一个灯珠FPGA需要发送24bit(GRB888格式)数据, 每一bit数据都是由一段时间高电平和一段时间低电平组成,如下图所示。 

        然后一个点阵由多少个灯珠构成,那每次刷新就需要传输多少个24bit数据,并且在 每两次刷新之间需要280us的复位时间,复位状态下输入为低电平0即可;需要注意的是, 每个灯珠对应的数据需要按照如下图所示的顺序发送,按照G、B、R从高位到低位发送。

2 基于8*8图像显示

2.1 思路

        WS2812B是一种常见的RGB LED灯带,每个灯珠内部都有一个芯片控制,通过发送特定的时序数据来控制其亮灭。发送数据时,需要按照一定的时序发送24位RGB数据,其中高位在前低位在后,格式为GRB。并且1个LED需要24bit数据,其复位时间需要280us以上(8*8矩阵需要64led:64*24)。数据采用单总线,归零码的通讯方式;一个比特数据时,逻辑 0对应的高电平时间约为(400)220-380,低电平时间约为(800)580-1000;逻辑 1 对应的高电平时间约为(800)580-1000,低电平时间约为(400)220-380。1bit传输时钟时间大概就是1200=T_H+T_L;

/**************************************************************
@File    :   ws2812b_driver.v
@Time    :   2024/12/09 19:49:10
@Author  :   劉劉 
@EditTool:   VS Code 
@Font    :   UTF-8 
@Function:   WS2812B驱动模块(WS2812B属于单工)[GRB]
WS2812B 只有一个数据输入引脚 DI
**************************************************************/
module ws2812b_driver(
    input                clk        ,         
    input                rst_n      , 
    output     reg       dq           
);
parameter   TIME_0_H    =   400/20,//220—380
            TIME_0_L    =   800/20,//580—1000
            TIME_1_H    =   800/20,//580—1000
            TIME_1_L    =   400/20,//220—380
            TIME_1BIT   =   1200/20,//0_H+0_L与1_H+1_L:1200
            TIME_RES    =   300_000_000/20;//RES > 280us 1张图像到下一张图像的延时

parameter   IDLE    =   3'b001,
            DATA    =   3'b010,
            DONE    =   3'b100;

wire    idle_to_data;
wire    data_to_done;
wire    done_to_idle;

reg [2:0]   steat_c,steat_n;

reg	[6:0] cnt_64;
wire		  add_64_cnt,end_64_cnt;	

reg	[4:0] cnt_24;
wire		  add_24_cnt,end_24_cnt;	

reg	[$clog2(TIME_1BIT)-1:0] cnt_1_bit;
wire		  add_1_bit_cnt,end_1_bit_cnt;	

reg	[1:0] cnt_picture;
wire		  add_picture_cnt,end_picture_cnt;	

reg	[$clog2(TIME_RES)-1:0] cnt;
wire		  add_cnt,end_cnt;	

reg [23:0]  data_1;

reg [23:0]  data_2;

wire    [23:0]  data [191:0];   //寄存器组 192个24位宽的寄存器
/**************************************************************
        状态机                     
**************************************************************/
always @(posedge clk or negedge rst_n) begin
    if(!rst_n)
        steat_c <= IDLE;
    else 
        steat_c <= steat_n;
end

always @(*) begin
    case (steat_c)
        IDLE    :if(idle_to_data)
                    steat_n = DATA;
                else
                    steat_n = steat_c;
        DATA    :if(data_to_done)
                    steat_n = DONE;
                else
                    steat_n = steat_c;
        DONE    :if(done_to_idle)
                    steat_n = IDLE;
                else
                    steat_n = steat_c;  
        default : steat_n = IDLE;        
    endcase
end

assign    idle_to_data  =   (steat_c == IDLE) && rst_n;
assign    data_to_done  =   (steat_c == DATA) && end_64_cnt;
assign    done_to_idle  =   (steat_c == DONE) && end_cnt;

/**************************************************************
        计数器:64=8*8 led               
**************************************************************/
always@(posedge clk or negedge rst_n)	
    if(!rst_n)								
        cnt_64 <= 'd0;						
    else    if(add_64_cnt) begin				
        if(end_64_cnt)						
            cnt_64 <= 'd0;  				
        else									
            cnt_64 <= cnt_64 + 1'b1;		
    end											
assign add_64_cnt = end_24_cnt ;
assign end_64_cnt = add_64_cnt && cnt_64 == 64 - 1 ;

/**************************************************************
        计数器:1个led灯亮24bit计数器                       
**************************************************************/
always@(posedge clk or negedge rst_n)	
    if(!rst_n)								
        cnt_24 <= 'd0;						
    else    if(add_24_cnt) begin				
        if(end_24_cnt)						
            cnt_24 <= 'd0;  				
        else									
            cnt_24 <= cnt_24 + 1'b1;		
    end											
assign add_24_cnt = end_1_bit_cnt ;
assign end_24_cnt = add_24_cnt && cnt_24 == 24 - 1 ;

/**************************************************************
        计数器:1bit发送的时间                  
**************************************************************/
always@(posedge clk or negedge rst_n)	
    if(!rst_n)								
        cnt_1_bit <= 'd0;						
    else    if(add_1_bit_cnt) begin				
        if(end_1_bit_cnt)						
            cnt_1_bit <= 'd0;  				
        else									
            cnt_1_bit <= cnt_1_bit + 1'b1;		
    end											
assign add_1_bit_cnt = steat_c == DATA ;
assign end_1_bit_cnt = add_1_bit_cnt && cnt_1_bit == TIME_1BIT - 1 ;

/**************************************************************
        计数器:传输多少个图像                       
**************************************************************/
always@(posedge clk or negedge rst_n)	
    if(!rst_n)								
        cnt_picture <= 'd0;						
    else    if(add_picture_cnt) begin				
        if(end_picture_cnt)						
            cnt_picture <= 'd0;  				
        else									
            cnt_picture <= cnt_picture + 1'b1;		
    end											
assign add_picture_cnt = end_cnt ;
assign end_picture_cnt = add_picture_cnt && cnt_picture == 3-1 ;

/**************************************************************
        计数器:发一帧图像的回复复位时间                     
**************************************************************/
always@(posedge clk or negedge rst_n)	
    if(!rst_n)								
        cnt <= 'd0;						
    else    if(add_cnt) begin				
        if(end_cnt)						
            cnt <= 'd0;  				
        else									
            cnt <= cnt + 1'b1;		
    end											
assign add_cnt = steat_c == DONE ;
assign end_cnt = add_cnt && cnt == TIME_RES - 1 ;

/**************************************************************
        每一bit的高电平 或 低电平持续时间判断                    
**************************************************************/
always @(posedge clk or negedge rst_n) begin
    if(!rst_n)
        dq    <=  'b0;
    else begin
        case (steat_c)
            DATA    :   if(data_2 == 1)begin
                            if(cnt_1_bit <= 30)
                                dq <= 1'b1;
                            else
                                dq <= 1'b0;
                        end
                        else begin
                         
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值