27.数码管的驱动,使用74HC595移位寄存器芯片

发布于:2024-07-11 ⋅ 阅读:(26) ⋅ 点赞:(0)

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)引脚绑定: