如何基于Xilinx EGO1学习板实现番茄钟功能?

2026-05-23 06:081阅读0评论SEO教程
  • 内容介绍
  • 文章标签
  • 相关推荐

本文共计3067个文字,预计阅读时间需要13分钟。

仿原创新设计一、总体设计

1.仿原创新工作法简介+仿原创新工作法由意大利于奇系列创意造就。

内容如下:工作25分钟,休息5分钟,循环四次后休息15分钟。项目基于Xilinx Ego1开发板实现一个“计‘时器。”

番茄钟设计 一、总体设计 1.番茄工作法简介

番茄工作法由意大利的奇列洛创造。其内容就是:工作25分钟休息5分钟,循环四次后休息15分钟。

本项目就是基于Xilinx Ego1开发板实现一个计时器,该计时器能实现:

  • 25分钟工作倒计时
  • 5分钟休息倒计时
二、开发板介绍

开发板用户手册(提取码:2019)

板子搭载了8Mbit的SRAM芯片,对于本程序基本不用考虑内存不够的问题。主要看看引脚的定义和数码管部分。还有就是,注意板子的时钟是100MHz,对应P17引脚。

三、系统设计

本系统属于时序系统,所以采用状态机,以下是状态转化图

ok,万事俱备,下面开始写bug。

1.计时系统的构建 1.1 秒脉冲发生器

系统中需要秒脉冲的两个模块是25min倒计时和5min倒计时模块,不妨按下图设计时钟系统

EGO1的时钟是100MHz,构建计时器的关键就是分频得到秒脉冲。由于系统中有多处用到秒脉冲信号,所以不妨单独写一个秒脉冲发生模块:

