您好,欢迎来到易妖游戏网。
搜索
您的当前位置:首页北邮数电实验 洗衣机控制器

北邮数电实验 洗衣机控制器

来源:易妖游戏网


数字电路与逻辑设计实验

基于CPLD 的简易洗衣机控制器的设计与实现

姓 名

学 院 信息与通信工程学院

专 业 信息工程

班 级

学 号

班内序号

1

1. 实验任务要求

1.1. 基本要求:

(1) 洗衣机的工作步骤为洗涤、漂洗和脱水三个过程,工作时间分别为:洗涤30 秒(进水5 秒,洗衣15 秒,排水5 秒,甩干5 秒),漂洗25 秒(进水5 秒,漂洗10 秒,排水5 秒,甩干5 秒),脱水15 秒(排水5 秒,甩干10 秒);掌握QuartusII图形模块单元的生成与调用。

(2) 用一个按键实现洗衣程序的手动选择:A、单洗涤;B、单漂洗;C、单脱水;D、漂洗和脱水;E、洗涤、漂洗和脱水全过程。

(3) 用发光二极管显示洗衣机的工作状态(洗衣、漂洗和脱水),并倒计时显示每个状态的工作时间,全部过程结束后,应有声音提示使用者,并保持在停止状态,直至再次开始。

(4) 用点阵动画显示洗衣机工作过程中进水、波轮或滚筒转动、排水和甩干等的工作情况,四种工作情况的动画显示要有区别且尽可能的形象。

(5) 用一个按键实现暂停洗衣和继续洗衣的控制,暂停后继续洗衣应回到暂停之前保留的状态。

1.2. 提高要求:

(1) 三个过程的时间有多个选项供使用者选择。

2

(2) 可以预约洗衣时间。

(3) 自拟其它功能。

2. 系统设计

2.1. 设计思路

按照实验要求,整个系统可按功能分为时钟分频、逻辑控制、按键功能、蜂鸣器报警、数码管显示、LED显示、点阵显示。设计思路是先完成分频和逻辑控制的基本功能,在此基础上加入按键控制、报警和几个显示功能。

2.1.1 输入部分:

设置了外部时钟,开始信号,暂停/继续信号,状态选择信号。

2.1.2 控制部分:

(1) 分频进程,将外部输入的50MHz时钟信号分频为1Hz和500Hz时钟信号,应用于倒计时计数和扫频;

(2) 逻辑控制进程,在符合前提条件的情况下,根据预置的状态对输入数据进行分析判断,对应相应过程的洗衣,并完成不同状态的转变,将改变的输出信号送至输出部分显示;

(3) 按键防抖动进程,避免在切换瞬间,因按键的来回弹跳对信号造成误操作;

3

(4) 按键状态控制进程,判断按键前一状态来确定下一状态。

2.1.3 输出部分:

(1) LED显示进程,显示当前选择的洗衣状态。

(2) 数码管计数扫频及显示进程,将各个洗衣状态对应的时间及倒计时情况进行显示;

(3) 点阵动画行扫描、计时及显示进程,根据不同的洗衣状态设计不同动画,并进行显示;

(4) 报警进程,通过判断本次洗衣过程是否结束来发出报警信号。

2.2. 总体框图

2.2.1 总体框图

4

2.2.2 MOS图

2.2.3 流程图

5

开始接通电源选择模式(显示时间和当前状态)否开始?是运行过程(倒计时和动画显示)否继续?过程暂停是暂停?否是过程结束 否报警结束?是结束

2.3.分块设计

2.3.1 分频进程 (1) 进程说明

分频程序由2个程序来实现,利用分频的思想,从50MHz经过分频模块,得到1Hz和500Hz的时钟信号,其中1Hz的时钟信号用于其他进程的计时,500Hz时钟信号用于数码

6

管扫频、点阵行扫频、按键防抖等进程。

(2) 信号说明

clock:输入的时钟信号;

clk:第一个进程分频后1Hz的时钟信号,每触发一次高电平时间为1秒;

clk1:第二个进程分频后500Hz的时钟信号。

2.3.2 逻辑控制进程 (1) 进程说明

为整个程序的主体,在输入拨码的高电平上升沿触发时,进行不同洗衣模式的切换;根据选择的洗衣模式,确定洗衣的时间。与led及点阵相关的代码是之后写进去的,为了逻辑思考的方便和减少代码量没有重新写进程。

长状态(比如70秒的全过程)中三个分状态的切换,通过一个计时器、一个计数器和一个变量来完成。在倒计时开始后,变量记录下一个分状态的时间长,在状态切换时赋值给倒计时变量;同时,在倒计时开始后,点阵时间计数器开始计时,在小过程动画切换时间点,计数器计数,用于控制点阵显示进程。

LED显示的实现为直接把选择状态的二进制码进行赋值。

(2) 信号说明

7

clk: 1Hz时钟信号;

start、pause: 作为前提判断条件;

state:洗衣状态对应的二进制码;

time:倒计时时间变量;

temp:记录下一状态时间的变量;

add:点阵计时变量;

point:计数器,记录当前时间对应的动画状态。

2.3.3 按键防抖进程 (1) 进程说明

按键防抖动模块负责暂停/继续按键的防抖动功能。按键是机械式开关结构,在开关切换的瞬间会在接触点出现来回弹跳的现象,这种弹跳现象可能造成误动作而影响到正确性,当按下按键一次然后松开后,实际产生的按键信号跳动了多次,经过取样信号的检查后将会造成误判。因此必须加上弹跳消除电路,避免误操作信号的发生。

