(以下内容是我们3人小组完成大作业时共同合力完成的,每个人耗费心血很多,发篇文章纪念一下)
开发板要完成基本工作:
- 能正常完成时钟的时、分、秒走时,并及时进位;
- 使用1Hz 闪烁频率的LED闪烁或者1Hz颜色切换频率改变颜色等方式实现秒的指示;
- 使用两位七段数码管显示时、分和秒,其切换方式为:默认显示“分钟”,按住K4键显示“小时”,按住K3键显示“秒”;
- 使用K1和K2键调整时间,分别为“+”和“-”,当K4按下,则K1和K2调整“小时”,当K4放开,则K1和K2调整“分钟”,当K3按下,则K1和K2调整“秒”;
- 整点报时:当时间到达每个整点,则全彩LED以某种固定颜色按1Hz频率闪烁相应次数(按24小时制);
下面是我们的设计创新部分(代码附后):
- 整点报时:时钟走到哪一小时,则全彩LED闪烁相应次数。
- 完成闹钟功能:将sw3开关设置为1,开始设置固定时钟和分钟,当时间计时到达时,八个led灯闪烁一分钟;
- 完成倒计时功能:sw4开关设置为1,进入倒计时设置环节,sw2关闭调整时间,K1 K2 K3 K4 与时钟功能一样;sw4关闭进入时钟功能;sw1倒计时与时钟清零互不干扰。同时带有预警效果(倒计时最后一分钟红灯闪烁)。
管脚分配图如下:
基本功能的完整代码展示:
下面附上代代相传的代码,代码主体是分频部分和时钟计时的代码,很多代码都是重复的,结合AI比较容易能读懂。(创新功能的代码在后面)
// 小脚丫FPGA开发板设计简易数字时钟
module time_clock (CLK,reset,seg_led_1,seg_led_2,led,key,sw2,sw3,RGB1,RGB2); //定义时钟信号,复位信号,两个数字显示器,按键,开关,三色灯
input CLK,reset;
input [3:0]key;
input sw2,sw3;
output reg [8:0] seg_led_1;
output reg [8:0] seg_led_2;
output reg [7:0] led; //8个led灯,用于闹钟闪烁
output reg [2:0] RGB1=3'b 111; //初始化所有通道都被设置为高电平,最亮
output reg [2:0] RGB2=3'b 111;
reg [3:0] num1 ; //num i 是走时的位,count i 是计数,limiti 是闹钟位
reg [3:0] count1;
reg [3:0] limit1;
reg [3:0] num2 ;
reg [3:0] count2;
reg [3:0] limit2;
reg [3:0] num3 ;
reg [3:0] count3;
reg [3:0] limit3;
reg [3:0] num4 ;
reg [3:0] count4;
reg [3:0] limit4;
reg [3:0] num5 ;
reg [3:0] count5;
reg [3:0] limit5;
reg [3:0] num6 ;
reg [3:0] count6;
reg [3:0] limit6;
reg [30:0]cnt_1s;
reg [30:0]cnt_05s;
reg [15 : 0] count;
reg [15 : 0] count0;
reg [8:0] seg [9:0]; // reg [8:0] seg [9:0];放在一起: 一个包含10个元素的数组,每个元素都是一个9位宽的寄存器,用于显示数字0到9
wire CLK_1s; //定义1s分频得到的时钟秒针计数器的触发
//1s间隔脉冲模块,产生一个1s的秒针时钟信号
parameter T1 = 12000000; //小脚丫自带的时钟信号12MHz,1/T1=1Hz,生成一个秒的指示
always@(posedge CLK) begin //检测到时钟上升,触发always块内部的语句
if(!reset)
cnt_1s <= 0; //如果复位信号reset为低电平(即复位被激活),则计数器cnt_1s将被重置为0 。确保系统能够在需要时从头开始计时的常见做法
else if(cnt_1s == T1-1) //如果马上要到切换的时刻
cnt_1s<=0; //置零
else //如果不是就进1s
cnt_1s<= cnt_1s + 1;
end
//间隔脉冲模块,产生一个调整间隔时钟信号 //用于产生另一个分频来用于调整时钟时的指示,可以使得调整更加顺滑
parameter T2 = 1500000;
always@(posedge CLK) begin
if(!reset)
cnt_05s <= 0;
else if(cnt_05s == T2-1)
cnt_05s<= 0;
else
cnt_05s<= cnt_05s + 1;
end
divide #(.WIDTH(32),.N(12000000)) u2 ( //传递参数 // 会输出1Hz分频用于秒针走时指示
.CLK(CLK),
.reset_n(reset), //例化的端口信号都连接到定义好的信号
.clkout(CLK_1s)
);
always @(posedge CLK or negedge reset) //时钟信号的上升沿或者复位信号的下降沿触发
begin
if (!reset) //复位信号为低电平的时候,全部清零,异步清零
begin
num1 <= 0;
num2<=0;
num3 <= 0;
num4<=0;
num5 <= 0;
num6<=0;
end
//计时部分
else
begin
if(sw2==1) //sw2是调整时间的开关,当sw2=1,开启:开始计时 sw2=0,关闭:调整时间
begin //sw3为闹钟设置开关 ,sw3=1,开启:设置闹钟模式 sw3=0,关闭:退出设置闹钟模式
if(cnt_1s==T1-1 )
begin //num1,2:秒针的第二位和第一位;num3,4:分针的第二位和第一位;num5,6:时针的第二位和第一位
if((num2==5)&&(num1==9)) //秒针走到59时,如果马上切换则置零
begin
num1<=0;
num2<=0;
if((num4==5)&&(num3==9)) //分针走到59时,如果马上切换则置零
begin
num3<=0;
num4<=0;
if((num6==2)&&(num5==3)) //时针走到24时,如果马上切换则置零
begin
num5<=0;
num6<=0;
end
else if(num5==9) //时针第二位走到9就进位,比如9->10
begin
num5<=0;
num6<=num6+1;
end
else //否则时针第二位正常进位,比如10->11
begin
num5<=num5+1;
end
end
else if(num3==9) //分针第二位走到9就进位,比如49->50
begin
num3<=0;
num4<=num4+1;
end
else //否则分针第二位正常进位,比如50->51
begin
num3<=num3+1;
end
end
else if(num1==9) //秒针第二位走到9就进位,比如49->50
begin
num1<=0;
num2<=num2+1;
end
else //否则分针第二位正常进位,比如50->51
begin
num1<=num1+1;
end
end
end
//调整时间部分模块,切换为T2-1,即更加顺滑的切换
if(sw2==0 && sw3==0) //关闭sw2和sw3,进入调时部分
begin
if(key[2]==1 && key[3]==1) //调整分针(K3和K4默认弹起)
begin
if(key[0]==0) //K1按下,加1s
begin //后面都是进位
if(cnt_05s==T2-1)
begin
if((num4==5)&&(num3==9))
begin
num3<=0;
num4<=0;
end
else if(num3==9 )
begin
num3<=0;
num4<=num4+1;
end
else
begin
num3<=num3+1;
end
end
end
else if(key[1]==0) //K2按下,减1s
begin //后面都是进位
if(cnt_05s==T2-1)
begin
if(num3==0 && num4==0)
begin
num3<=9;
num4<=5;
end
else if(num3==0)
begin
num3<=9;
num4<=num4-1;
end
else
num3<=num3-1;
end
end
else //不按就是不变
begin
num3<=num3;
num4<=num4;
end
end
else if(key[2]==1 && key[3]==0) //调整时针(K3弹起,K4按下)
begin
if( key[0]==0 ) //K1按下加1s
begin
if(cnt_05s==T2-1)
begin
if((num6==2)&&(num5==3))
begin
num5<=0;
num6<=0;
end
else if(num5==9)
begin
num5<=0;
num6<=num6+1;
end
else
begin
num5<=num5+1;
end
end
end
else if(key[1]==0) //K2按下减1s
begin
if(cnt_05s==T2-1)
begin
if(num5==0 && num6==0)
begin
num5<=3;
num6<=2;
end
else if(num5==0)
begin
num5<=9;
num6<=num6-1;
end
else
num5<=num5-1;
end
end
else
begin
num5<=num5;
num6<=num6;
end
end
else if(key[2]==0 && key[3]==1) //调整秒针(K3按下,K4弹起)
begin
if( key[0]==0 ) //K1按下加1s
begin
if(cnt_05s==T2-1)
begin
if((num2==5)&&(num1==9))
begin
num1<=0;
num2<=0;
end
else if(num1==9)
begin
num1<=0;
num2<=num2+1;
end
else
begin
num1<=num1+1;
end
end
end
else if(key[1]==0) //K2按下减1s
begin
if(cnt_05s==T2-1)
begin
if(num1==0 && num2==0)
begin
num1<=9;
num2<=5;
end
else if(num1==0)
begin
num1<=9;
num2<=num2-1;
end
else
num1<=num1-1;
end
end
else
begin
num1<=num1;
num2<=num2;
end
end
end
//闹钟设置模块,默认为分针的闹钟,即不设置秒钟
if(sw3==1 ) //sw3打开,开始闹钟设置
begin
if(key[2]==1 && key[3]==1) //调整分针,后面部分和上面调时一样,只不过cnt换成了limit
begin
if( key[0]==0 )
begin
if(cnt_05s==T2-1)
begin
if((limit4==5)&&(limit3==9))
begin
limit3<=0;
limit4<=0;
end
else if(limit3==9 )
begin
limit3<=0;
limit4<=limit4+1;
end
else
begin
limit3<=limit3+1;
end
end
end
else if(key[1]==0)
begin
if(cnt_05s==T2-1)
begin
if(limit3==0 && limit4==0)
begin
limit3<=9;
limit4<=5;
end
else if(limit3==0)
begin
limit3<=9;
limit4<=limit4-1;
end
else
limit3<=limit3-1;
end
end
else
begin
limit3<=limit3;
limit4<=limit4;
end
end
else if(key[2]==1 && key[3]==0) //调整时针
begin
if( key[0]==0 )
begin
if(cnt_05s==T2-1)
begin
if((limit6==2)&&(limit5==3))
begin
limit5<=0;
limit6<=0;
end
else if(limit5==9)
begin
limit5<=0;
limit6<=limit6+1;
end
else
begin
limit5<=limit5+1;
end
end
end
else if(key[1]==0)
begin
if(cnt_05s==T2-1)
begin
if(limit5==0 && limit6==0)
begin
limit5<=3;
limit6<=2;
end
else if(limit5==0)
begin
limit5<=9;
limit6<=limit6-1;
end
else
limit5<=limit5-1;
end
end
else
begin
limit5<=limit5;
limit6<=limit6;
end
end
end
end
end
//数码管显示部分模块
initial //定义一个初始过程块,它只会在仿真开始时执行一次,且只执行一次。
begin
seg[0] = 9'h3f; //7段显示数字 0
seg[1] = 9'h06; //7段显示数字 1
seg[2] = 9'h5b; //7段显示数字 2
seg[3] = 9'h4f; //7段显示数字 3
seg[4] = 9'h66; //7段显示数字 4
seg[5] = 9'h6d; //7段显示数字 5
seg[6] = 9'h7d; //7段显示数字 6
seg[7] = 9'h07; //7段显示数字 7
seg[8] = 9'h7f; //7段显示数字 8
seg[9] = 9'h6f; //7段显示数字 9
end
always @(posedge CLK) //这个部分是显示部分
begin
if(sw3==0) //sw3关闭
begin //普通计时
if(key[2]==1 && key[3]==0) //K3弹起,K4按下,显示小时
begin
count5<=num5;
count6<=num6;
seg_led_1<=seg[count6];
seg_led_2<=seg[count5];
end
else if(key[2]==0 && key[3]==1) //K3按下,K4弹起,显示秒
begin
count1<=num1;
count2<=num2;
seg_led_1<=seg[count2];
seg_led_2<=seg[count1];
end
else //默认显示分钟
begin
count4<=num4;
count3<=num3;
seg_led_1<=seg[count4];
seg_led_2<=seg[count3];
end
end
else //sw3开启,显示闹钟的数字管
begin
if(key[2]==1 && key[3]==0)
begin
count5<=limit5;
count6<=limit6;
seg_led_1<=seg[count6];
seg_led_2<=seg[count5];
end
else if(key[2]==0 && key[3]==1)
begin
count1<=limit1;
count2<=limit2;
seg_led_1<=seg[count2];
seg_led_2<=seg[count1];
end
else
begin
count4<=limit4;
count3<=limit3;
seg_led_1<=seg[count4];
seg_led_2<=seg[count3];
end
end
end
//整点报时:三色灯闪烁1min红色信号不停翻转,实现三色灯秒钟闪烁
always @(posedge CLK_1s)
begin
RGB2[0]<=~RGB2[0]; //平时一个三色灯随着秒针走动在闪烁
if(num3==0 && num4==0) //整点的时候,即分针为00时,另一个三色灯开始翻转闪烁1min直到变为01
begin
RGB1[0]<=~RGB1[0];
end
else
begin
RGB1[0]<=1;
end
end
//闹钟闪烁:1min,原理与三色灯类似
always @(posedge CLK_1s)
begin
if(limit3 == num3 && limit4 == num4 && limit5 == num5 && limit6 == num6) //时针和分针走到预定闹钟位置时触发
begin
led<=~led; //8个led灯开始不停翻转闪烁1min直到分针变化
end
else
begin
led<=8'b 11111111; //其余时间常亮
end
end
endmodule
// Module Function:任意整数时钟分频
module divide ( CLK,reset_n,clkout);
input CLK,reset_n; //输入信号,其中clk连接到FPGA的C1脚,频率为12MHz
output clkout; //输出信号,可以连接到LED观察分频的时钟
//parameter是verilog里常数语句
parameter WIDTH = 24; //计数器的位数,计数的最大值为 2**WIDTH-1
parameter N = 12_000_000; //分频系数,请确保 N < 2**WIDTH-1,否则计数会溢出
reg [WIDTH-1:0] cnt_p,cnt_n; //cnt_p为上升沿触发时的计数器,cnt_n为下降沿触发时的计数器
reg CLK_p,CLK_n; //CLK_p为上升沿触发时分频时钟,CLK_n为下降沿触发时分频时钟
//上升沿触发时计数器的控制
always @ (posedge CLK or negedge reset_n ) //posedge和negedge是verilog表示信号上升沿和下降沿
//当clk上升沿来临或者reset_n变低的时候执行一次always里的语句
begin
if(!reset_n)
cnt_p<=0;
else if (cnt_p==(N-1))
cnt_p<=0;
else cnt_p<=cnt_p+1; //计数器一直计数,当计数到N-1的时候清零,这是一个模N的计数器
end
//上升沿触发的分频时钟输出,如果N为奇数得到的时钟占空比不是50%;如果N为偶数得到的时钟占空比为50%
always @ (posedge CLK or negedge reset_n)
begin
if(!reset_n)
CLK_p<=0;
else if (cnt_p<(N>>1)) //N>>1表示右移一位,相当于除以2去掉余数
CLK_p<=0;
else
CLK_p<=1; //得到的分频时钟正周期比负周期多一个clk时钟
end
//下降沿触发时计数器的控制
always @ (negedge CLK or negedge reset_n)
begin
if(!reset_n)
cnt_n<=0;
else if (cnt_n==(N-1))
cnt_n<=0;
else cnt_n<=cnt_n+1;
end
//下降沿触发的分频时钟输出,和clk_p相差半个时钟
always @ (negedge CLK)
begin
if(!reset_n)
CLK_n<=0;
else if (cnt_n<(N>>1))
CLK_n<=0;
else
CLK_n<=1; //得到的分频时钟正周期比负周期多一个clk时钟
end
assign clkout = (N==1)?CLK:(N[0])?(CLK_p&CLK_n):CLK_p; //条件判断表达式
//当N=1时,直接输出clk
//当N为偶数也就是N的最低位为0,N(0)=0,输出clk_p
//当N为奇数也就是N最低位为1,N(0)=1,输出clk_p&CLK_n。正周期多所以是相与
endmodule
完成设计创新部分的完整代码展示:
完整代码和解释如下:
-
// Module Function:时钟设计 module time_clock ( input CLK, //CLK: 输入信号,连接到FPGA的时钟引脚,提供时钟信号。 input reset, //reset: 输入信号,连接到FPGA的复位引脚,用于异步复位。 input [3:0] key, //key: 输入信号,连接到按键,用于调整时间、设置闹钟等操作。 input sw2, sw3, sw4, output reg [8:0] seg_led_1, //seg_led_1, seg_led_2: 输出信号,分别连接到数码管的第1个和第2个七段显示。 output reg [8:0] seg_led_2, output reg [7:0] led, //led: 输出信号,连接到LED灯,用于指示整点时间。 output reg [2:0] RGB1 = 3'b111, //RGB1, RGB2: 输出信号,分别连接到两个三色LED灯,用于指示整点时间和闹钟时间 output reg [2:0] RGB2 = 3'b111 ); //num1、num2、num3、num4、num5、num6:这些计数器分别用于实现秒、分钟、小时的时间计时,其中 num1 和 num2 组合用于实现秒,num3 和 num4 组合用于实现分钟,num5 和 num6 组合用于实现小时。 //cnt1、cnt2、cnt3、cnt4、cnt5、cnt6:这些计数器与 num1~num6 对应,用于在调整时间模式下暂存 num1~num6 的值。 //limit1、limit2、limit3、limit4、limit5、limit6:这些计数器用于设置闹钟时间。 //cnt_1s 和 cnt_05s:这两个计数器用于产生1秒和0.5秒的时钟脉冲,用于计时和调整时间。 //seg:这是一个数组,用于存储数字0-9对应的七段码,用于数码管显示。 reg [3:0] num1; //定义了一个4位的计数器 reg [3:0] cnt1; reg [3:0] limit1; reg [3:0] num2; reg [3:0] cnt2; reg [3:0] limit2; reg [3:0] num3; //定义了一个4位的计数器 reg [3:0] cnt3; reg [3:0] limit3; reg [3:0] num4; reg [3:0] cnt4; reg [3:0] limit4; reg [3:0] num5; //定义了一个4位的计数器 reg [3:0] cnt5; reg [3:0] limit5; reg [3:0] num6; reg [3:0] cnt6; reg [3:0] limit6; reg [30:0] cnt_1s; reg [30:0] cnt_05s; reg [15:0] cnt; reg [15:0] cnt0; reg [8:0] seg [9:0]; //倒计时需要的变量 reg [3:0] djs_num1; reg [3:0] djs_num2; reg [3:0] djs_num3; reg [3:0] djs_num4; reg [3:0] djs_num5; reg [3:0] djs_num6; wire CLK_1s; //定义一个中间变量,表示分频得到的时钟,用作计数器的触发 //间隔脉冲模块,产生一个 秒针 时钟信号 parameter T1 = 12000000; always @(posedge CLK or negedge reset) begin if (!reset) cnt_1s <= 0; else if (cnt_1s == T1 - 1) cnt_1s <= 0; else cnt_1s <= cnt_1s + 1; end //间隔脉冲模块,产生一个调整 间隔 信号时钟信号 parameter T2 = 1500000; always @(posedge CLK or negedge reset) begin if (!reset) cnt_05s <= 0; else if (cnt_05s == T2 - 1) cnt_05s <= 0; else cnt_05s <= cnt_05s + 1; end divide #(.WIDTH(32), .N(12000000)) u2 ( //传递参数 .CLK(CLK), .reset_n(reset), //例化的端口信号都连接到定义好的信号 .CLKout(CLK_1s) ); always @(posedge CLK or negedge reset) begin if (!reset) begin // 在时钟状态下的异步清零 num1 <= 0; num2 <= 0; num3 <= 0; num4 <= 0; num5 <= 0; num6 <= 0; end else if (sw4 == 0) begin if (sw2 == 1) begin // sw2调整时间的开关 1:开始计时 0:调整时间 sw3为闹钟设置开关 设置闹钟模式sw3:1 退出设置闹钟模式sw3:0 if (cnt_1s == T1 - 1) begin //秒 if ((num2 == 5) && (num1 == 9)) begin num1 <= 0; num2 <= 0; //分钟 if ((num4 == 5) && (num3 == 9)) begin num3 <= 0; num4 <= 0; //小时 if ((num6 == 2) && (num5 == 3)) begin num5 <= 0; num6 <= 0; end else if (num5 == 9) begin num5 <= 0; num6 <= num6 + 1; end else begin num5 <= num5 + 1; end end else if (num3 == 9) begin num3 <= 0; num4 <= num4 + 1; end else begin num3 <= num3 + 1; end end else if (num1 == 9) begin num1 <= 0; num2 <= num2 + 1; end else begin num1 <= num1 + 1; end end end if (sw2 == 0 && sw3 == 0) begin // 既要保证非倒计时状态和非闹钟设置状态 if (key[2] == 1 && key[3] == 1) begin // 调整分针 if (key[0] == 0) begin // K1按下加号 if (cnt_05s == T2 - 1) begin if ((num4 == 5) && (num3 == 9)) begin num3 <= 0; num4 <= 0; end else if (num3 == 9) begin num3 <= 0; num4 <= num4 + 1; end else begin num3 <= num3 + 1; end end end else if (key[1] == 0) begin if (cnt_05s == T2 - 1) begin if (num3 == 0 && num4 == 0) begin num3 <= 9; num4 <= 5; end else if (num3 == 0) begin num3 <= 9; num4 <= num4 - 1; end else begin num3 <= num3 - 1; end end end else begin num3 <= num3; num4 <= num4; end end else if (key[2] == 1 && key[3] == 0) begin // 调整时针 if (key[0] == 0) begin if (cnt_05s == T2 - 1) begin if ((num6 == 2) && (num5 == 3)) begin num5 <= 0; num6 <= 0; end else if (num5 == 9) begin num5 <= 0; num6 <= num6 + 1; end else begin num5 <= num5 + 1; end end end else if (key[1] == 0) begin if (cnt_05s == T2 - 1) begin if (num5 == 0 && num6 == 0) begin num5 <= 3; num6 <= 2; end else if (num5 == 0) begin num5 <= 9; num6 <= num6 - 1; end else begin num5 <= num5 - 1; end end end else begin num5 <= num5; num6 <= num6; end end else if (key[2] == 0 && key[3] == 1) begin // 调整秒针 if (key[0] == 0) begin if (cnt_05s == T2 - 1) begin if ((num2 == 5) && (num1 == 9)) begin num1 <= 0; num2 <= 0; end else if (num1 == 9) begin num1 <= 0; num2 <= num2 + 1; end else begin num1 <= num1 + 1; end end end else if (key[1] == 0) begin if (cnt_05s == T2 - 1) begin if (num1 == 0 && num2 == 0) begin num1 <= 9; num2 <= 5; end else if (num1 == 0) begin num1 <= 9; num2 <= num2 - 1; end else begin num1 <= num1 - 1; end end end else begin num1 <= num1; num2 <= num2; end end end if (sw3 == 1) begin // 设置闹钟 if (key[2] == 1 && key[3] == 1) begin // 调整分针 if (key[0] == 0) begin if (cnt_05s == T2 - 1) begin if ((limit4 == 5) && (limit3 == 9)) begin limit3 <= 0; limit4 <= 0; end else if (limit3 == 9) begin limit3 <= 0; limit4 <= limit4 + 1; end else begin limit3 <= limit3 + 1; end end end else if (key[1] == 0) begin if (cnt_05s == T2 - 1) begin if (limit3 == 0 && limit4 == 0) begin limit3 <= 9; limit4 <= 5; end else if (limit3 == 0) begin limit3 <= 9; limit4 <= limit4 - 1; end else begin limit3 <= limit3 - 1; end end end else begin limit3 <= limit3; limit4 <= limit4; end end else if (key[2] == 1 && key[3] == 0) begin // 调整时针 if (key[0] == 0) begin if (cnt_05s == T2 - 1) begin if ((limit6 == 2) && (limit5 == 3)) begin limit5 <= 0; limit6 <= 0; end else if (limit5 == 9) begin limit5 <= 0; limit6 <= limit6 + 1; end else begin limit5 <= limit5 + 1; end end end else if (key[1] == 0) begin if (cnt_05s == T2 - 1) begin if (limit5 == 0 && limit6 == 0) begin limit5 <= 3; limit6 <= 2; end else if (limit5 == 0) begin limit5 <= 9; limit6 <= limit6 - 1; end else begin limit5 <= limit5 - 1; end end end else begin limit5 <= limit5; limit6 <= limit6; end end end end else begin // 在倒计时状态下的异步清零 if (!reset) begin djs_num1 <= 0; djs_num2 <= 0; djs_num3 <= 0; djs_num4 <= 0; djs_num5 <= 0; djs_num6 <= 0; end else begin // 开始计时 if (sw2 == 0) begin // 关闭sw2开始调整时间 if (key[2] == 1 && key[3] == 1) begin // 调整分针 if (key[0] == 0) begin if (cnt_05s == T2 - 1) begin if ((djs_num4 == 5) && (djs_num3 == 9)) begin djs_num3 <= 0; djs_num4 <= 0; end else if (djs_num3 == 9) begin djs_num3 <= 0; djs_num4 <= djs_num4 + 1; end else begin djs_num3 <= djs_num3 + 1; end end end else if (key[1] == 0) begin if (cnt_05s == T2 - 1) begin if (djs_num3 == 0 && djs_num4 == 0) begin djs_num3 <= 9; djs_num4 <= 5; end else if (djs_num3 == 0) begin djs_num3 <= 9; djs_num4 <= djs_num4 - 1; end else begin djs_num3 <= djs_num3 - 1; end end end else begin djs_num3 <= djs_num3; djs_num4 <= djs_num4; end end else if (key[2] == 1 && key[3] == 0) begin // 调整时针 if (key[0] == 0) begin if (cnt_05s == T2 - 1) begin if ((djs_num6 == 2) && (djs_num5 == 3)) begin djs_num5 <= 0; djs_num6 <= 0; end else if (djs_num5 == 9) begin djs_num5 <= 0; djs_num6 <= djs_num6 + 1; end else begin djs_num5 <= djs_num5 + 1; end end end else if (key[1] == 0) begin if (cnt_05s == T2 - 1) begin if (djs_num5 == 0 && djs_num6 == 0) begin djs_num5 <= 3; djs_num6 <= 2; end else if (djs_num5 == 0) begin djs_num5 <= 9; djs_num6 <= djs_num6 - 1; end else begin djs_num5 <= djs_num5 - 1; end end end else begin djs_num5 <= djs_num5; djs_num6 <= djs_num6; end end else if (key[2] == 0 && key[3] == 1) begin // 调整秒针 if (key[0] == 0) begin if (cnt_05s == T2 - 1) begin if ((djs_num2 == 5) && (djs_num1 == 9)) begin djs_num1 <= 0; djs_num2 <= 0; end else if (djs_num1 == 9) begin djs_num1 <= 0; djs_num2 <= djs_num2 + 1; end else begin djs_num1 <= djs_num1 + 1; end end end else if (key[1] == 0) begin if (cnt_05s == T2 - 1) begin if (djs_num1 == 0 && djs_num2 == 0) begin djs_num1 <= 9; djs_num2 <= 5; end else if (djs_num1 == 0) begin djs_num1 <= 9; djs_num2 <= djs_num2 - 1; end else begin djs_num1 <= djs_num1 - 1; end end end else begin djs_num1 <= djs_num1; djs_num2 <= djs_num2; end end end if (sw2 == 1) begin // 开始倒计时 if (cnt_1s == T1 - 1) begin if ((djs_num2 == 0) && (djs_num1 == 0) && (djs_num4 == 0) && (djs_num3 == 0) && (djs_num6 == 0) && (djs_num5 == 0)) begin // 确保不进入else里面,到达000000后停止 djs_num1 <= 0; djs_num2 <= 0; djs_num3 <= 0; djs_num4 <= 0; djs_num5 <= 0; djs_num6 <= 0; end else if ((djs_num2 == 0) && (djs_num1 == 0)) begin djs_num1 <= 9; djs_num2 <= 5; // 分钟 if ((djs_num4 == 0) && (djs_num3 == 0)) begin djs_num3 <= 9; djs_num4 <= 5; // 小时 if ((djs_num6 == 0) && (djs_num5 == 0)) begin djs_num5 <= 9; djs_num6 <= 5; end else if (djs_num5 == 0) begin djs_num5 <= 9; djs_num6 <= djs_num6 - 1; end else begin djs_num5 <= djs_num5 - 1; end end else if (djs_num3 == 0) begin djs_num3 <= 9; djs_num4 <= djs_num4 - 1; end else begin djs_num3 <= djs_num3 - 1; end end else if (djs_num1 == 0) begin djs_num1 <= 9; djs_num2 <= djs_num2 - 1; end else begin djs_num1 <= djs_num1 - 1; end end end end end end //数码管显示 initial begin // initial和always不同,其中语句只执行一次 //对存储器中第一个数赋值9'b00_0011_1111,相当于共阴极接地,DP点变低不亮,7段显示数字 0// seg[0] = 9'h3f; seg[1] = 9'h06; //7段显示数字 1 seg[2] = 9'h5b; //7段显示数字 2 seg[3] = 9'h4f; //7段显示数字 3 seg[4] = 9'h66; //7段显示数字 4 seg[5] = 9'h6d; //7段显示数字 5 seg[6] = 9'h7d; //7段显示数字 6 seg[7] = 9'h07; //7段显示数字 7 seg[8] = 9'h7f; //7段显示数字 8 seg[9] = 9'h6f; //7段显示数字 9 end always @(posedge CLK) begin if (sw4 == 0) begin if (sw3 == 0) begin // 没有设置闹钟 不是倒计时 if (key[2] == 1 && key[3] == 0) begin cnt5 <= num5; cnt6 <= num6; seg_led_1 <= seg[cnt6]; seg_led_2 <= seg[cnt5]; end else if (key[2] == 0 && key[3] == 1) begin cnt1 <= num1; cnt2 <= num2; seg_led_1 <= seg[cnt2]; seg_led_2 <= seg[cnt1]; end else begin cnt4 <= num4; cnt3 <= num3; seg_led_1 <= seg[cnt4]; seg_led_2 <= seg[cnt3]; end end else begin if (key[2] == 1 && key[3] == 0) begin cnt5 <= limit5; cnt6 <= limit6; seg_led_1 <= seg[cnt6]; seg_led_2 <= seg[cnt5]; end else if (key[2] == 0 && key[3] == 1) begin cnt1 <= limit1; cnt2 <= limit2; seg_led_1 <= seg[cnt2]; seg_led_2 <= seg[cnt1]; end else begin cnt4 <= limit4; cnt3 <= limit3; seg_led_1 <= seg[cnt4]; seg_led_2 <= seg[cnt3]; end end end else begin // 是倒计时 if (key[2] == 1 && key[3] == 0) begin cnt5 <= djs_num5; cnt6 <= djs_num6; seg_led_1 <= seg[cnt6]; seg_led_2 <= seg[cnt5]; end else if (key[2] == 0 && key[3] == 1) begin cnt1 <= djs_num1; cnt2 <= djs_num2; seg_led_1 <= seg[cnt2]; seg_led_2 <= seg[cnt1]; end else begin cnt4 <= djs_num4; cnt3 <= djs_num3; seg_led_1 <= seg[cnt4]; seg_led_2 <= seg[cnt3]; end end end //整点报时:三色灯闪烁1min红色信号不停翻转,实现三色灯秒钟闪烁 always @(posedge CLK_1s) begin RGB1[2]<=~RGB1[2]; //平时一个三色灯随着秒针走动在闪烁 if(num3==0 && num4==0) //整点的时候,即分针为00时,另一个三色灯开始翻转闪烁1min直到变为01 begin if(num1==0 && num2==0) begin RGB2[2]<=0; RGB2[0]<=0; RGB2[1]<=1; end if(num2<num6&&~(num1==0 && num2==0)) begin RGB2[1]<=~RGB2[1]; end if(num1<num5 &&num2==num6) begin RGB2[1]<=~RGB2[1]; end else begin RGB2[1]<=1; RGB2[0]<=1; RGB2[2]<=1; end end else begin RGB2[1]<=1; RGB2[0]<=1; RGB2[2]<=1; end end //-------------------------------------------闹钟闪烁 always @(posedge CLK_1s) begin if (sw4 == 0) begin if (limit3 == num3 && limit4 == num4 && limit5 == num5 && limit6 == num6) begin led <= ~led; end else begin led <= 8'b11111111; end end else begin // 倒计时还有一分钟结束时结束led闪烁 if ((djs_num3 == 0 && djs_num4 == 0 && djs_num5 == 0 && djs_num6 == 0) && (djs_num1 > 0 && djs_num2 > 0)) begin led <= ~led; end else begin led <= 8'b11111111; end end end endmodule // Module Function:任意整数时钟分频 module divide ( input CLK, //输入信号,其中CLK连接到FPGA的C1脚,频率为12MHz input reset_n, //输入信号,复位信号,低电平有效 output CLKout //输出信号,可以连接到LED观察分频的时钟 ); //parameter是verilog里常数语句 parameter WIDTH = 24; //计数器的位数,计数的最大值为 2**WIDTH-1 parameter N = 12000000; //分频系数,请确保 N < 2**WIDTH-1,否则计数会溢出 reg [WIDTH-1:0] num_p, num_n; //num_p为上升沿触发时的计数器,num_n为下降沿触发时的计数器 reg CLK_p, CLK_n; //CLK_p为上升沿触发时分频时钟,CLK_n为下降沿触发时分频时钟 //上升沿触发时计数器的控制 always @(posedge CLK or negedge reset_n) begin if (!reset_n) num_p <= 0; else if (num_p == (N - 1)) num_p <= 0; else num_p <= num_p + 1; //计数器一直计数,当计数到N-1的时候清零,这是一个模N的计数器 end //上升沿触发的分频时钟输出,如果N为奇数得到的时钟占空比不是50%;如果N为偶数得到的时钟占空比为50% always @(posedge CLK or negedge reset_n) begin if (!reset_n) CLK_p <= 0; else if (num_p < (N >> 1)) //N>>1表示右移一位,相当于除以2去掉余数 CLK_p <= 0; else CLK_p <= 1; //得到的分频时钟正周期比负周期多一个CLK时钟 end //下降沿触发时计数器的控制 always @(negedge CLK or negedge reset_n) begin if (!reset_n) num_n <= 0; else if (num_n == (N - 1)) num_n <= 0; else num_n <= num_n + 1; end //下降沿触发的分频时钟输出,和CLK_p相差半个时钟 always @(negedge CLK) begin if (!reset_n) CLK_n <= 0; else if (num_n < (N >> 1)) CLK_n <= 0; else CLK_n <= 1; //得到的分频时钟正周期比负周期多一个CLK时钟 end assign CLKout = (N == 1) ? CLK : (N[0]) ? (CLK_p & CLK_n) : CLK_p; //条件判断表达式 //当N=1时,直接输出CLK //当N为偶数也就是N的最低位为0,N(0)=0,输出CLK_p //当N为奇数也就是N最低位为1,N(0)=1,输出CLK_p&CLK_n。正周期多所以是相与 endmodule