module sec_gen( input clk, //系统时钟 input sec_en, //25min秒脉冲使能信号 output reg sec_out, //给25min倒计时模块的时钟 output reg sec_con //给5min倒计时模块的时钟 ); reg [25:0] n; always @(posedge clk or posedge sec_en)begin if(sec_en) sec_out<=sec_con; else sec_out<=sec_out; end always @(posedge clk) begin if(n==26'd5000000) //此处将将秒脉冲设置为0.1s了,方便调试 n<=26'd1; else n<=(n+26'd1); end always @(posedge clk) begin if(n==26'd5000000) sec_con<=~sec_con; else sec_con<=sec_con end endmodule

说明:

  • 之所以设置两个时钟输出,是为了方便“时间暂停”的实现:25min倒计时过程中,如果按下暂停键,系统会启动5min等待计时,此时给25min倒计时模块的时钟信号恒为“0”或‘’1“,这样暂停结束后,只需要重新给25min模块提供秒脉冲信号,它就能从暂停的地方继续计时。
  • 对于五分钟倒计时则没有保存断点时间的需求:它要么计时5min后结束,要么中断,下次开始又是从5min开始计时。
  • 由于EGO1的RAM较大,可以使用26位寄存器,所以为了图方便,这里直接分频得到秒脉冲,某些板子的寄存器没有26位,这种情况下,最好对时钟信号进行多次分频。
2.2 25min倒计时

//25分钟倒计时模块 module timer( input sec, //秒脉冲信号 input time_rst, //重置 output reg carry_25, //25分钟计时结束信号 output reg [15:0]t //低八位为秒,高八位为分 ); always @(posedge sec or negedge time_rst)begin if(time_rst) t<=16'b0010_0101_0000_0000; //计时满了25min,carry_25拉高,同时将时钟重置为25min else if(t[15:0]==16'd0)begin t<=16'b0010_0101_0000_0000; carry_25<=1'b1; end else if(t[11:0]==12'd0)begin t[11:8]<=4'd9; t[15:12]<=(t[15:12]-4'd1); end else if(t[7:0]==8'd0)begin t[7:4]<=4'd5; t[3:0]<=4'd9; t[11:8]<=(t[11:8]-4'd1); carry_25<=1'b0; end else if(t[3:0]==4'd0)begin t[3:0]<=4'd9; t[7:4]<=(t[7:4]-4'd1); end else t[3:0]<=(t[3:0]-4'd1); end endmodule

说明:

这里的大寄存器同样可以分解成小寄存器,比较优美的写法是多个always结构并行,这里也是图个方便,直接用多个else if,需要注意的是:

if-else if语句不是并行执行的,而是按照代码前后顺序,挨个执行else if ,且一旦符合判断条件,后面的else if 都不会执行

(所以使用多个always并行是更保守的做法)

2.3 5min倒计时

//五分钟等待模块 module time_5( input sec,//秒脉冲信号 input min5_en, //五分钟等待的使能信号 output reg carry_5 //五分钟计时结束的信号 ); reg [11:0]t;//低八位表示秒,高四位表示分 always @(posedge sec or negedge min5_en)begin if(!min5_en)begin t<=16'b0101_0000_0000; carry_5<=1'b0; end else if(t[11:0]==11'd0)begin t<=16'b0101_0000_0000; carry_5<=1'b1; end else if(t[7:0]==8'd0)begin t[7:4]<=4'd5; t[3:0]<=4'd9; t[11:8]<=(t[11:8]-4'd1); carry_5<=1'b0; end else if(t[3:0]==4'd0)begin t[3:0]<=4'd9; t[7:4]<=(t[7:4]-4'd1); end else t[3:0]<=(t[3:0]-4'd1); end endmodule

说明:

跟25min模块一样,唯一需要注意的是,传入该模块的秒脉冲是持续有效的(无稳态),而传入25min模块的秒脉冲是可以通过暂停信号来达到稳态的。

2.数码管显示

背景知识:

数码管分为共阴极和共阳极,共阴极就是把所有的管子负极连接到一起,这样当需要某个管子发光时,就给它的正极输入一个高电平(逻辑1);相反共阳极就是将管子的正极都连接起来接到电源上,当需要管子亮时就输入低电平(逻辑0)。EGO1的数码管是共阴极的

此外,板子上的数码管是四个为一组的,每组数码管受一个四选一多路选择器控制,也就是说同一时间,四个数码管只有一个能使用。所以输出的方式是,四个数码管轮流输出,但是这个轮换的速率很快,快到人眼看不出来,这样人看到就是四个罐子都在发光(显示屏也是这么工作的)。

//数码管控制模块 module pipe( input clk, //系统100MHz时钟 input run_stop, input [15:0]x, output reg [6:0]a_to_g, //单个数码管的输出信号 output reg [3:0]an //数码管选择信号 ); reg [20:0]clkdiv; wire [1:0]rank; reg [3:0]digit; assign rank=clkdiv[20:19]; initial clkdiv<=21'd0; //对系统100MHz时钟进行分频,作为数码管的扫描频率 always @(posedge clk or negedge run_stop)begin if(!run_stop) clkdiv<=21'd0; else clkdiv<=clkdiv+21'd1; end always @*begin if(!run_stop) an=4'd0; else case(rank) 2'd0:an=4'b0001; 2'd1:an=4'b0010; 2'd2:an=4'b0100; 2'd3:an=4'b1000; endcase end always @* case(rank) 2'd0:digit=x[3:0]; 2'd1:digit=x[7:4]; 2'd2:digit=x[11:8]; 2'd3:digit=x[15:12]; default:digit=4'd0; endcase always @* case(digit) 4'd0:a_to_g=7'b1111110; 4'd1:a_to_g=7'b0110000; 4'd2:a_to_g=7'b1101101; 4'd3:a_to_g=7'b1111001; 4'd4:a_to_g=7'b0110011; 4'd5:a_to_g=7'b1011011; 4'd6:a_to_g=7'b1011111; 4'd7:a_to_g=7'b1110000; 4'd8:a_to_g=7'b1111111; 4'd9:a_to_g=7'b1111011; default:a_to_g=7'b1111110; endcase endmodule 3.按键消抖

背景知识:

如下图,按键按下到弹起的过程中,电平是高频抖动的,这样如果不加入按键消抖处理,那么在信号抖动的过程中多次触发(比如我们想要的是按下按键暂停计时,如果不加防抖,那么就可能出现计时暂停、打开多次交替进行)。

消抖的基本原理也很简单:让按键信号必须保持一段时间才算有效。简单点讲,就是我收到一个按键信号(如果按键按下是0),先不着急执行按键按下后的程序,而是等几个时钟周期,再看看按键信号还是不是0,如果不是,说明按键在抖动,这个信号是非稳态信号,我就认为它是无效信号;如果还是0,说明确实收到了按键信号,我就开始执行后面的程序。所以,这个等待的时间就必须比抖动时间长,而比键稳定时间短

//按键消抖模块 module debounce( input clk, //系统时钟 input run_stop, input key_in, //输入的按键信号 output wire key_out //输出消抖后的按键信号 ); reg key_value; reg key_p_flag; reg key_reg; reg [20:0]delay_cnt; parameter DELAY_TIME=21'd1500000; //按键持续时间1/100M s //key_reg:按键输入寄存器 always@(posedge clk or negedge run_stop) if(!run_stop) key_reg<=1'b0; else key_reg<=key_in; //delay_cnt:延时计数器 always@(posedge clk or negedge run_stop) if(!run_stop) delay_cnt<=21'b0; else if(key_in!=key_reg) delay_cnt<=DELAY_TIME; else if(delay_cnt>0) delay_cnt<=delay_cnt-1'b1; else delay_cnt<=21'd0; //key_value always@(posedge clk or negedge run_stop) if(!run_stop) key_value<=1'b0; else if(delay_cnt==1'b1) key_value<=key_in; else key_value<=key_value; //key_p_falg:按键上升沿标志信号 always@(posedge clk or negedge run_stop) if(!run_stop) key_p_flag<=1'b0; else if(delay_cnt==1'b1&&key_in==1) key_p_flag<=1'b1; else key_p_flag<=1'b0; assign key_out=key_p_flag; endmodule 4.状态机控制器

背景知识:

具体解释看知乎状态机

其实就是个很简单的东西套了一个高大上的名字。以一个大学生为例,假设他只有上课、吃饭、睡觉、上厕所这四个状态,他每天按一定的时序在这四个状态之间切换,而处于每个状态下他就只能做这个状态下规定的事情(比如上课状态下他就不会吃东西,而吃饭状态下也不会排遗),各个状态之间相互独立。

直接上代码:

module states( input run_stop, //番茄钟工作开关 input reset_up, //重置开关 input pause_up, //暂停开关 input clk, //板载的100MHz时钟 input carry_25, //25分钟计时的进位 input carry_5, //五分钟等待的进位 output reg min5_en, //五分钟等待计时的控制 output reg sec_out_en, //秒脉冲的控制信号 output reg time_rst ///时间重置信号 ); reg [2:0]nstate; //next state reg [2:0]cstate; //current state parameter WORK=3'b001; parameter STOP=3'b010; parameter WAIT_5=3'b100; parameter RESET=3'b101; initial nstate=STOP; //如果按下了停止,那么现在的状态就保持STOP //反之,现在的状态就会变成下一个状态 always @(posedge clk or negedge run_stop) begin if(!run_stop) cstate<=STOP; else cstate<=nstate; end //状态转换(按照当前状态,决定下一个状态是什么) always @* begin case(cstate) STOP:begin if(run_stop)begin nstate=WORK; end else nstate=STOP; end WORK:begin if(run_stop==1'b0) nstate=STOP; else if(reset_up==1'b1) nstate=RESET; else if(pause_up==1'b1 || carry_25==1'b1)begin nstate=WAIT_5; end else nstate=WORK; end RESET: nstate=WAIT_5; WAIT_5:begin if(carry_5==1'b1) nstate=WORK; else if(reset_up) nstate=RESET; else if(pause_up) nstate=WORK; else nstate=WAIT_5; end default:nstate=STOP; endcase end //每个状态下,程序要干的事情 always @* begin case(cstate) //停止状态下:5分钟倒计时停止、25分钟倒计时停止、时间重置 STOP:begin min5_en<=1'b0; sec_out_en<=1'b0; time_rst<=1'b1; end //工作状态下:5分钟倒计时停止,25分钟倒计时工作 WORK:begin min5_en<=1'b0; time_rst<=1'b0; sec_out_en<=1'b1; end //等待状态下:5分钟倒计时开始,25分钟倒计时暂停 WAIT_5:begin min5_en<=1'b1; sec_out_en<=1'b0; time_rst<=1'b0; end //重置状态下:5分钟倒计时停止、25分钟倒计时停止、时间重置 RESET:begin sec_out_en<=1'b0; time_rst<=1'b1; min5_en<=1'b0; end default:begin sec_out_en<=1'b0; time_rst<=1'b1; min5_en<=1'b0; end endcase end endmodule

注意事项:

  • 组合逻辑中不要使用非阻塞赋值(状态转换的部分属于组合逻辑),时序逻辑中最好使用非阻塞赋值(描述各个状态下的内容的部分)
  • 阻塞赋值和非阻塞赋值的区别
四、资料下载

使用第三部分的内容可以完成基本的番茄钟功能。

这里提供一个加了一点花里胡哨的东西的番茄钟:

pan.baidu.com/s/1W9OtsmrOPexmkA-3EEXnqA 提取码:2019

添加了这些东西:

  • 倒计时的时候有个八位的跑马灯
  • 五分钟等待计时的时候有五个led灯,每过一分钟熄灭一个
  • 摸鱼状态:按下停止后会进入一个正计时状态,并将时间通过数码管显示,这样就能知道已经多久没有工作了。

它的状态转换图如下:

本文共计3067个文字,预计阅读时间需要13分钟。

仿原创新设计一、总体设计

1.仿原创新工作法简介+仿原创新工作法由意大利于奇系列创意造就。

内容如下:工作25分钟,休息5分钟,循环四次后休息15分钟。项目基于Xilinx Ego1开发板实现一个“计‘时器。”

番茄钟设计 一、总体设计 1.番茄工作法简介

番茄工作法由意大利的奇列洛创造。其内容就是:工作25分钟休息5分钟,循环四次后休息15分钟。

本项目就是基于Xilinx Ego1开发板实现一个计时器,该计时器能实现:

  • 25分钟工作倒计时
  • 5分钟休息倒计时
二、开发板介绍

开发板用户手册(提取码:2019)

板子搭载了8Mbit的SRAM芯片,对于本程序基本不用考虑内存不够的问题。主要看看引脚的定义和数码管部分。还有就是,注意板子的时钟是100MHz,对应P17引脚。

三、系统设计

本系统属于时序系统,所以采用状态机,以下是状态转化图

ok,万事俱备,下面开始写bug。

1.计时系统的构建 1.1 秒脉冲发生器

系统中需要秒脉冲的两个模块是25min倒计时和5min倒计时模块,不妨按下图设计时钟系统

EGO1的时钟是100MHz,构建计时器的关键就是分频得到秒脉冲。由于系统中有多处用到秒脉冲信号,所以不妨单独写一个秒脉冲发生模块:

module sec_gen( input clk, //系统时钟 input sec_en, //25min秒脉冲使能信号 output reg sec_out, //给25min倒计时模块的时钟 output reg sec_con //给5min倒计时模块的时钟 ); reg [25:0] n; always @(posedge clk or posedge sec_en)begin if(sec_en) sec_out<=sec_con; else sec_out<=sec_out; end always @(posedge clk) begin if(n==26'd5000000) //此处将将秒脉冲设置为0.1s了,方便调试 n<=26'd1; else n<=(n+26'd1); end always @(posedge clk) begin if(n==26'd5000000) sec_con<=~sec_con; else sec_con<=sec_con end endmodule

说明:

  • 之所以设置两个时钟输出,是为了方便“时间暂停”的实现:25min倒计时过程中,如果按下暂停键,系统会启动5min等待计时,此时给25min倒计时模块的时钟信号恒为“0”或‘’1“,这样暂停结束后,只需要重新给25min模块提供秒脉冲信号,它就能从暂停的地方继续计时。
  • 对于五分钟倒计时则没有保存断点时间的需求:它要么计时5min后结束,要么中断,下次开始又是从5min开始计时。
  • 由于EGO1的RAM较大,可以使用26位寄存器,所以为了图方便,这里直接分频得到秒脉冲,某些板子的寄存器没有26位,这种情况下,最好对时钟信号进行多次分频。
2.2 25min倒计时

//25分钟倒计时模块 module timer( input sec, //秒脉冲信号 input time_rst, //重置 output reg carry_25, //25分钟计时结束信号 output reg [15:0]t //低八位为秒,高八位为分 ); always @(posedge sec or negedge time_rst)begin if(time_rst) t<=16'b0010_0101_0000_0000; //计时满了25min,carry_25拉高,同时将时钟重置为25min else if(t[15:0]==16'd0)begin t<=16'b0010_0101_0000_0000; carry_25<=1'b1; end else if(t[11:0]==12'd0)begin t[11:8]<=4'd9; t[15:12]<=(t[15:12]-4'd1); end else if(t[7:0]==8'd0)begin t[7:4]<=4'd5; t[3:0]<=4'd9; t[11:8]<=(t[11:8]-4'd1); carry_25<=1'b0; end else if(t[3:0]==4'd0)begin t[3:0]<=4'd9; t[7:4]<=(t[7:4]-4'd1); end else t[3:0]<=(t[3:0]-4'd1); end endmodule

说明:

这里的大寄存器同样可以分解成小寄存器,比较优美的写法是多个always结构并行,这里也是图个方便,直接用多个else if,需要注意的是:

if-else if语句不是并行执行的,而是按照代码前后顺序,挨个执行else if ,且一旦符合判断条件,后面的else if 都不会执行

(所以使用多个always并行是更保守的做法)

2.3 5min倒计时

//五分钟等待模块 module time_5( input sec,//秒脉冲信号 input min5_en, //五分钟等待的使能信号 output reg carry_5 //五分钟计时结束的信号 ); reg [11:0]t;//低八位表示秒,高四位表示分 always @(posedge sec or negedge min5_en)begin if(!min5_en)begin t<=16'b0101_0000_0000; carry_5<=1'b0; end else if(t[11:0]==11'd0)begin t<=16'b0101_0000_0000; carry_5<=1'b1; end else if(t[7:0]==8'd0)begin t[7:4]<=4'd5; t[3:0]<=4'd9; t[11:8]<=(t[11:8]-4'd1); carry_5<=1'b0; end else if(t[3:0]==4'd0)begin t[3:0]<=4'd9; t[7:4]<=(t[7:4]-4'd1); end else t[3:0]<=(t[3:0]-4'd1); end endmodule

说明:

跟25min模块一样,唯一需要注意的是,传入该模块的秒脉冲是持续有效的(无稳态),而传入25min模块的秒脉冲是可以通过暂停信号来达到稳态的。

2.数码管显示

背景知识:

数码管分为共阴极和共阳极,共阴极就是把所有的管子负极连接到一起,这样当需要某个管子发光时,就给它的正极输入一个高电平(逻辑1);相反共阳极就是将管子的正极都连接起来接到电源上,当需要管子亮时就输入低电平(逻辑0)。EGO1的数码管是共阴极的

此外,板子上的数码管是四个为一组的,每组数码管受一个四选一多路选择器控制,也就是说同一时间,四个数码管只有一个能使用。所以输出的方式是,四个数码管轮流输出,但是这个轮换的速率很快,快到人眼看不出来,这样人看到就是四个罐子都在发光(显示屏也是这么工作的)。

//数码管控制模块 module pipe( input clk, //系统100MHz时钟 input run_stop, input [15:0]x, output reg [6:0]a_to_g, //单个数码管的输出信号 output reg [3:0]an //数码管选择信号 ); reg [20:0]clkdiv; wire [1:0]rank; reg [3:0]digit; assign rank=clkdiv[20:19]; initial clkdiv<=21'd0; //对系统100MHz时钟进行分频,作为数码管的扫描频率 always @(posedge clk or negedge run_stop)begin if(!run_stop) clkdiv<=21'd0; else clkdiv<=clkdiv+21'd1; end always @*begin if(!run_stop) an=4'd0; else case(rank) 2'd0:an=4'b0001; 2'd1:an=4'b0010; 2'd2:an=4'b0100; 2'd3:an=4'b1000; endcase end always @* case(rank) 2'd0:digit=x[3:0]; 2'd1:digit=x[7:4]; 2'd2:digit=x[11:8]; 2'd3:digit=x[15:12]; default:digit=4'd0; endcase always @* case(digit) 4'd0:a_to_g=7'b1111110; 4'd1:a_to_g=7'b0110000; 4'd2:a_to_g=7'b1101101; 4'd3:a_to_g=7'b1111001; 4'd4:a_to_g=7'b0110011; 4'd5:a_to_g=7'b1011011; 4'd6:a_to_g=7'b1011111; 4'd7:a_to_g=7'b1110000; 4'd8:a_to_g=7'b1111111; 4'd9:a_to_g=7'b1111011; default:a_to_g=7'b1111110; endcase endmodule 3.按键消抖

背景知识:

如下图,按键按下到弹起的过程中,电平是高频抖动的,这样如果不加入按键消抖处理,那么在信号抖动的过程中多次触发(比如我们想要的是按下按键暂停计时,如果不加防抖,那么就可能出现计时暂停、打开多次交替进行)。

消抖的基本原理也很简单:让按键信号必须保持一段时间才算有效。简单点讲,就是我收到一个按键信号(如果按键按下是0),先不着急执行按键按下后的程序,而是等几个时钟周期,再看看按键信号还是不是0,如果不是,说明按键在抖动,这个信号是非稳态信号,我就认为它是无效信号;如果还是0,说明确实收到了按键信号,我就开始执行后面的程序。所以,这个等待的时间就必须比抖动时间长,而比键稳定时间短

//按键消抖模块 module debounce( input clk, //系统时钟 input run_stop, input key_in, //输入的按键信号 output wire key_out //输出消抖后的按键信号 ); reg key_value; reg key_p_flag; reg key_reg; reg [20:0]delay_cnt; parameter DELAY_TIME=21'd1500000; //按键持续时间1/100M s //key_reg:按键输入寄存器 always@(posedge clk or negedge run_stop) if(!run_stop) key_reg<=1'b0; else key_reg<=key_in; //delay_cnt:延时计数器 always@(posedge clk or negedge run_stop) if(!run_stop) delay_cnt<=21'b0; else if(key_in!=key_reg) delay_cnt<=DELAY_TIME; else if(delay_cnt>0) delay_cnt<=delay_cnt-1'b1; else delay_cnt<=21'd0; //key_value always@(posedge clk or negedge run_stop) if(!run_stop) key_value<=1'b0; else if(delay_cnt==1'b1) key_value<=key_in; else key_value<=key_value; //key_p_falg:按键上升沿标志信号 always@(posedge clk or negedge run_stop) if(!run_stop) key_p_flag<=1'b0; else if(delay_cnt==1'b1&&key_in==1) key_p_flag<=1'b1; else key_p_flag<=1'b0; assign key_out=key_p_flag; endmodule 4.状态机控制器

背景知识:

具体解释看知乎状态机

其实就是个很简单的东西套了一个高大上的名字。以一个大学生为例,假设他只有上课、吃饭、睡觉、上厕所这四个状态,他每天按一定的时序在这四个状态之间切换,而处于每个状态下他就只能做这个状态下规定的事情(比如上课状态下他就不会吃东西,而吃饭状态下也不会排遗),各个状态之间相互独立。

直接上代码:

module states( input run_stop, //番茄钟工作开关 input reset_up, //重置开关 input pause_up, //暂停开关 input clk, //板载的100MHz时钟 input carry_25, //25分钟计时的进位 input carry_5, //五分钟等待的进位 output reg min5_en, //五分钟等待计时的控制 output reg sec_out_en, //秒脉冲的控制信号 output reg time_rst ///时间重置信号 ); reg [2:0]nstate; //next state reg [2:0]cstate; //current state parameter WORK=3'b001; parameter STOP=3'b010; parameter WAIT_5=3'b100; parameter RESET=3'b101; initial nstate=STOP; //如果按下了停止,那么现在的状态就保持STOP //反之,现在的状态就会变成下一个状态 always @(posedge clk or negedge run_stop) begin if(!run_stop) cstate<=STOP; else cstate<=nstate; end //状态转换(按照当前状态,决定下一个状态是什么) always @* begin case(cstate) STOP:begin if(run_stop)begin nstate=WORK; end else nstate=STOP; end WORK:begin if(run_stop==1'b0) nstate=STOP; else if(reset_up==1'b1) nstate=RESET; else if(pause_up==1'b1 || carry_25==1'b1)begin nstate=WAIT_5; end else nstate=WORK; end RESET: nstate=WAIT_5; WAIT_5:begin if(carry_5==1'b1) nstate=WORK; else if(reset_up) nstate=RESET; else if(pause_up) nstate=WORK; else nstate=WAIT_5; end default:nstate=STOP; endcase end //每个状态下,程序要干的事情 always @* begin case(cstate) //停止状态下:5分钟倒计时停止、25分钟倒计时停止、时间重置 STOP:begin min5_en<=1'b0; sec_out_en<=1'b0; time_rst<=1'b1; end //工作状态下:5分钟倒计时停止,25分钟倒计时工作 WORK:begin min5_en<=1'b0; time_rst<=1'b0; sec_out_en<=1'b1; end //等待状态下:5分钟倒计时开始,25分钟倒计时暂停 WAIT_5:begin min5_en<=1'b1; sec_out_en<=1'b0; time_rst<=1'b0; end //重置状态下:5分钟倒计时停止、25分钟倒计时停止、时间重置 RESET:begin sec_out_en<=1'b0; time_rst<=1'b1; min5_en<=1'b0; end default:begin sec_out_en<=1'b0; time_rst<=1'b1; min5_en<=1'b0; end endcase end endmodule

注意事项:

  • 组合逻辑中不要使用非阻塞赋值(状态转换的部分属于组合逻辑),时序逻辑中最好使用非阻塞赋值(描述各个状态下的内容的部分)
  • 阻塞赋值和非阻塞赋值的区别
四、资料下载

使用第三部分的内容可以完成基本的番茄钟功能。

这里提供一个加了一点花里胡哨的东西的番茄钟:

pan.baidu.com/s/1W9OtsmrOPexmkA-3EEXnqA 提取码:2019

添加了这些东西:

  • 倒计时的时候有个八位的跑马灯
  • 五分钟等待计时的时候有五个led灯,每过一分钟熄灭一个
  • 摸鱼状态:按下停止后会进入一个正计时状态,并将时间通过数码管显示,这样就能知道已经多久没有工作了。

它的状态转换图如下: