FPGA笔记——WS2812B

一、手册分析

WS2812B的0、1不是单纯的拉高拉低电平,而是在一个周期内高低电平占空比不同。1码—高电平占580ns~1us(先高后低)、低电平占220ns~380ns。0码—高电平占580ns~1us(先低后高)、低电平占580ns~1us。而1帧与1帧之间的间隔要低电平280us以上。(帧:显示一幅画面)

 及联电路:这个过程包括将一个电路的输出连接到另一个电路的输入来形成连续的操作关系。这种级联是通过将一个电路中的输出端口与另一个电路中的输入端口相连接来完成的。简单来说就是挨个给电流,第一个信号(24bit)给第一个led后第二个信号(24bit)给第二个led。一帧后要刷新一个RESET后才开始下一帧。

此外、我们还知道WS2812B有64个LED灯珠,每个灯珠要24bit数据控制,00000000_00000000_00000000.通过这24bit来控制灯珠颜色与亮度。且这24bit是高位先发。

二、代码分析

module ws2812_ctrl(
    input          clk   ,  //系统时钟
    input          rst_n ,  //复位鑫海
    output         din      //ws2812b的数据输入  

);

parameter TIME = 7'd64                         ; //传输一个数据的最大时间 64*20=1280ns
parameter Zhen = 5'd24                         ; //一帧有24个数据//一个灯的数据
parameter MAX  = 7'd64                         ; //一共要点64个灯。  
parameter RGB  = 24'b00000000_00001111_00000000; // 红色
parameter RGB1 = 24'b00001111_00000000_00000000; // 蓝色
parameter RGB2 = 24'b00000000_00000000_00001111; // 绿色


reg [6:0]cnt0             ;//计数一bit数据传输的最长周期,
wire          add_cnt0    ;
wire          end_cnt0    ;

reg  [4:0]  cnt_1z        ; //一个灯珠要24bit数据
wire        add_cnt_1z    ;
wire        end_cnt_1z    ;

reg   [6:0] cnt_64z       ; //一共有64给灯珠。
wire        add_cnt_64z   ;
wire        end_cnt_64z   ;

reg [26:0]  cnt_rst       ; //计数复位信号,用于自动刷新计数
wire        add_cnt_rst   ;
wire        end_cnt_rst   ;

reg [8:0]   cnt_state     ; //灯珠闪烁的三种状态,一种颜色一帧,3种颜色循环。
wire        add_cnt_state ;
wire        end_cnt_state ;

reg [23:0]  rgb_b         ;
reg         tx_done       ;//1bit数据传输完的使能信号 
reg         rgb_r         ; //寄存每次传输的RGB数据;
reg         data_out1     ; //1码 和 0码 的转换 




//计数一bit数据传输的最长周期
always @(posedge clk or negedge rst_n) begin
    if (rst_n==0) begin
        cnt0 <= 0;
    end
    else if(add_cnt0) begin
        if(end_cnt0)
            cnt0 <= 0;
        else
            cnt0 <= cnt0+1 ;
   end
end
assign add_cnt0 = tx_done ;
assign end_cnt0 = add_cnt0  && cnt0 == 64 - 1;

//一帧数据传输24bit
always @(posedge clk or negedge rst_n) begin
    if (rst_n==0) begin
        cnt_1z <= 24;
    end
    else if(add_cnt_1z) begin
        if(end_cnt_1z)
            cnt_1z <= 24;
        else
            cnt_1z <= cnt_1z-1 ;
   end
end
assign add_cnt_1z = end_cnt0;
assign end_cnt_1z = add_cnt_1z  && cnt_1z == 1; //减到0就停止计数

//一共发送64帧;
always @(posedge clk or negedge rst_n) begin
    if (rst_n==0) begin
        cnt_64z <= 0;
    end
    else if(add_cnt_64z) begin
        if(end_cnt_64z)
            cnt_64z <= 0;
        else
            cnt_64z <= cnt_64z+1 ;
   end
end
assign add_cnt_64z = end_cnt_1z;
assign end_cnt_64z = add_cnt_64z  && cnt_64z == 64 - 1;

//灯珠闪烁三种颜色变换
always @(posedge clk or negedge rst_n) begin
    if (rst_n==0) begin
        cnt_state <= 0;
    end
    else if(add_cnt_state) begin
        if(end_cnt_state)
            cnt_state <= 0;
        else
            cnt_state <= cnt_state+1 ;
   end
end
assign add_cnt_state = end_cnt_64z;          //一帧结束后计数一次
assign end_cnt_state = add_cnt_state  && cnt_state == 3 - 1;

//复位信号
always @(posedge clk or negedge rst_n) begin
    if (rst_n==0) begin           //复位状态和发送数据使能为1时数据清零
        cnt_rst <= 0;
    end
    else if(tx_done  == 1)begin   //当数据传输使能有效时复位计数器一直为低,
        cnt_rst <= 0 ;
    end
    else if(add_cnt_rst) begin    
        if(end_cnt_rst)
            cnt_rst <= cnt_rst;
        else
            cnt_rst <= cnt_rst+1 ;
   end
end
assign add_cnt_rst = 1;
assign end_cnt_rst = add_cnt_rst  && cnt_rst == 5000_0000 - 1;

//传输数据使能信号
always  @(posedge clk or negedge rst_n)begin
    if(rst_n==1'b0)begin
        tx_done <= 0 ;  
    end
    else if(end_cnt_64z)begin //当计数完64帧以后 发送数据使能拉低
        tx_done <= 0;
    end
    else if(end_cnt_rst) begin  //复位完成,发送数据使能拉低 
        tx_done <= 1;  
    end
    else  begin
        tx_done <= tx_done;
    end
end
//当复位后以及1帧(64个灯珠亮完)后,使能信号拉低,复位计数器开始计数,计数5000_0000,计数结束后
//使能信号拉高,数据开始传输。实现自动帧刷新。


//灯珠的三种颜色按顺序
always  @(*)begin
    if(rst_n==1'b0)begin
        rgb_b <= 24'd0 ;
    end
    else  begin
        case(cnt_state)
            0: rgb_b = RGB  ;    //这里是一帧一帧改,可以改变cnt_state计数方式来感觉显示
            1: rgb_b = RGB1 ;
            2: rgb_b = RGB2 ;
        default : ;
        endcase
    end
end


//将颜色数据的每一个bit赋值给寄存器
always  @(posedge clk or negedge rst_n)begin
    if(rst_n==1'b0)begin
        rgb_r <= rgb_b[23];
    end
    else  begin
        rgb_r <= rgb_b[cnt_1z-1] ;
    end
end


//0码和1码
always  @(posedge clk or negedge rst_n)begin
    if(rst_n==1'b0 )begin
        data_out1 <= 0 ;
    end
    else if(tx_done == 0)begin
        data_out1 <= 0 ;
    end
    else if((rgb_r == 1'b0 )&&( tx_done == 1) ) begin //发送0码
        if(cnt0 < 15)begin
        data_out1 <= 1 ;
        end
        else begin
            data_out1 <= 0 ;
        end
    end
    else if((rgb_r == 1'b1) && (tx_done==1))begin //发送1码
        if(cnt0 < 35)begin //小于35未高电平
            data_out1 <= 1 ;
        end
        else begin
            data_out1 <= 0 ;
        end
    end
    else  begin
        data_out1 <= data_out1 ;
    end
end
assign  din = data_out1 ; //赋值给din信号


endmodule

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值