以500Hz信号为时钟输入,变量m作为状态计数,当按键输入信号为高电平时,在时钟上升沿m加1,当m大于20时,即按键时间超过40ms时记为按键有效,把处理后信号赋值为高电平;否则按键无效,把处理后信号赋值为低电平。

8

(2) 信号说明

clk2:分频后500Hz时钟信号;

pause_in:原始输入的按键信号;

pause:输出的防抖动的按键信号;

2.3.4 按键状态控制进程 (1) 进程说明

按键状态控制进程负责暂停/继续按键处理后的的电平状态切换。按键和拨码不同处在于松手后按键恢复低电平,因此要持续时间保持或改变电平状态,需要另写一进程进行控制。

使用变量pa作为0/1计数,开始洗衣后,在防抖处理后的信号的上升沿时进行判断,若pa为1则维持暂停,输出低电平信号,同时pa赋值0;若pa为0.说明此时状态为暂停,按键后应该继续洗衣,所以输出高电平信号,同时pa赋值0。输出的信号就是其他进程中使用的暂停/继续信号。

(2) 信号说明

start:开始信号;

pause1:输入的防抖动按键信号;

9

pause:输出的保持状态按键信号。

2.3.5 数码管显示进程 (1) 进程说明

数码管显示选定洗衣状态的总时间以及倒计时的情况。六个七段数码管中选择了两个来显示秒数的十位和个位,实际上轮流点亮而非一起点亮,通过使用扫频时钟信号和计数器来完成扫描,因为扫描频率足够大,利用人眼效应会使人感觉两个数码管同时亮。

(2) 信号说明

clk2: 分频后500Hz时钟信号;

cnt:扫频计数器,直接控制cat[5..0]和t的切换;

time:倒计时过程中的当前时间;

cat[5..0]:数码管显示位,”111011”和”110111”随扫频信号反复切换;

t:十位、个位要显示的数字,随扫频信号反复切换;

distime[4..0]:表示6个数码管将要显示的数字。

2.3.6 报警器进程 (1) 进程说明

10

使用1Hz信号时钟,在时钟上升沿判断当前状态,如果一个状态已结束,即state为”000”,则报警信号赋值为高电平,利用循环来限定蜂鸣器出响时间,出响时间即为计数器初值。

(2) 信号说明

clk: 1Hz时钟信号;

state:选定的洗衣状态;

alarm:报警输出信号,高电平为出响;

alarmtime:计数器,控制报警出响时间;

2.3.7 点阵进程 (1) 进程说明

负责显示不同洗衣过程对应的图案。

可选择的每个洗衣状态中包含进水、洗衣、漂洗、排水、甩干多个小过程,需要一个计数器控制每个小过程的时间,分析实验要求发现每个小过程的时间都是5秒的倍数,所以把每个小动画设计成5秒一个周期的循环动画。

与数码管显示同理,点阵的变化显示也需要通过扫频处理,需要设置专门的计数器负责扫行计数。通过计数器产生点阵扫描,对行信号轮流进行扫描,为高电平的列信号表示

11

被扫描行中对应列二极管发光。当扫描频率足够大时,可以让人以为不同行的二极管同时点亮。

点阵的动画设计部分,设定了五种动画对应五个不同的小状态,设置变量记录当前时间对应的触发状态,进而控制点阵显示。

(2) 信号说明

clk: 1Hz时钟信号;

start、pause、state:作为前提判断条件;

periodtime:5s计时器,每个小过程的动画周期;

runnum:扫行计数器;

point:计数器,记录当前时间对应的动画状态;

row [7..0]:点阵列变量;

colorg [7..0]、colorr [7..0]:点阵列变量。

3. 仿真波形及波形分析

注:为方便仿真,我修改了频率,并把每个进程提取出来分别进行了仿真。

12

3.1 分频部分

3.1.1 仿真波形图

3.1.2 仿真使用代码

3.1.3 仿真波形分析

13

进程p1分频系数为10,进程q2分频系数为20。关于count的IF语句描述了一个计数模值为10的计数器,该计数器每一个计数周期结束,信号clk翻转一次,这样信号clk的周期为时钟信号clock周期的10倍,实现了对clock的10分频。20分频同理。实际实验中使用的是50MHz和500Hz的分频。

3.2 状态转换部分

3.2.1 仿真波形图

3.2.2 仿真使用代码

3.2.3 仿真波形分析

14

初始状态为“000”,当模式选择开关高电平的上升沿到来时,状态改变一次。输出的LED状态显示依次为 001、010、100、100、110、111、000。

3.3 按键部分

3.3.1 仿真波形图

3.3.2 仿真使用代码

3.3.3 仿真波形分析

15

执行语句的条件为开始开关处于高电平,pause_in是输入的按键信号,当输入按键信号高电平持续时间大于3个时钟信号,输出pause1信号的为高电平,pause1信号才有效;否则,当输入按键信号高电平持续时间小于3个时钟信号,如第0ns之后的按键高电平信号,没有触发有效的pause1信号,即实现了防抖的功能。

第一个pause_in高电平信号之后,即pause1信号第一次置为高电平时,输出高电平的pause信号,进入暂停状态,此信号就是在其他进程中使用的最终信号;pause1信号第二次置为高电平时,输出低电平的pause信号,继续开始。

