通过 7 段 LED 循环字母的有效方法
Efficient way to loop letters through 7-seg LEDs
我正在尝试在我的 FPGA 板上的四个 7 段 LED 上滚动 'Happy Bday' 字样。在每个循环中,单词会向左移动一个字母。到目前为止,我已经能够通过为每个组合定义一个状态并循环遍历这些状态来做到这一点。我想知道是否有更好的方法来做到这一点,因为如果我想滚动更多的单词,我将不得不有很多状态。
module bday (
input rst_b, clk, start,
output logic [6:0] led [3:0]
);
logic clk_d;
logic [25:0] count;
state_t state; // state enum
always @(posedge clk) begin
count <= count + 1;
if (count == 10000000)
begin
count <= '0;
clk_d <= !clk_d; // divide clock down from 50MHz source
end
end
always_ff @ (posedge clk_d, negedge rst_b)
begin
if (!rst_b)
begin
state <= S_idle;
for (int i = 0; i < 4; i++) led[i] <= '1;
end
else // letters below are 7-bit parameters to light up the 7-seg LED correctly
case (state)
S_idle : if (start) state <= S_1; else state <= S_idle;
S_1 : begin state <= S_2; led[0] = H; led[1] = A; led[2] = P; led[3] = P; end
S_2 : begin state <= S_3; led[0] = A; led[1] = P; led[2] = P; led[3] = Y; end
S_3 : begin state <= S_4; led[0] = P; led[1] = P; led[2] = Y; led[3] = BLANK; end
S_4 : begin state <= S_5; led[0] = P; led[1] = Y; led[2] = BLANK; led[3] = B; end
S_5 : begin state <= S_6; led[0] = Y; led[1] = BLANK; led[2] = B; led[3] = D; end
S_6 : begin state <= S_7; led[0] = BLANK; led[1] = B; led[2] = D; led[3] = A; end
S_7 : begin state <= S_8; led[0] = B; led[1] = D; led[2] = A; led[3] = Y; end
S_8 : begin state <= S_9; led[0] = D; led[1] = A; led[2] = Y; led[3] = BLANK; end
S_9 : begin state <= S_10; led[0] = A; led[1] = Y; led[2] = BLANK; led[3] = H; end
S_10 : begin state <= S_11; led[0] = Y; led[1] = BLANK; led[2] = H; led[3] = A; end
S_11 : begin state <= S_1; led[0] = BLANK; led[1] = H; led[2] = A; led[3] = P; end
default : state <= S_idle;
endcase
end
endmodule
您可以做两件事。
将滚动行为与要显示的消息分开
always_ff @ (posedge clk_d, negedge rst_b)
if (!rst_b)
for (int i = 0; i < 3; i++) led[i] <= '1;
else
for (int i = 0; i < 3; i++) led[i] <= led[i+1];
然后使用一个数组和一个计数器从您的消息中挑选字母
parameter logic [6:0] message[15] = {H,A,P,P,Y,BLANK,B,I,R,T,H,D,A,Y,BLANK};
logic [7:0] counter;
always_ff @ (posedge clk_d, negedge rst_b)
if (!rst_b)
begin
counter <=0;
led[3] <= '1;
end
else
led[3] <= message[counter];
if (counter < 15)
counter <= counter+1;
else
counter <= 0;
我会使用的解决方案是制作 "ROM"。你可以做一个同步的,也可以做一个异步的。
module async_rom64(
input logic [5:0] address,
output logic [6:0] led [3:0]
);
always @( * )
case (address)
6'd0 : {led[0] , led[1] , led[2] , led[3] } = {H,A,p,P};
6'd1 : {led[0] , led[1] , led[2] , led[3] } = {A,P,P,Y};
6'd2 : {led[0] , led[1] , led[2] , led[3] } = {P,P,Y,BLANK};
// ...
// 6'd63 : ...
endcase
endmodule
现在你只要改变ROM的地址,就会出现一组新的LED图案。
从这里您可以根据需要将其复杂化。
- 例如,您可以添加一个 'last' 位,它告诉地址计数器它必须再次从零开始计数。
- 您可以为每个州添加延迟。
- 您将重复字段添加到例如重复一个模式,然后转到下一个。
我正在尝试在我的 FPGA 板上的四个 7 段 LED 上滚动 'Happy Bday' 字样。在每个循环中,单词会向左移动一个字母。到目前为止,我已经能够通过为每个组合定义一个状态并循环遍历这些状态来做到这一点。我想知道是否有更好的方法来做到这一点,因为如果我想滚动更多的单词,我将不得不有很多状态。
module bday (
input rst_b, clk, start,
output logic [6:0] led [3:0]
);
logic clk_d;
logic [25:0] count;
state_t state; // state enum
always @(posedge clk) begin
count <= count + 1;
if (count == 10000000)
begin
count <= '0;
clk_d <= !clk_d; // divide clock down from 50MHz source
end
end
always_ff @ (posedge clk_d, negedge rst_b)
begin
if (!rst_b)
begin
state <= S_idle;
for (int i = 0; i < 4; i++) led[i] <= '1;
end
else // letters below are 7-bit parameters to light up the 7-seg LED correctly
case (state)
S_idle : if (start) state <= S_1; else state <= S_idle;
S_1 : begin state <= S_2; led[0] = H; led[1] = A; led[2] = P; led[3] = P; end
S_2 : begin state <= S_3; led[0] = A; led[1] = P; led[2] = P; led[3] = Y; end
S_3 : begin state <= S_4; led[0] = P; led[1] = P; led[2] = Y; led[3] = BLANK; end
S_4 : begin state <= S_5; led[0] = P; led[1] = Y; led[2] = BLANK; led[3] = B; end
S_5 : begin state <= S_6; led[0] = Y; led[1] = BLANK; led[2] = B; led[3] = D; end
S_6 : begin state <= S_7; led[0] = BLANK; led[1] = B; led[2] = D; led[3] = A; end
S_7 : begin state <= S_8; led[0] = B; led[1] = D; led[2] = A; led[3] = Y; end
S_8 : begin state <= S_9; led[0] = D; led[1] = A; led[2] = Y; led[3] = BLANK; end
S_9 : begin state <= S_10; led[0] = A; led[1] = Y; led[2] = BLANK; led[3] = H; end
S_10 : begin state <= S_11; led[0] = Y; led[1] = BLANK; led[2] = H; led[3] = A; end
S_11 : begin state <= S_1; led[0] = BLANK; led[1] = H; led[2] = A; led[3] = P; end
default : state <= S_idle;
endcase
end
endmodule
您可以做两件事。
将滚动行为与要显示的消息分开
always_ff @ (posedge clk_d, negedge rst_b)
if (!rst_b)
for (int i = 0; i < 3; i++) led[i] <= '1;
else
for (int i = 0; i < 3; i++) led[i] <= led[i+1];
然后使用一个数组和一个计数器从您的消息中挑选字母
parameter logic [6:0] message[15] = {H,A,P,P,Y,BLANK,B,I,R,T,H,D,A,Y,BLANK};
logic [7:0] counter;
always_ff @ (posedge clk_d, negedge rst_b)
if (!rst_b)
begin
counter <=0;
led[3] <= '1;
end
else
led[3] <= message[counter];
if (counter < 15)
counter <= counter+1;
else
counter <= 0;
我会使用的解决方案是制作 "ROM"。你可以做一个同步的,也可以做一个异步的。
module async_rom64(
input logic [5:0] address,
output logic [6:0] led [3:0]
);
always @( * )
case (address)
6'd0 : {led[0] , led[1] , led[2] , led[3] } = {H,A,p,P};
6'd1 : {led[0] , led[1] , led[2] , led[3] } = {A,P,P,Y};
6'd2 : {led[0] , led[1] , led[2] , led[3] } = {P,P,Y,BLANK};
// ...
// 6'd63 : ...
endcase
endmodule
现在你只要改变ROM的地址,就会出现一组新的LED图案。
从这里您可以根据需要将其复杂化。
- 例如,您可以添加一个 'last' 位,它告诉地址计数器它必须再次从零开始计数。
- 您可以为每个州添加延迟。
- 您将重复字段添加到例如重复一个模式,然后转到下一个。