fpga项目: ws2812灯 - minichao9901/TangNano-20k-Zynq-7020 GitHub Wiki

1) ws2812灯简介

https://blog.csdn.net/zhuoqingjoking97298/article/details/120871808


2)画时序图

代码实现思路:

  1. 采用状态机+2个计数器作为核心
  2. 由start_pulse启动
  3. out用纯组合逻辑实现

3)代码

代码结构

代码

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2023/12/08 23:37:12
// Design Name: 
// Module Name: ws2812_top
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module ws2812_top(
    input clk,
    input rst,
    
    output led
    );
    
assign rst_n=~rst;
wire [23:0] po_data; 

gen_color_data gen_color_data_inst (
   .clk            (clk),         
   .rst_n          (rst_n),       
   .po_start_pulse (po_start_pulse),
   .po_data  (po_data)
);

ws2812 ws2812_inst (
   .clk            (clk),         
   .pi_start_pulse (po_start_pulse),
   .rst_n          (rst_n),       
   .pi_color       (po_data),
   .out            (led)         
);  
  
endmodule
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2023/12/08 22:35:15
// Design Name: 
// Module Name: ws2812
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module ws2812(
    input clk,
    input rst_n,
    input pi_start_pulse,
    input [23:0] pi_color,  //g[7:0],r[7:0],b[7:0]
    output reg out
    );

parameter FCLK=27_000_000;
parameter T0H=11;    //0.4us
parameter T0L=23;    //0.85us
parameter T1H=23;    //0.85us
parameter T1L=11;    //0.4us
parameter TRESET=1350;    //50us

parameter IDLE=2'b01;
parameter DATA=2'b10;

reg [5:0] baud_cnt;
reg [4:0] bit_cnt;
reg [1:0] state;

//baud_cnt
always @(posedge clk or negedge rst_n)
if(rst_n==0)
    baud_cnt<=0;
else if(pi_start_pulse)
    baud_cnt<=0;
else if(baud_cnt==33)
    baud_cnt<=0;
else if(state==DATA)
    baud_cnt<=baud_cnt+1;

//bit_cnt    
always @(posedge clk or negedge rst_n)
if(rst_n==0)
    bit_cnt<=23;
else if(pi_start_pulse)
    bit_cnt<=23;
else if(baud_cnt==33 && bit_cnt==0)
    bit_cnt<=23;
else if(baud_cnt==33)
    bit_cnt<=bit_cnt-1;    

//state    
always @(posedge clk or negedge rst_n)
if(rst_n==0)
    state<=IDLE;
else
    case(state)
        IDLE: if(pi_start_pulse)
                state<=DATA;
        DATA: if(baud_cnt==33 && bit_cnt==0)
                state<=IDLE;
    endcase
    
//out
always @(*) begin
    if(rst_n==0)
        out=0;
    else if(state==IDLE)
        out=0;
    else if(state==DATA) begin
        if(pi_color[bit_cnt]==0)
            out=(baud_cnt<T0H)? 1:0;
        else
            out=(baud_cnt<T1H)? 1:0;           
    end
end
    
endmodule
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2023/12/08 23:30:09
// Design Name: 
// Module Name: gen_color_data
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module gen_color_data(
    input clk,
    input rst_n, 
       
    output reg po_start_pulse,
    output reg [23:0] po_data   
    );
    
parameter FCLK=27_000_000;
parameter DLY_MS=FCLK/2;  //0.5ms
parameter EVENT_MAX=7;  //实际状态数是EVENT_MAX-1,看波形EVENT_MAX这个状态只出现了1个cycle

parameter RED=24'h00ff00;
parameter GREEN=24'hff0000;
parameter BLUE=24'h0000ff;  
parameter CYAN=GREEN+BLUE;
parameter YELLOW=RED+GREEN;
parameter MAGENTA=RED+BLUE; 

reg [24:0] timer;
reg [5:0] event_t;
reg timer_flag;
wire [5:0] event_o;

always @(posedge clk or negedge rst_n)
if(rst_n==0)
    timer<=0;
else if(timer==DLY_MS-1)
    timer<=0;    
else
    timer<=timer+1;


always @(posedge clk or negedge rst_n)
if(rst_n==0)
    timer_flag<=0;
else if(timer==DLY_MS-2)
    timer_flag<=1;
else
    timer_flag<=0;
    
always @(posedge clk or negedge rst_n)
if(rst_n==0)
    event_t<=1;  //注意复位值是1,这样方便event_o的使用
else if(event_t==EVENT_MAX)
    event_t<=1;  //注意复位值是1,这样方便event_o的使用
else if(timer_flag)
    event_t<=event_t+1;

assign event_o=timer_flag? event_t: 0;  //generate counter-value pulse    
 
always @(posedge clk or negedge rst_n)
if(rst_n==0) begin
    po_start_pulse<=0;
    po_data<=0;
end
else if(event_o)
    case(event_o)
        1: send_data(RED);
        2: send_data(GREEN);
        3: send_data(BLUE); 
        4: send_data(CYAN);
        5: send_data(YELLOW);
        6: send_data(MAGENTA); 
    endcase
else
    po_start_pulse<=0; 
 
task send_data;
    input [23:0] datax;
    begin
       po_start_pulse<=1;
       po_data<=datax;
    end
endtask    

endmodule

4) tang nano-20k引脚约束

IO_LOC "clk" 4;
IO_LOC "rst" 88;

IO_LOC "led" 79;

5) 测试波形

输出6种颜色,每种颜色间隔0.5s

6) 仿真tb

我们看到,event_o=7的状态只停留了1个cycle,就切换到了event_o=1