Lab7_时序逻辑验证

一、简易电子时钟

  • 功能描述:
      设计一简易电子时钟,支持时、分、秒显示,其中HEX7-HEX6显示时,HEX5-HEX4显示分,HEX1-HEX0显示秒,假设进制为:18秒=1分钟;13分钟=1小时;9小时=1天。

  • 设计方案:
      首先,设计三个寄存器分别用来存储当前时、分、秒的计时结果,并将秒级作为最低级,进行嵌套循环:
      ①每逢时钟上升沿,秒加一,并对其进行判断,若符合进位条件,则该位置零,同时上一位加一;若上一位同时也符合进位条件,则继续向上一位进位。
      ②时钟上升沿出现的时间间隔为1s,则对应时钟频率为1Hz,初始时钟采用开发板自带的50MHz振荡器,对该信号进行分频,其中M=50M

  • 关键代码:

module elec_clk(
	input clk,
	output reg [7:0] second=8'b00000000,
	output reg [7:0] minute=8'b00000000,
	output reg [7:0] hour=8'b00000000);
	
	always@(posedge clk)	begin
		second <= second + 8'b00000001;
		if(second == 8'b00010001)	begin	//second:18
			second <= 8'b00000000;
			minute <= minute + 8'b00000001;
			if(minute == 8'b00001100)	begin	//minute:13
				minute <= 8'b00000000;
				hour <= hour + 8'b00000001;
				if(hour == 8'b00001000)	//hour:9
					hour <= 8'b00000000;
			end
		end
	end
	
endmodule


module fpga_clk(
	input CLOCK_50,
	output [6:0] HEX0,
	output [6:0] HEX1,
	output [6:0] HEX4,
	output [6:0] HEX5,
	output [6:0] HEX6,
	output [6:0] HEX7);
	
	wire clock;
	wire [7:0] second_bin;
	wire [7:0] second_bcd;
	wire [7:0] minute_bin;
	wire [7:0] minute_bcd;
	wire [7:0] hour_bin;
	wire [7:0] hour_bcd;
	
	clk_div	U0(
		.clk(CLOCK_50),
		.rstn(1),
		.clk_out(clock));
		
	elec_clk U1(
		.clk(clock),
		.second(second_bin),
		.minute(minute_bin),
		.hour(hour_bin));
		
	bin2bcd 	U3(
		.bin_code(second_bin),
		.bcd_code(second_bcd));
		
	bin2bcd U4(
		.bin_code(minute_bin),
		.bcd_code(minute_bcd));
		
	bin2bcd U5(
		.bin_code(hour_bin),
		.bcd_code(hour_bcd));
		
	led_display H0(
		.ctrl(0),
		.data(hour_bcd[3:0]),
		.dev0(HEX6));
		
	led_display H1(
		.ctrl(0),
		.data(hour_bcd[7:4]),
		.dev0(HEX7));
		
	led_display M0(
		.ctrl(0),
		.data(minute_bcd[3:0]),
		.dev0(HEX4));
		
	led_display M1(
		.ctrl(0),
		.data(minute_bcd[7:4]),
		.dev0(HEX5));
		
	led_display S0(
		.ctrl(0),
		.data(second_bcd[3:0]),
		.dev0(HEX0));
		
	led_display S1(
		.ctrl(0),
		.data(second_bcd[7:4]),
		.dev0(HEX1));
		
endmodule 
  • 综合结果:
      顶级模块的综合结果如图1,仅由分频模块和字符循环模块组成:


数电第11周周结_by_yc-小白菜博客

图1 顶级模块的综合结果

  elec_clk模块的综合结果如图2:


数电第11周周结_by_yc-小白菜博客

图2 elec_clk模块的综合结果

  summary结果如图3:


数电第11周周结_by_yc-小白菜博客

图3 summary结果

  • 总结分析:
      可以尝试将进位数据作为parameter,从而便于整个函数在后续过程中被调用。

  • 运行结果:
      另附视频。

二、七段管循环显示

  • 功能描述:
      ①在8个七段管上循环显示字符串:BUAA_1952-2022_(其中_表示七段管全灭);
      ②同时四个LED灯(LEDR[14-7])随BUAA的移动而移动;
      ③SW[17]作为复位信号,电平有效,LED灯全灭;
      ④SW[0]作为使能信号,电平有效,七段管和LED灯正常循环,低电平时,二者暂停循环;
      ⑤循环显示时间间隔为0.5s,即每隔0.5s字符串向左移一位。


数电第11周周结_by_yc-小白菜博客

图4 显示示例

  • 设计方案:
      ①循环显示的时间间隔为0.5s,我们选择每逢时钟上升沿进行一次移位,则对应时钟的频率为2Hz,初始时钟采用开发板自带的50MHz振荡器,对该信号进行分频,其中M=25M
      ②使用一个长度为7N的寄存器变量来存储字符,每个字符占七位,同时考虑到复位信号有效时,能够回复到初始状态,则应分别创建一个初始寄存器来寄存初始字符串,另一个寄存器来存储循环移位的结果,与此同时设置一个7*8的寄存器用来存储七段管上字符情况
      ③对于LED灯,可知不同循环阶段时对应的亮暗情况是不同的,这里选择用i循环的状态做标记,遍历出i的状态及相应的LED灯亮暗情况。
  • 关键代码:
module str_display(
	input 			clk,
	input 			reset,
	input                   ensignal,
	input      [104:0]      str,
	output reg [55:0]       seven,
	output reg [7:0]        LED_state);
	
	reg        [104:0]      shift_str;
	reg        [3:0]        i=14;
	
	always@(posedge clk)	begin
		if(reset)	begin
			shift_str[104 -: 105] <=str[104 -: 105];
			seven[55 -: 56] <= 56'b1;
			LED_state <= 8'b00000000;
		end
		else if(!ensignal)	begin
			shift_str[104 -: 105] <= shift_str[104 -: 105];
			seven[55 -: 56] <= seven[55 -: 56];
                        LED_state <= LED_state;
		end
		else	begin
			seven[55:0] <= {seven[48 -: 49],shift_str[104 -: 7]};
			shift_str[104:0] <= {shift_str[97 -: 98],shift_str[104 -: 7]};
			case(i)
				4'b1110:  LED_state <= 8'b00000001;
				4'b1101:  LED_state <= 8'b00000011;
				4'b1100:  LED_state <= 8'b00000111;
				4'b1011:  LED_state <= 8'b00001111;
				4'b1010:  LED_state <= 8'b00011110;
				4'b1001:  LED_state <= 8'b00111100;
				4'b1000:  LED_state <= 8'b01111000;
				4'b0111:  LED_state <= 8'b11110000;
				4'b0110:  LED_state <= 8'b11100000;
				4'b0101:  LED_state <= 8'b11000000;
				4'b0100:  LED_state <= 8'b10000000;
				default:  LED_state <= 8'b00000000;
			endcase
			if(i==0)
				i<=14;
			else
            	i<=i-1'b1;
		end
	end
	
endmodule

module fpga_seven(
	input 		   CLOCK_50,
	input      [17:0]  SW,
	output 	   [17:0]  LEDR,
	output     [6:0]   HEX0,
	output     [6:0]   HEX1,
	output     [6:0]   HEX2,
	output     [6:0]   HEX3,
	output     [6:0]   HEX4,
	output     [6:0]   HEX5,
	output     [6:0]   HEX6,
	output     [6:0]   HEX7);
	
	wire               clk;
	wire 	   [55:0]  seven;
	wire	   [7:0]   LED_state;
	reg  	   [104:0] str=105'b000000010000011001000100100011111111111001001000000100100100100011111101001001000000010010001001001111111;
	
	clk_div	U0(
		.clk(CLOCK_50),
		.rstn(1),
		.clk_out(clk));
	
	str_display U1(
		.clk(clk),
		.reset(SW[17]),
		.ensignal(SW[0]),
		.str(str),
		.seven(seven),
		.LED_state(LED_state));
	
	assign LEDR[14 -: 8]=LED_state[7 -: 8];
	assign HEX7=seven[55 -: 7];
	assign HEX6=seven[48 -: 7];
	assign HEX5=seven[41 -: 7];
	assign HEX4=seven[34 -: 7];
	assign HEX3=seven[27 -: 7];
	assign HEX2=seven[20 -: 7];
	assign HEX1=seven[13 -: 7];
	assign HEX0=seven[6  -: 7];
	
endmodule
  • 综合结果:
      顶级模块的综合结果如图5,仅由分频模块和字符循环模块组成:


数电第11周周结_by_yc-小白菜博客

图5 顶级模块的综合结果

  str_display模块的综合结果如图6:


数电第11周周结_by_yc-小白菜博客

图6 str_display模块的综合结果

  7


数电第11周周结_by_yc-小白菜博客

图7 summary结果

  • 总结分析:
      最初进行设计时,将大部分功能的实现全部放在了顶级模块中,结果造成在调整思路时异常混乱,将功能模块和顶级模块的实现分开可以使得整体设计的脉络更加清晰,同时有利于在不同的电路中进行复用。

  • 运行结果:
      另附视频。