在圖像處理領域,光線是非常重要的前提。燈源最好是環形燈,就像那些網紅給自己打光一樣,環形燈光照均勻。
WS2812B-LED環形燈工作時序如下:
數據的0/1用不同佔空比的pwm表示
0碼和1碼以及復位時間如上圖所示。
RGB888總共24位,每位0/1輸出,一個環形燈16個led,一個總週期需要連續發16個24位數據,再復位一段時間重新下一個輪迴。
數據高位先發,本程序爲0爲最先發的23爲最後發的。
設計思路:
主體爲一個3段式狀態機,0/1碼的週期設爲一致,只是高低電平持續時間互換,一個計數器設置週期循環。狀態輸出依照24位數據的當前位按0/1不同輸出,每個LED設爲一個狀態,每個LED結束轉到下一個狀態。最後一個LED轉到RST狀態,RST也需要一個計數器,計數到一定值跳出該狀態回到IDLE。
來一個彩圖
代碼如下
module LED
(
input clk,
input rst,
output led
);
//clk 50M
parameter T0H = 6'd17;
parameter T0L = 6'd50;//0碼的高低電平時間
parameter T1H = 6'd50;
parameter T1L = 6'd17;//1碼
parameter RST = 14'd15000;//復位時間
parameter LED_1 = 25'b0_1111_0000_1111_0000_1111_0000;
parameter LED_2 = 25'b0_1111_0000_0000_0000_1111_0000;
parameter LED_3 = 25'b0_0000_0000_1111_0000_1111_0000;
parameter LED_4 = 25'b0_1111_0000_1111_0000_0000_0000;
parameter LED_5 = 25'b0_1100_0000_1111_1100_1111_0000;
parameter LED_6 = 25'b0_1111_0000_1100_0000_1111_1100;
parameter LED_7 = 25'b0_1111_1100_1111_0000_1100_0000;//反向取值從0-23爲高位至低位GRB的順序
parameter LED_8 = 25'b0_1010_0000_1111_0110_1111_0110;//第25位故意添加,由於bit_cnt在24變0
//FSM 16個LED,一個復位狀態
parameter IDLE = 16'b0000_0000_0000_0000;
parameter LED_one = 16'b0000_0000_0000_0001;
parameter LED_two = 16'b0000_0000_0000_0010;
parameter LED_thr = 16'b0000_0000_0000_0100;
parameter LED_fou = 16'b0000_0000_0000_1000;
parameter LED_fiv = 16'b0000_0000_0001_0000;
parameter LED_six = 16'b0000_0000_0010_0000;
parameter LED_sev = 16'b0000_0000_0100_0000;
parameter LED_eig = 16'b0000_0000_1000_0000;
parameter LED_nin = 16'b0000_0001_0000_0000;
parameter LED_ten = 16'b0000_0010_0000_0000;
parameter LED_ele = 16'b0000_0100_0000_0000;
parameter LED_twe = 16'b0000_1000_0000_0000;
parameter LED_thi = 16'b0001_0000_0000_0000;
parameter LED_fou_ten = 16'b0010_0000_0000_0000;
parameter LED_fiv_ten = 16'b0100_0000_0000_0000;
parameter LED_six_ten = 16'b1000_0000_0000_0000;
parameter RST_FSM = 16'b1100_0000_0000_0000;
reg [15:0] state;
reg [15:0] state_n;//狀態
reg [6:0] cycle_cnt;//週期計數
reg led_pwm;// Led 輸出
reg shift;//24位移位輸出
reg state_tran;//狀態轉移第一個led到最後一個
reg state_tran_rst;//狀態轉移,復位至LEd+
reg [13:0] rst_cnt;//復位輸出
reg [4:0] bit_cnt;//對24位進行計數移位
//LEd數據高低週期,一個0/1碼持續時間
always @(posedge clk or negedge rst)
begin
if(!rst)
cycle_cnt <= 7'd0;
else if(cycle_cnt == (T0H + T0L - 6'd1))
cycle_cnt <= 7'd0;
else if(state != RST_FSM)//一輪傳輸下來,復位後對齊
cycle_cnt <= cycle_cnt + 1'b1;
else
cycle_cnt <= 7'd0;
end
//FSM 1
always @ (posedge clk or negedge rst)
begin
if(!rst)
state <= IDLE;
else
state <= state_n;
end
//FSM 2 狀態輸出
always @ (posedge clk or negedge rst)
begin
if(!rst)
begin
led_pwm <= 1'b0;
shift <= 1'b0;
end
else
begin
case(state)
IDLE :
begin
led_pwm <= 1'b1;
end
LED_one:
begin
shift <= LED_1[bit_cnt];//隨着cnt的計數,變換0/1,
if(shift == 1'b1)
begin
if(cycle_cnt == T1H)
led_pwm <= 1'b0;
else if(cycle_cnt == (T1H + T0H - 6'd1))
led_pwm <= 1'b1;
else
led_pwm <= led_pwm;
end
else
begin
if(cycle_cnt == T0H)
led_pwm <= 1'b0;
else if(cycle_cnt == (T1H + T0H - 6'd1))
led_pwm <= 1'b1;
else
led_pwm <= led_pwm;
end
end
LED_two:
begin
shift <= LED_2[bit_cnt];
if(shift == 1'b1)
begin
if(cycle_cnt == T1H)
led_pwm <= 1'b0;
else if(cycle_cnt == (T1H + T0H - 6'd1))
led_pwm <= 1'b1;
else
led_pwm <= led_pwm;
end
else
begin
if(cycle_cnt == T0H)
led_pwm <= 1'b0;
else if(cycle_cnt == (T1H + T0H - 6'd1))
led_pwm <= 1'b1;
else
led_pwm <= led_pwm;
end
end
LED_thr:
begin
shift <= LED_3[bit_cnt];
if(shift == 1'b1)
begin
if(cycle_cnt == T1H)
led_pwm <= 1'b0;
else if(cycle_cnt == (T1H + T0H - 6'd1))
led_pwm <= 1'b1;
else
led_pwm <= led_pwm;
end
else
begin
if(cycle_cnt == T0H)
led_pwm <= 1'b0;
else if(cycle_cnt == (T1H + T0H - 6'd1))
led_pwm <= 1'b1;
else
led_pwm <= led_pwm;
end
end
LED_fou:
begin
shift <= LED_4[bit_cnt];
if(shift == 1'b1)
begin
if(cycle_cnt == T1H)
led_pwm <= 1'b0;
else if(cycle_cnt == (T1H + T0H - 6'd1))
led_pwm <= 1'b1;
else
led_pwm <= led_pwm;
end
else
begin
if(cycle_cnt == T0H)
led_pwm <= 1'b0;
else if(cycle_cnt == (T1H + T0H - 6'd1))
led_pwm <= 1'b1;
else
led_pwm <= led_pwm;
end
end
LED_fiv:
begin
shift <= LED_5[bit_cnt];
if(shift == 1'b1)
begin
if(cycle_cnt == T1H)
led_pwm <= 1'b0;
else if(cycle_cnt == (T1H + T0H - 6'd1))
led_pwm <= 1'b1;
else
led_pwm <= led_pwm;
end
else
begin
if(cycle_cnt == T0H)
led_pwm <= 1'b0;
else if(cycle_cnt == (T1H + T0H - 6'd1))
led_pwm <= 1'b1;
else
led_pwm <= led_pwm;
end
end
LED_six:
begin
shift <= LED_6[bit_cnt];
if(shift == 1'b1)
begin
if(cycle_cnt == T1H)
led_pwm <= 1'b0;
else if(cycle_cnt == (T1H + T0H - 6'd1))
led_pwm <= 1'b1;
else
led_pwm <= led_pwm;
end
else
begin
if(cycle_cnt == T0H)
led_pwm <= 1'b0;
else if(cycle_cnt == (T1H + T0H - 6'd1))
led_pwm <= 1'b1;
else
led_pwm <= led_pwm;
end
end
LED_sev:
begin
shift <= LED_7[bit_cnt];
if(shift == 1'b1)
begin
if(cycle_cnt == T1H)
led_pwm <= 1'b0;
else if(cycle_cnt == (T1H + T0H - 6'd1))
led_pwm <= 1'b1;
else
led_pwm <= led_pwm;
end
else
begin
if(cycle_cnt == T0H)
led_pwm <= 1'b0;
else if(cycle_cnt == (T1H + T0H - 6'd1))
led_pwm <= 1'b1;
else
led_pwm <= led_pwm;
end
end
LED_eig:
begin
shift <= LED_8[bit_cnt];
if(shift == 1'b1)
begin
if(cycle_cnt == T1H)
led_pwm <= 1'b0;
else if(cycle_cnt == (T1H + T0H - 6'd1))
led_pwm <= 1'b1;
else
led_pwm <= led_pwm;
end
else
begin
if(cycle_cnt == T0H)
led_pwm <= 1'b0;
else if(cycle_cnt == (T1H + T0H - 6'd1))
led_pwm <= 1'b1;
else
led_pwm <= led_pwm;
end
end
LED_nin:
begin
shift <= LED_8[bit_cnt];
if(shift == 1'b1)
begin
if(cycle_cnt == T1H)
led_pwm <= 1'b0;
else if(cycle_cnt == (T1H + T0H - 6'd1))
led_pwm <= 1'b1;
else
led_pwm <= led_pwm;
end
else
begin
if(cycle_cnt == T0H)
led_pwm <= 1'b0;
else if(cycle_cnt == (T1H + T0H - 6'd1))
led_pwm <= 1'b1;
else
led_pwm <= led_pwm;
end
end
LED_ten:
begin
shift <= LED_7[bit_cnt];
if(shift == 1'b1)
begin
if(cycle_cnt == T1H)
led_pwm <= 1'b0;
else if(cycle_cnt == (T1H + T0H - 6'd1))
led_pwm <= 1'b1;
else
led_pwm <= led_pwm;
end
else
begin
if(cycle_cnt == T0H)
led_pwm <= 1'b0;
else if(cycle_cnt == (T1H + T0H - 6'd1))
led_pwm <= 1'b1;
else
led_pwm <= led_pwm;
end
end
LED_ele:
begin
shift <= LED_6[bit_cnt];
if(shift == 1'b1)
begin
if(cycle_cnt == T1H)
led_pwm <= 1'b0;
else if(cycle_cnt == (T1H + T0H - 6'd1))
led_pwm <= 1'b1;
else
led_pwm <= led_pwm;
end
else
begin
if(cycle_cnt == T0H)
led_pwm <= 1'b0;
else if(cycle_cnt == (T1H + T0H - 6'd1))
led_pwm <= 1'b1;
else
led_pwm <= led_pwm;
end
end
LED_twe:
begin
shift <= LED_5[bit_cnt];
if(shift == 1'b1)
begin
if(cycle_cnt == T1H)
led_pwm <= 1'b0;
else if(cycle_cnt == (T1H + T0H - 6'd1))
led_pwm <= 1'b1;
else
led_pwm <= led_pwm;
end
else
begin
if(cycle_cnt == T0H)
led_pwm <= 1'b0;
else if(cycle_cnt == (T1H + T0H - 6'd1))
led_pwm <= 1'b1;
else
led_pwm <= led_pwm;
end
end
LED_thi:
begin
shift <= LED_4[bit_cnt];
if(shift == 1'b1)
begin
if(cycle_cnt == T1H)
led_pwm <= 1'b0;
else if(cycle_cnt == (T1H + T0H - 6'd1))
led_pwm <= 1'b1;
else
led_pwm <= led_pwm;
end
else
begin
if(cycle_cnt == T0H)
led_pwm <= 1'b0;
else if(cycle_cnt == (T1H + T0H - 6'd1))
led_pwm <= 1'b1;
else
led_pwm <= led_pwm;
end
end
LED_fou_ten:
begin
shift <= LED_3[bit_cnt];
if(shift == 1'b1)
begin
if(cycle_cnt == T1H)
led_pwm <= 1'b0;
else if(cycle_cnt == (T1H + T0H - 6'd1))
led_pwm <= 1'b1;
else
led_pwm <= led_pwm;
end
else
begin
if(cycle_cnt == T0H)
led_pwm <= 1'b0;
else if(cycle_cnt == (T1H + T0H - 6'd1))
led_pwm <= 1'b1;
else
led_pwm <= led_pwm;
end
end
LED_fiv_ten:
begin
shift <= LED_2[bit_cnt];
if(shift == 1'b1)
begin
if(cycle_cnt == T1H)
led_pwm <= 1'b0;
else if(cycle_cnt == (T1H + T0H - 6'd1))
led_pwm <= 1'b1;
else
led_pwm <= led_pwm;
end
else
begin
if(cycle_cnt == T0H)
led_pwm <= 1'b0;
else if(cycle_cnt == (T1H + T0H - 6'd1))
led_pwm <= 1'b1;
else
led_pwm <= led_pwm;
end
end
LED_six_ten:
begin
shift <= LED_1[bit_cnt];
if(shift == 1'b1)
begin
if(cycle_cnt == T1H)
led_pwm <= 1'b0;
else if(cycle_cnt == (T1H + T0H - 6'd1))
led_pwm <= 1'b1;
else
led_pwm <= led_pwm;
end
else
begin
if(cycle_cnt == T0H)
led_pwm <= 1'b0;
else if(cycle_cnt == (T1H + T0H - 6'd1))
led_pwm <= 1'b1;
else
led_pwm <= led_pwm;
end
end
RST_FSM:
begin
led_pwm <= 1'b0;
end
default:
begin
led_pwm <= 1'b0;
end
endcase
end
end
assign led = led_pwm;
//FSM 3 狀態轉移
always @ (*)
begin
case (state)
IDLE:
state_n = LED_one;
LED_one:
begin
if(state_tran)
state_n = LED_two;
else
state_n = state;
end
LED_two:
begin
if(state_tran)
state_n = LED_thr;
else
state_n = state;
end
LED_thr:
begin
if(state_tran)
state_n = LED_fou;
else
state_n = state;
end
LED_fou:
begin
if(state_tran)
state_n = LED_fiv;
else
state_n = state;
end
LED_fiv:
begin
if(state_tran)
state_n = LED_six;
else
state_n = state;
end
LED_six:
begin
if(state_tran)
state_n = LED_sev;
else
state_n = state;
end
LED_sev:
begin
if(state_tran)
state_n = LED_eig;
else
state_n = state;
end
LED_eig:
begin
if(state_tran)
state_n = LED_nin;
else
state_n = state;
end
LED_nin:
begin
if(state_tran)
state_n = LED_ten;
else
state_n = state;
end
LED_ten:
begin
if(state_tran)
state_n = LED_ele;
else
state_n = state;
end
LED_ele:
begin
if(state_tran)
state_n = LED_twe;
else
state_n = state;
end
LED_twe:
begin
if(state_tran)
state_n = LED_thi;
else
state_n = state;
end
LED_thi:
begin
if(state_tran)
state_n = LED_fou_ten;
else
state_n = state;
end
LED_fou_ten:
begin
if(state_tran)
state_n = LED_fiv_ten;
else
state_n = state;
end
LED_fiv_ten:
begin
if(state_tran)
state_n = LED_six_ten;
else
state_n = state;
end
LED_six_ten:
begin
if(state_tran)
state_n = RST_FSM;
else
state_n = state;
end
RST_FSM:
begin
if(state_tran_rst)
state_n = IDLE;
else
state_n = state;
end
default:
state_n =RST_FSM;
endcase
end
//記錄24位的時間,方便轉移狀態led
always @(posedge clk or negedge rst)
begin
if(!rst)
begin
bit_cnt <= 5'd0;
state_tran <= 1'b0;
end
else if (bit_cnt == 5'd24)
begin
bit_cnt <= 5'd0;
state_tran <= 1'b1;
end
else if(cycle_cnt == (T0H + T0L - 6'd1))
begin
bit_cnt <= bit_cnt + 1'b1;
state_tran <= 1'b0;
end
else
begin
bit_cnt <= bit_cnt;
state_tran <= 1'b0;
end
end
//記錄rst的時間,狀態轉換
always @(posedge clk or negedge rst)
begin
if(!rst)
rst_cnt <= 14'd0;
else if(state == RST_FSM)
rst_cnt <= rst_cnt + 1'b1;
else
rst_cnt <= 14'd0;
end
//rst的時間一到就髮狀態轉移信號,開始下一輪
always @(posedge clk or negedge rst)
begin
if(!rst)
state_tran_rst <= 1'b0;
else if(rst_cnt == RST)
state_tran_rst <=1'b1;
else
state_tran_rst <= 1'b0;
end
endmodule