【Verilog】FPGA驱动WS2812B点阵

这篇具有很好参考价值的文章主要介绍了【Verilog】FPGA驱动WS2812B点阵。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

1.整体框架

2.器件选择

        WS2812B-64 8x8点阵:

3.手册解读

        灯珠引脚:

        连接方式: 

         数据传输方式:

         数据波形构成:

         数据波形持续时间:

4.模块设计

        数据处理模块设计:

        控制模块设计:

        顶层设计:

5.仿真调试

        testbench:

        do文件:

        ModelSim仿真:

6.上板


1.整体框架

        通过按键触发控制模块数据处理模块将编辑好的数据进行单比特输出,控制模块根据数据处理模块输出的bit值产生0码,1码,复位码对应的波形并输出到WS1212B器件。

【Verilog】FPGA驱动WS2812B点阵

2.器件选择

        WS2812B-64 8x8点阵:

【Verilog】FPGA驱动WS2812B点阵

3.手册解读

        灯珠引脚:

【Verilog】FPGA驱动WS2812B点阵

        连接方式: 

        ws2812b的VDD默认5V,上一个灯珠输出端连接下一个灯珠的输入端。

【Verilog】FPGA驱动WS2812B点阵

         数据传输方式:

        每个灯珠只接收24bit数据,溢出的数据传输到下一个灯珠,直至64个灯珠全部接收完数据。【Verilog】FPGA驱动WS2812B点阵

      24bit数据发送顺序为G→R→B,MSB(最高有效位)先发。 【Verilog】FPGA驱动WS2812B点阵

         数据波形构成:

【Verilog】FPGA驱动WS2812B点阵

         数据波形持续时间:

【Verilog】FPGA驱动WS2812B点阵

4.模块设计

        数据处理模块设计:

编辑点阵上每个灯珠的对应数值,数值越大,灯珠的亮度就越高,如:

