ws2812静态显示图片
文章目录一.原理1.码型2.数据传输方法3.辅助理解二.生成图片三.设计思路1.模块图2.状态转移3.调用rom核4.调用FIFO核四.代码五.仿真一.原理1.码型ws2812中码型为归零码。其区别在于0码的占空比低1码的占空比高。如下图所示0码1码复位码时间约束如下上图中高低电平时间给的是范围那么我们可以根据范围内取合适的值例如T0H取300nsT0L取900nsT1H取600nsT1L取600ns保证T0HT0LT1HT1L2.数据传输方法我们可以理解为共64个位置每个位置需要24bit的数据我们生成64*24bit的数据这些数据每经历一个位置就把这个位置给足24bit的数据然后再经历下一个位置走完64个位置也就把数据给完了。24bit数据结构如下我们看到注释中写道两个需要注意的点高位先发与我们印象中从0-7不同顺序是从7-0GRB顺序我们通常情况下数据会以RGB的顺序生成。我们需要对这两个点在代码中进行调整否则会导致我们生成的灯光效果与我们预想的颜色不一样。典型应用电路可以与上文中数据传输方法结合理解3.辅助理解二.生成图片打开电脑自带的画图软件可以在搜索栏搜索点击左上角的文件-属性选择单位为像素宽度高度均为8绘图后保存为24位位图.bmp文件bmp文件转换为mif文件注意要将mif文件保存至工程文件夹prj文件夹下笔者曾因这个问题一直没有生成对应数据三.设计思路1.模块图2.状态转移3.调用rom核rom(read only memory)只读存储器。可以读出mif文件的数据这里rom用在ws2812_ctrl模块中。约束数据宽度和数据深度选中复位和读使能加入mif文件和ram一样rom输出信号较输入信号同样经过了两个触发器需要打两拍以保证没有数据丢失。4.调用FIFO核前文说到24bit数据高位先发遵循GRB顺序这里用FIFO来调节它约束数据宽度和数据深度添加复位信号前显模式四.代码ws2812_driver.v/**************************************功能介绍*********************************** Date : 2023年8月14日13:45:15 Author : Alegg xy. Version : 1.0 Description: 接口模块 *********************************************************************************/ //---------模块及端口声名------------------------------------------------------ module ws2812_driver( input clk , input rst_n , input pix_data_vld, input [23:0] pix_data, output ready , output reg ws2812_io ); //---------参数定义--------------------------------------------------------- //状态参数 localparam IDLE 3d0,// RST 3d1,// DATA 3d2;// reg [2:0] cstate ;//现态 reg [2:0] nstate ;//次态 //0,1电平对应值 localparam T0H 300/20, T0L 900/20, T1H 600/20, T1L 600/20; parameter MAX_400US 15d20000; parameter MAX_1200NS 6d60; parameter MAX_BIT 5d24;//24bit数据 parameter MAX_NUM 7d64;//64个灯 //---------内部信号定义----------------------------------------------------- reg [31:0] cnt_400us ; wire add_cnt_400us ; wire end_cnt_400us ; reg [11:0] cnt_1200ns ; wire add_cnt_1200ns ; wire end_cnt_1200ns ; 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 ; //fifo信号定义 wire [23:0] fifo_wr_data; wire [23:0] fifo_rd_data; wire fifo_wr_req; wire fifo_rd_req; wire fifo_empty; wire fifo_full; //400us计数器 always (posedge clk or negedge rst_n)begin if(!rst_n)begin cnt_400us d0; end else if(add_cnt_400us)begin if(end_cnt_400us)begin cnt_400us d0; end else begin cnt_400us cnt_400us 1d1; end end end assign add_cnt_400us cstate RST; assign end_cnt_400us add_cnt_400us cnt_400us MAX_400US - 1d1; //1200ns计数器 always (posedge clk or negedge rst_n)begin if(!rst_n)begin cnt_1200ns d0; end else if(add_cnt_1200ns)begin if(end_cnt_1200ns)begin cnt_1200ns d0; end else begin cnt_1200ns cnt_1200ns 1d1; end end end assign add_cnt_1200ns cstate DATA; assign end_cnt_1200ns add_cnt_1200ns cnt_1200ns MAX_1200NS - 1d1; //24bit计数器 always (posedge clk or negedge rst_n)begin if(!rst_n)begin cnt_bit d0; end else if(add_cnt_bit)begin if(end_cnt_bit)begin cnt_bit d0; end else begin cnt_bit cnt_bit 1d1; end end end assign add_cnt_bit end_cnt_1200ns; assign end_cnt_bit add_cnt_bit cnt_bit MAX_BIT - 1d1; //64个灯计数器 always (posedge clk or negedge rst_n)begin if(!rst_n)begin cnt_num d0; end else if(add_cnt_num)begin if(end_cnt_num)begin cnt_num d0; end else begin cnt_num cnt_num 1d1; end end end assign add_cnt_num end_cnt_bit; assign end_cnt_num add_cnt_num cnt_num MAX_NUM - 1d1; //状态跳转条件 wire IDLE_RST; wire RST_DATA; wire DATA_IDLE; assign IDLE_RST (cstate IDLE) pix_data_vld;//开始传输数据信号 assign RST_DATA (cstate RST) end_cnt_400us;//计400us assign DATA_IDLE (cstate DATA) end_cnt_num;//计满64个24bit //第一段时序逻辑描述状态转移 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 (IDLE_RST) begin nstate RST; end else begin nstate cstate; end end RST : begin if (RST_DATA) begin nstate DATA; end else begin nstate cstate; end end DATA : begin if (DATA_IDLE) begin nstate IDLE; end else begin nstate cstate; end end default : nstate cstate; endcase end //fifo例化 fifo fifo_inst ( .aclr ( ~rst_n ), .clock ( clk ), .data ( fifo_wr_data ), .rdreq ( fifo_rd_req ), .wrreq ( fifo_wr_req ), .empty ( fifo_empty ), .full ( fifo_full ), .q ( fifo_rd_data ), .usedw ( ) ); assign fifo_wr_data {pix_data[15:8],pix_data[23:16],pix_data[7:0]};//传输进去的是GRB assign fifo_wr_req pix_data_vld ~fifo_full; assign fifo_rd_req end_cnt_bit ~fifo_empty; always(posedge clk or negedge rst_n) if(!rst_n) ws2812_io 0; else case(cstate) IDLE : ws2812_io 0; RST : ws2812_io 0; DATA : if(fifo_rd_data[23-cnt_bit]) begin //发送数据1 if(cnt_1200ns T1H) ws2812_io 1; else ws2812_io 0; end else begin //发送数据0 if(cnt_1200ns T0H) ws2812_io 1; else ws2812_io 0; end default : ws2812_io 1; endcase assign ready cstate IDLE; endmodulews2812_ctrl.v/**************************************功能介绍*********************************** Date : 2023年8月14日14:23:39 Author : Alegg xy. Version : 1.0 Description: 显示一张图片 *********************************************************************************/ //---------模块及端口声名------------------------------------------------------ module ws2812_ctrl( input clk , input rst_n , input ready , output [23:0] pix_data, output pix_data_vld ); //---------参数定义--------------------------------------------------------- localparam IDLE d0, DATA d1, DONE d2; //---------内部信号定义----------------------------------------------------- reg [2:0] cstate ;//现态 reg [2:0] nstate ;//次态 reg [5:0] cnt_x ; wire add_cnt_x ; wire end_cnt_x ; reg [5:0] cnt_y ; wire add_cnt_y ; wire end_cnt_y ; //rom wire rom_rd_data_vld; wire rom_rd_req; reg rom_rd_req_r1;//打一拍 reg rom_rd_req_r2;//打两拍 //横坐标计数器 always (posedge clk or negedge rst_n)begin if(!rst_n)begin cnt_x d0; end else if(add_cnt_x)begin if(end_cnt_x)begin cnt_x d0; end else begin cnt_x cnt_x 1d1; end end end assign add_cnt_x cstate DATA; assign end_cnt_x add_cnt_x cnt_x 7; //纵坐标计数器 always (posedge clk or negedge rst_n)begin if(!rst_n)begin cnt_y d0; end else if(add_cnt_y)begin if(end_cnt_y)begin cnt_y d0; end else begin cnt_y cnt_y 1d1; end end end assign add_cnt_y end_cnt_x; assign end_cnt_y add_cnt_y cnt_y 7; //第一段时序逻辑描述状态转移 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 (ready) begin nstate DATA; end else begin nstate cstate; end end DATA:begin if (end_cnt_y) begin nstate DONE; end else begin nstate cstate; end end default : nstate IDLE; endcase end //rom例化 rom rom_inst ( .aclr ( ~rst_n ), .address ( cnt_x cnt_y * 8 ), .clock ( clk ), .rden ( rom_rd_req ), .q ( pix_data ) ); //打两拍 always (posedge clk or negedge rst_n) begin if (!rst_n) begin rom_rd_req_r1 d0; rom_rd_req_r2 d0; end else begin rom_rd_req_r1 rom_rd_req; rom_rd_req_r2 rom_rd_req_r1; end end assign rom_rd_req cstate DATA; assign rom_rd_data_vld rom_rd_req_r2; assign pix_data_vld rom_rd_data_vld; endmoduletop.v/**************************************功能介绍*********************************** Date : 2023年8月14日15:45:36 Author : Alegg xy. Version : 1.0 Description: 顶层模块 *********************************************************************************/ //---------模块及端口声名------------------------------------------------------ module top( input clk , input rst_n , output ws2812_io ); //---------参数定义--------------------------------------------------------- wire pix_data_vld; wire [23:0] pix_data; wire ready; //---------内部信号定义----------------------------------------------------- ws2812_driver u_ws2812_driver( .clk (clk), .rst_n (rst_n), .pix_data_vld (pix_data_vld), .pix_data (pix_data), .ready (ready), .ws2812_io (ws2812_io) ); ws2812_ctrl u_ws2812_ctrl( .clk (clk), .rst_n (rst_n), .ready (ready), .pix_data (pix_data), .pix_data_vld (pix_data_vld) ); endmodule五.仿真tb_top.vtimescale 1ns/1ns module tb_top(); //激励信号定义 reg tb_clk ; reg tb_rst_n ; //输出信号定义 wire tb_ws2812_io; //时钟周期参数定义 parameter CLOCK_CYCLE 20; defparam u_top.u_ws2812_driver.MAX_400US 20; // defparam u_top.u_ws2812_ctrl3.MAX_500ms 25; //模块例化 top u_top( .clk (tb_clk ), .rst_n (tb_rst_n ), .ws2812_io (tb_ws2812_io ) ); //产生时钟 initial tb_clk 1b0; always #(CLOCK_CYCLE/2) tb_clk ~tb_clk; //产生激励 initial begin tb_rst_n 1b1; #(CLOCK_CYCLE*2); tb_rst_n 1b0; #(CLOCK_CYCLE*20); tb_rst_n 1b1; end endmodule仿真效果