设计题目 | 洗衣机控制器设计 |
任务要求 |
|
实验设备及软件 | 实验设备:21EDA EPM240-CPLD 软件:Quartus II 13.0 (64-bit) ModelSim-Altera |
VHDL软件设计报告
一、设计任务及要求
1) 设计一个电子定时器,控制洗衣机作如下运转:设计一个电子定时器,控制洗衣机作如下运转:定时启动--正转20秒--暂停10秒--反转20秒--暂停10秒--定时未到回到“正转20秒--暂停10秒循环”,定时到则停止;
2) 若定时到,则停机发出音响信号;
3) 用两个数码管显示洗涤的预置时间(分钟数),按倒计时方式对洗涤过程作计时显示,直到时间到停机;洗涤过程由“开始”信号开始;
4) 三只LED灯表示“正转”、“反转”、“暂停”三个状态。
二、设计原理简介
2.1 洗衣机控制器原理
全自动洗衣机具有时间预置及状态显示等功能。其工作流程为:定时启动 正转20秒 暂停10秒 反转20秒 暂停10秒 定时未到,重复上述过程,若定时已到,停止发出音响。状态控制模块的设计主要是定时器的设计,利用减法计数器,时序控制电路和工作状态控制电路等组成,可以实现正转、反转和暂停等洗衣机的工作过程,并且用两个数码管可以显示预置洗涤时间,按倒计时方式对洗涤过程进行计数显示,直到时间到停机。其工作过程图如下图:
图1.1 自动洗衣机工作流程
2.2 状态控制模块原理(washing_state.vhd)
洗衣机控制器要求有启动按键、三种状态(正转、暂停、反转)以及结束信号功能。每个功能都由时钟信号驱动,当时钟信号为1Hz时,利用CLK周期为1秒,可以实现60秒的秒计时循环。在此基础上,又可以实现预置时间分钟数的递减。记录启动按键的单脉冲信号的上边沿,并将其设为IF条件,控制计时器归0以及状态变化起始位置。三种状态由60秒倒计时改变状态灯,依次为(20s, 10s, 20s, 10s)的(正转、暂停、反转、暂停)。最后,按照预置时间归0,发出结束信号即可实现所有功能。
图1.2 流程图
2.3 倒计时显示模块原理(BCD.vhd)
利用循环将预置时间的十位依次减“0000 1010”,同时十位TENS依次加“0000 0001”,之后将余下的时间直接赋值给个位ONES,即是将预置时间改写到两位上,方便后续接入两个数码管显示时间。
2.4顶层设计模块(washing_machine.vhd)
将控制模块和显示模块的端口接入顶层设计模块,使其协同工作。分别输出“状态”(正转“100”、暂停“010”、反转“001”);倒计时十位“TENS”和倒计时个位“ONES”;以及结束信号。
三、设计方案与实现
3.1 设计软件环境搭建
本设计使用软件QUARTUS II 13.0开发,使用VHDL语言编写,采用ModelSi Altera进行仿真。新建工程文件命名为washing_machine,并新建BCD.vhd、washing_machine.vhd、washing_state.vhd等文件。
之后按照Processing--Start--Start Test Bench Template Writer运行,编写好.tbh仿真模板的文件,进入Assignments--setting导入仿真模板。
注:设置仿真工具路径:Tools--options--EDA Tool Options
3.2 代码实现方案
要求设计洗衣机控制器,可分为以下两个部分:代码基础部分,以及基于基础部分实现设计要求的功能实现部分。
代码基础部分包括状态机(控制洗衣机的工作状态与结束状态)与秒钟计时器(每一分钟产生一个计时脉冲);
功能实现部分,大致分为基于状态机实现结束状态时结束信号灯发光;以及基于一分钟定时脉冲实现倒计时功能(每分钟减一);最后,还有基于60秒计时器实现(20s正转、10s暂停、20s反转、10s暂停)的状态循环功能。
时钟显示功能。具体解释如下:
一分钟脉冲:每次秒钟计时器计时到59s时,一分钟脉冲信号变为高电平,在一个时钟周期之后恢复低电平。
时钟显示功能:首先规定一个输入信号,用于存储预定洗衣机工作时间,例如15分钟,每当一分钟脉冲产生,便将倒计时减一,并将其显示在输出上,即将倒计时分钟数分别以十位和个位显示为输出。
LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.std_logic_unsigned.all;
--二进制转BCD码,将输入binary以分钟数十位和个位显示
ENTITY BCD IS
PORT (
clk : IN STD_LOGIC;
binary : IN STD_LOGIC_VECTOR(7 DOWNTO 0);--二进制输入
Tens : OUT STD_LOGIC_VECTOR(3 DOWNTO 0);--十位
Ones : OUT STD_LOGIC_VECTOR(3 DOWNTO 0)--个位
);
END BCD;--定义端口
ARCHITECTURE RTL OF BCD IS
SIGNAL state : STD_LOGIC_VECTOR(1 DOWNTO 0) := "00";
SIGNAL data_buf : STD_LOGIC_VECTOR(7 DOWNTO 0) := "00000000";
SIGNAL Tens_buf : STD_LOGIC_VECTOR(7 DOWNTO 0) := "00000000";
SIGNAL Ones_buf : STD_LOGIC_VECTOR(3 DOWNTO 0) := "0000";
BEGIN
PROCESS (clk)
--该过程由clk时钟触发。当clk上升沿(从'0'到'1')发生时,IF (clk'EVENT AND clk = '1') THEN条件为真,并执行内部的CASE语句。
BEGIN
IF (clk'EVENT AND clk = '1') THEN
CASE state IS
WHEN "00" =>
data_buf <= binary;
Tens_buf <= "00000000";
Ones_buf <= "0000";
state <= "01";
WHEN "01" =>
IF (data_buf >= "00001010") THEN--是否大于10
data_buf <= data_buf - "00001010";--减10
Tens_buf <= Tens_buf + "00000001";--十位加1
Ones_buf <= Ones_buf;
state <= "01";
--当你输入预置时间binary,将会赋值data_buf,此时利用循环将十位赋值给Tens_buf
ELSE
data_buf <= data_buf;
Tens_buf <= Tens_buf;--十位
Ones_buf <= data_buf(3 DOWNTO 0);--个位
state <= "10";
--跳出上一个循环后,赋值Oens_buf
END IF;
WHEN "10" =>
data_buf <= binary;
Tens <= Tens_buf(3 DOWNTO 0);
Ones <= Ones_buf;
state <= "00";
WHEN OTHERS =>
END CASE;
END IF;
END PROCESS;
END RTL;
结束信号功能。具体解释如下:
状态机:为了实现洗衣机工作状态和结束状态的切换,增加一个中间状态—等待状态。即是等待状态、倒计时状态与结束状态。检测到启动信号则状态机从等待状态进入倒计时状态,否则停在等待状态;倒计时状态由洗衣机倒计时控制,倒计时归零,则进入结束状态;进入结束状态后,在下一个时钟周期自动进入等待状态。
结束功能:在状态机进入结束状态时,结束信号变为高电平。
LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.std_logic_unsigned.all;
--实现功能,led灯显示工作状态,结束亮灯报警,以及显示剩余时间(顶层设计)
ENTITY washing_machine IS
PORT (
clk_in : IN STD_LOGIC;--1Hz
start_key : IN STD_LOGIC;--启动按键
led : OUT STD_LOGIC_VECTOR(2 DOWNTO 0);--正转,反转,暂停
end_led : OUT STD_LOGIC;--洗衣结束信号
minute_Tens : OUT STD_LOGIC_VECTOR(3 DOWNTO 0);--分钟十位BCD码
minute_Ones : OUT STD_LOGIC_VECTOR(3 DOWNTO 0)--分钟个位BCD码
);
END washing_machine;
ARCHITECTURE behaveral OF washing_machine IS
--两个component将另外两个vhd代码置于本模块内
component washing_state IS
PORT (
clk_in : IN STD_LOGIC;--1Hz
start_key : IN STD_LOGIC;--启动按键
led : OUT STD_LOGIC_VECTOR(2 DOWNTO 0);--正转,反转,暂停
end_led : OUT STD_LOGIC;--洗衣结束信号
time_out : OUT STD_LOGIC_VECTOR(7 DOWNTO 0)--分钟时间
);
END component;
component BCD IS
PORT (
clk : IN STD_LOGIC;
binary : IN STD_LOGIC_VECTOR(7 DOWNTO 0);--二进制输入,预定时间
Tens : OUT STD_LOGIC_VECTOR(3 DOWNTO 0);--十位
Ones : OUT STD_LOGIC_VECTOR(3 DOWNTO 0)--个位
);
END component;
--这里由于本模块没有time_out,只有tens和ones,故再此引入
signal time_out:STD_LOGIC_VECTOR(7 DOWNTO 0);--分钟时间
BEGIN
--洗衣机状态控制模块
U_washing_state:washing_state
PORT MAP(
clk_in =>clk_in,--1Hz
start_key =>start_key,--启动按键
led =>led,--正转,反转,暂停
end_led =>end_led,--洗衣结束信号
time_out =>time_out--分钟时间
);
--实例化了washing_state组件,并将其命名为U_washing_state。通过PORT MAP子句将washing_state组件的端口连接到当前实体的相应信号上。
--二进制转BCD码
U_BCD: BCD
PORT MAP(
clk =>clk_in,
binary =>time_out,--二进制输入
Tens =>minute_Tens,--十位
Ones =>minute_Ones--个位
);
END behaveral;
60s计时器基础和(正转、暂停、反转、暂停)的状态循环控制,具体介绍如下:
60s计时器:采用1Hz的时钟周期,即每一个时钟周期时长为1s,介于此,每逢一个时钟周期的上升沿信号,就在60s计时器上加1,从0开始,到59为一循环,即在59之后一个时钟周期将60s计时器复位。同时,为一分钟脉冲作基础。
(正转、暂停、反转、暂停)的状态循环控制:题设要求为20s正转、10s暂停、20s反转、10s暂停,恰好为60s,基于60s计时器实现状态循环控制,每当遇到时钟信号上升沿,检测60s计时器的值,若介于0到19之间,令状态为正转;若介于20到29之间,令状态为暂停;若介于30到49,令状态为反转;若介于50到59之间,令状态为暂停。
LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.std_logic_unsigned.all;
--洗衣机状态控制模块
ENTITY washing_state IS
PORT (
clk_in : IN STD_LOGIC;--1Hz
start_key : IN STD_LOGIC;--启动按键
led : OUT STD_LOGIC_VECTOR(2 DOWNTO 0);--正转,反转,暂停
end_led : OUT STD_LOGIC;--洗衣结束信号
time_out : OUT STD_LOGIC_VECTOR(7 DOWNTO 0)--分钟时间
);
END washing_state;
ARCHITECTURE behaveral OF washing_state IS
--此处定义了大量输入输出以外的信号,用于后续功能实现
SIGNAL state : STD_LOGIC_VECTOR(1 DOWNTO 0) := "01";
--启动按键与相关信号
SIGNAL start_key_rise : STD_LOGIC;
SIGNAL start_key_1 : STD_LOGIC := '0';
SIGNAL start_key_2 : STD_LOGIC := '0';
--预置洗衣时间15分钟
SIGNAL washing_time : STD_LOGIC_VECTOR(7 DOWNTO 0) := "00001111";
--结束时亮的led
SIGNAL end_led_buf : STD_LOGIC := '1';
--秒 计时脉冲 60秒一循环 同时 用于正转,暂停,反转三个状态
SIGNAL second_cnt : STD_LOGIC_VECTOR(7 DOWNTO 0) := "00000000";
--分钟计时脉冲
SIGNAL min_en : STD_LOGIC := '0';
--同步
SIGNAL synchronization : STD_LOGIC := '0';
SIGNAL second_en_1s : STD_LOGIC := '0';
SIGNAL second_en : STD_LOGIC;
SIGNAL second_div_cnt : STD_LOGIC_VECTOR(9 DOWNTO 0) := "0000000000";
-- SIGNAL minute_cnt : STD_LOGIC_VECTOR(7 DOWNTO 0) := "00000000";
----------------------------------------------------------------------
BEGIN
time_out <= washing_time; --连续不断地将右侧的值赋值给左侧的输出信号
PROCESS (clk_in) --时钟敏感
BEGIN
IF (clk_in'EVENT AND clk_in = '1') THEN --时钟上升沿变化
start_key_1 <= start_key;
start_key_2 <= start_key_1;-- 启动按钮寄存器缓存
END IF;
END PROCESS;
start_key_rise <= start_key_1 AND (NOT(start_key_2));--确保 信号start_key_rise 在启动按键上升沿触发,且变为1
--启动按键部分
-----------------------------------------------------------------------
-----------------------------------------------------------------------
PROCESS (clk_in)--状态机
BEGIN
IF (clk_in'EVENT AND clk_in = '1') THEN --上升沿
CASE state IS
WHEN "00" =>--状态00,等待状态,若有启动信号则到状态01
IF (start_key_rise = '1') THEN
state <= "01";
ELSE
state <= "00";
END IF;
WHEN "01" =>--状态01,倒计时状态,直到计时到0,到状态10,即结束
IF (washing_time > "00000000") THEN
state <= "01";
ELSE
state <= "10";
END IF;
WHEN "10" =>--结束状态,返回00
state <= "00";
WHEN OTHERS =>
state <= "00";
END CASE;
END IF;
END PROCESS;
--状态机(有启动按键进入倒计时状态,没有就等待)
-----------------------------------------------------------------------
-----------------------------------------------------------------------
PROCESS (clk_in) --上升沿
BEGIN
IF (clk_in'EVENT AND clk_in = '1') THEN --上升沿
IF (state = "00") THEN
end_led_buf <= '1'; --状态00,提示洗衣结束
ELSE
end_led_buf <= '0';
END IF;
END IF;
END PROCESS;
end_led <= end_led_buf;
--结束提醒部分
-----------------------------------------------------------------------
PROCESS (start_key)
BEGIN
IF (start_key'EVENT AND start_key = '1' ) THEN
synchronization <= '1';
END IF;
END PROCESS;
-----------------------------------------------------------------------
PROCESS (clk_in)
BEGIN
IF (clk_in'EVENT AND clk_in = '1') THEN --上升沿
IF (start_key_rise = '1') THEN --启动键只有一个时钟周期的脉冲,启动则赋予秒计时器0值
second_cnt <= "00000000";
ELSE
IF (second_cnt >= "00111011") THEN --秒计时到59返回0
second_cnt <= "00000000";
ELSE
second_cnt <= second_cnt + "00000001";
END IF;
END IF;
END IF;
END PROCESS;
--秒计时器--60秒一循环
-----------------------------------------------------------------------
-----------------------------------------------------------------------
PROCESS (clk_in)
BEGIN
IF (clk_in'EVENT AND clk_in = '1') THEN --上升沿
IF (second_cnt = "00111011") THEN --秒计时到59,生成分计时脉冲
min_en <= '1';
ELSE
min_en <= '0';
END IF;
END IF;
END PROCESS;
--60秒倒计时记录
-----------------------------------------------------------------------
-----------------------------------------------------------------------
PROCESS (clk_in)
BEGIN
IF (clk_in'EVENT AND clk_in = '1') THEN --上升沿
IF (start_key_rise = '1') THEN
washing_time <= "00001111"; --预置计时时间15分钟 --可修改
ELSIF (min_en = '1') THEN --分钟脉冲到了,分钟时间减1
IF (washing_time > "00000000") THEN
washing_time <= washing_time - "00000001";
ELSE
washing_time <= "00000000";
END IF;
ELSE
washing_time <= washing_time;
END IF;
END IF;
END PROCESS;
second_en <= second_en_1s;
--分钟倒计时,结合秒钟倒计时运行
-----------------------------------------------------------------------
-----------------------------------------------------------------------
-- PROCESS (clk_in)
-- BEGIN
-- IF (clk_in'EVENT AND clk_in = '1') THEN --上升沿
-- IF (start_key_rise = '1') THEN
-- minute_cnt <= "00000000";--复位
-- ELSIF (min_en = '1') THEN
-- IF (minute_cnt = "00000101") THEN
-- minute_cnt <= "00000000";
-- ELSE
-- minute_cnt <= minute_cnt + "00000001";
-- END IF;
-- ELSE
-- minute_cnt <= minute_cnt;
-- END IF;
-- END IF;
-- END PROCESS;
--5分钟 一循环,用于(正转、暂停、反转)的时间控制 可修改
-----------------------------------------------------------------------
PROCESS (clk_in)
BEGIN
IF (clk_in'EVENT AND clk_in = '1') THEN --上升沿
IF (washing_time > "00000000" AND synchronization = '1') THEN
IF (second_cnt < "00010100") THEN--20秒,正转灯(100)亮
led <= "100";
ELSIF (second_cnt >= "00010100" AND second_cnt < "00011110") THEN--10秒,暂停灯(010)亮
led <= "010";
ELSIF (second_cnt >= "00011110" AND second_cnt < "00110010") THEN--20秒,反转灯(001)亮
led <= "001";
ELSE
led <= "010";--最后10秒,暂停灯(010)亮
END IF;
ELSE
led <= "000";
END IF;
END IF;
END PROCESS;
-----------------------------------------------------------------------
END behaveral;
3.2 RTL图
图2.1 RTL图
四、仿真结果分析
4.1 仿真模板(vht文件)
LIBRARY ieee;
USE ieee.std_logic_1164.all;
ENTITY washing_machine_vhd_tst IS
END washing_machine_vhd_tst;
ARCHITECTURE washing_machine_arch OF washing_machine_vhd_tst IS
-- signals
SIGNAL clk_in : STD_LOGIC;--时钟信号
SIGNAL end_led : STD_LOGIC;--结束信号
SIGNAL led : STD_LOGIC_VECTOR(2 DOWNTO 0);--状态(正转,暂停,反转)信号
SIGNAL minute_Ones : STD_LOGIC_VECTOR(3 DOWNTO 0);--倒计时分钟个位
SIGNAL minute_Tens : STD_LOGIC_VECTOR(3 DOWNTO 0);--倒计时分钟十位
SIGNAL start_key : STD_LOGIC;--启动按键
COMPONENT washing_machine
PORT (
clk_in : IN STD_LOGIC;
end_led : OUT STD_LOGIC;
led : OUT STD_LOGIC_VECTOR(2 DOWNTO 0);
minute_Ones : OUT STD_LOGIC_VECTOR(3 DOWNTO 0);
minute_Tens : OUT STD_LOGIC_VECTOR(3 DOWNTO 0);
start_key : IN STD_LOGIC
);
END COMPONENT;
BEGIN
i1 : washing_machine
PORT MAP (
-- 列出主端口和信号之间的连接
clk_in => clk_in,
end_led => end_led,
led => led,
minute_Ones => minute_Ones,
minute_Tens => minute_Tens,
start_key => start_key
);
----------------------------------------------------------------------
init : PROCESS
-- 使得启动信号产生一个脉冲
BEGIN
start_key<='0';--启动按键初始为低电平
wait for 500 ns;--500ns后
start_key<='1';--开始信号
wait for 500 ns;
start_key<='0';
wait for 500 ns;
WAIT;
END PROCESS init;
----------------------------------------------------------------------
--此处以100ns一个时钟来模拟,是为了快速得到仿真
--正常情况下应该使用1Hz,如此使得秒钟计时器正常运作
--产生时钟
always : PROCESS
BEGIN
clk_in<='1';
wait for 50 ns;
clk_in<='0';
wait for 50 ns;
END PROCESS always;
END washing_machine_arch;
图3.1 仿真模板代码
4.2 仿真图
图3.2 状态变化仿真
图3.3 倒计时仿真
图3.4 状态变化仿真
图3.4 暂停状态仿真—观察运行时间
4.3 仿真结果分析
由仿真图可见,本次实验目标已完成,已知预置时间为15分钟。倒计时显示正常。
可以看到,状态显示在启动信号上边沿后一个时钟周期开始显示,并且以20s(20个时钟周期,之后所说秒数也是由时钟周期数仿真代替的)正转、10s暂停、20s反转、10s暂停循环。
结束信号在状态变化归0后一个时钟周期电压值变为高电平。
可见所要求的功能已全部实现。