WS2812B-LED工作时序如下:
数据的0/1用不同占空比的pwm表示
0码和1码以及复位时间如上图所示。
RGB888总共24位,每位0/1输出,一个88led灯,一个总周期需要连续发64个24位数据,再复位一段时间重新下一个轮回。
数据高位先发,本程序为0为最先发的23为最后发的。
设计思路:
ws2812b led灯工作前需要复位,所以我们设置一个状态RESET来进行复位操作,拉低dq_out300us,然后设置一个发送数据状态WR_BIT,我们需要发送6424bit的数据在一个周期里面,每24bit代表一个灯的颜色状态,所以我们定义两个计数器
一个记录bit发送数量:bit_cnt
一个记录发送的24bit的个数:rbg_data
具体代码如下:
/*================================================
Filename : ws2812b
AutDATAor : xq
Description : ws2812b模块驱动
Date : 2023年8月11日09:50:48
Email : 1617784441@qq.com
Company :
================================================*/
module ws2812b_ctrl(
input sys_clk , //时钟信号 50MDATAz
input sys_rst_n , //复位信号,低有效
output reg dq_out//
);
//参数定义
parameter IDLE = 2'd0 ;
parameter RESET = 2'd1 ;
parameter WR_BIT = 2'd2 ;
parameter BIT_MAX = 5'd23 ;
parameter TIME_1S = 26'd4999_9999;
parameter RESET_MAX = 14'd14_999 ;//300US
parameter GREEN = 24'b00000000_00000000_01010000 ;
parameter RED = 24'b01010000_00000000_00000000 ;
parameter WHITE = 24'hFFFFFF ;
parameter LIGHT_CORAL = 24'h30D5C8;
parameter SEASHELL = 24'h7AB8CC;
parameter COFFEE = 24'h4D3900 ;
parameter H = 64'b1100001111000011110000111111111111111111110000111100001111000011;
parameter A = 64'b0000000000000000000110000011110001100110111111111100001111000011;
parameter B = 64'b0000000011111111100000011000000111111111100000011000000111111111;
parameter C = 64'b0000000001111110110000111100000011000000110000110111111000000000;
parameter D = 64'b0000000011111110110000111100001111000011110000111111111000000000;
parameter E = 64'b0000000011111111110000001100000011111111110000001100000011111111;
parameter F = 64'b0000000011111111110000001100000011111111110000001100000011000000;
//信号定义
reg [25:0] cnt_1s;
wire [63:0] DATA;
reg [6:0] cnt_max;
reg [13:0] cnt_num ;
reg [6:0] rgb_led ;
reg [4:0 ] bit_cnt ;
reg [1:0] state_c ;
reg [1:0] state_n ;
reg [2:0] cnt_data;
reg [23:0] color_data;
reg [7:0] address;
//逻辑组成
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)begin
cnt_1s <= 26'd0;
end
else if(cnt_1s==TIME_1S)begin
cnt_1s <= 26'd0;
end
else begin
cnt_1s <= cnt_1s + 1'd1;
end
end
ram_256x8 ram_256x8_inst (
.aclr ( ~sys_rst_n ),
.address ( address ),
.clock ( sys_clk ),
.data ( ),
.rden ( 1'b1 ),
.wren ( 1'b0 ),
.q ( DATA )
);
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)begin
address <= 8'd0;
end
else if(cnt_1s==TIME_1S&&address==59)begin
address <= 8'd0;
end
else if(cnt_1s==TIME_1S)begin
address <= address+1'b1;
end
else begin
address <= address;
end
end
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)begin
cnt_data <= 3'd0;
end
else if(cnt_1s==TIME_1S&&cnt_data==5)begin
cnt_data <= 3'd0;
end
else if(cnt_1s==TIME_1S)begin
cnt_data <= cnt_data+1'd1;
end
else begin
cnt_data <= cnt_data;
end
end
always @(*) begin
if(!sys_rst_n)begin
color_data=24'd0;
end
else begin
case (cnt_data)
0:begin color_data=GREEN ;end
1:begin color_data=RED ;end
2:begin color_data=WHITE ;end
3:begin color_data=LIGHT_CORAL;end
4:begin color_data=SEASHELL ;end
5:begin color_data=COFFEE ;end
default: ;
endcase
end
end
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)begin
state_c <= IDLE;
end
else begin
state_c <= state_n;
end
end
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)begin
cnt_max <= 7'd0;
end
else if(color_data[bit_cnt]==1&&DATA[rgb_led])begin
cnt_max <= 7'd74;
end
else if(color_data[bit_cnt]==0&&DATA[rgb_led])begin
cnt_max <= 7'd49;
end
else if(DATA[rgb_led]==0)begin
cnt_max <= 7'd49;
end
else begin
cnt_max <= 7'd0;
end
end
always @(*) begin
case (state_c)
IDLE:begin
state_n = RESET;
end
RESET:begin
if(cnt_num==RESET_MAX)begin
state_n = WR_BIT;
end
else begin
state_n = RESET;
end
end
WR_BIT:begin
if(rgb_led==7'd63&&bit_cnt==BIT_MAX&&cnt_num==cnt_max)begin
state_n = IDLE;
end
else begin
state_n = WR_BIT;
end
end
default: state_n = IDLE;
endcase
end
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)begin
cnt_num <= 14'd0;
end
else if(state_c==RESET&&cnt_num==RESET_MAX)begin
cnt_num <= 14'd0;
end
else if(state_c==WR_BIT&&cnt_num==cnt_max)begin
cnt_num <= 14'd0;
end
else if(state_c==RESET||state_c==WR_BIT)begin
cnt_num <=cnt_num+1'd1;
end
else begin
cnt_num <= 14'd0;
end
end
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)begin
bit_cnt <= 5'd0;
end
else if(state_c==WR_BIT&&bit_cnt==BIT_MAX&&cnt_num==cnt_max)begin
bit_cnt <= 5'd0;
end
else if(state_c==WR_BIT&&cnt_num==cnt_max)begin
bit_cnt <= bit_cnt + 1'd1;
end
else begin
bit_cnt <= bit_cnt;
end
end
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)begin
rgb_led <= 7'd0;
end
else if(state_c==WR_BIT&&bit_cnt==BIT_MAX&&cnt_num==cnt_max&&rgb_led==7'd63)begin
rgb_led <= 7'd0;
end
else if(state_c==WR_BIT&&bit_cnt==BIT_MAX&&cnt_num==cnt_max)begin
rgb_led <= rgb_led + 1'd1;
end
else begin
rgb_led <= rgb_led;
end
end
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)begin
dq_out <= 1'b0;
end
case (state_c)
IDLE :begin dq_out<=1'b0;end
RESET :begin dq_out<=1'b0;end
WR_BIT:begin
if(color_data[bit_cnt]==1&&DATA[rgb_led])begin
if(cnt_num<38)begin
dq_out <= 1'b1;
end
else begin
dq_out <= 1'b0;
end
end
else if(color_data[bit_cnt]==0&&DATA[rgb_led])begin
if(cnt_num<15)begin
dq_out <= 1'b1;
end
else begin
dq_out <= 1'b0;
end
end
else if(DATA[rgb_led]==0)begin
if(cnt_num<15)begin
dq_out <= 1'b1;
end
else begin
dq_out <= 1'b0;
end
end
end
default: dq_out <= 1'b0;
endcase
end
endmodule
ram是256x64规模的ram,存的64位宽数据上的每一位都可以决定一个LED的两灭 例如data[0]=1则 第一个led灯亮 若data[0]=0则 led灯灭
也可以不要ram 稍微修改一下就好了