目录
前言
来分享第一个案例了!简易电子时钟的Verilog设计,电子时钟应该算是走嵌入式和FPGA开发的敲门砖了叭(也可能是流水灯)。本次设计实现的平台是Altera的DE2开发板。
一、简易电子时钟的功能要求
一个简易的电子时钟应该包含以下功能:
- 正常显示时分秒
- 可调节时间
在此基础上也还可以继续扩展功能,本次由于刚入门,便只实现了基本功能。

二、设计思路&整体框架
要正常计时,我们需要一个1Hz的信号。在Verilog中采用分频器对基准时钟进行分频,使用这个1Hz信号进行计数,便可以产生时分秒。再将时分秒用数码管显示出来,第一个功能成功实现;在第一个基础上,设置一个拨码开关,用以区分正常模式和调时模式。当电子时钟处于调时模式时,最低位数码管闪烁,按下增1按键时数字加1;按下移位按键时闪烁位向高位移动。当模式调回正常模式时,从修改后的时间开始计时。
综上,需要一个分频器、一个时间管理模块、需要六个数码管显示译码器。整体框图如下:

对于分频器这一ip,之后会出文详述,此处使用的是占空比50%的偶分频。数码管显示译码模块属于较为简单的模块,读者在看其Verilog代码时很容易便理解。
三、完整代码
开门见山!先上整个完整能编译的Verilog代码!
module simple_electronic_clock(clk,key_add,key_displace,switch_mode,hour_decode,min_decode,sec_decode);
input clk;//基准时钟50MHz
input key_add;//增一按键
input key_displace;//移位按键
input switch_mode;//模式开关
output [13:0] hour_decode;//小时译码
output [13:0] min_decode;//分钟译码
output [13:0] sec_decode;//秒译码
wire clk_1Hz,clk_2Hz;//分频后的1Hz、2Hz信号
wire [1:0] mode_cnt;//调时的闪烁位
wire [7:0] hour,min,sec;//时,分,秒
divider(clk_2Hz,clk_1Hz,clk);//分频器
time_management(clk_1Hz,switch_mode,key_add,key_displace,hour,min,sec,mode_cnt);//时间管理模块
digital_tube_decode(clk_2Hz,mode_cnt,hour,min,sec,hour_decode,min_decode,sec_decode);//数码管显示译码模块
endmodule
module divider(clk_2Hz,clk_1Hz,clk);//分频器
output reg clk_1Hz,clk_2Hz;
input clk;
reg [24:0] count,count2;//内部计数单元
//count计满24999999时信号反向,产生1Hz信号
always@(posedge clk) begin
if(count==25'd24999999)
begin
count<=25'b0;
clk_1Hz<=~clk_1Hz;
end
else
count<=count+1'b1;
end
//count2计满12499999时信号反向,产生2Hz信号
always@(posedge clk) begin
if(count==25'd12499999)
begin
count2<=25'b0;
clk_2Hz<=~clk_2Hz;
end
else
count2<=count2+1'b1;
end
endmodule
module time_management(clk_1Hz,switch_mode,key_add,key_displace,hour,min,sec,mode_cnt);//时间管理模块
input clk_1Hz,switch_mode,key_add,key_displace;
output reg [7:0] hour,min,sec;
output reg [1:0] mode_cnt;//调时的闪烁位标志
//时间计时&调时
always @(posedge clk_1Hz) begin
case (switch_mode)
1'b0:sec[3:0] <= sec[3:0] + 1'b1;//正常模式计时
1'b1:begin //调时模式
if(key_add) begin
case (mode_cnt)
2'b00:sec[3:0] <= sec[3:0] + 1'b1;//秒时间加一
2'b01:min[3:0] <= min[3:0] + 1'b1;//分时间加一
2'b10:hour[3:0] <= hour[3:0] + 1'b1;//时时间加一
default:;
endcase
end
end
default:;
endcase
//以下为进位条件判断
if(sec[3:0] == 4'd10) begin
sec[3:0] <= 4'b0;
sec[7:4] <= sec[7:4] + 1'b1;
end
if(sec[7:4] == 4'd6) begin
sec[7:4] <= 4'b0;
min[3:0] <= min[3:0] + 1'b1;
end
if(min[3:0] == 4'd10) begin
min[3:0] <= 4'b0;
min[7:4] <= min[7:4] + 1'b1;
end
if(min[7:4] == 4'd6) begin
min[7:4] <= 4'b0;
hour[3:0] <= hour[3:0] + 1'b1;
end
if(hour[3:0] == 4'd10) begin
hour[3:0] <= 4'b0;
hour[7:4] <= hour[7:4] + 1'b1;
end
if(hour[3:0] == 4'd4 && hour[7:4] == 4'd2) begin
hour[3:0] <= 4'b0;
hour[7:4] <= 4'b0;
end
end
//移位按键触发移位
always @(posedge key_displace) begin
if(switch_mode) begin
if(mode_cnt == 2'b10) mode_cnt <= 2'b0;
else mode_cnt <= mode_cnt + 1'b1;
end
end
endmodule
module digital_tube_decode(clk_2Hz,mode_cnt,hour,min,sec,hour_decode,min_decode,sec_decode);
input clk_2Hz;
input [1:0] mode_cnt;
input [7:0] hour,min,sec;
output reg [13:0] hour_decode,min_decode,sec_decode;
reg flag;
//闪烁产生
always @(posedge clk_2Hz) begin
flag <= ~flag;
end
//显示译码
always @(posedge clk_2Hz) begin
case (mode_cnt) //根据闪烁位标志,使得闪烁位数字闪烁
2'b00:begin
hour_decode[6:0] <= decode(hour[3:0]);
hour_decode[13:7] <= decode(hour[7:4]);
min_decode[6:0] <= decode(min[3:0]);
min_decode[13:7] <= decode(min[3:0]);
if(flag) begin
sec_decode[6:0] <= decode(sec[3:0]);
sec_decode[13:7] <= decode(sec[3:0]);
end
else begin //7'b1111111为数码管全灭,下面同理
sec_decode[6:0] <= 7'b1111111;
sec_decode[13:7] <= 7'b1111111;
end
end
2'b01:begin
hour_decode[6:0] <= decode(hour[3:0]);
hour_decode[13:7] <= decode(hour[7:4]);
sec_decode[6:0] <= decode(sec[3:0]);
sec_decode[13:7] <= decode(sec[7:4]);
if(flag) begin
min_decode[6:0] <= decode(min[3:0]);
min_decode[13:7] <= decode(min[7:4]);
end
else begin
min_decode[6:0] <= 7'b1111111;
min_decode[13:7] <= 7'b1111111;
end
end
2'b10:begin
sec_decode[6:0] <= decode(sec[3:0]);
sec_decode[13:7] <= decode(sec[7:4]);
min_decode[6:0] <= decode(min[3:0]);
min_decode[13:7] <= decode(min[7:4]);
if(flag) begin
hour_decode[6:0] <= decode(hour[3:0]);
hour_decode[13:7] <= decode(hour[7:4]);
end
else begin
hour_decode[6:0] <= 7'b1111111;
hour_decode[13:7] <= 7'b1111111;
end
end
default:;
endcase
end
//译码函数,便于重复调用
function [6:0] decode;
input [3:0] num;
begin
case (num)
4'd0:decode=7'b1000000;
4'd1:decode=7'b1111001;
4'd2:decode=7'b0100100;
4'd3:decode=7'b0110000;
4'd4:decode=7'b0011001;
4'd5:decode=7'b0010010;
4'd6:decode=7'b0000010;
4'd7:decode=7'b1111000;
4'd8:decode=7'b0000000;
4'd9:decode=7'b0010000;
default: decode=7'b1111111;
endcase
end
endfunction
endmodule
四、仿真
仿真就等我之后有空再弄叭(dog)。
总结
这篇文是我第一个Verilog案例,主要讲解设计思路,当然还有更好的电子时钟例码,我这个算是无脑编写QaQ
2万+



被折叠的 条评论
为什么被折叠?