3.4数码管部分

3.4.1 仿真波形图

16

3.4.2 仿真使用代码

17

3.4.3 仿真波形分析

以40秒模式为例。执行语句的条件为开始开关处于高电平,观察仿真波形可以看到扫频时钟信号每触发一次高电平,扫行信号cat在110111和111011之前切换一次。

clk为计时信号,clk2为扫频信号,频率做了修改以便于仿真。

为了方便观察,我把原代码中的distime变量的改为了distime_ge和distime_shi两个变量。distime_ge为数码管显示的个位,可以看到,以cat信号两次高电平为周期,distime_ge的值变化一次,为\"1111011\"、\"1111111\"、\"1110000\"、\"1011111\"、\"1011011\"、\"0110011\"、\"1111001\"、\"1101101\"、\"0110000\"、\"1111110\",即从9到0递减;distime_shi为数码管显示的十位,可以看到distime_shi先是显示\"0110011\",即最初的数字4,开始倒计时后显示\"1111001\",即数字3,在十个clk时钟信号后变成

18

\"1101101\",即数字2。

3.5报警器部分

3.5.1 仿真波形图

3.5.2 仿真使用代码

3.5.3 仿真波形分析

在state为“000”,即结束状态时,alarm为高电平,时间为4个时钟信号的长度,即蜂鸣器发出了4秒声响。state为其他值是alarm均为低电平。

19

在时钟上升沿判断,当state为“000”时,进入计数循环,变量值从0累加到4时以后赋给alarm高电平。

3.6点阵时间分配部分

3.6.1 仿真波形图

3.6.2 仿真使用代码

3.6.3 仿真波形分析

20

执行语句的条件为开始开关处于高电平,在每个时钟信号上升沿计数,add累加1,在动画切换时间点,比如add=5时,把动画对应的触发状态赋给变量point,在点阵动画设计进程中把point作为判断条件,使用case语句判断要调用的动画语句。

仿真波形以state为“100”为例,为了便于仿真把point用二进制信号表示。

3.7点阵动画设计部分

3.7.1 仿真波形图

3.7.2 仿真使用代码

21

3.7.3 仿真波形分析

开始开关处于高电平时,当时钟信号clk处于上升沿时,periodtime累加1,即为周期为5的计数器。行变量row中“1” 表示点阵的对应行点亮, “0”表示对应行不亮。color两个变量表示点阵的列,“1” 表示对应列点亮, “0”表示对应列不亮。

以进水动画为例,计数器每加1,行变量row、两个不同颜色的列变量colorg和colorr改变一次状态,改变的显示即为程序中的设定值。

4. 源代码

library ieee;

use ieee.std_logic_11.all;

entity washerzy is

port(

clock: in std_logic; --时钟

start: in std_logic; --开始

pause_in: in std_logic; --暂停和继续

change: in std_logic; --选择状态

22

alarm: out std_logic; --报警

dismode: out std_logic_vector(2 downto 0); ---led显示状态

distime: out std_logic_vector(6 downto 0); --数码管显示数

cat: out std_logic_vector(5 downto 0); --数码管显示位

row: out std_logic_vector(7 downto 0); --点阵行

colorg: out std_logic_vector(7 downto 0); --颜色一

colorr: out std_logic_vector(7 downto 0) --颜色二

);

end washerzy ;

architecture total of washerzy is

signal count: integer range 0 to 24999999; --分频计数

signal clk: std_logic;

signal clk_count: integer range 0 to 49999;

23

signal clk2: std_logic;

signal mode: std_logic_vector(2 downto 0); --选择模式

signal state: std_logic_vector(2 downto 0); --当前状态

signal temp: integer range 0 to 40; --状态转换 替换时间

signal time: integer range 0 to 70; --倒计时

signal add: integer range 0 to 70:=0; --点阵计时

signal point: integer range 0 to 5:=0; --点阵动画状态

signal unit: integer range 0 to 9; --数码管显示数字

signal cnt: integer range 0 to 1; --数码管扫频显示两数字 计数

signal timecount:integer range 4 downto 0; --报警器出响时间

signal rownum:integer range 0 to 7; --点阵 扫频频率变化

signal periodtime:integer range 0 to 4; --点阵 1hz变化

signal pause: std_logic; --按键状态处理后

24

signal pause1: std_logic; --防抖处理后

begin

fenpin1:process (clock) ------1s

begin

if (clock'event and clock = '1') then

if (count=24999999) then

count<=0;

clk<=not clk;

else count<=count+1;

end if;

end if;

end process fenpin1;

fenpin2:process(clock) --扫频用

25

begin

if (clock'event and clock = '1') then

if (clk_count=49999) then

clk_count<=0;

clk2<=not clk2;

else clk_count<=clk_count+1;

end if;

end if;

end process fenpin2;

controlst:process (start,clk,pause,change,state)

begin

if (start='0') then

add<=0;

26

if (change'event and change='1') then --改变状态

case mode is

when \"000\"=> mode <=\"001\";

when \"001\"=> mode <=\"010\";

when \"010\"=> mode <=\"100\";

when \"100\"=> mode <=\"110\";

when \"110\"=> mode <=\"111\";

when others=> mode <=\"000\";

end case;

end if;

state<=mode;

case state is

when \"001\"=>temp<=0; --洗衣(进水5,洗衣15,排水5,甩干5)

27

time<=30;

when \"010\"=>temp<=0; --漂洗(进水5,漂洗10,排水5,甩干5)

time<=25;

when \"100\"=>temp<=0; --脱水(排水5,甩干10)

time<=15;

when \"110\"=>temp<=15; --漂洗和脱水

time<=40;

when \"111\"=>temp<=40; --洗衣,漂洗和脱水全过程

time<=70;

when \"000\"=>temp<=0;

time<=0;

when others =>temp<=0;

time<=0;

28

end case;

else

if (pause='0') then

if (clk'event and clk='1' and time/=0)then

time<=time-1;

add<=add+1;

if (time=1)then --完成本过程后当前状态归零

state<=\"000\";

add<=0;

point<=0;

elsif (time=temp) then

case state is

when \"111\"=>state<=\"110\"; -----洗涤结束,开始漂洗

29

temp<=15;

when \"100\"=>state<=\"100\"; -----微调.漂洗结束,开始脱水

temp<=0;

when others=>temp<=0;

state<=\"000\";

end case;

elsif(time=temp+1)then

case state is

when \"111\"=>add<=0;

when \"110\"=>add<=0;

state<=\"100\";

when others=> add<=add;

end case;

30

end if;

case state is

when \"100\" => case add is

-- point对应动画:1进水,2漂洗,3洗衣,4排水,5甩干

when 0 => point<=4;

when 1 => point<=4;

when 5 => point<=5;

when 15 => point<=0;

when others => point<=point;

end case;

when \"010\" => case add is

when 0 => point<=1;

when 5 => point<=3;

31

when 15 => point<=4;

when 20 => point<=5;

when 25 => point<=0;

when others => point<=point;

end case;

when \"110\" => case add is

when 0 => point<=1;

when 1 => point<=1;

when 5 => point<=3;

when 15 => point<=4;

when 20 => point<=5;

when others => point<=point;

end case;

32

when \"001\" => case add is

when 0 => point<=1;

when 5 => point<=2;

when 20 => point<=4;

when 25 => point<=5;

when 30 => point<=0;

when others => point<=point;

end case;

when \"111\" => case add is

when 0 => point<=1;

when 5 => point<=2;

when 20 => point<=4;

when 25 => point<=5;

33

when others => point<=point;

end case;

when others => point<=0;

end case;

end if;

end if;

end if;

dismode <=state;

end process controlst;

shuma:process (clk2,cnt,time,unit)

begin

if (clk2'event and clk2='1')then

if cnt=1 then ------数码管扫频计数

34

cnt<=0;

else

cnt<=cnt+1;

end if;

end if;

case cnt is

when 0=>cat<=\"111011\";unit<=time mod 10; --个位

when 1=>cat<=\"110111\";unit<=time/10; --十位

when others=>cat<=\"111111\";

end case;

case unit is ---数码管示数

when 1=>distime<=\"0110000\";

when 2=>distime<=\"1101101\";

35

when 3=>distime<=\"1111001\";

when 4=>distime<=\"0110011\";

when 5=>distime<=\"1011011\";

when 6=>distime<=\"1011111\";

when 7=>distime<=\"1110000\";

when 8=>distime<=\"1111111\";

when 9=>distime<=\"1111011\";

when others=>distime<=\"1111110\";

end case;

end process shuma;

alarmclock:process(state,clk)

begin

if (clk'event and clk='1') then --报警器

36

case state is

when \"000\" =>alarm<='1';

if (timecount = 0)then

alarm <='0';

else

timecount<=timecount-1;

end if;

when others => alarm <='0';

timecount<=4; --出响时间

end case;

end if;

end process alarmclock;

pddianzhen:process (clk,pause,start,state)

37

begin

if(start='1') then

if(pause='0') then

if(state/=\"000\") then

if(clk' event and clk='1') then

if periodtime=4 then --点阵动画 每个画面计时(1s)

periodtime<=0;

else

periodtime<=periodtime+1;

end if;

end if;

end if;

end if;

38

else periodtime<=0;

end if;

end process pddianzhen;

saohang:process(pause,clk2,start,state) ---扫行

begin

if(start='1') then

if(pause='0') then

if(state/=\"000\")then

if(clk2' event and clk2='1') then

if rownum=7 then

rownum<=0;

else

rownum<=rownum+1;

39

end if;

end if;

end if;

end if;

else rownum<=0;

end if;

end process saohang;

dianzhen:process(point,pause,periodtime,rownum) begin

if(start='1') then

if(pause='0') then

case point is

when 1 =>case periodtime is --进水

40

点阵动画的设计

---

when 0 =>row<=\"00000000\"; colorg<=\"01010101\";colorr<=\"10101010\";

when 1 =>row<=\"11111110\"; colorg<=\"01010101\";colorr<=\"10101010\";

when 2 =>row<=\"11111100\"; colorg<=\"01010101\";colorr<=\"10101010\";

when 3 =>row<=\"11110000\"; colorg<=\"01010101\";colorr<=\"10101010\";

when 4 =>row<=\"11000000\"; colorg<=\"01010101\";colorr<=\"10101010\";

when others =>row<=\"00000000\"; colorg<=\"00000000\";colorr<=\"11111111\";

end case;

when 2 =>case periodtime is --漂洗

when 1 =>case rownum is

when 0=>row<=\"11111110\"; colorg<=\"11111111\";colorr<=\"00000000\";

when 1=>row<=\"11111101\"; colorg<=\"10001001\";colorr<=\"00000000\";

when 2=>row<=\"11111011\"; colorg<=\"10001001\";colorr<=\"00000000\";

when 3=>row<=\"11110111\"; colorg<=\"10001001\";colorr<=\"01110000\";

41

when 4=>row<=\"11101111\"; colorg<=\"10010001\";colorr<=\"00001110\";

when 5=>row<=\"11011111\"; colorg<=\"10010001\";colorr<=\"00000000\";

when 6=>row<=\"10111111\"; colorg<=\"10010001\";colorr<=\"00000000\";

when 7=>row<=\"01111111\"; colorg<=\"11111111\";colorr<=\"00000000\";

end case;

when 2 =>case rownum is

when 0=>row<=\"11111110\"; colorg<=\"11111111\";colorr<=\"00000000\";

when 1=>row<=\"11111101\"; colorg<=\"10000011\";colorr<=\"01000000\";

when 2=>row<=\"11111011\"; colorg<=\"10000101\";colorr<=\"00100000\";

when 3=>row<=\"11110111\"; colorg<=\"10001001\";colorr<=\"00010000\";

when 4=>row<=\"11101111\"; colorg<=\"10010001\";colorr<=\"00001000\";

when 5=>row<=\"11011111\"; colorg<=\"10100001\";colorr<=\"00000100\";

when 6=>row<=\"10111111\"; colorg<=\"11000001\";colorr<=\"00000010\";

42

when 7=>row<=\"01111111\"; colorg<=\"11111111\";colorr<=\"00000000\";

end case;

when 3 =>case rownum is

when 0=>row<=\"11111110\"; colorg<=\"11111111\";colorr<=\"00000000\";

when 1=>row<=\"11111101\"; colorg<=\"10000001\";colorr<=\"00001000\";

when 2=>row<=\"11111011\"; colorg<=\"10000001\";colorr<=\"00001000\";

when 3=>row<=\"11110111\"; colorg<=\"11110001\";colorr<=\"00001000\";

when 4=>row<=\"11101111\"; colorg<=\"10001111\";colorr<=\"00010000\";

when 5=>row<=\"11011111\"; colorg<=\"10000001\";colorr<=\"00010000\";

when 6=>row<=\"10111111\"; colorg<=\"10000001\";colorr<=\"00010000\";

when 7=>row<=\"01111111\"; colorg<=\"11111111\";colorr<=\"00000000\";

end case;

when 4 =>case rownum is

43

when 0=>row<=\"11111110\"; colorg<=\"11111111\";colorr<=\"00000000\";

when 1=>row<=\"11111101\"; colorg<=\"11000001\";colorr<=\"00000010\";

when 2=>row<=\"11111011\"; colorg<=\"10100001\";colorr<=\"00000100\";

when 3=>row<=\"11110111\"; colorg<=\"10010001\";colorr<=\"00001000\";

when 4=>row<=\"11101111\"; colorg<=\"10001001\";colorr<=\"00010000\";

when 5=>row<=\"11011111\"; colorg<=\"10000101\";colorr<=\"00100000\";

when 6=>row<=\"10111111\"; colorg<=\"10000011\";colorr<=\"01000000\";

when 7=>row<=\"01111111\"; colorg<=\"11111111\";colorr<=\"00000000\";

end case;

when others =>row<=\"11111111\"; colorg<=\"00000000\";colorr<=\"00000000\";

end case;

when 3 =>case periodtime is --洗衣

when 1 =>case rownum is

44

when 0=>row<=\"11111110\"; colorg<=\"00001000\";colorr<=\"00000000\";

when 1=>row<=\"11111101\"; colorg<=\"00001000\";colorr<=\"00000000\";

when 2=>row<=\"11111011\"; colorg<=\"00001000\";colorr<=\"00000000\";

when 3=>row<=\"11110111\"; colorg<=\"00001000\";colorr<=\"11110000\";

when 4=>row<=\"11101111\"; colorg<=\"00010000\";colorr<=\"00001111\";

when 5=>row<=\"11011111\"; colorg<=\"00010000\";colorr<=\"00000000\";

when 6=>row<=\"10111111\"; colorg<=\"00010000\";colorr<=\"00000000\";

when 7=>row<=\"01111111\"; colorg<=\"00010000\";colorr<=\"00000000\";

end case;

when 2 =>case rownum is

when 0=>row<=\"11111110\"; colorr<=\"00000001\";colorg<=\"10000000\";

when 1=>row<=\"11111101\"; colorr<=\"00000010\";colorg<=\"01000000\";

when 2=>row<=\"11111011\"; colorr<=\"00000100\";colorg<=\"00100000\";

45

when 3=>row<=\"11110111\"; colorr<=\"00001000\";colorg<=\"00010000\";

when 4=>row<=\"11101111\"; colorr<=\"00010000\";colorg<=\"00001000\";

when 5=>row<=\"11011111\"; colorr<=\"00100000\";colorg<=\"00000100\";

when 6=>row<=\"10111111\"; colorr<=\"01000000\";colorg<=\"00000010\";

when 7=>row<=\"01111111\"; colorr<=\"10000000\";colorg<=\"00000001\";

end case;

when 3 =>case rownum is

when 0=>row<=\"11111110\"; colorg<=\"00000000\";colorr<=\"00001000\";

when 1=>row<=\"11111101\"; colorg<=\"00000000\";colorr<=\"00001000\";

when 2=>row<=\"11111011\"; colorg<=\"00000000\";colorr<=\"00001000\";

when 3=>row<=\"11110111\"; colorg<=\"11110000\";colorr<=\"00001000\";

when 4=>row<=\"11101111\"; colorg<=\"00001111\";colorr<=\"00010000\";

when 5=>row<=\"11011111\"; colorg<=\"00000000\";colorr<=\"00010000\";

46

when 6=>row<=\"10111111\"; colorg<=\"00000000\";colorr<=\"00010000\";

when 7=>row<=\"01111111\"; colorg<=\"00000000\";colorr<=\"00010000\";

end case;

when 4 =>case rownum is

when 0=>row<=\"11111110\"; colorg<=\"10000000\";colorr<=\"00000001\";

when 1=>row<=\"11111101\"; colorg<=\"01000000\";colorr<=\"00000010\";

when 2=>row<=\"11111011\"; colorg<=\"00100000\";colorr<=\"00000100\";

when 3=>row<=\"11110111\"; colorg<=\"00010000\";colorr<=\"00001000\";

when 4=>row<=\"11101111\"; colorg<=\"00001000\";colorr<=\"00010000\";

when 5=>row<=\"11011111\"; colorg<=\"00000100\";colorr<=\"00100000\";

when 6=>row<=\"10111111\"; colorg<=\"00000010\";colorr<=\"01000000\";

when 7=>row<=\"01111111\"; colorg<=\"00000001\";colorr<=\"10000000\";

end case;

47

when others =>row<=\"11111111\"; colorg<=\"00000000\";colorr<=\"00000000\";

end case;

when 4 =>case periodtime is --排水

when 0 =>row<=\"11111111\"; colorg<=\"01010101\";colorr<=\"10101010\";

when 1 =>row<=\"00000000\"; colorg<=\"01010101\";colorr<=\"10101010\";

when 2 =>row<=\"11000000\"; colorg<=\"01010101\";colorr<=\"10101010\";

when 3 =>row<=\"11110000\"; colorg<=\"01010101\";colorr<=\"10101010\";

when 4 =>row<=\"11111100\"; colorg<=\"01010101\";colorr<=\"10101010\";

when others =>row<=\"00000000\"; colorg<=\"00000000\";colorr<=\"11111111\";

end case;

when 5 =>case periodtime is --甩干

when 1 =>case rownum is

when 0=>row<=\"11111110\"; colorg<=\"11111111\";colorr<=\"00000000\";

48

when 1=>row<=\"11111101\"; colorg<=\"10000001\";colorr<=\"01111110\";

when 2=>row<=\"11111011\"; colorg<=\"10000001\";colorr<=\"01111110\";

when 3=>row<=\"11110111\"; colorg<=\"10000001\";colorr<=\"01000010\";

when 4=>row<=\"11101111\"; colorg<=\"10000001\";colorr<=\"01000010\";

when 5=>row<=\"11011111\"; colorg<=\"10000001\";colorr<=\"01000010\";

when 6=>row<=\"10111111\"; colorg<=\"10000001\";colorr<=\"01111110\";

when 7=>row<=\"01111111\"; colorg<=\"11111111\";colorr<=\"00000000\";

end case;

when 2 =>case rownum is

when 0=>row<=\"11111110\"; colorg<=\"00000000\";colorr<=\"00000000\";

when 1=>row<=\"11111101\"; colorg<=\"00000000\";colorr<=\"01111110\";

when 2=>row<=\"11111011\"; colorg<=\"00111100\";colorr<=\"01111110\";

when 3=>row<=\"11110111\"; colorg<=\"00111100\";colorr<=\"01000010\";

49

when 4=>row<=\"11101111\"; colorg<=\"00100100\";colorr<=\"01000010\";

when 5=>row<=\"11011111\"; colorg<=\"00111100\";colorr<=\"01000010\";

when 6=>row<=\"10111111\"; colorg<=\"00000000\";colorr<=\"01111110\";

when 7=>row<=\"01111111\"; colorg<=\"00000000\";colorr<=\"00000000\";

end case;

when 3 =>case rownum is

when 0=>row<=\"11111110\"; colorg<=\"00000000\";colorr<=\"00000000\";

when 1=>row<=\"11111101\"; colorg<=\"00000000\";colorr<=\"00000000\";

when 2=>row<=\"11111011\"; colorg<=\"00111100\";colorr<=\"00000000\";

when 3=>row<=\"11110111\"; colorg<=\"00111100\";colorr<=\"00011000\";

when 4=>row<=\"11101111\"; colorg<=\"00100100\";colorr<=\"00011000\";

when 5=>row<=\"11011111\"; colorg<=\"00111100\";colorr<=\"00000000\";

when 6=>row<=\"10111111\"; colorg<=\"00000000\";colorr<=\"00000000\";

50

when 7=>row<=\"01111111\"; colorg<=\"00000000\";colorr<=\"00000000\";

end case;

when 4 =>case rownum is

when 0=>row<=\"11111110\"; colorg<=\"00000000\";colorr<=\"00000000\";

when 1=>row<=\"11111101\"; colorg<=\"00000000\";colorr<=\"00000000\";

when 2=>row<=\"11111011\"; colorg<=\"00000000\";colorr<=\"00000000\";

when 3=>row<=\"11110111\"; colorg<=\"00000000\";colorr<=\"00011000\";

when 4=>row<=\"11101111\"; colorg<=\"00000000\";colorr<=\"00011000\";

when 5=>row<=\"11011111\"; colorg<=\"00000000\";colorr<=\"00000000\";

when 6=>row<=\"10111111\"; colorg<=\"00000000\";colorr<=\"00000000\";

when 7=>row<=\"01111111\"; colorg<=\"00000000\";colorr<=\"00000000\";

end case;

when others =>row<=\"11111111\"; colorg<=\"00000000\";colorr<=\"00000000\";

51

end case;

when others=>row<=\"11111111\"; colorg<=\"00000000\";colorr<=\"00000000\";

end case;

end if;

end if;

end process dianzhen;

pausestate:process (pause1,start,clk2) --按键触发状态,判断改变或维持按键状态

variable u:integer range 0 to 1; --计数,按键对应的两状态

begin

if (start='1') then

if (pause1 'event and pause1='1' )then

if u = 1 then

u:=0;

52

pause<='0';

else u:=u+1;pause<='1';

end if;

end if;

end if;

end process pausestate;

anti_shake:process(clk2,pause_in) variable m:integer range 0 to 20; begin

if(clk2'event and clk2='1')then

if(pause_in='1')then if(m=20)then

pause1<='1';

--防抖

定义变量来计数时钟个数

53

--

m:=0;

else

m:=m+1;

end if;

else

pause1<= '0';

end if; --按键时间是n个时钟周期

end if;

end process anti_shake;

end total;

5. 功能说明及资源利用情况

5.1 功能说明

实现了洗衣机实验要求的基本功能,能够提供五种不同洗衣组合的模式选择。

54

5.1.1模块功能说明

(1) 拨码开关1负责开始和结束;

(2) 拨码开关2负责选择洗衣模式;

(3) 按键负责在模式运行过程中的暂停和继续;

(4) 数码管负责显示开机后初始状态、选择模式对应的总时间和运行后的倒计时;

(5) LED指示灯负责显示当前选择的洗衣状态;

(6) 点阵按照设定顺序显示不同过程(进水、漂洗、洗衣、排水、甩干)的动画:进水的动画为自底部向上逐行点亮,每列的颜色为红绿交替;漂洗的动画为绿方框中红绿十字旋转;洗衣的动画为整个点阵红绿十字旋转;排水的动画为自顶部向下逐行点亮,其中每列的颜色为红绿交替;甩干的动画为红绿颜色交替的回型,从外圈依次熄灭。

(7) 蜂鸣器负责在当前洗衣过程结束后报警,作为任务结束的提示。

5.1.2 具体过程说明

(1) 使负责开始的拨码开关1置低电平,连接电源后,数码管亮起显示“00”,LED灯都不亮,即初始状态。

(2) 拨动负责选择模式的拨码开关2,每置一次高电平,选定的模式切换一次,外部显示为数码管和LED的切换变化。数码管显示当前选定模式对应的总时间;led显示当前选定模式对应的二进制码表示,led亮起表示1,不亮表示0。

55

(3) 选定状态后(以40秒漂洗和脱水模式为例),拨动拨码开关1置高电平,开始运行本次过程,数码管显示开始倒计时(从40开始每过一秒减1),点阵依次显示各个小过程对应的动画(首先是漂洗状态,进水5秒+漂洗10秒+排水5秒+甩干5秒,然后是脱水状态,排水5秒+甩干10秒),LED的显示不变。在运行过程中,按一次负责暂停功能的按键开关,数码管显示的时间数字和点阵显示的画面保持暂停时刻的显示状态,LED的显示不变;再按一次暂停按键,数码管显示的时间数字继续按秒递减,点阵继续显示动画。倒计时结束后,蜂鸣器出响4秒(实际上是5秒左右会有轻微误差,与触发电平时刻有关),数码管保持显示“00”,LED都不亮,表示回到初始状态。

(4) 本次过程结束后,可以重新设置洗衣模式继续执行程序。拨下负责开始的拨码开关置低电平,重新拨动负责选择模式的拨码开关,选择其他的状态运行,操作和显示与前面的叙述同理,不再赘述。

5.2资源利用情况

56

6. 故障及问题分析

1)关于管脚配置问题

最初实现了用拨码开关实现暂停、继续洗衣的控制功能,在这个代码的基础上我改写为用按键实现,添加了防抖和保持按键状态两个进程。写完防抖进程后,编译时报错Error: Node ”pause” of type Logic cell has no legal location,我逐行检查了代码中与pause相关的语句,但没有发现错误,查资料后意识到是管脚分配的问题。为了减少工作量,在改写代码时我重新定义了pause_in作为输入,把原来的输入pause改为了signal,但是编译前忽略了在pin界面去掉pause并要给pause_in配置管脚的步骤。

2)关于按键控制暂停/继续的问题

在写保持按键状态进程之前,我尝试了多种方法,想能不能只用一个进程解决按键控制问题,比如修改防抖进程中最后的else语句pause1<= '0';为pause1<= pause1;,理论上这样可以保持原有状态,但实际操作以后,实验板的反应跟没改代码的时候并没有区别。后来我想,不然就再另写一个进程,专门控制按键状态,这个想法最后成功了。另外在编

57

写按键状态进程的过程中,我按照原有的思想, 想通过时钟上升沿来作为触发判断当前按键触发过的状态,这时一起做实验的同学建议说直接用防抖处理过的信号pause1的上升沿作为判断会不会更好,分析以后我认同了她的想法,这样避免了每个时钟上升沿都要做一次判断,我也认识到了自己思维的局限性。

3)关于敏感参数表的问题

为了方便调试,点阵的代码是在新建的工程中编写和编译的,下载到板子上通过以后,再简单修改成进程,加入到洗衣机程序中,编译通过后下载到板子上,其他模块正常运行,点阵模块却没有反应。经过检查以后,发现是敏感参数表的问题,在点阵进程中虽然使用了开始信号作为判断条件,但在敏感参数表中忘记了加入开始信号。改正后再次下载点阵有了显示,但按暂停键后动画未停止,检查发现是忽略了加入pause判断条件,这次我没忘记在敏感参数表中写这个信号,最后实现了功能。

4)关于蜂鸣器发声的问题

刚加入蜂鸣器模块时,调试程序编译通过以后,蜂鸣器一直不响,和同学讨论后知道了只有一定频率范围的频率才能使蜂鸣器发声,而我选择了高频所以没成功,修改后解决了这个问题。一起做实验的另一位同学也遇到了蜂鸣器不响的情况,不过他是因为实验板有问题,这提醒了我,以后遇到类似的情况,如果没能查出代码的问题,就把代码多下载到几块实验板上试试看。

之后我和另一位同学想要尝试修改蜂鸣器出响的时间,开始采用的是用时钟信号作为计数判断条件的方法,没有得到好的效果,查资料后发现了变量赋初值语句的用法,然后先在结构说明部分给变量赋初值,但实际出响时间也不是4秒左右。多次尝试以后,最终采

58

用了循环语句的写法,并在最后一句给变量赋值,问题得到了解决。

5)关于代码规范的问题

在代码全部编写完成并实现了最终功能后,我开始整理规范代码,并加入注释,以增强代码的可读性。我按照使用顺序整理端口名后, 再次编译后报错,但错误指向的那行代码并没有错误,根据之前的经验我上网搜索了这个错误原因。发现原来是我在把最后一行移动到前面位置以后,没有注意到分号的修改,最后一行的末尾没有分号,分号在右括号外。另外在检查代码的过程中我发现有两个定义的变量功能重复了可以合并,有的进程也可以合并等等,我修改了一些。

7. 实验总结及心得体会

本次综合实验是上学期的基础实验上的延伸和拓展,对VHDL语言、Quartus II软件以及EDA工具的要求程度较高,必须要有一定的理论知识和编程基础才能完成。一个学期以前,我们还停留在编写基本的代码语句,对VHDL程序的基本架构有所了解的水平上,这次实验就要求我们编写一个中小型有关状态机的VHDL程序,一开始上课的时候我心里还是十分担忧的。不过俗话说得好,功夫不怕有心人。老师在第一节给我们讲了这次实验的基本要求,并从画总体框图、流程图、MOS图等逐步领我们入门。

实验刚开始,主要是理清思路,对实验要求有个总体的理解。先编写主体程序,实现基本功能,然后附加上多个进程,实现其他的功能。由于之前没有系统的学习过VHDL语言,编写起来也是困难重重,比如刚开始编写的时候,因为对代码的编写不太熟悉,经常漏写判断条件,导致编译成功后操作无效果。在写完主体程序后,本来的想法是每个显示功能写一个进程,但是后来发现,有些功能综合起来写比分开写要更容易一些,毕竟有些

59

功能的实现是联系在一起的,比如状态和LED显示,只需要在控制进程多加一行代码就可以完成。对代码有了整体的认识后,再次整理了代码,做了较大的改动。最后一步步地实现了各个功能。

短短的三周时间,我逐渐认识到硬件实验与软件实验的区别,。由最开始的几十个错误慢慢纠正,最后顺利完成代码编写并得以下载,过程也是挺曲折的,而且即使在代码编译和仿真时完全正常,并且自己感觉代码逻辑没有出错的情况下,代码下载到板子上以后还是不能实现想要的功能,仍然需要找到出错的原因并对相关的代码进行修改。但坚持下来了总会有收获,毕竟这是通过努力换来的。同学之间的探讨帮助,讨论后解决不了的问题及时查资料寻找解决办法,这些对实验的完成也起着重要的作用,比如,另一个一起做实验的同学告诉我,他实践以后发现同一个进程应该只能用一个时钟来控制,用两个时钟就会编译报错,他的提醒让我少走了不少弯路。

通过这次实验我对于Quartus II软件的运用更为熟练了,对VHDL语言的理解也加深了,但我认为更重要的收获是使我的实际操作能力得到了提升,在与同学讨论过程中我看到了自己存在潜力的一些方面,比如逻辑思维较强,也认识到了自己思维的局限性,比如习惯运用熟悉的方法编写程序而不是最简洁有效的方法,我很感谢这样的实验,这样的收获能让我真正受益一生。

60

因篇幅问题不能全部显示,请点此查看更多更全内容

Copyright © 2019- vipyiyao.com 版权所有 湘ICP备2023022495号-8

违法及侵权请联系:TEL:199 18 7713 E-MAIL:2724546146@qq.com

本站由北京市万商天勤律师事务所王兴未律师提供法律服务