一,芯片介绍
1.管脚说明
2.数据传输时间
3.时序波形
4.数据传输方法
5.常用电路连接
二.项目要求
串口发送hex格式数据(00~FF),实时显示到WS2812B上(串口输入什么,WS2812就显示什么)
1.设计思路
通过串口接收到pc机发送的16进制数据后寄存器来,之后在contrl模块中,根据接收到的8bit数据分为两个4bit数据分为上下两位,之后根据这两个高低4bit数据匹配起始地址,之后将高低两个起始地址分别赋给高低两个计数器起始寄存器,通过一个flag信号来控制高低两个寄存器驱动,来控制输出高低位的地址,在通过y计数器来控制y轴,通过这三个计数器来匹配提前存在rom中的地址,之后rom将24bit数据传送到驱动模块达到串口发送什么就显示什么。
三.系统架构设计
四.模块说明
1.信号端口列表
- 顶层:
module top(
input wire clk ,
input wire rst_n ,
input wire rx ,//串口接收
output wire ws2812b_io//io发送
);
- 串口接收
module uart_rx#
(
parameter BPS = 115200,
parameter CLK_FRE = 50_000_000,
parameter CHECK_BIT = "NONE"//NONE 不校验 DDO奇校验 EVEN偶校验
)
(
input wire clk ,
input wire rst_n ,
input wire rx ,//串口接收
output wire ready ,//表示rx已经准备好接收数据了
output wire [7:0] rx_data ,//rx的接收数据
output wire rx_data_vld//rx数据发送信号
);
- ws2812_control:
module ws2812_control(
input clk ,
input rst_n ,
input [7:0] rx_data ,//串口接收数据
input rx_data_vld ,//串口数据发送信号
output [23:0] pix_data ,//rom读取数据
output pix_data_vld ,//rom读取信号
input ready //可以接收图像数据了
);
- ws2812_dirver:
module ws2812_dirver(
input wire clk ,
input wire rst_n ,
input wire [23:0] data_in ,//rom读取数据
input wire fifo_wr_vld,//fifo写信号
output reg ws2812b_io ,//串行输出
output wire ready //预备信号
);
2.状态转移图
-
RX:
-
ws2812b_contrl:
-
Ws2812b_dirver
3.时序图
五.具体代码
/**************************************功能介绍***********************************
Date :
Author : WZY.
Version :
Description: 顶层
*********************************************************************************/
//---------<模块及端口声名>------------------------------------------------------
module top(
input wire clk ,
input wire rst_n ,
input wire rx ,//串口接收
output wire ws2812b_io//io发送
);
//---------<参数定义>---------------------------------------------------------
wire [7:0] rx_data;
wire rx_data_vld;
wire [23:0] pix_data;
wire pix_data_vld;
wire ready ;
//---------<内部信号定义>-----------------------------------------------------
uart_rx#
(
.BPS( 115200),
.CLK_FRE ( 50_000_000),
.CHECK_BIT ("NONE")//NONE 不校验 DDO奇校验 EVEN偶校验
) uart_rx_inst
(
/*input wire */ .clk (clk),
/*input wire */ .rst_n (rst_n),
/*input wire */ .rx (rx),
/*output wire */ .ready (),
/*output wire [7:0]*/ .rx_data (rx_data),
/*output wire */ .rx_data_vld (rx_data_vld)
);
ws2812_control ws2812_control(
.clk (clk),
.rst_n (rst_n),
.rx_data (rx_data),
.rx_data_vld (rx_data_vld),
.pix_data (pix_data),
.pix_data_vld (pix_data_vld),
.ready (ready) //可以接收图像数据了
);
// ws2812_control ws2812_control(
// .clk (clk),
// .rst_n (rst_n),
// .rx_data (8'h12),
// .rx_data_vld (1),
// .pix_data (pix_data),
// .pix_data_vld (pix_data_vld),
// .ready (ready) //可以接收图像数据了
// );
ws2812_dirver ws2812_dirver_inst(
.clk (clk),
.rst_n (rst_n),
.data_in (pix_data),
.fifo_wr_vld(pix_data_vld),
.ws2812b_io (ws2812b_io),
.ready (ready)
);
endmodule
/**************************************功能介绍***********************************
Date :
Author : WZY.
Version :
Description: 串口接收模块()
*********************************************************************************/
//模块例化
// uart_rx#
// (
// parameter BPS = 115200,
// parameter CLK_FRE = 50_000_000,
// parameter CHECK_BIT = "NONE"//NONE 不校验 DDO奇校验 EVEN偶校验
// ) uart_rx_inst
// (
// /*input wire */ clk (clk),
// /*input wire */ rst_n (rst_n),
// /*input wire */ rx (),
// /*output wire */ ready (),
// /*output wire [7:0]*/ rx_data (),
// /*output wire */ rx_data_vld ()
// );
//---------<模块及端口声名>------------------------------------------------------
module uart_rx#
(
parameter BPS = 115200,
parameter CLK_FRE = 50_000_000,
parameter CHECK_BIT = "NONE"//NONE 不校验 DDO奇校验 EVEN偶校验
)
(
input wire clk ,
input wire rst_n ,
input wire rx ,//串口接收
output wire ready ,//表示rx已经准备好接收数据了
output wire [7:0] rx_data ,//rx的接收数据
output wire rx_data_vld//rx数据发送信号
);
//---------<参数定义>---------------------------------------------------------
parameter MAX_1bit = CLK_FRE/BPS;
//状态机参数定义
localparam IDLE = 5'b00001,//空闲状态等待数据输入
START = 5'b00010,//开始标志位接收状态
DATA = 5'b00100,//数据接收状态
CHECK = 5'b01000,//奇偶校验位接收
STOP = 5'b10000;//停止标志位接收状态
//---------<内部信号定义>-----------------------------------------------------
reg [4:0] cstate ;//现态
reg [4:0] nstate ;//次态
wire idle2start;
wire start2data;
wire data2stop ;
wire data2check;
wire check2stop;
wire stop2idle ;
reg [7:0] rx_data_r;
reg temp;//校验位接收
reg flag;//数据有效使能
//下降沿检测参数
reg rx_0;
reg rx_1;
wire nege;
//计数器参数
reg [3:0] num ;
reg [8:0] cnt_start ;
wire add_cnt_start ;
wire end_cnt_start ;
reg [11:0] cnt_data ;
wire add_cnt_data ;
wire end_cnt_data ;
reg [2:0] cnt_num ;
wire add_cnt_num ;
wire end_cnt_num ;
reg [8:0] cnt_stop ;
wire add_cnt_stop ;
wire end_cnt_stop ;
reg rx_data_vld_r;
//****************************************************************
// rx控制状态机
//****************************************************************
//第一段:时序逻辑描述状态转移
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cstate <= IDLE;
end
else begin
cstate <= nstate;
end
end
//第二段:组合逻辑描述状态转移规律和状态转移条件
always @(*) begin
case(cstate)
IDLE : begin
if (idle2start) begin
nstate = START;
end
else begin
nstate = cstate;
end
end
START : begin
if (start2data) begin
nstate = DATA;
end
else begin
nstate = cstate;
end
end
DATA : begin
if (data2stop) begin
nstate = STOP;
end
else if (data2check) begin
nstate = CHECK;
end
else begin
nstate = cstate;
end
end
CHECK : begin
if (check2stop) begin
nstate = STOP;
end
else begin
nstate = cstate;
end
end
STOP : begin
if (stop2idle) begin
nstate = IDLE;
end
else begin
nstate = cstate;
end
end
default : nstate = IDLE;
endcase
end
assign idle2start = cstate == IDLE && nege;//检测到下降沿跳转
assign start2data = cstate == START && end_cnt_num;//接收1bit开始位
assign data2stop = cstate == DATA && end_cnt_num && CHECK_BIT == "NONE";//若没有校验位则跳转到stop状态
assign data2check = cstate == DATA && end_cnt_num && CHECK_BIT != "NONE";
assign check2stop = cstate == CHECK && end_cnt_num;//校验位接收
assign stop2idle = cstate == STOP && end_cnt_num;//接收1bit结束位
//第三段:描述输出,时序逻辑或组合逻辑皆可
always @(*) begin
if (!rst_n) begin
rx_data_r = 8'b0;
temp =0;
end
else case (cstate)
DATA : if (cnt_data == MAX_1bit/2) begin //中间取样
rx_data_r[cnt_num] = rx_0;
end
CHECK : if (cnt_data == MAX_1bit/2) begin //中间取样
temp = rx_0;
end
default:rx_data_r = rx_data_r;
endcase
end
assign rx_data = rx_data_r;
assign rx_data_vld = (CHECK_BIT == "NONE")?data2stop:flag;
assign ready = cstate == IDLE;
//****************************************************************
// 1bit数据
//****************************************************************
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_data <= 12'd0;
end
else if(add_cnt_data)begin
if(end_cnt_data)begin
cnt_data <= 12'd0;
end
else begin
cnt_data <= cnt_data + 1'b1;
end
end
end
assign add_cnt_data = cstate != IDLE;
assign end_cnt_data = add_cnt_data && cnt_data == MAX_1bit-1;
//****************************************************************
// 选择数据位计数器
//****************************************************************
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_num <= 3'd0;
end
else if(add_cnt_num)begin
if(end_cnt_num)begin
cnt_num <= 3'd0;
end
else begin
cnt_num <= cnt_num + 1'b1;
end
end
end
assign add_cnt_num = end_cnt_data;
assign end_cnt_num = add_cnt_num && cnt_num == num - 1;
//****************************************************************
// 数据控制
//****************************************************************
always @(*) begin
case (cstate)
IDLE : num = 1;
START: num = 1;
DATA : num = 8;
CHECK: num = 1;
STOP : num = 1;
default: num = 1;
endcase
end
//****************************************************************
// 校验位检测
//****************************************************************
always @(*) begin
if (!rst_n) begin
flag = 0;
end
else if (cstate == IDLE) begin
flag = 0;
end
else if (cstate == CHECK && end_cnt_num) begin
if (CHECK_BIT == "DDO") begin
if (temp == (~^rx_data_r)) begin
flag = 1;
end
else begin
flag = 0;
end
end
else if (CHECK_BIT == "EVEN") begin
if (temp == (^rx_data_r)) begin
flag = 1;
end
else begin
flag = 0;
end
end
end
else begin
flag = 0;
end
end
//****************************************************************
// 下降沿检测
//****************************************************************
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
rx_0 = 0;
rx_1 = 0;
end
else begin
rx_0 <= rx;
rx_1 <= rx_0;
end
end
assign nege = ~rx_0 && rx_1;
// always @(posedge clk or negedge rst_n) begin
// if (!rst_n) begin
// rx_data_vld_r <= 0;
// end
// else if (CHECK_BIT == "NONE"&&data2stop) begin
// rx_data_vld_r <= 1;
// end
// else if (CHECK_BIT!= "NONE"&&data2check&&flag) begin
// rx_data_vld_r <= 1;
// end
// else if (CHECK_BIT!= "NONE"&&data2check&&(flag == 0)) begin
// rx_data_vld_r <= 0;
// end
// else begin
// rx_data_vld_r <= rx_data_vld_r;
// end
// end
// assign rx_data_vld = rx_data_vld_r;
endmodule
/**************************************************************
@File : ws2812_control2.v
@Time : 2023/08/14 10:04:56
@Author : WangHaodong
@EditTool: VS Code
@Font : UTF-8
@Function: 显示一张图片
**************************************************************/
module ws2812_control(
input clk ,
input rst_n ,
input [7:0] rx_data ,//串口接收数据
input rx_data_vld ,//串口数据发送信号
output [23:0] pix_data ,//rom读取数据
output pix_data_vld ,//rom读取信号
input ready //可以接收图像数据了
);
localparam RED = 24'hFF0000, //红色
ORANGE = 24'hFF8000, //橙色
YELLOW = 24'hFFFF00, //黄色
GREEN = 24'h00FF00, //绿色
CYAN = 24'h00FFFF, //青色
BLUE = 24'h0000FF, //蓝色
PURPPLE = 24'h8000FF, //紫色
BLACK = 24'h000000, //黑色
WHITE = 24'hFFFFFF, //白色
GRAY = 24'hC0C0C0; //灰色
parameter IDLE = 0,
DATA = 1,
DOWN = 2;
reg [2:0] state ;
reg [6:0] cnt_x_high;
wire add_x_high_cnt,end_x_high_cnt;
reg [6:0] cnt_x_low;
wire add_x_low_cnt,end_x_low_cnt;
reg [4:0] cnt_y;
wire add_y_cnt,end_y_cnt;
wire rom_rd_req ;
wire rom_rd_data_vld ;
reg rom_rd_req_r1 ;
reg rom_rd_req_r2 ;
//数据寄存
reg [7:0] rx_data_r;
//flag控制输出信号
reg flag ;
//起始地址寄存器
reg [6:0] num_high ;//高位起始地址
reg [6:0] num_low ;//地位起始地址
/**************************************************************
状态机
**************************************************************/
always@(posedge clk or negedge rst_n)
if(!rst_n)
state <= IDLE;
else case(state)
IDLE : if(ready&&rx_data_vld)
state <=DATA;
DATA : if(end_y_cnt)
state <=DOWN;
// DOWN : if (end_cnt_delay)
// state <= IDLE;
default : state <= IDLE;
endcase
//****************************************************************
// 数据寄存
//****************************************************************
always @(*) begin
if (!rst_n) begin
rx_data_r <= 0;
end
else if (rx_data_vld&&state==IDLE) begin
rx_data_r <= rx_data;
end
else begin
rx_data_r <= rx_data_r;
end
end
//****************************************************************
// flag使能
//****************************************************************
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
flag <= 0;
end
else if (end_x_high_cnt||end_x_low_cnt) begin
flag <= ~flag;
end
else begin
flag <= flag;
end
end
//****************************************************************
// 起始地址
//****************************************************************
always @(*) begin
if (!rst_n) begin
num_high = 0;
end
if (state == IDLE && rx_data_vld) begin
case (rx_data[7:4])
4'd0: num_high = 0;
4'd1: num_high = 4;
4'd2: num_high = 8;
4'd3: num_high = 12;
4'd4: num_high = 16;
4'd5: num_high = 20;
4'd6: num_high = 24;
4'd7: num_high = 28;
4'd8: num_high = 32;
4'd9: num_high = 36;
4'd10: num_high = 40;
4'd11: num_high = 44;
4'd12: num_high = 48;
4'd13: num_high = 52;
4'd14: num_high = 56;
4'd15: num_high = 60;
default:num_high = 1;
endcase
end
end
always @(*) begin
if (!rst_n) begin
num_low = 0;
end
if (state == IDLE && rx_data_vld) begin
case (rx_data[3:0])
4'd0: num_low = 0;
4'd1: num_low = 4;
4'd2: num_low = 8;
4'd3: num_low = 12;
4'd4: num_low = 16;
4'd5: num_low = 20;
4'd6: num_low = 24;
4'd7: num_low = 28;
4'd8: num_low = 32;
4'd9: num_low = 36;
4'd10: num_low = 40;
4'd11: num_low = 44;
4'd12: num_low = 48;
4'd13: num_low = 52;
4'd14: num_low = 56;
4'd15: num_low = 60;
default:num_low = 1;
endcase
end
end
/**************************************************************
图像数据个数计数器
**************************************************************/
//横坐标高位
always@(posedge clk or negedge rst_n)
if(!rst_n)
cnt_x_high <= 6'd0;
else if (state == IDLE && rx_data_vld) begin
cnt_x_high<=num_high;
end
else if(add_x_high_cnt) begin
if(end_x_high_cnt)
cnt_x_high <= num_high;
else
cnt_x_high <= cnt_x_high + 1'b1;
end
assign add_x_high_cnt = (state == DATA)&&(flag == 0);
assign end_x_high_cnt = add_x_high_cnt && cnt_x_high == num_high+3;
//横坐标低位
always@(posedge clk or negedge rst_n)
if(!rst_n)
cnt_x_low <= 6'd0;
else if (state == IDLE && rx_data_vld) begin
cnt_x_low <= num_low;
end
else if(add_x_low_cnt) begin
if(end_x_low_cnt)
cnt_x_low <= num_low;
else
cnt_x_low <= cnt_x_low + 1'b1;
end
assign add_x_low_cnt = state == DATA&&(flag==1);
assign end_x_low_cnt = add_x_low_cnt && cnt_x_low == num_low+3;
//纵坐标
always@(posedge clk or negedge rst_n)
if(!rst_n)
cnt_y <= 'd0;
else if(add_y_cnt) begin
if(end_y_cnt)
cnt_y <= 'd0;
else
cnt_y <= cnt_y + 1'b1;
end
assign add_y_cnt = end_x_low_cnt;
assign end_y_cnt = add_y_cnt && cnt_y == 8 - 1;
wire [31:0] address;
wire data_out;
reg flag_0;
reg flag_1;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
flag_0 <= 0;
flag_1 <= 0;
end
else begin
flag_0 <= flag;
flag_1 <= flag_0;
end
end
//存放了一张图片
rom rom_inst (
.aclr ( ~rst_n ),
.address ( address ),
.clock ( clk ),
.rden (rom_rd_req),
.q (data_out)
);
assign pix_data = flag_1?(data_out?BLUE:BLACK)
:(data_out?RED:BLACK);
assign rom_rd_req = state == DATA;
assign address = flag?(cnt_y*64+cnt_x_low):(cnt_y*64+cnt_x_high);
always@(posedge clk or negedge rst_n)
if(!rst_n) begin
rom_rd_req_r1 <= 0;
rom_rd_req_r2 <= 0;
end
else begin
rom_rd_req_r1 <= rom_rd_req;
rom_rd_req_r2 <= rom_rd_req_r1;
end
assign rom_rd_data_vld = rom_rd_req_r2;
assign pix_data_vld = rom_rd_data_vld;//打两拍使得读出数据和fifo中写入数据同步
endmodule
/**************************************功能介绍***********************************
Date :
Author : WZY.
Version :
Description: 这是项目的逻辑状态机模块
*********************************************************************************/
//---------<模块及端口声名>------------------------------------------------------
module ws2812_dirver(
input wire clk ,
input wire rst_n ,
input wire [23:0] data_in ,//rom读取数据
input wire fifo_wr_vld,//fifo写信号
output reg ws2812b_io ,//串行输出
output wire ready //预备信号
);
//---------<参数定义>---------------------------------------------------------
//状态机参数定义
parameter IDLE = 3'b001,//空闲状态
RST = 3'b010,//复位状态
DATA = 3'b100;//数据传输状态
//---------<内部信号定义>-----------------------------------------------------
reg [2:0] cstate ;//现态
reg [2:0] nstate ;//次态
wire idle2rst ;
wire rst2data ;
wire data2idle ;
//fifoIP核参数定义
wire [23:0] fifo_wr_data;
wire [23:0] fifo_rd_data;
wire empty ;
wire full ;
wire fifo_rd_req ;
wire fifo_wr_req ;
//复位参数定义
reg [14:0] cnt_rst ;
wire add_cnt_rst ;
wire end_cnt_rst ;
//数据传输参数定义
reg [5:0] cnt_cyc ;
wire add_cnt_cyc ;
wire end_cnt_cyc ;
reg [4:0] cnt_bit ;
wire add_cnt_bit ;
wire end_cnt_bit ;
reg [5:0] cnt_num ;
wire add_cnt_num ;
wire end_cnt_num ;
//****************************************************************
// 状态机
//****************************************************************
//第一段:时序逻辑描述状态转移
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cstate <= IDLE;
end
else begin
cstate <= nstate;
end
end
//第二段:组合逻辑描述状态转移规律和状态转移条件
always @(*) begin
case(cstate)
IDLE : begin
if (idle2rst) begin
nstate = RST;
end
else begin
nstate = cstate;
end
end
RST : begin
if (rst2data) begin
nstate = DATA;
end
else begin
nstate = cstate;
end
end
DATA : begin
if (data2idle) begin
nstate = IDLE;
end
else begin
nstate = cstate;
end
end
default : nstate = IDLE;
endcase
end
assign idle2rst = cstate == IDLE && fifo_wr_vld;//当检测到读使能时由空闲状态转换到复位状态
assign rst2data = cstate == RST && end_cnt_rst;//当复位完成后转到数据输入状态
assign data2idle = cstate == DATA && end_cnt_num;//当数据输入完成后返回空闲状态
//第三段:描述输出,时序逻辑或组合逻辑皆可
//****************************************************************
// IP核FIFO读取
//****************************************************************
fifo_test fifo_test_inst (
.aclr ( ~rst_n ),
.clock ( clk ),
.data ( fifo_wr_data ),
.rdreq ( fifo_rd_req ),
.wrreq ( fifo_wr_req),
.empty ( empty ),
.full ( full ),
.q ( fifo_rd_data ),
.usedw ( )
);
assign fifo_wr_data = {data_in[15:8],data_in[23:16],data_in[7:0]} ;//RGB->GRB
assign fifo_wr_req = fifo_wr_vld&&~full;//当检测到写使能并且不为满时拉高
assign fifo_rd_req = end_cnt_bit&& ~empty;//每次读取计时到一个数据后并且不为空时读出一个数据
//****************************************************************
// 复位计时
//****************************************************************
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_rst <= 15'd0;
end
else if(add_cnt_rst)begin
if(end_cnt_rst)begin
cnt_rst <= 15'd0;
end
else begin
cnt_rst <= cnt_rst + 1'b1;
end
end
end
assign add_cnt_rst = cstate == RST;
assign end_cnt_rst = add_cnt_rst && cnt_rst == 400_000/20 - 1;
//****************************************************************
// 数据传输计时
//****************************************************************
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_cyc <= 6'd0;
end
else if(add_cnt_cyc)begin
if(end_cnt_cyc)begin
cnt_cyc <= 6'd0;
end
else begin
cnt_cyc <= cnt_cyc + 1'b1;
end
end
end
assign add_cnt_cyc = cstate == DATA;
assign end_cnt_cyc = add_cnt_cyc && cnt_cyc == 1200/20 - 1;
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_bit <= 5'd0;
end
else if(add_cnt_bit)begin
if(end_cnt_bit)begin
cnt_bit <= 5'd0;
end
else begin
cnt_bit <= cnt_bit + 1'b1;
end
end
end
assign add_cnt_bit = end_cnt_cyc;
assign end_cnt_bit = add_cnt_bit && cnt_bit == 24-1;
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_num <= 6'd0;
end
else if(add_cnt_num)begin
if(end_cnt_num)begin
cnt_num <= 6'd0;
end
else begin
cnt_num <= cnt_num + 1'b1;
end
end
end
assign add_cnt_num = end_cnt_bit;
assign end_cnt_num = add_cnt_num && cnt_num == 64-1;
//****************************************************************
// 用户接口
//****************************************************************
always @(posedge clk or negedge rst_n) begin
case (cstate)
IDLE : ws2812b_io = 0;
RST : ws2812b_io = 0;
DATA : begin
if (fifo_rd_data[23-cnt_bit] == 1) begin
ws2812b_io = (cnt_cyc <30)?1:0;
end
else begin
ws2812b_io = (cnt_cyc<15)?1:0;
end
end
default: ws2812b_io = 0;
endcase
end
//****************************************************************
// ready控制
//****************************************************************
assign ready = cstate == IDLE;
endmodule
`timescale 1ns/1ns
module top_tb();
//激励信号定义
reg clk ;
reg rst_n ;
reg rx ;
//输出信号定义
wire ws2812b_io;
//时钟周期参数定义
parameter CYCLE = 20;
// defparam top_inst.ws2812_control.MAX_500S = 10;
//模块例化
top top_inst(
.clk (clk),
.rst_n (rst_n),
.rx (rx),
.ws2812b_io (ws2812b_io)
);
// ws2812_control ws2812_control_inst(
// .clk (clk),
// .rst_n (rst_n),
// .rx_data (8'h12),
// .rx_data_vld (1),
// .pix_data (),
// .pix_data_vld (),
// .ready (1) //可以接收图像数据了
// );
//产生时钟
initial clk = 1'b0;
always #(CYCLE/2) clk = ~ clk;
//产生激励
initial begin
rst_n = 0;
rx = 1 ;
#20
rst_n = 1;
#20
rx = 1 ;
#(CYCLE*10)
rx = 0 ; //开始位发送
#(CYCLE*10)
rx = 1 ; //发送数据1
#(CYCLE*10)
rx = 0 ; //发送数据0
#(CYCLE*10)
rx = 1 ; //发送数据1
#(CYCLE*10)
rx = 0 ; //发送数据0
#(CYCLE*10)
rx = 1 ; //发送数据1
#(CYCLE*10)
rx = 0 ; //发送数据0
#(CYCLE*10)
rx = 1 ; //发送数据1
#(CYCLE*10)
rx = 0 ; //发送数据0
// #(CYCLE*10)
// rx = 1 ; //发送标志位0//偶校验
#(CYCLE*10)
rx = 1 ; //发送结束位
// wait(top_inst.ws2812_dirver_inst.ready);
// rx = 0 ; //开始位发送
// #(CYCLE*10)
// rx = 0 ; //发送数据1
// #(CYCLE*10)
// rx = 0 ; //发送数据0
// #(CYCLE*10)
// rx = 1 ; //发送数据1
// #(CYCLE*10)
// rx = 0 ; //发送数据0
// #(CYCLE*10)
// rx = 1 ; //发送数据1
// #(CYCLE*10)
// rx = 1 ; //发送数据0
// #(CYCLE*10)
// rx = 1 ; //发送数据1
// #(CYCLE*10)
// rx = 0 ; //发送数据0
// // #(CYCLE*10)
// // rx = 1 ; //发送标志位0//偶校验
// #(CYCLE*10)
// rx = 1 ; //发送结束位
#(CYCLE*1000);
end
// initial begin
// rst_n = 0;
// #20
// rst_n = 1;
// #(CYCLE*100);
// end
endmodule
六.仿真
-
顶层:
-
Rx:
可以看出来接收数据跟发送波形相同,并且在下一次数据接收到来之前数据保持不变达到了寄存的目的 -
ws2812b_contrl
可以看到起始地址跟接收到的数据相互匹配正确,并且也把其实地址正确的赋值给了两个计数寄存器,并且最终地址正确
七.上板验证
ws2812b