本次所实现的功能如下:
1.洗衣机有三个状态:正转 反转 暂停(分别用三个LED指示)
2.工作流程为:正转20S-->暂停10S-->反转20S-->暂停10S
3.洗衣机当前所处的状态会在数码管第三位显示出来(1表示正转 2表示反转 3表示暂停)
4.洗衣机的工作时间可以设置,单位为分钟。(默认工作时间为1分钟)
5.预设值的工作时间也在数码管显示出来 (数码管的第一位 第二位)
6.预设值的工作时间到了以后 蜂鸣器报警 用于提示已经完成洗衣
设计思路与讲解:
还是采用分层设计的方式,首先写了一个洗衣机逻辑控制的文件,数码管显示部分是直接例化的一个已经写好的数码管显示模块。详细分析如下:
首先进行模块的输入输出端口定义:时钟和复位是必须要的,然后就是三个led灯端口,一个蜂鸣器端口,以及四位八段数码管的端口
接下来定义时钟分频系数,因为洗衣机的倒计时是以秒为单位的,而系统时钟是50M,从50M分频到1HZ,所用的分频系数就是50_000_000
再定义几个分频时用到的变量,对系统时钟进行分频,得到1HZ的信号:
分频模块如下:
当hz_cnt计数到HZ_NUM的一半时,对clk_hz取反,就能得到占空比为50的频率为1HZ的方波。
然后就是时间的控制逻辑了:
复位的时候,秒计数器sec为0,time_flag为0(这个变量用于标记洗衣机是否已经完成了洗衣操作,当到达所设置的洗衣时间时,该变量为1).正常情况下,sec每过一秒就自增1(因为这个模块的驱动时钟是clk_hz),如果sec加到了59,但是分钟数还是大于1,说明洗衣未完成,则sec清0,进行下一轮计数,否则,sec保持不动,将time_flag标记为1,用于指示洗衣机已经完成洗衣。
对于分钟控制模块,刚复位的时候,分钟数默认为1(默认洗衣机的洗衣时间为1分钟),如果sec加到59了,分钟数就自减1;如果洗衣机的洗衣时间只剩下一分钟了,而且此时sec又加到了58(如果是59的话会出现bug),那么minute就清0,代表洗衣时间已经结束了。
接下来是蜂鸣器的控制:
只要time_flag为1,也就是洗衣完成了,蜂鸣器就报警。
Led的控制也比较简单:
主要就是根据sec所处的不同时段,对不同的led状态进行赋值,并对状态变量status赋值
最后显示部分,是将要显示的各个数字提取出来,传递到数码管模块进行显示。
关于数码显示的具体内容,可以参考:
https://blog.csdn.net/guangali/article/details/130754726?spm=1001.2014.3001.5501
洗衣机模块的完整代码如下:
module xiyiji(
input clk,
input reset,
output reg led1, //正转指示灯 高电平亮
output reg led2, //反转指示灯
output reg led3, //暂停指示灯
output reg beep, //蜂鸣器,时间到时报警 低电平响
output [3:0] seg_sel, // 数码管位选,最左侧数码管为最高位
output [6:0] seg_led // 数码管段选
);
parameter HZ_MUN=26'd50_000_000; //分频到1S的分频数
reg [25:0] hz_cnt; //分频计数器
reg clk_hz; //分频得到的1HZ信号
reg [5:0] sec; //秒信号
reg [3:0] status; //洗衣机当前状态显示 1.正转 2.反转 3.暂停
reg time_flag; //定时时间到 该标志置为1
wire [15:0] data; //要在数码管显示的数据
reg [5:0] minute; //预置的分钟数
wire [3:0] minute_ge; //分钟个位
wire [3:0] minute_shi; //分钟十位
//分频模块
always @(posedge clk or negedge reset) begin
if(!reset)
hz_cnt<=26'd0;
else if(hz_cnt==HZ_MUN/2-1)
begin
hz_cnt<=26'd0;
clk_hz<=~clk_hz;
end
else
hz_cnt<=hz_cnt+1;
end
//秒控制模块
always @(posedge clk_hz or negedge reset) begin
if(!reset)
begin
sec<=6'd0;
time_flag<=1'b0;
end
else if(sec==6'd59 && minute>1) //一个周期走完后 秒清0
sec<=6'd0;
else if(minute<=6'd1 && sec==6'd58)
begin
sec<=6'd58;
time_flag<=1'b1;
end
else
sec<=sec+1;
end
//分钟控制模块
always @(posedge clk_hz or negedge reset ) begin
if(!reset)
minute<=6'd1;
else if(sec==6'd59)
minute<=minute-1;
else if(minute==6'd1 && sec==6'd58)
minute<=6'd0;
else
minute<=minute;
end
//蜂鸣器模块
always @(posedge clk or negedge reset) begin
if(!reset)
beep<=1;
else if(time_flag==1) //蜂鸣器为低电平时 响
beep<=0;
else
beep<=1;
end
//led指示模块
always @(*) begin
if(sec<20) //正转
begin
led1=1;
led2=0;
led3=0;
status=4'd1;
end
else if(sec<30) //暂停
begin
led1=0;
led2=0;
led3=1;
status=4'd3;
end
else if(sec<50) //反转
begin
led1=0;
led2=1;
led3=0;
status=4'd2;
end
else //暂停
begin
led1=0;
led2=0;
led3=1;
status=4'd3;
end
end
assign minute_ge=minute%10;
assign minute_shi=minute/10;
assign data={4'd0,status,minute_shi,minute_ge};
seg_led seg_led_inst(
.clk (clk),
.rst_n (reset),
.data (data),
.seg_sel (seg_sel),
.seg_led (seg_led)
);
endmodule