目录
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仿真:
文章来源:https://www.toymoban.com/news/detail-485082.html
6.上板
VID_20221107_091813文章来源地址https://www.toymoban.com/news/detail-485082.html
到了这里,关于【Verilog】FPGA驱动WS2812B点阵的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!