赞
踩
目的及要求
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
仿真结果:
开始转动前:
开始转动后:
板级验证:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。