目的及要求
1.洗衣机的工作步骤为洗衣、漂洗和脱水三个过程,工作时间分别为:洗 衣45秒,漂洗30 秒,脱水15 秒;
2.用一个按键实现洗衣程序的手动选择:A、单洗涤;B、单漂洗;C、单脱水;D、漂洗和脱水;E、洗涤、漂洗和脱水全过程;
3. 用3个LED灯分别表示当前工作状态,并且以1HZ频率闪烁(洗衣、漂洗和脱水),数码管倒计时显示每个步骤剩余的工作时间,这里采用数码管动态显示。全部过程结束后,应提示使用者;
4. 用一个按键实现暂停洗衣和继续洗衣的控制,暂停后继续洗衣应回到暂停之前保留的状态;
5.洗涤和漂洗过程中电机正运转方式为:正转5s ->暂停2s ->反转5s,若洗涤时间没到则重复以上过程,脱水则一直正转。
设计规范:功能、性能要求、端口信号说明;
类型 |
名称 |
位宽 |
描述 |
input |
Clk |
1 |
时钟信号125MHZ |
input |
Rst |
1 |
复位 |
input |
Mode |
1 |
模式选择 |
input |
Sta_Pause |
1 |
启动/暂停 |
output |
Beep |
1 |
洗衣完成 |
output |
Led_wash |
1 |
洗涤状态灯 |
output |
Led_rinse |
1 |
漂洗状态灯 |
output |
Led_dry |
1 |
脱水状态灯 |
output |
Seg_sel |
4 |
位选信号 |
output |
Seg_led |
7 |
七段管段选信号 |
output |
Roll_pos |
1 |
电机正转 |
output |
Roll_neg |
1 |
电机反转 |
设计程序代码:
`define CLK_NUM 125_000_000 //输入的时钟频率
//
// Company:
// Engineer:
//
// Create Date: 2023/11/24 09:50:24
// Design Name:
// Module Name: washing_machine
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module washing_machine(
input Clk,
input Rst,Mode,Sta_Pause,
output wire Led_wash,
output wire Led_rinse,
output wire Led_dry,
output reg Beep,
output wire Roll_neg,
output wire Roll_pos,
output [3:0] seg_sel,
output [6:0] seg_led
);
parameter Mode0=5'b00000,ModeA=5'b00001,ModeB=5'b00010,ModeC=5'b00100,ModeD=5'b01000,ModeE=5'b10000;
parameter forward=2'b01,stop=2'b00,backward=2'b10;
parameter wash=3'b001,rinse=3'b010,dry=3'b100;
reg [4:0] next_state,present_state;
reg [2:0] work_state;
reg [1:0] motor_state,motor_prestate;
reg [26:0] hz_cnt;
reg [2:0] cnt_motor;
reg Clk_hz;
reg Mode_last;
reg do_not;
reg [5:0] minute;
reg [5:0] sec;
reg [3:0] status;//模式显示
reg [2:0] cnt_beep;
wire time_flag;
wire Mode_d; //_d为去抖
wire Sta_Pause_d;
wire [3:0] minute_ge;
wire [3:0] minute_shi;
wire [3:0] sec_ge;
wire [3:0] sec_shi;
wire [15:0] data;
//状态转移逻辑,1/选择工作模式
always @(posedge Clk or negedge Rst) begin
if(!Rst)
next_state<=ModeA;
else if(time_flag)
next_state<=ModeA;
else begin
Mode_last <= Mode_d;
case(next_state)
ModeA: begin
if(Mode_last==0 && Mode_d==1) begin
next_state<=ModeB;
end
else next_state<=ModeA;
end
ModeB: begin
if(Mode_last==0 && Mode_d==1) begin
next_state<=ModeC;
end
else next_state<=ModeB;
end
ModeC: begin
if(Mode_last==0 && Mode_d==1) begin
next_state<=ModeD;
end
else next_state<=ModeC;
end
ModeD: begin
if(Mode_last==0 && Mode_d==1) begin
next_state<=ModeE;
end
else next_state<=ModeD;
end
ModeE: begin
if(Mode_last==0 && Mode_d==1) begin
next_state<=ModeA;
end
else next_state<=ModeE;
end
endcase
end
end
//状态跳转,Mode0用于表示实际工作状态为空闲,2/按下开始
always@(posedge Clk or negedge Rst) begin
if(!Rst)
begin
present_state<=Mode0;
end
else if(present_state==Mode0 && Sta_Pause_d==1) begin
present_state<= next_state;
end
else if(minute==6'd0 && sec==6'd0)
begin
present_state <= Mode0;
end
end
//分、秒控制模块
always@(posedge Clk_hz or negedge Rst) begin
if(!Rst)
begin
sec<=6'd0;
minute<=6'd0;
end
else if(present_state==Mode0) begin
case(next_state)
ModeA: begin minute <= 6'd0; sec <= 6'd45; status <= 4'hA; end
ModeB: begin minute <= 6'd0; sec <= 6'd30; status <= 4'hB; end
ModeC: begin minute <= 6'd0; sec <= 6'd15; status <= 4'hC; end
ModeD: begin minute <= 6'd0; sec <= 6'd45; status <= 4'hD; end
ModeE: begin minute <= 6'd1; sec <= 6'd30; status <= 4'hE; end
endcase
end
else if(!do_not) begin //暂停工作
sec<=sec;
minute<=minute;
status <= status;
end
else if(minute>=6'd1 && sec==6'd0) begin
sec<=6'd59;
minute<=minute-1;
status <= status;
end
else if(minute==6'd0 && sec==6'd0) //工作结束
begin
sec<=6'd0;
minute<=6'd0;
status <= 4'h0;
end
else begin
sec<=sec-1;
minute<=minute;
status <= status;
end
end
assign time_flag = (minute==6'd0 && sec==6'd1) ? 1'b1:1'b0;//最后一秒准备报警
//3/选择工作状态
always @(posedge Clk or negedge Rst) begin
if(!Rst || present_state==Mode0)
work_state<=3'b000;
else if(present_state==ModeA) begin
work_state <= wash;
end
else if(present_state==ModeB) begin
work_state <= rinse;
end
else if(present_state==ModeC) begin
work_state <= dry;
end
else if(present_state==ModeD) begin
if(sec<=30) work_state <= dry;
else work_state <= rinse;
end
else if(present_state==ModeE) begin
if(minute==0 && sec<=15) work_state <= dry;
else if(minute==0 && sec<=45) work_state <= rinse;
else work_state <= wash;
end
end
//电机状态,4/具体到电机转动方向
always @(posedge Clk_hz or negedge Rst) begin
if(!Rst || present_state==Mode0) begin
motor_state<=stop;
motor_prestate <= backward;
cnt_motor <= 0;
end
else if(!do_not) begin //暂停键按下
motor_state <= stop;
motor_prestate <= forward;
cnt_motor <= 0;
end
else if(work_state==dry) begin
motor_state <= forward;
end
else if((sec>45 && sec<=47)||(minute==1 && sec>15 && sec<=17)) begin //状态转换前电机停止
motor_state<=stop;
motor_prestate <= backward;
cnt_motor <= 0;
end
else begin
case(motor_state)
forward: begin //正转5s停
if(cnt_motor==3'd4) begin
motor_state <= stop;
motor_prestate <= forward; //标记停前转动方向
cnt_motor <= 0;
end
else cnt_motor <= cnt_motor+1'd1;
end
stop: begin
if(cnt_motor==3'd1 && motor_prestate == forward) begin
motor_state <= backward;
cnt_motor <= 0;
end
else if(cnt_motor==3'd1 && motor_prestate == backward) begin
motor_state <= forward;
cnt_motor <= 0;
end
else cnt_motor <= cnt_motor+1'd1;
end
backward: begin
if(cnt_motor==3'd4) begin
motor_state <= stop;
cnt_motor <= 0;
motor_prestate <= backward;
end
else cnt_motor <= cnt_motor+1'd1;
end
endcase
end
end
//暂停启动控制,6/暂停
always @(posedge Sta_Pause_d or negedge Rst) begin
if(!Rst)
do_not<=1'b0;
else
do_not<= ~do_not;
end
//分频,得到1hz的时钟
always @(posedge Clk or negedge Rst) begin
if(!Rst) begin
hz_cnt<=27'd0;
Clk_hz<=1'd0;
end
else if(hz_cnt==`CLK_NUM/2-1)
begin
hz_cnt<=27'd0;
Clk_hz<=~Clk_hz;
end
else
hz_cnt<=hz_cnt+1;
end
//蜂鸣器模块 cnt_beep在计数1-6内响
always @(posedge Clk_hz or negedge Rst) begin
if(!Rst) begin
Beep<=0;
cnt_beep<=0;
end
else if(time_flag) cnt_beep <= cnt_beep+1;
else if(cnt_beep >= 3'd1 && cnt_beep <= 3'd6) begin
cnt_beep <= cnt_beep+1;
Beep<=1;
end
else if(cnt_beep == 3'd7) begin
cnt_beep <= 0;
Beep<=0;
end
else
Beep<=0;
end
//led指示模块
assign Led_wash=(work_state==wash)? 1'b1 : 1'b0;
assign Led_rinse=(work_state==rinse)? 1'b1 : 1'b0;
assign Led_dry=(work_state==dry)? 1'b1 : 1'b0;
//电机转动
assign Roll_pos=(motor_state==forward)? 1'b1 : 1'b0;
assign Roll_neg=(motor_state==backward)? 1'b1 : 1'b0;
//数据输出
assign minute_ge=minute%10;
assign minute_shi=minute/10;
assign sec_ge=sec%10;
assign sec_shi=sec/10;
assign data={status,minute_ge,sec_shi,sec_ge};
//数码管的例化
seg_led seg_led_inst(
.Clk (Clk),
.Rst (Rst),
.data (data),
.sel (seg_sel),
.seg_led (seg_led)
);
//按键去抖例化
debounce debounce_Sta(
.Clk (Clk),
.Rst (Rst),
.btn (Sta_Pause),
.btn_deb (Sta_Pause_d)
);
debounce debounce_Mode(
.Clk (Clk),
.Rst (Rst),
.btn (Mode),
.btn_deb (Mode_d)
);
endmodule
//数码管显示模块
module seg_led(
input Clk,Rst,
input [15:0] data,
output reg [3:0] sel,
output reg [6:0] seg_led
);
reg [15:0] ms_cnt;
reg ms_clk;
reg [3:0] num_display;
reg [15:0] num;
reg [1:0] sel_num; //选择哪一位数码管被点亮
//给4位数码管赋值
always @(posedge Clk or negedge Rst) begin
if(!Rst)
num<=16'd0;
else
begin
num[15:12] <= data[15:12];
num[11:8] <= data[11:8];
num[ 7:4] <= data[7:4];
num[ 3:0] <= data[3:0];
end
end
always @(posedge Clk or negedge Rst) begin //产生1ms脉冲
if(!Rst)
begin
ms_cnt<=16'd0;
ms_clk<=1'b0;
end
else if(ms_cnt==`CLK_NUM/2000-1)
begin
ms_cnt<=16'd0;
ms_clk<=~ms_clk;
end
else
ms_cnt<=ms_cnt+1;
end
//每毫秒选择管
always @(posedge ms_clk or negedge Rst) begin
if(!Rst)
sel_num<=0;
else
sel_num<=sel_num+1;
end
//选择管译码
always @(posedge Clk or negedge Rst) begin
if(!Rst)
sel<=4'b1111;
else
begin
case(sel_num)
3'd0: begin
sel<= 4'b1110; //显示数码管最低位
num_display<=num[3:0];
end
3'd1: begin
sel<= 4'b1101; //显示数码管第1位
num_display<=num[7:4];
end
3'd2: begin
sel<= 4'b1011; //显示数码管第2位
num_display<=num[11:8];
end
3'd3: begin
sel<= 4'b0111; //显示数码管第3位
num_display<=num[15:12];
end
default sel<= 4'b1111;
endcase
end
end
//数字译码
always @(posedge Clk or negedge Rst) begin
if(!Rst)
seg_led<=7'b100_0000;
else
begin
case(num_display)
4'h0 : seg_led <= 7'b100_0000;
4'h1 : seg_led <= 7'b111_1001;
4'h2 : seg_led <= 7'b010_0100;
4'h3 : seg_led <= 7'b011_0000;
4'h4 : seg_led <= 7'b001_1001;
4'h5 : seg_led <= 7'b001_0010;
4'h6 : seg_led <= 7'b000_0010;
4'h7 : seg_led <= 7'b111_1000;
4'h8 : seg_led <= 7'b000_0000;
4'h9 : seg_led <= 7'b001_0000;
4'hA: seg_led <= 7'b000_1000; //A
4'hB : seg_led <= 7'b000_0011;
4'hC : seg_led <= 7'b100_0110;
4'hD : seg_led <= 7'b010_0001;
4'hE : seg_led <= 7'b000_0110;
4'hF : seg_led <= 7'b000_1110;
default : seg_led <= 7'b100_0000;
endcase
end
end
endmodule
//按键去抖模块
module debounce(input wire btn,Clk,Rst, //按键输入信号
output reg btn_deb //去抖后的按键信号
);
parameter debounce_time = `CLK_NUM/500 ; //去抖时间
reg [22:0] counter ; //计数器
//状态机
parameter STATE_IDLE = 2'b00;
parameter STATE_PRE_DEBOUNCE = 2'b01;
parameter STATE_DEBOUNCE = 2'b10;
reg [1:0] state = STATE_IDLE;
always @(posedge Clk or negedge Rst) begin
if(!Rst) begin
counter <=0;
state <= STATE_IDLE;
btn_deb <= 1'b0;
end
else begin
case (state)
STATE_IDLE: begin
if (btn == 1'b1) begin
state <= STATE_PRE_DEBOUNCE;
counter <= 23'd0;
end else begin
state <= STATE_IDLE;
btn_deb <= 1'b0;
end
end
STATE_PRE_DEBOUNCE: begin
if (btn == 1'b1 && counter < debounce_time) begin
counter <= counter + 1;
state <= STATE_PRE_DEBOUNCE;
end else if (btn == 1'b1 && counter >= debounce_time) begin
counter <= 23'd0;
state <= STATE_DEBOUNCE;
btn_deb <= 1'b1;
end else begin
state <= STATE_IDLE;
btn_deb <= 1'b0;
end
end
STATE_DEBOUNCE: begin
if (btn == 1'b1) begin
state <= STATE_DEBOUNCE;
btn_deb <= 1'b1;
end else begin
state <= STATE_IDLE;
btn_deb <= 1'b0;
end
end
default: begin
state <= STATE_IDLE;
btn_deb <= 1'b0;
end
endcase
end
end
endmodule
testbench代码:
`timescale 1ms/10us
`define CLK_CYCLE 0.02
module tb_washing;
reg Clk ;
reg Rst ;
reg Mode ;
reg Sta_Pause;
wire Led_wash ;
wire Led_rinse;
wire Led_dry ;
wire Beep;
wire Roll_neg ;
wire Roll_pos;
wire [3:0] seg_sel ;
wire [6:0] seg_led ;
washing_machine u1(
. Clk (Clk),
. Rst (Rst),
. Mode (Mode),
. Sta_Pause (Sta_Pause),
. Led_wash (Led_wash),
. Led_rinse (Led_rinse),
. Led_dry (Led_dry),
. Beep (Beep),
. Roll_neg (Roll_neg),
. Roll_pos (Roll_pos),
. seg_sel (seg_sel),
. seg_led (seg_led)
);
initial begin
Clk = 1'b0;
Rst = 1'b0;
Mode = 1'b0;
Sta_Pause = 1'b0;
#300
Rst = 1'b1;
#100
repeat (2) @(posedge Clk);
Mode = 1'b1;
#400
Mode = 1'b0;
#400
Mode = 1'b1;
#0.1
Mode = 1'b0;
#0.1
Mode = 1'b1;
#400
Mode = 1'b0;
#400
Mode = 1'b1;
#400
Mode = 1'b0;
#400
Mode = 1'b1;
#400
Mode = 1'b0;
#400
Sta_Pause = 1'b1;
#0.1
Sta_Pause = 1'b0;
#0.1
Sta_Pause = 1'b1;
#400
Sta_Pause = 1'b0;
@(posedge Led_rinse);
Sta_Pause = 1'b1;
#400
Sta_Pause = 1'b0;
#4000
Sta_Pause = 1'b1;
#400
Sta_Pause = 1'b0;
#100000
$finish;
end
always #(`CLK_CYCLE / 2) Clk = ~Clk;
endmodule
仿真结果:
开始转动前:
开始转动后:
板级验证:文章来源:https://www.toymoban.com/news/detail-832091.html
文章来源地址https://www.toymoban.com/news/detail-832091.html
到了这里,关于FPGA自动洗衣机的设计与验证(Verilog编写)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!