PS:升腾A7pro系列FPGA没有数码管外设,因此以AC620FPGA为例展开实验。
(1)共阳极数码管和共阴极数码管示意图:
- AC620中的数码管属于共阳极数码管,段选端口(dp,g,f,e,d,c,b,a)低电平即可点亮led。
- 人眼的视觉停留效应:当led以小于20ms的时间间隔进行闪烁时,在人眼看来,就是一直亮着的。
- 预使8个数码管实现动态扫描的效果,需要扫描间隔小于20ms/8 =2.5ms,不妨取1ms。
- 第一毫秒位选sel[0]高电平,其余sel[0:6]低电平;第二毫秒位选sel[1]高电平,其余sel[0]、sel[2:6]低电平,依次循环。
(2)段选、位选Verilog代码:
module hex(clk,reset_n,data,sel,seg);
input clk;
input reset_n;
input [31:0]data;
output reg[7:0]sel;
output reg[7:0]seg;
//1ms = 1_000_000ns = 20ns * 50_000;
reg [15:0]cnt;
reg [2:0]sel_cnt;
reg [3:0]temp_data;
reg [7:0]r_sel;
parameter MCNT = 49_999;
//1ms计数器模块
always@(posedge clk or negedge reset_n)
if(!reset_n)
cnt <= 16'd0;
else if(cnt == MCNT)
cnt <= 16'd0;
else
cnt <= cnt + 16'd1;
//sel_cnt计数器模块设计
always@(posedge clk or negedge reset_n)
if(!reset_n)
sel_cnt <= 3'd0;
else if(cnt == MCNT)
sel_cnt <= sel_cnt + 3'd1;
else
sel_cnt <= sel_cnt;
//r_sel信号设计
always@(posedge clk or negedge reset_n)
if(!reset_n)
r_sel <= 8'h01;
else begin
case(sel_cnt)
3'd0: r_sel <= 8'h01;
3'd1: r_sel <= 8'h02;
3'd2: r_sel <= 8'h04;
3'd3: r_sel <= 8'h08;
3'd4: r_sel <= 8'h10;
3'd5: r_sel <= 8'h20;
3'd6: r_sel <= 8'h40;
3'd7: r_sel <= 8'h80;
endcase
end
//sel信号设计 打一拍的目的是为了和seg信号同步
always@(posedge clk)
sel <= r_sel;
//temp_data信号设计
always@(posedge clk or negedge reset_n)
if(!reset_n)
temp_data <= 4'd0;
else begin
case(sel_cnt)
3'd0:temp_data <= data[3:0];
3'd1:temp_data <= data[7:4];
3'd2:temp_data <= data[11:8];
3'd3:temp_data <= data[15:12];
3'd4:temp_data <= data[19:16];
3'd5:temp_data <= data[23:20];
3'd6:temp_data <= data[27:24];
3'd7:temp_data <= data[31:28];
endcase
end
//seg信号设计
always@(posedge clk or negedge reset_n)
if(!reset_n)
seg <= 8'hff;
else begin
case(temp_data)
4'h0:seg <= 8'b1100_0000;
4'h1:seg <= 8'b1111_1001;
4'h2:seg <= 8'b1010_0100;
4'h3:seg <= 8'b1011_0000;
4'h4:seg <= 8'b1001_1001;
4'h5:seg <= 8'b1001_0010;
4'h6:seg <= 8'b1000_0010;
4'h7:seg <= 8'b1111_1000;
4'h8:seg <= 8'b1000_0000;
4'h9:seg <= 8'b1001_0000;
4'ha:seg <= 8'b1000_1000;
4'hb:seg <= 8'b1000_0011;
4'hc:seg <= 8'b1100_0110;
4'hd:seg <= 8'b1010_0001;
4'he:seg <= 8'b1000_0110;
4'hf:seg <= 8'b1000_1110;
endcase
end
endmodule
(3)对应仿真文件代码:
`timescale 1ns/1ns
module hex_tb;
reg clk;
reg reset_n;
reg [31:0]data;
wire [7:0]sel;
wire [7:0]seg;
hex hex_inst(
.clk(clk),
.reset_n(reset_n),
.data(data),
.sel(sel),
.seg(seg)
);
defparam hex_inst.MCNT = 499;
initial clk = 1'd1;
always #10 clk = ~clk;
initial begin
reset_n <= 1'd0;
#25;
reset_n <= 1'd1;
#15;
data <= 32'h00112233;
#200_000;
data <= 32'h44556677;
#200_000;
data <= 32'h8899aabb;
#200_000;
data <= 32'hccddeeff;
#200_000;
$stop;
end
endmodule
(4)仿真波形:
(5)74HC595芯片:
74HC595芯片内部工作原理:
- 先传段选,再传位选,先传高位,再传低位。(段位高低)
- 74HC595芯片在3.3v工作电压下,可以承受的工作频率为12.5MHz。
(6)74HC595驱动代码:
module hc595_driver(clk,reset_n,sel,seg,DIO,SCLK,RCLK);
input clk;
input reset_n;
input [7:0]sel;
input [7:0]seg;
output reg DIO;
output reg SCLK;
output reg RCLK;
//74HC595芯片在3.3v工作电压下,可以承受的工作频率为12.5MHz,对应一个周期为80ns,半个周期为两个系统时钟周期
reg div_cnt;
reg [4:0]bit_cnt;
//分频计数器设计
always@(posedge clk or negedge reset_n)
if(!reset_n)
div_cnt <= 1'd0;
else
div_cnt <= div_cnt + 1'd1;
//bit_cnt设计
always@(posedge clk or negedge reset_n)
if(!reset_n)
bit_cnt <= 5'd0;
else if(div_cnt == 1'd1)
bit_cnt <= bit_cnt + 5'd1;
else
bit_cnt <= bit_cnt;
//序列机设计
always@(posedge clk or negedge reset_n)
if(!reset_n)begin
DIO <= 1'd0;
RCLK <= 1'd0;
SCLK <= 1'd0;
end
else if(div_cnt == 1'd1)begin
case(bit_cnt)
5'd0: begin DIO <= seg[7];SCLK <= 1'd0;RCLK <= 1'd1;end
5'd1: begin SCLK <= 1'd1;RCLK <= 1'd0;end
5'd2: begin DIO <= seg[6];SCLK <= 1'd0;end
5'd3: begin SCLK <= 1'd1;end
5'd4: begin DIO <= seg[5];SCLK <= 1'd0;end
5'd5: begin SCLK <= 1'd1;end
5'd6: begin DIO <= seg[4];SCLK <= 1'd0;end
5'd7: begin SCLK <= 1'd1;end
5'd8: begin DIO <= seg[3];SCLK <= 1'd0;end
5'd9: begin SCLK <= 1'd1;end
5'd10:begin DIO <= seg[2];SCLK <= 1'd0;end
5'd11:begin SCLK <= 1'd1;end
5'd12:begin DIO <= seg[1];SCLK <= 1'd0;end
5'd13:begin SCLK <= 1'd1;end
5'd14:begin DIO <= seg[0];SCLK <= 1'd0;end
5'd15:begin SCLK <= 1'd1;end
5'd16:begin DIO <= sel[7];SCLK <= 1'd0;end
5'd17:begin SCLK <= 1'd1;end
5'd18:begin DIO <= sel[6];SCLK <= 1'd0;end
5'd19:begin SCLK <= 1'd1;end
5'd20:begin DIO <= sel[5];SCLK <= 1'd0;end
5'd21:begin SCLK <= 1'd1;end
5'd22:begin DIO <= sel[4];SCLK <= 1'd0;end
5'd23:begin SCLK <= 1'd1;end
5'd24:begin DIO <= sel[3];SCLK <= 1'd0;end
5'd25:begin SCLK <= 1'd1;end
5'd26:begin DIO <= sel[2];SCLK <= 1'd0;end
5'd27:begin SCLK <= 1'd1;end
5'd28:begin DIO <= sel[1];SCLK <= 1'd0;end
5'd29:begin SCLK <= 1'd1;end
5'd30:begin DIO <= sel[0];SCLK <= 1'd0;end
5'd31:begin SCLK <= 1'd1;end
endcase
end
else begin
DIO <= DIO;
RCLK <= RCLK;
SCLK <= SCLK;
end
endmodule
(7)顶层代码:
module hex_top(clk,reset_n,sw,DIO,SCLK,RCLK);
input clk;
input reset_n;
input [3:0]sw;
output DIO;
output SCLK;
output RCLK;
reg [31:0]data;
wire [7:0]sel;
wire [7:0]seg;
hex hex_inst(
.clk(clk),
.reset_n(reset_n),
.data(data),
.sel(sel),
.seg(seg)
);
hc595_driver hc595_driver_inst(
.clk(clk),
.reset_n(reset_n),
.sel(sel),
.seg(seg),
.DIO(DIO),
.SCLK(SCLK),
.RCLK(RCLK)
);
//data设计
always@(posedge clk or negedge reset_n)
if(!reset_n)
data <= 32'd0;
else begin
case(sw)
4'h1:data <= 32'h76543210;
4'h2:data <= 32'hfedcba98;
4'h4:data <= 32'h98765432;
4'h8:data <= 32'h12345678;
default:data <= 32'h00000000;
endcase
end
endmodule
(8)引脚绑定: