【Verilog】FPGA驱动WS2812B点阵

目录

1.整体框架

2.器件选择

        WS2812B-64 8x8点阵:

3.手册解读

        灯珠引脚:

        连接方式: 

         数据传输方式:

         数据波形构成:

         数据波形持续时间:

4.模块设计

        数据处理模块设计:

        控制模块设计:

        顶层设计:

5.仿真调试

        testbench:

        do文件:

        ModelSim仿真:

6.上板


1.整体框架

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

2.器件选择

        WS2812B-64 8x8点阵:

3.手册解读

        灯珠引脚:

        连接方式: 

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

         数据传输方式:

        每个灯珠只接收24bit数据,溢出的数据传输到下一个灯珠,直至64个灯珠全部接收完数据。

      24bit数据发送顺序为G→R→B,MSB(最高有效位)先发。 

         数据波形构成:

         数据波形持续时间:

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仿真:

6.上板

VID_20221107_091813

  • 12
    点赞
  • 65
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值