灯珠显示蓝色最亮display_data <= {{8{1'b0}},{8{1'b0}},{8{1'b1}}};

//----------------------------------------------------------------------------------------
// File name:           FPGA__WS2812B
// Last modified Date:  2022年10月21日
// Created by:          清影空明
// Descriptions:        数据处理模块
// Capture:             点阵循环显示 “FPGA”
//----------------------------------------------------------------------------------------
module data_drive(
    input                       clk		    ,
    input					    rst_n	    ,
    input                       req         ,
    input   wire    [15:0]      cnt_delay   ,   //帧延时计数器

    output  wire                rgb_done    ,   //完成1帧图像的显示
    output  reg     [23:0]      data            //输出1个灯珠的rgb数据
);

//Parameter Define

//Reg Define
reg     [23:0]      display_data [63:0]     ;   //存放显示数据
reg     [6:0]       cnt_rgb                 ;   //灯珠显示计数

//Wire Define
wire                add_cnt_rgb             ;
wire                end_cnt_rgb             ;

//integer
integer a,b,c,d,e,f,g,h,i,j;

//灯珠显示计数器
    always @(posedge clk or negedge rst_n)begin 
        if(!rst_n)
            cnt_rgb <= 1'b0 ;
        else if(add_cnt_rgb)
            if(end_cnt_rgb)
                cnt_rgb <= 1'b0 ;
            else
                cnt_rgb = cnt_rgb + 1'b1 ;
    end
    assign add_cnt_rgb = req;
    assign end_cnt_rgb = add_cnt_rgb && cnt_rgb == 64 - 1;
    assign rgb_done = end_cnt_rgb ;

//数据生成
    always @(posedge clk or negedge rst_n)begin 
        if(!rst_n)begin
            for (a=0;a<64;a=a+1) begin
                display_data[a] <= 1'b0 ;
            end
        end
        else begin
            if(cnt_delay == 0)begin//F
                for(b=0;b<2;b=b+1)begin
                    display_data[b]    <= {{8{1'b0}},{8{1'b0}},{8{1'b0}}};     
                    display_data[b+8]  <= {{8{1'b0}},{8{1'b0}},{8{1'b0}}};    
                    display_data[b+16] <= {{8{1'b0}},{8{1'b0}},{8{1'b0}}};    
                    display_data[b+24] <= {{8{1'b0}},{8{1'b0}},{8{1'b0}}};    
                    display_data[b+32] <= {{8{1'b0}},{8{1'b0}},{8{1'b0}}};    
                    display_data[b+40] <= {{8{1'b0}},{8{1'b0}},{8{1'b0}}};    
                    display_data[b+48] <= {{8{1'b0}},{8{1'b0}},{8{1'b0}}};    
                    display_data[b+56] <= {{8{1'b0}},{8{1'b0}},{8{1'b0}}}; 
                end
                for(b=0;b<1;b=b+1)begin
                    display_data[b+7]    <= {{8{1'b0}},{8{1'b0}},{8{1'b0}}};     
                    display_data[b+8+7]  <= {{8{1'b0}},{8{1'b0}},{8{1'b0}}};    
                    display_data[b+16+7] <= {{8{1'b0}},{8{1'b0}},{8{1'b0}}};    
                    display_data[b+24+7] <= {{8{1'b0}},{8{1'b0}},{8{1'b0}}};    
                    display_data[b+32+7] <= {{8{1'b0}},{8{1'b0}},{8{1'b0}}};    
                    display_data[b+40+7] <= {{8{1'b0}},{8{1'b0}},{8{1'b0}}};    
                    display_data[b+48+7] <= {{8{1'b0}},{8{1'b0}},{8{1'b0}}};    
                    display_data[b+56+7] <= {{8{1'b0}},{8{1'b0}},{8{1'b0}}}; 
                end
                for(b=0;b<2;b=b+1)begin
                    display_data[b+2]    <= {{8{1'b1}},{8{1'b1}},{8{1'b0}}};     
                    display_data[b+8+2]  <= {{8{1'b1}},{8{1'b1}},{8{1'b0}}};    
                    display_data[b+16+2] <= {{8{1'b1}},{8{1'b1}},{8{1'b0}}};    
                    display_data[b+24+2] <= {{8{1'b1}},{8{1'b1}},{8{1'b0}}};    
                    display_data[b+32+2] <= {{8{1'b1}},{8{1'b1}},{8{1'b0}}};    
                    display_data[b+40+2] <= {{8{1'b1}},{8{1'b1}},{8{1'b0}}};    
                    display_data[b+48+2] <= {{8{1'b1}},{8{1'b1}},{8{1'b0}}};    
                    display_data[b+56+2] <= {{8{1'b1}},{8{1'b1}},{8{1'b0}}};      
                end
                for(b=0;b<3;b=b+1)begin
                    display_data[b+4]    <= {{8{1'b1}},{8{1'b1}},{8{1'b0}}};     
                    display_data[b+8+4]  <= {{8{1'b1}},{8{1'b1}},{8{1'b0}}};    
                    display_data[b+16+4] <= {{8{1'b0}},{8{1'b0}},{8{1'b0}}};    
                    display_data[b+24+4] <= {{8{1'b1}},{8{1'b1}},{8{1'b0}}};    
                    display_data[b+32+4] <= {{8{1'b1}},{8{1'b1}},{8{1'b0}}};    
                    display_data[b+40+4] <= {{8{1'b0}},{8{1'b0}},{8{1'b0}}};    
                    display_data[b+48+4] <= {{8{1'b0}},{8{1'b0}},{8{1'b0}}};    
                    display_data[b+56+4] <= {{8{1'b0}},{8{1'b0}},{8{1'b0}}};      
                end
            end
            else if(cnt_delay == 450)begin
                for (c=0;c<64;c=c+1) begin
                    display_data[c] <= 1'b0 ;
                end
            end
            else if(cnt_delay == 600)begin//P
                for(d=0;d<2;d=d+1)begin
                    display_data[d+2]    <= {{8{1'b1}},{8{1'b0}},{8{1'b1}}};     
                    display_data[d+8+2]  <= {{8{1'b1}},{8{1'b0}},{8{1'b1}}};    
                    display_data[d+16+2] <= {{8{1'b1}},{8{1'b0}},{8{1'b1}}};    
                    display_data[d+24+2] <= {{8{1'b1}},{8{1'b0}},{8{1'b1}}};    
                    display_data[d+32+2] <= {{8{1'b1}},{8{1'b0}},{8{1'b1}}};    
                    display_data[d+40+2] <= {{8{1'b1}},{8{1'b0}},{8{1'b1}}};    
                    display_data[d+48+2] <= {{8{1'b1}},{8{1'b0}},{8{1'b1}}};    
                    display_data[d+56+2] <= {{8{1'b1}},{8{1'b0}},{8{1'b1}}};      
                end
                for(d=0;d<1;d=d+1)begin
                    display_data[d+4]    <= {{8{1'b1}},{8{1'b0}},{8{1'b1}}};     
                    display_data[d+8+4]  <= {{8{1'b1}},{8{1'b0}},{8{1'b1}}};    
                    display_data[d+16+4] <= {{8{1'b0}},{8{1'b0}},{8{1'b0}}};    
                    display_data[d+24+4] <= {{8{1'b1}},{8{1'b0}},{8{1'b1}}};    
                    display_data[d+32+4] <= {{8{1'b1}},{8{1'b0}},{8{1'b1}}};    
                    display_data[d+40+4] <= {{8{1'b0}},{8{1'b0}},{8{1'b0}}};    
                    display_data[d+48+4] <= {{8{1'b0}},{8{1'b0}},{8{1'b0}}};    
                    display_data[d+56+4] <= {{8{1'b0}},{8{1'b0}},{8{1'b0}}};      
                end
                for(d=0;d<1;d=d+1)begin
                    display_data[d+5]    <= {{8{1'b0}},{8{1'b0}},{8{1'b0}}};     
                    display_data[d+8+5]  <= {{8{1'b1}},{8{1'b0}},{8{1'b1}}};    
                    display_data[d+16+5] <= {{8{1'b0}},{8{1'b0}},{8{1'b0}}};    
                    display_data[d+24+5] <= {{8{1'b1}},{8{1'b0}},{8{1'b1}}};    
                    display_data[d+32+5] <= {{8{1'b0}},{8{1'b0}},{8{1'b0}}};    
                    display_data[d+40+5] <= {{8{1'b0}},{8{1'b0}},{8{1'b0}}};    
                    display_data[d+48+5] <= {{8{1'b0}},{8{1'b0}},{8{1'b0}}};    
                    display_data[d+56+5] <= {{8{1'b0}},{8{1'b0}},{8{1'b0}}};      
                end
                for(d=0;d<1;d=d+1)begin
                    display_data[d+6]    <= {{8{1'b0}},{8{1'b0}},{8{1'b0}}};     
                    display_data[d+8+6]  <= {{8{1'b0}},{8{1'b0}},{8{1'b0}}};    
                    display_data[d+16+6] <= {{8{1'b1}},{8{1'b0}},{8{1'b1}}};    
                    display_data[d+24+6] <= {{8{1'b0}},{8{1'b0}},{8{1'b0}}};    
                    display_data[d+32+6] <= {{8{1'b0}},{8{1'b0}},{8{1'b0}}};    
                    display_data[d+40+6] <= {{8{1'b0}},{8{1'b0}},{8{1'b0}}};    
                    display_data[d+48+6] <= {{8{1'b0}},{8{1'b0}},{8{1'b0}}};    
                    display_data[d+56+6] <= {{8{1'b0}},{8{1'b0}},{8{1'b0}}};      
                end            
            end
            else if(cnt_delay == 1050)begin
                for (e=0;e<64;e=e+1) begin
                    display_data[e] <= 1'b0 ;
                end
            end
            else if(cnt_delay == 1200)begin//G
                for(f=0;f<1;f=f+1)begin
                    display_data[f+1]    <= {{8{1'b0}},{8{1'b0}},{8{1'b0}}};     
                    display_data[f+8+1]  <= {{8{1'b0}},{8{1'b0}},{8{1'b0}}};    
                    display_data[f+16+1] <= {{8{1'b0}},{8{1'b0}},{8{1'b1}}};    
                    display_data[f+24+1] <= {{8{1'b0}},{8{1'b0}},{8{1'b1}}};    
                    display_data[f+32+1] <= {{8{1'b0}},{8{1'b0}},{8{1'b1}}};    
                    display_data[f+40+1] <= {{8{1'b0}},{8{1'b0}},{8{1'b1}}};    
                    display_data[f+48+1] <= {{8{1'b0}},{8{1'b0}},{8{1'b0}}};    
                    display_data[f+56+1] <= {{8{1'b0}},{8{1'b0}},{8{1'b0}}};      
                end
                for(f=0;f<1;f=f+1)begin
                    display_data[f+2]    <= {{8{1'b0}},{8{1'b0}},{8{1'b0}}};     
                    display_data[f+8+2]  <= {{8{1'b0}},{8{1'b0}},{8{1'b1}}};    
                    display_data[f+16+2] <= {{8{1'b0}},{8{1'b0}},{8{1'b1}}};    
                    display_data[f+24+2] <= {{8{1'b0}},{8{1'b0}},{8{1'b1}}};    
                    display_data[f+32+2] <= {{8{1'b0}},{8{1'b0}},{8{1'b1}}};    
                    display_data[f+40+2] <= {{8{1'b0}},{8{1'b0}},{8{1'b1}}};    
                    display_data[f+48+2] <= {{8{1'b0}},{8{1'b0}},{8{1'b1}}};    
                    display_data[f+56+2] <= {{8{1'b0}},{8{1'b0}},{8{1'b0}}};      
                end
                for(f=0;f<3;f=f+1)begin
                    display_data[f+3]    <= {{8{1'b0}},{8{1'b0}},{8{1'b1}}};     
                    display_data[f+8+3]  <= {{8{1'b0}},{8{1'b0}},{8{1'b1}}};    
                    display_data[f+16+3] <= {{8{1'b0}},{8{1'b0}},{8{1'b0}}};    
                    display_data[f+24+3] <= {{8{1'b0}},{8{1'b0}},{8{1'b1}}};    
                    display_data[f+32+3] <= {{8{1'b0}},{8{1'b0}},{8{1'b1}}};    
                    display_data[f+40+3] <= {{8{1'b0}},{8{1'b0}},{8{1'b0}}};    
                    display_data[f+48+3] <= {{8{1'b0}},{8{1'b0}},{8{1'b1}}};    
                    display_data[f+56+3] <= {{8{1'b0}},{8{1'b0}},{8{1'b1}}};      
                end
                for(f=0;f<1;f=f+1)begin
                    display_data[f+6]    <= {{8{1'b0}},{8{1'b0}},{8{1'b0}}};     
                    display_data[f+8+6]  <= {{8{1'b0}},{8{1'b0}},{8{1'b1}}};    
                    display_data[f+16+6] <= {{8{1'b0}},{8{1'b0}},{8{1'b0}}};    
                    display_data[f+24+6] <= {{8{1'b0}},{8{1'b0}},{8{1'b1}}};    
                    display_data[f+32+6] <= {{8{1'b0}},{8{1'b0}},{8{1'b1}}};    
                    display_data[f+40+6] <= {{8{1'b0}},{8{1'b0}},{8{1'b1}}};    
                    display_data[f+48+6] <= {{8{1'b0}},{8{1'b0}},{8{1'b1}}};    
                    display_data[f+56+6] <= {{8{1'b0}},{8{1'b0}},{8{1'b0}}};      
                end
                for(f=0;f<1;f=f+1)begin
                    display_data[f+7]    <= {{8{1'b0}},{8{1'b0}},{8{1'b0}}};     
                    display_data[f+8+7]  <= {{8{1'b0}},{8{1'b0}},{8{1'b0}}};    
                    display_data[f+16+7] <= {{8{1'b0}},{8{1'b0}},{8{1'b0}}};    
                    display_data[f+24+7] <= {{8{1'b0}},{8{1'b0}},{8{1'b1}}};    
                    display_data[f+32+7] <= {{8{1'b0}},{8{1'b0}},{8{1'b1}}};    
                    display_data[f+40+7] <= {{8{1'b0}},{8{1'b0}},{8{1'b1}}};    
                    display_data[f+48+7] <= {{8{1'b0}},{8{1'b0}},{8{1'b0}}};    
                    display_data[f+56+7] <= {{8{1'b0}},{8{1'b0}},{8{1'b0}}};      
                end
            end
            else if(cnt_delay == 1650)begin
                for (g=0;g<64;g=g+1) begin
                    display_data[g] <= 1'b0 ;
                end
            end
            else if(cnt_delay == 1800)begin//A
                for(h=0;h<1;h=h+1)begin
                    display_data[h+1]    <= {{8{1'b0}},{8{1'b0}},{8{1'b0}}};   display_data[h+   6] <= {{8{1'b0}},{8{1'b0}},{8{1'b0}}};     
                    display_data[h+8+1]  <= {{8{1'b0}},{8{1'b0}},{8{1'b0}}};   display_data[h+8+ 6] <= {{8{1'b0}},{8{1'b0}},{8{1'b0}}};    
                    display_data[h+16+1] <= {{8{1'b1}},{8{1'b1}},{8{1'b1}}};   display_data[h+16+6] <= {{8{1'b1}},{8{1'b1}},{8{1'b1}}};    
                    display_data[h+24+1] <= {{8{1'b1}},{8{1'b1}},{8{1'b1}}};   display_data[h+24+6] <= {{8{1'b1}},{8{1'b1}},{8{1'b1}}};    
                    display_data[h+32+1] <= {{8{1'b1}},{8{1'b1}},{8{1'b1}}};   display_data[h+32+6] <= {{8{1'b1}},{8{1'b1}},{8{1'b1}}};    
                    display_data[h+40+1] <= {{8{1'b1}},{8{1'b1}},{8{1'b1}}};   display_data[h+40+6] <= {{8{1'b1}},{8{1'b1}},{8{1'b1}}};    
                    display_data[h+48+1] <= {{8{1'b1}},{8{1'b1}},{8{1'b1}}};   display_data[h+48+6] <= {{8{1'b1}},{8{1'b1}},{8{1'b1}}};    
                    display_data[h+56+1] <= {{8{1'b1}},{8{1'b1}},{8{1'b1}}};   display_data[h+56+6] <= {{8{1'b1}},{8{1'b1}},{8{1'b1}}};      
                end
                for(h=0;h<1;h=h+1)begin
                    display_data[h+2]    <= {{8{1'b0}},{8{1'b0}},{8{1'b0}}};   display_data[h+   5] <= {{8{1'b0}},{8{1'b0}},{8{1'b0}}};     
                    display_data[h+8+2]  <= {{8{1'b1}},{8{1'b1}},{8{1'b1}}};   display_data[h+8+ 5] <= {{8{1'b1}},{8{1'b1}},{8{1'b1}}};    
                    display_data[h+16+2] <= {{8{1'b1}},{8{1'b1}},{8{1'b1}}};   display_data[h+16+5] <= {{8{1'b1}},{8{1'b1}},{8{1'b1}}};    
                    display_data[h+24+2] <= {{8{1'b1}},{8{1'b1}},{8{1'b1}}};   display_data[h+24+5] <= {{8{1'b1}},{8{1'b1}},{8{1'b1}}};    
                    display_data[h+32+2] <= {{8{1'b1}},{8{1'b1}},{8{1'b1}}};   display_data[h+32+5] <= {{8{1'b1}},{8{1'b1}},{8{1'b1}}};    
                    display_data[h+40+2] <= {{8{1'b1}},{8{1'b1}},{8{1'b1}}};   display_data[h+40+5] <= {{8{1'b1}},{8{1'b1}},{8{1'b1}}};    
                    display_data[h+48+2] <= {{8{1'b1}},{8{1'b1}},{8{1'b1}}};   display_data[h+48+5] <= {{8{1'b1}},{8{1'b1}},{8{1'b1}}};    
                    display_data[h+56+2] <= {{8{1'b1}},{8{1'b1}},{8{1'b1}}};   display_data[h+56+5] <= {{8{1'b1}},{8{1'b1}},{8{1'b1}}};      
                end
                for(h=0;h<1;h=h+1)begin
                    display_data[h+3]    <= {{8{1'b1}},{8{1'b1}},{8{1'b1}}};   display_data[h+   4] <= {{8{1'b1}},{8{1'b1}},{8{1'b1}}};     
                    display_data[h+8+3]  <= {{8{1'b1}},{8{1'b1}},{8{1'b1}}};   display_data[h+8+ 4] <= {{8{1'b1}},{8{1'b1}},{8{1'b1}}};    
                    display_data[h+16+3] <= {{8{1'b1}},{8{1'b1}},{8{1'b1}}};   display_data[h+16+4] <= {{8{1'b1}},{8{1'b1}},{8{1'b1}}};    
                    display_data[h+24+3] <= {{8{1'b0}},{8{1'b0}},{8{1'b0}}};   display_data[h+24+4] <= {{8{1'b0}},{8{1'b0}},{8{1'b0}}};    
                    display_data[h+32+3] <= {{8{1'b1}},{8{1'b1}},{8{1'b1}}};   display_data[h+32+4] <= {{8{1'b1}},{8{1'b1}},{8{1'b1}}};    
                    display_data[h+40+3] <= {{8{1'b1}},{8{1'b1}},{8{1'b1}}};   display_data[h+40+4] <= {{8{1'b1}},{8{1'b1}},{8{1'b1}}};    
                    display_data[h+48+3] <= {{8{1'b0}},{8{1'b0}},{8{1'b0}}};   display_data[h+48+4] <= {{8{1'b0}},{8{1'b0}},{8{1'b0}}};    
                    display_data[h+56+3] <= {{8{1'b0}},{8{1'b0}},{8{1'b0}}};   display_data[h+56+4] <= {{8{1'b0}},{8{1'b0}},{8{1'b0}}};      
                end
            end
            else if(cnt_delay == 2400)begin
                for(i=0;i<8;i=i+1)begin
                    display_data[i]    <= {{8{1'b0}},{8{1'b0}},{8{1'b1}}};
                    display_data[i+8]  <= {{8{1'b0}},{8{1'b1}},{8{1'b0}}};
                    display_data[i+16] <= {{8{1'b0}},{8{1'b1}},{8{1'b1}}};
                    display_data[i+24] <= {{8{1'b1}},{8{1'b0}},{8{1'b0}}};
                    display_data[i+32] <= {{8{1'b1}},{8{1'b0}},{8{1'b1}}};
                    display_data[i+40] <= {{8{1'b1}},{8{1'b1}},{8{1'b0}}};
                    display_data[i+48] <= {{8{1'b1}},{8{1'b1}},{8{1'b1}}};
                    display_data[i+56] <= {{5{1'b0}},{3{1'b1}},{5{1'b0}},{3{1'b1}},{5{1'b0}},{3{1'b1}}};
                end
            end
            else if(cnt_delay == 2600)begin
                for (j=0;j<64;j=j+1) begin
                    display_data[j] <= 1'b0 ;
                end
            end
        end
    end

//数据移出
    always @(posedge clk or negedge rst_n)begin 
        if(!rst_n)begin
            data <= 1'b0 ;
        end
        else begin
            data <= display_data [cnt_rgb] ;
        end
    end

endmodule

        控制模块设计:

当按键按下时,控制模块从数据处理模块中取出24bit数据,判断每个比特数值,输出对应bit的波形。

//----------------------------------------------------------------------------------------
// File name:           FPGA__WS2812B
// Last modified Date:  2022年10月21日
// Created by:          清影空明
// Descriptions:        控制模块
// Capture:             点阵循环显示 “FPGA”
//----------------------------------------------------------------------------------------
module LED_CTRL(
    input                       clk     ,
    input					    rst_n	,
    input   wire    [1:0]       key     ,       //按键触发

    output  reg                 dout            //波形输出
);

//Parameter Define

//Reg Define
reg     [23:0]      display_data [63:0]     ;   //存放显示数据
reg                 req                     ;
reg     [7:0]       cnt                     ;   //波形延时计数器
reg     [4:0]       cnt_data                ;   //bit计数器
reg     [15:0]      cnt_delay               ;   //帧延时定时器
reg                 bit0_flag               ;   //数据0显示标志位
reg                 bit1_flag               ;   //数据1显示标志位
reg                 clear_flag              ;   //清屏标志位

//Wire Define
wire    [23:0]      data                    ;   //存储单个灯珠显示数据
wire                add_cnt                 ;
wire                end_cnt                 ;
wire                add_cnt_data            ;
wire                end_cnt_data            ;
wire                add_cnt_delay           ;
wire                end_cnt_delay           ;
wire                rgb_done                ;

//例化数据处理模块
data_drive  u_data_drive (
    .clk                     ( clk               ),
    .rst_n                   ( rst_n             ),
    .req                     ( end_cnt_data      ),
    .cnt_delay               ( cnt_delay  [15:0] ),

    .rgb_done                ( rgb_done          ),
    .data                    ( data       [23:0] )
);

//req
    always @(posedge clk or negedge rst_n)begin 
        if(!rst_n)begin
            req <= 1'b0 ;
        end
        else if(key) begin
            req <= 1'b1 ;
        end
    end

//波形延迟计数器
    always @(posedge clk or negedge rst_n)begin 
        if(!rst_n)begin
            cnt <= 1'b0 ;
        end
        else if(add_cnt)
            if(end_cnt)
                cnt <= 1'b0 ;
            else
                cnt = cnt + 1'b1 ;
    end
    assign add_cnt = req;
    assign end_cnt = add_cnt && cnt == 125 - 1;

//bit计数器
    always @(posedge clk or negedge rst_n)begin 
        if(!rst_n)
            cnt_data <= 1'b0 ;
        else if(add_cnt_data)
            if(end_cnt_data)
                cnt_data <= 1'b0 ;
            else
                cnt_data = cnt_data + 1'b1 ;
    end
    assign add_cnt_data = end_cnt;
    assign end_cnt_data = add_cnt_data && cnt_data == 24 - 1;

//帧延时计数器
    always @(posedge clk or negedge rst_n)begin 
        if(!rst_n)
            cnt_delay <= 1'b0 ;
        else if(add_cnt_delay)
            if(end_cnt_delay)
                cnt_delay <= 1'b0 ;
            else
                cnt_delay = cnt_delay + 1'b1 ;
    end
    assign add_cnt_delay = rgb_done;
    assign end_cnt_delay = add_cnt_delay && cnt_delay == 2900-1;

//输出清0
    always @(posedge clk or negedge rst_n)begin 
        if(!rst_n)begin
            clear_flag <= 1'b0 ;
        end
        else if(cnt_delay==(150*3)||cnt_delay==(350*3)||cnt_delay==(550*3)||cnt_delay==(750*3)||cnt_delay==2600) begin
            clear_flag <= 1'b1;
        end
        else if(cnt_delay==0||cnt_delay==600||cnt_delay==1200||cnt_delay==1800||cnt_delay==2400)begin
            clear_flag <= 1'b0;
        end
    end

//数据标志位
    always @(posedge clk or negedge rst_n)begin 
        if(!rst_n)begin
            bit0_flag <= 1'b0 ;
            bit1_flag <= 1'b0 ;
        end
        else if(data[23-cnt_data]) begin
            bit0_flag <= 1'b0;
            bit1_flag <= 1'b1;
        end
        else if(~data[23-cnt_data]) begin
            bit0_flag <= 1'b1 ;
            bit1_flag <= 1'b0 ;
        end
    end

//数据输出
    always @(posedge clk or negedge rst_n)begin 
        if(!rst_n)begin
            dout <= 1'b0 ;
        end
        else if((bit0_flag || bit1_flag) && cnt==1'b1)
            dout <= 1'b1 ;
        else if(bit0_flag && cnt==40 || bit1_flag && cnt==80 || clear_flag)
            dout <= 1'b0 ;
    end

endmodule

        顶层设计:

//----------------------------------------------------------------------------------------
// File name:           FPGA__WS2812B
// Last modified Date:  2022年10月21日
// Created by:          清影空明
// Descriptions:        顶层模块
// Capture:             点阵循环显示 “FPGA”
//----------------------------------------------------------------------------------------
module WS2812B_top (
    input   wire                clk     ,
    input   wire                rst_n   ,
    input   wire    [1:0]       key     ,

    output  reg                 dout
);

//Parameter Define

//Reg Define

//Wire Define
wire                Tclk            ;
wire                sym_rst_n       ;
wire                locked          ;
wire    [1:0]       key_value       ;

//PLL时钟
    pll	u_pll (
        .areset                 ( !rst_n        ),
        .inclk0                 ( clk           ),
        .c0                     ( Tclk          ),
        .locked                 ( locked        )
    );

//控制模块
    LED_CTRL  u_LED_CTRL (
        .clk                     ( clk          ),
        .rst_n                   ( rst_n        ),
        .key                     ( key_value    ),

        .dout                    ( dout         )
    );

//按键消抖
    key_debounce  u_key_debounce (
        .clk                     ( clk          ),
        .rst_n                   ( rst_n        ),
        .key_in                  ( key  [1:0]   ),

        .key_out                 ( key_value    )
    );
    
    assign sym_rst_n = rst_n & locked;

endmodule

5.仿真调试

        testbench:

`timescale  1ns / 1ns

module tb_WS2812B;

// WS2812B Parameters
parameter PERIOD  = 20;


// WS2812B Inputs
reg             clk                     ;
reg             rst_n                   ;
reg   [1:0]     key                     ;

// WS2812B Outputs
wire  dout                              ;


initial
begin
    forever #(PERIOD/2)  clk=~clk;
end

WS2812B_top  u_WS2812B_top (
    .clk                     ( clk          ),
    .rst_n                   ( rst_n        ),
    .key                     ( key    [1:0] ),

    .dout                    ( dout         )
);


initial
begin
    clk = 0;
    rst_n = 0;
    #(PERIOD*5);
    rst_n = 1;
    @(posedge u_WS2812B_top.u_LED_CTRL.end_cnt_delay);
    $stop;
end

endmodule

        do文件:

vlib work
vmap work work

#编译testbanch文件
vlog    tb.v
#编译   设计文件
vlog    ../rtl/WS2812B.v
vlog    ../IP/pll/pll.v

#指定仿真层
vsim -novopt work.tb
#添加信号到波形窗
add wave -position insertpoint sim:/tb//*

run -all

        ModelSim仿真:

【Verilog】FPGA驱动WS2812B点阵

6.上板

VID_20221107_091813文章来源地址https://www.toymoban.com/news/detail-485082.html

到了这里,关于【Verilog】FPGA驱动WS2812B点阵的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • WS2812B灯带

     开发WS2812B灯带笔记 目录 什么是WS2812B灯 WS2812B灯带连接原理图 WS2812B灯带的数据和数据传输是啥样的? 补充:什么是RGB? 那么WS2812B灯的24bit数据如何构造? WS2812B灯的逻辑“1”和逻辑“0” 代码部分 实现ns级别延时 WS2812B是一种智能控制LED光源,将控制电路和RGB芯片集成在

    2024年02月07日
    浏览(47)
  • GPIO模拟时序控制外设1——WS2812B

    上一篇文章中介绍了整个板子的最基本功能模块——使用GPIO的通用输入输出实现简单的按键输入以及推挽输出控制的功能。本文深入一步,在只使用GPIO的输入输出功能的基础上,通过查看对应模块的芯片手册,模拟其对应的通信时序来驱动对应的模块。 首先来个网红模块—

    2024年02月12日
    浏览(47)
  • 【流光溢彩】物联网入门 - ESP8266 + WS2812B 制作流光溢彩灯带

    ESP8266 模块 x1 WS2812B 灯带(60/米,根据显示器四周长度买即可) x1 杜邦线 若干 DC 电源 x1 1. ESP8266 串口驱动 一般购买详情页都会有写,没有就找商家要一个。 一般是 CH340 或者 CP2102,我买的是 CP2102 2. WLED 固件 固件开源地址:https://github.com/Aircoookie/WLED/releases 下载 ESP8266.bin 结

    2024年02月09日
    浏览(40)
  • 【雕爷学编程】Arduino动手做(138)---64位WS2812点阵屏模块4

    37款传感器与执行器的提法,在网络上广泛流传,其实Arduino能够兼容的传感器模块肯定是不止这37种的。鉴于本人手头积累了一些传感器和执行器模块,依照实践出真知(一定要动手做)的理念,以学习和交流为目的,这里准备逐一动手尝试系列实验,不管成功(程序走通)

    2024年02月16日
    浏览(43)
  • WS2812B彩灯 STM32HAL库开发:PWM+DMA(stm32f103c8t6)

    目录 一、摘要 二、WS2812B介绍 三、CUBEMX配置 四、程序介绍(KEIL编译器) 五、数据手册         1、本文使用示例单片机型号为 stm32f103c8t6 ,RGB型号为 WS2812B ;          2、主要实现功能是实现用 PWM+DMA 使RGB_LED亮起不同颜色的灯光;         3、目的:简单调通该型号

    2024年02月03日
    浏览(49)
  • ESP32(MicroPython) WS2812点阵+可交互超声波云台+网页显示温湿度

    ESP32 RGB点阵 三种随机颜色模式 由于之前的RGB点阵程序中的后两个模式灯的颜色过饱和影响观感,本程序把这两个模式整合到所有灯取随机颜色的程序,分别实现所有灯各取随机颜色、每一圈的灯取随机颜色和每相邻4灯取同一种随机颜色。 本程序增加了服务器功能,可以通

    2024年02月12日
    浏览(45)
  • FPGA + WS2812采灯控制

    WS2812C-2020-V1是一个集控制电路与发光电路于一体的智能外控LED光源;其外型采用最新的molding封 装工艺,将IC与发光芯片封装在一个2020的封装尺寸中,每个元件即为一个像素点;像素点内部包含了智能数字 接口数据锁存信号整形放大驱动电路,还包含有高精度的内部振荡器和

    2024年02月13日
    浏览(47)
  • WS2812全彩RGB驱动方法

    买了一个圆形的WS2812模块玩玩,特来总结一下驱动方法,感觉对比于普通的RGB灯来说,还是有点不一样的。 踩了一些坑,也在此列出。 驱动方法其实很简单,就是发送一个24bit的数据即可,数据0和1的定义分别如下。 它没有所谓的空闲态,如果两个24bit的数据传输时间间隔相

    2024年02月12日
    浏览(43)
  • (STM32笔记5)ws2812驱动开发

    ws2812 需要开发的外设:ws2812 开发环境:MDK 开发板:stm32最小系统板 杜邦线无数 一、原理阐述 (一) 这个ws2812有很多种,一个小灯、灯带,矩形像素屏等等。 这些都是DIN连接输入,DOUT连接输出,另外两个引脚是GNE和VCC   (二) 数据传输原理: 第1个WS2812B灯珠接收到了第1个

    2024年01月19日
    浏览(44)
  • STM32驱动全彩LED灯模块WS2812

    WS2812全彩LED灯模块系列,可以进行级联实现灯带的效果,MCU端通过一个管脚可以控制所有级联的LED灯的不同发光颜色显示。 WS2811(未集成LED)的级联电路如下所示: WS2812(集成LED)的级联电路如下所示: STM32是3.3V供电芯片,输出Push-Pull模式只有3.3V,WS2812采用5V供电,输入Vi

    2024年01月17日
    浏览(42)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包