FPGA自动洗衣机的设计与验证(Verilog编写)

目的及要求

        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

电机反转

设计程序代码(125M是真实上板的频率,这里为了提高速度,进行仿真时,需要把第一行的125000000改成50000)

`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


仿真结果:

开始转动前:

开始转动后:

板级验证:

基于cyclone3 FPGA设计的智能洗衣机控制器课设报告文档+quartus9.1工程源码文件,可以做为你的学习设计参考。 1.课程设计名称及开发环境 题 目:智能洗衣机控制器的设计开发环境:本课设是基于DE0的板子,使用Verilog HDL开发的。 2.参考设计内容与要求 ① 设计一个智能洗衣机控制器,能够实现洗衣,漂洗和脱水的功能。 ②要求能够使用按键模拟对洗衣机的控制,能够设置工作模式,为了便于观察,将洗衣机设定的工作模式(1~5)和整个过程所剩的工作时间用数码管显示出来(时间分辨率为1分钟),能够将洗衣机当前所处的状态(注水,洗衣,排水,甩干)用发光管或者数码管显示出来。 【模式1】: 洗衣模式--强力洗( 洗衣30分钟) 【模式2】 :洗衣模式--普通洗 (洗衣20分钟) 【模式3】 :洗衣模式--轻柔洗(洗衣10分钟) 【模式4】 :漂洗模式 【模式5】 :甩干模式 注:在以上5个模式中,每次注水1分钟,漂洗5分钟,排水1分钟,甩干1分钟,模式1~3的洗衣时间如上所示,具体的洗衣步骤如下: 【模式1~3】:注水->洗衣->排水->甩干->注水->漂洗->排水->甩干 ->注水->漂洗->排水->甩干。 【模式4】:注水->漂洗->排水->甩干->注水->漂洗->排水->甩干。 【模式5】:甩干。 【要求】:实现逻辑控制过程,可以选择性的加入注水口无水报警等人性化的状态提示,操作完毕使用蜂鸣器鸣叫两秒提示。 ③ 画出洗衣机控制器的状态机,写出状态编码方案。 ④ 用Verilog语言对设计进行描述,设计一个测试方案,并能够下载到实验板上调试成功。 // 顶层模块 module init(cp_50,cp_502,BUTTON,key_0,key_1,key_2,key_3,key_4,key_5,key_6,LEDG,led0,led1,led2,led3,VGA_HS,VGA_VS,VGA_R,VGA_G,VGA_B); input cp_50,cp_502; input [2:0] BUTTON; input key_0,key_1,key_2,key_3,key_4,key_5,key_6; output [9:0] LEDG; output [7:0] led0, led1,led2,led3; output VGA_HS; // VGA H_SYNC output VGA_VS; // VGA V_SYNC output [3:0] VGA_R; // VGA Red[3:0] output [3:0] VGA_G; // VGA Green[3:0] output [3:0] VGA_B; // VGA Blue[3:0] reg [7:0]TIME; reg [9:0]LEDG; wire [3:0]flag; wire out0; always @(posedge cp_50) begin case (flag) 4'b0001: LEDG[9:0]<=10'b0000000001; 4'b0010: LEDG[9:0]<=10'b0000000011; 4'b0011: LEDG[9:0]<=10'b0000000111; 4'b0100: LEDG[9:0]<=10'b0000001111; 4'b0101: LEDG[9:0]<=10'b0000011111; 4'b0110: LEDG[9:0]<=10'b0000111111; 4'b0111: LEDG[9:0]<=10'b0001111111; 4'b1000: LEDG[9:0]<=10'b0011111111; 4'b1001: LEDG[9:0]<=10'b0111111111; 4'b1010: LEDG[9:0]<=10'b1111111111; 4'b1011: LEDG[9:0]<=10'b0111111111; 4'b1100: LEDG[9:0]<=10'b0011111111; 4'b1101: LEDG[9:0]<=10'b0001111111; 4'b1110: LEDG[9:0]<=10'b0000111111; 4'b1111: LEDG[9:0]<=10'b0000011111; default: LEDG[9:0]<=10'b0000001111;
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值