第6章 VHDL设计应用实例 6.1 8位加法器的设计 6.3 序列检测器的设计 6.4 正负脉宽数控调制信号发生器的设计

Slides:



Advertisements
Similar presentations
什么是SOPC: SOPC是英文System On a Programmable Chip的缩写,称为片上可编程系统。SOPC将传统的EDA技术、计算机系统、嵌入式系统、数字信号处理等融为一体,综合了各自的优势,且在结构上形成一块芯片。 为什么用SOPC:SOPC是现代电子技术和电子系统设计的发展趋势,建立了电子系统设计的新模式。用户利用SOPC开发平台,自行设计高速、高性能的DSP处理器、特定功能的CPU及其外围接口电路,创建结构最为简洁的电子系统。
Advertisements

做实验过程中发现的问题: 新建时工程文件夹建立了,但所建实体文件并没存放在其中 文件名不能用汉字
第2章 FPGA/CPLD结构与应用.
《 E D A 技 术》 课 程 教 学 讲授:伍宗富 湖南文理学院电气与信息工程学院 2017年3月19日星期日.
第4章 VHDL设计初步.
电工电子实验中心.
EPF10K10TI144-4晶片燒錄.
硬件描述语言VHDL及其应用 哈工大微电子中心 王 进 祥 讲课地点:A213 电话:
第三章 组合逻辑电路 第一节 组合电路的分析和设计 第二节 组合逻辑电路中的竞争与冒险 第三节 超高速集成电路硬件描述语言VHDL
第1章 FPGA概述 1.1 FPGA的发展历程 1.2 FPGA的基本原理 1.3 FPGA的设计方法 1.4 FPGA的设计流程
第五章 总线 及其形成 本节课之前,大家学习了:
VHDL數位電路實習與專題設計 文魁資訊-UE301
陳維魁 博士 儒林圖書公司 第七章 參數的傳遞 陳維魁 博士 儒林圖書公司.
VHDL數位電路實習與專題設計 文魁資訊-UE301
Chapter 5 Verilog 硬體描述語言
8.9二进制振幅键控(ASK) 调制器与解调器设计
Chapter 5 Verilog硬體描述語言
Ch01-2 Verilog語法 資料流(DataFlow)設計 行為(Behavior)設計
第17章 Verilog中的高级结构 学习内容: 任务和函数的定义和调用 怎样使用命名块 怎样禁止命名块和任务 有限状态机(FSM)及建模.
EDA技术 廖义奎.
VHDL 硬體描述語言 數位電路設計實務 第四章 VHDL 的語言結構.
第七章 MCS-51系统扩展 一、程序存储器扩展
VHDL 硬體描述語言 數位電路設計實務 第六章 函數副程序以及套件程式庫.
EDA原理及应用 何宾
使用VHDL設計—4位元減法器 通訊一甲 B 楊穎穆.
EDA原理及应用 何宾
第九章 数字系统设计 数字系统设计概述 ASM图、MDS图以及 ASM图至MDS图的转换 数字密码引爆器系统设计 数字系统设计实例 小结.
欢迎参加VHDL培训 VHDL培训教程 浙江大学电子信息技术研究所 电子设计自动化(EDA)培训中心
第13章 数字电路基础 13.1 数字电路概述 13.2 数字电路中的数值与码制 13.3 逻辑代数 13.4 逻辑门电路
使用VHDL設計—向上&向下計數器 通訊一甲 B 楊穎穆.
使用VHDL設計-XOR_GATE 通訊一甲 B 楊穎穆.
Danny Mok Altera HK FAE AHDL培训教材 Danny Mok Altera HK FAE 2018/12/9 P.1.
EDA 技术及应用 实验安排.
第2章 Quartus II设计向导 2.1 频率计的VHDL设计 2.2 使用宏功能块设计频率计 2.3 嵌入式系统块ESB的应用
第14章 其它DSP设计库 14.1 总线控制库 14.2 复数信号库 14.3 Gates库 14.4 状态机函数库
本 章 重 点 单片机的简单I/O扩展 8255A可编程并口芯片 8279可编程键盘/显示器接口芯片 单片机键盘接口技术
单片机原理 单 片 机 单片机接口技术 单片机应用技术.
使用VHDL設計--Moore Machine
JTAG INTERFACE SRAM TESTER WITH C-LCM
陳慶瀚 機器智慧與自動化技術(MIAT)實驗室 國立中央大學資工系 2013年5月28日
EDA 技术实用教程 第 5 章 QuartusII 应用向导.
语法进阶.
第12章 图像边缘检测器的设计与分析 12.1 系统设计要求 12.2 系统设计方案 12.3 主要LPM原理图和VHDL源程序
精简指令集(RISC)CPU的构造原理和设计方法
第 2 章 数字逻辑电路基础 和计算机中的逻辑部件
第五章 VHDL设计基础 本章重点: 本章难点: VHDL程序结构 VHDL的基本数据类型 VHDL的基本描述语句 基本组合逻辑电路设计
義守大學電機工程學系 陳慶瀚 第3章 VHDL Concurrent語法 義守大學電機工程學系 陳慶瀚
第六章 VHDL设计共享.
第五章 VHDL主要描述语句.
移相正弦信号发生器设计 采用直接数字综合器DDS发生器的设计 原理:图1是此电路模型图
義守大學電機工程學系 陳慶瀚 第4章 VHDL Sequential語法 義守大學電機工程學系 陳慶瀚
使用VHDL設計—4位元ALU電路 通訊一甲 B 楊穎穆.
第一次上机安排 第六周 第七周 周一晚(提高1、2,通信001~012) 周二上(通信014~085) 周四上(通信086~154)
第九章 微处理器外部结构和总线操作时序.
抢答器 设计一个2人抢答器。要求如下: 设计任务 1.两人抢答,先抢为有效,用发光二极 管显示是否抢到优先答题权。
计算机学院 数字逻辑实验的要求.
使用VHDL設計 七段顯示器 通訊工程系 一年甲班 姓名 : 蘇建宇 學號 : B
數位邏輯設計 VHDL.
使用VHDL設計-XOR_GATE 通訊一甲 B 楊穎穆.
使用VHDL設計-8x1多工器 通訊一甲 B 楊穎穆.
問題解決與流程圖 高慧君 台北市立南港高中 2006年12月22日.
第7章 VHDL设计应用实例 7.1 8位加法器的设计 7.2 分频电路 7.3 数字秒表的设计.
单片机原理及应用 (C语言版) 第8章 单片机系统扩展
使用VHDL設計-七段顯示 通訊一甲 B 楊穎穆.
陳慶瀚 機器智慧與自動化技術(MIAT)實驗室 國立中央大學資工系 2009年10月22日
按键处理部分 王安然.
Programmable Logic System Design
陳慶瀚 機器智慧與自動化技術(MIAT)實驗室 國立中央大學資工系 2013年5月28日
第七章 基本逻辑电路设计.
Programmable Logic System Design
Presentation transcript:

第6章 VHDL设计应用实例 6.1 8位加法器的设计 6.3 序列检测器的设计 6.4 正负脉宽数控调制信号发生器的设计 6.1 8位加法器的设计 6.3 序列检测器的设计 6.4 正负脉宽数控调制信号发生器的设计 6.5 数字频率计的设计 6.6 数字秒表的设计

本设计中的8位二进制并行加法器即是由两个4位二进制并行加法器级联而成的,其电路原理图如图6.1所示。 6.1 8位加法器的设计 1.设计思路 多位加法器由4位二进制并行加法器级联构成是较好选择。 本设计中的8位二进制并行加法器即是由两个4位二进制并行加法器级联而成的,其电路原理图如图6.1所示。

图6.1 8位加法器电路原理图

2.VHDL源程序 1) 4位二进制并行加法器的源程序ADDER4B.VHD LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; USE IEEE.STD_LOGIC_UNSIGNED.ALL; ENTITY ADDER4B IS --4位二进制并行加法器 PORT(C4: IN STD_LOGIC; --低位来的进位

A4: IN STD_LOGIC_VECTOR(3 DOWNTO 0); --4位加数 B4: IN STD_LOGIC_VECTOR(3 DOWNTO 0); --4位被加数 S4: OUT STD_LOGIC_VECTOR(3 DOWNTO 0);--4位和 CO4: OUT STD_LOGIC); --进位输出 END ENTITY ADDER4B; ARCHITECTURE ART OF ADDER4B IS SIGNAL S5:STD_LOGIC_VECTOR(4 DOWNTO 0); --中间结果 SIGNAL A5,B5: STD_LOGIC_VECTOR(4 DOWNTO 0); --扩展加数以及被加数位

BEGIN A5<='0'& A4; --将4位加数矢量扩为5位,为进位提供空间 B5<='0'& B4; --将4位被加数矢量扩为5位,为进位提供空间 S5<=A5+B5+C4 ; S4<=S5(3 DOWNTO 0); --四位和给S4 CO4<=S5(4); --进位给CO4 END ARCHITECTURE ART;

2) 8位二进制加法器的源程序ADDER8B.VHD LIBRARY IEEE; USE IEEE.STE_LOGIC_1164.ALL; USE IEEE.STD_LOGIC_UNSIGNED.ALL: ENTITY ADDER8B IS --由4位二进制并行加法器级联而成的8位二进制加法器 PORT(C8:IN STD_LOGIC; A8:IN STD_LOGIC_VECTOR(7 DOWNTO 0); B8:IN STD_LOGIC_VECTOR(7 DOWNTO 0);

S8:OUT STD_LOGIC_VECTOR(7 DOWNTO 0); CO8:OUT STD_LOGIC); END ENTITY ADDER8B; ARCHITECTURE ART OF ADDER8B IS COMPONENT ADDER4B IS --对要调用的元件ADDER4B的界面端口进行定义 PORT(C4:IN STD_LOGIC; A4:IN STD_LOGIC_VECTOR(3 DOWNTO 0);

B4:IN STD_LOGIC_VECTOR(3 DOWNTO 0); S4:OUT STD_LOGIC_VECTOR(3 DOWNTO 0); CO4:OUT STD_LOGIC); END COMPONENT ADDER4B; SIGNAL SC:STD_LOGIC; --4位加法器的进位标志 BEGIN U1:ADDER4B --例化(安装)一个4位二进制加法器U1 PORT MAP(C4=>C8,A4=>A8(3 DOWNTO 0),B4=>B8(3 DOWNTO0), S4=>S8(3 DOWNTO 0),CO4=>SC);

U2:ADDER4B --例化(安装)一个4位二进制加法器U2 PORT MAP(C4=>SC,A4=>A8(7 DOWNTO 4),B4=>B8(7 DOWNTO 4),S4=>S8 (7 DOWNTO 4),CO4=>CO8); END ARCHITECTURE ART;

6.3 序列检测器的设计 1.设计思路 序列检测器可用于检测一组或多组由二进制码组成的脉冲序列信号。当序列检测器连续收到一组串行二进制码后,如果这组码与检测器中预先设置的码相同,则输出1,否则输出0。如图6.3所示,当一串待检测的串行数据进入检测器后,若此数在每一位的连续检测中都与预置的密码数相同,则输出“A”,否则仍然输出“B”。

图6.3 8位序列检测器逻辑图

2.VHDL源程序 LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; ENTITY CHK IS PORT(DIN:IN STD_LOGIC; --串行输入数据位 CLK,CLR:IN STD_LOGIC; --工作时钟/复位信号 D:IN STD_LOGIC_VECTOR(7 DOWNTO 0); --8位待检测预置数 AB:OUT STD_LOGIC_VECTOR(3 DOWNTO 0)); --检测结果输出

END ENTITY CHK; ARCHITECTURE ART OF CHK IS SIGNAL Q :INTEGER RANGE 0 TO 8;--作为标志位 BEGIN PROCESS ( CLK,CLR) IS IF CLR= '1' THEN Q<=0; ELSIF CLK'EVENT AND CLK= '1' THEN --时钟到来时,判断并处理当前输入的位

CASE Q IS WHEN 0 => IF DIN =D(7) THEN Q<= 1 ;ELSE Q<=0;END IF; WHEN 1 => IF DIN =D(6) THEN Q<= 2 ;ELSE Q<=0;END IF; WHEN 2 => IF DIN =D(5) THEN Q<= 3 ;ELSE Q<=0;END IF; WHEN 3=> IF DIN =D(4) THEN Q<= 4 ;ELSE Q<=0;END IF; WHEN 4 => IF DIN =D(3) THEN Q<= 5 ;ELSE Q<=0;END IF; WHEN 5 => IF DIN =D(2) THEN Q<= 6 ;ELSE Q<=0;END IF; WHEN 6 => IF DIN =D(1) THEN Q<= 7 ;ELSE Q<=0;END IF; WHEN 7 => IF DIN =D(0) THEN Q<= 8 ;ELSE Q<=0;END IF; WHEN OTHERS => Q<=0; END CASE; END IF ; END PROCESS;

PROCESS(Q) IS --检测结果判断输出 BEGIN IF Q= 8 THEN AB<= "1010"; --序列数检测正确,输出“A” ELSE AB<= "1011"; --序列数检测错误,输出“B” END IF ; END PROCESS; END ARCHITECTURE ART;

6.4 正负脉宽数控调制信号发生器的设计 1.设计思路 图6.4 是脉宽数控调制信号发生器逻辑图,此信号发生器是由两个完全相同的可自加载加法计数器LCNT8组成的,它的输出信号的高低电平脉宽可分别由两组8位预置数进行控制。

图6.4 脉宽数控调制信号发生器逻辑图

2.VHDL源程序 1) 8位可自加载加法计数器的源程序LCNT8.VHD LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; ENTITY LCNT8 IS --8位可自加载加法计数器 PORT(CLK,LD:IN STD_LOGIC; --工作时钟/预置值加载信号 D:IN INTEGER RANGE 0 TO 255 --8位分频预置数 CAO:OUT STD_LOGIC); --计数溢出输出 END ENTITY LCNT8;

ARCHITECTURE ART OF LCNT8 IS SIGNAL COUNT:INTEGER RANGE 0 TO 255; --8位计数器设置 BEGIN PROCESS ( CLK ) IS IF CLK'EVENT AND CLK= '1' THEN IF LD= '1' THEN COUNT<=D; --LD为高电平时加载预置数

ELSE COUNT<=COUNT+1; --否则继续计数 END IF; END PROCESS;

PROCESS (CLK, COUNT) IS BEGIN IF CLK'EVENT AND CLK='1' THEN IF COUNT=255 THEN CAO<= '1';ELSE CAO<= '0'; END IF; END IF; END PROCESS; END ARCHITECTURE ART;

2) 正负脉宽数控调制信号发生器的源程序 LIBRARY IEEE --正负脉宽数控调制信号发生器顶层文件 USE IEEE.STD_LOGIC_1164.ALL; ENTITY PULSE IS PORT (CLK:IN STD_LOGIC; --计数时钟 A,B:IN STD_LOGIC_VECTOR(7 DOWNTO 0); --8位计数预置数 PSOUT:OUT STD_LOGIC); --计数溢出并分频输出 END ENTITY PULSE;

ARCHITECTURE ART OF PULSE IS COMPONENT LCNT8 IS PORT(CLK,LD:IN STD_LOGIC; D:IN STD_LOGIC_VECTOR(7 DOWNTO 0); CAO:OUT STD_LOGIC); END COMPONENT LCNT8; SIGNAL CAO1,CAO2 :STD_LOGIC; SIGNAL LD1,LD2 :STD_LOGIC;--计数加载信号中间量

SIGNAL PSINT:STD_LOGIC; BEGIN U1:LCNT8 PORT MAP(CLK=>CLK,LD=>LD1,D=>A,CAO=>CAO1); U2:LCNT8 PORT MAP(CLK=>CLK,LD=>LD2,D=>B,CAO=>CAO2); PROCESS(CAO1,CAO2) IS IF CAO1= ‘1’ THEN PSINT<= ‘0’;--计数溢出信号清0

ELSIF CAO2 'EVENT AND CAO2= '1' THEN PSINT<='1'; END IF; END PROCESS; LD1<=NOT PSINT;LD2<=PSINT;PSOUT<=PSINT; END ARCHITECTURE ART;

6.5 数字频率计的设计 1. 设计思路 图6.5是8位十进制数字频率计的电路逻辑图,它由一个测频控制信号发生器TESTCTL、八个有时钟使能的十进制计数器CNT10、一个32位锁存器REG32B组成。

图6.5 8位十进制数字频率计逻辑图

1) 测频控制信号发生器设计 频率测量的基本原理是计算每秒钟内待测信号的脉冲个数。要使计数使能信号TSTEN能产生一个1秒脉宽的周期信号,对每个计数器CNT10的ENA使能端进行同步控制。 TSTEN为高电平时,计数;低电平时,停止计数,并保持当前值。 测频控制信号发生器的工作时序如图6.6所示。为了产生这个时序图,需建立一个由D触发器构成的二分频器,在每次时钟CLK(1HZ)上沿到来时, TSTEN值翻转,脉宽为1秒,作为闸门信号。

图6.6 测频控制信号发生器工作时序

设置锁存器的好处是,显示的数据稳定,不会由于周期性的清零信号而不断闪烁。 2) 寄存器REG32B设计 设置锁存器的好处是,显示的数据稳定,不会由于周期性的清零信号而不断闪烁。 3) 十进制计数器CNT10的设计 如图6.5所示,此十进制计数器的特殊之处是,有一时钟使能输入端ENA,用于锁定计数值。当高电平时计数允许,低电平时计数禁止。

2. VHDL源程序 1) 有时钟使能的十进制计数器的源程序CNT10.VHD LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; ENTITY CNT10 IS PORT (CLK:IN STD_LOGIC; --计数时钟信号 CLR:IN STD_LOGIC; --清零信号 ENA:IN STD_LOGIC; --计数使能信号 CQ:OUT INTEGER RANGE 0 TO 15;--4位计数结果输出 CARRY_OUT:OUT STD_LOGIC); --计数进位输出

END ENTITY CNT10; ARCHITECTURE ART OF CNT10 IS SIGNAL CQI :INTEGER RANGE 0 TO 15; BEGIN PROCESS(CLK,CLR,ENA) IS IF CLR= '1' THEN CQI<= 0; --计数器异步清零 ELSIF CLK'EVENT AND CLK= '1' THEN IF ENA= '1' THEN

IF CQI<9 THEN CQI<=CQI+1; ELSE CQI<=0;END IF;--等于9,则计数器清零 END IF; END PROCESS; PROCESS (CQI) IS BEGIN IF CQI=9 THEN CARRY_OUT<= '1'; --进位输出 ELSE CARRY_OUT<= '0';END IF; CQ<=CQI; END ARCHITECTURE ART;

2) 32位锁存器的源程序REG32B.VHD LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; ENTITY REG32B IS PORT(LOAD:IN STD_LOGIC; DIN:IN STD_LOGIC_VECTOR(31 DOWNTO 0); DOUT:OUT STD_LOGEC_VECTOR(31 DOWNTO 0)); END ENTITY REG32B;

ARCHITECTURE ART OF REG32B IS BEGIN PROCESS ( LOAD, DIN ) IS IF LOAD 'EVENT AND LOAD= '1' THEN DOUT<=DIN; --锁存输入数据 END IF; END PROCESS; END ARCHITECTURE ART;

3) 测频控制信号发生器的源程序TESTCTL.VHD LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; USE IEEE.STD_LOGIC_UNSIGNED.ALL ENTITY TESTCTL IS PORT (CLK:IN STD_LOGIC; --1 Hz测频控制时钟 TSTEN:OUT STD_LOGIC; --计数器时钟使能 CLR_CNT:OUT STD_LOGIC; --计数器清零 LOAD:OUT STD_LOGIC); --输出锁存信号

END ENTITY TESTCTL; ARCHITECTURE ART OF TESTCTL IS SIGNAL DIV2CLK :STD_LOGIC; BEGIN PROCESS ( CLK ) IS IF CLK'EVENT AND CLK= '1' THEN DIV2CLK<=NOT DIV2CLK;--1 HZ时钟二分频 END IF ;

END PROCESS; PROCESS ( CLK,DIV2CLK ) IS BEGIN IF CLK= '0' AND DIV2CLK = '0' THEN CLR_CNT<= ‘1’; --0.5S后产生计数器清零信号 ELSE CLR_CNT<= '0' ; END IF; LOAD<=NOT DIV2CLK; TSTEN<=DIV2CLK; --根据时序图来确定 END ARCHITECTURE ART;

4) 数字频率计的源程序FREQ.VHD LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; ENTITY FREQ IS PORT(FSIN:IN STD_LOGIC; CLK:IN STD_LOGIC; DOUT:OUT STD_LOGIC_VECTOR(31 DOWNTO 0)); END ENTITY FREQ; ARCHITECTURE ART OF FREQ IS

COMPONENT CNT10 IS --待调用的有时钟使能的十进制计数器端口定义 PORT(CLK,CLR,ENA:IN STD_LOGIC; CQ:OUT STD_LOGIC_VECTOR(3 DOWNTO 0); CARRY_OUT:OUT STD_LOGIC); END COMPONENT CNT10; COMPONENT REG32B IS --待调用的32位锁存器端口定义   ... COMPONENT TESTCTL IS --待调用的测频控制信号发生器端口定义

... SIGNAL SE,SC,SL:STD_LOGIC; SIGNAL S1,S2,S3,S4,S5,S6,S7,S7,S8:STD_LOGIC; SIGNAL SD:STD_LOGIC_VECTOR(31 DOWNTO 0); BEGIN U0:TESTCTL PORT MAP(CLK=>CLK,TSTEN=>SE, CLR_CNT=>SC,LOAD=>SL); U1:CNT10 PORT MAP(CLK=>FSIN,CLR=>SC,ENA=>SE,CQ=>SD (3 DOWNTO 0), CARRY_OUT=>S1); --名字关联

U2:CNT10 PORT MAP(CLK=>S1,CLR=>SC,ENA=>SE, CQ=>SD (7 DOWNTO 4),CARRY_OUT=>S2); U3:CNT10 PORT MAP(S2,SC,SE,SD (11 DOWNTO 8 ),S3); --位置关联 U4:CNT10 PORT MAP(S3,SC,SE,SD (15 DOWNTO 12),S4); U5:CNT10 PORT MAP(S4,SC,SE,SD (19 DOWNTO 16),S5); U6:CNT10 PORT MAP(S5,SC,SE,SD (23 DOWNTO 20),S6); U7:CNT10 PORT MAP(S6,SC,SE,SD (27 DOWNTO 24),S7); U8:CNT10 PORT MAP(S7,SC,SE,SD (31 DOWNTO 28),S8); U9:REG32B PORT MAP(LOAD=>SL,DIN=>SD(31 DOWNTO 0),DOUT=>DOUT); END ARCHITECTURE ART;

6.6 数字秒表的设计 1.设计思路 设计一个计时范围为0.01秒~1小时的数字秒表, 因此要有一个比较精确的计时基准信号,这里用周期为1/100 s的计时脉冲。对每一计数器需设置CLR清零信号输入外,并在六个计数器设置时钟使能信号ENA,即计时允许信号。因此数字秒表可由一个分频器、四个十进制计数器(1/100秒、1/10秒、1秒、1分)以及两个六进制计数器(10秒、10分)组成,如图6.7所示。

图6. 7中六个4位二进制计数输出的最小显示值分别为:DOUT[3. 0]1/100秒、DOUT[7. 4]1/10秒、DOUT[11 图6.7中六个4位二进制计数输出的最小显示值分别为:DOUT[3..0]1/100秒、DOUT[7..4]1/10秒、DOUT[11..8]1秒、DOUT[15..12]10秒、DOUT[19..16]1分、DOUT[23..20]10分。

图6.7 数字秒表电路逻辑图

2. VHDL源程序 1) 3 MHz→100 Hz分频器的源程序CLKGEN.VHD LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; ENTITY CLKGEN IS PORT (CLK:IN STD_LOGIC; --3 MHz信号输入 NEWCLK:OUT STD_LOGIC); --100 Hz计时时钟信号输出 END ENTITY CLKGEN;

ARCHITECTURE ART OF CLKGEN IS SIGNAL CNTER:INTEGER RANGE 0 TO 10#29999#; --十进制计数预制数 BEGIN PROCESS(CLK) IS --分频计数器,由3 MHz时钟产生100 Hz信号 BEGIN IS IF CLK’EVENT AND CLK='1' THEN IF CNTER=10#29999# THEN CNTER<=0; --3 MHz信号变为100 Hz,计数常数为30000

ELSE CNTER<=CNTER+1; END IF; END PROCESS; PROCESS(CNTER) IS --计数溢出信号控制 BEGIN IF CNTER=10#29999# THEN NEWCLK<='1'; ELSE NEWCLK<='0'; END ARCHITECTURE ART;

2) 六进制计数器的源程序CNT6.VHD(十进制计数器的源程序CNT10.VHD与此类似) LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; USE IEEE.STD_LOGIC_UNSIGNED.ALL; ENTITY CNT6 IS PORT (CLK:IN STD_LOGIC; CLR:IN STD_LOGIC; ENA: IN STD_LOGIC; CQ:OUT STD_LOGIC_VECTOR(3 DOWNTO 0); CARRY_OUT: OUT STD_LOGIC );

END ENTITY CNT6; ARCHITECTURE ART OF CNT6 IS SIGNAL CQI:STD_LOGIC_VECTOR(3 DOWNTO 0); BEGIN PROCESS(CLK,CLR,ENA) IS IF CLR='1' THEN CQI<="0000"; ELSIF CLK'EVENT AND CLK='1' THEN IF ENA='1' THEN IF CQI=“0101” THEN CQI<=“0000”;---六进制为0101 十进制计数器为1001 ELSE CQI<=CQI+'1';END IF; END IF;

END IF; END PROCESS; PROCESS(CQI) IS BEGIN IF CQI=“0000” THEN CARRY_OUT<='1'; ELSE CARRY_OUT<='0';END IF; CQ<=CQI; END ARCHITECTURE ART;

3) 数字秒表的源程序TIMES.VHD LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; ENTITY TIMES IS PORT(CLR:IN STD_LOGIC; CLK:IN STD_LOGIC; ENA:IN STD_LOGIC; DOUT:OUT STD_LOGIC_VECTOR(23 DOWNTO 0)); END ENTITY TIMES; ARCHITECTURE ART OF TIMES IS

COMPONENT CLKGEN IS PORT(CLK:IN STD_LOGIC; NEWCLK:OUT STD_LOGIC); END COMPONENT CLKGEN; COMPONENT CNT10 IS PORT(CLK,CLR,ENA:IN STD_LOGIC; CQ:OUT STD_LOGIC_VECTOR(3 DOWNTO 0); CARRY_OUT:OUT STD_LOGIC);

END COMPONENT CNT10; COMPONENT CNT6 IS PORT(CLK,CLR,ENA:IN STD_LOGIC; CQ:OUT STD_LOGIC_VECTOR(3 DOWNTO 0); CARRY_OUT:OUT STD_LOGIC); END COMPONENT CNT6; SIGNAL S0:STD_LOGIC; SIGNAL S1,S2,S3,S4,S5:STD_LOGIC; BEGIN

U0:CLKGEN PORT MAP(CLK=>CLK,NEWCLK=>S0); --名字关联 U1:CNT10 PORT MAP(S0, CLR, ENA, DOUT(3 DOWNTO 0),S1); --位置关联 U2:CNT10 PORT MAP(S1, CLR, ENA, DOUT(7 DOWNTO 4),S2); U3:CNT10 PORT MAP(S2, CLR, ENA, DOUT(11 DOWNTO 8),S3); U4:CNT6 PORT MAP(S3, CLR, ENA, DOUT(15 DOWNTO 12),S4); U5:CNT10 PORT MAP(S4, CLR, ENA, DOUT(19 DOWNTO 16),S5); U6:CNT6 PORT MAP(S5, CLR, ENA, DOUT(23 DOWNTO 20)); END ARCHITECTURE ART;

6.7 MCS-51单片机与FPGA/CPLD总线接口逻辑设计 单片机具有性能价格比高、功能灵活、易于人机对话和良好的数据处理能力等特点;PLD则具有高速、高可靠以及开发便捷规范等方面的优点,以此两类器件相结合的电路结构在许多高性能仪器仪表和电子产品中被广泛应用。单片机与CPLD的接口方式一般有两种,即总线方式与独立方式。

单片机以总线方式与FPGA/CPLD进行数据与控制信息通信有许多优点: (1) 速度快。其通信工作时序是纯硬件行为,对于MCS-51单片机,只需一条单字节指令就能完成所需的读/写时序,如:MOV @DPTR,A;MOV A,@DPTR。 (2) 节省PLD芯片的I/O口线。如图6.8,如果将图中的译码DECODER设置足够的译码输出,以及安排足够的锁存器,就能仅通过19根I/O口线在FPGA/CPLD与单片机之间进行各种类型的数据与控制信息交换。

图6.8 CPLD/FPGA与MCS-51单片机的总线接口通信逻辑图

(3) 相对于非总线方式,单片机的编程便捷,控制可靠。 (4) 在FPGA/CPLD中通过逻辑切换,单片机易于与SRAM或ROM接口。这种方式有许多实用之处,如利用类似于微处理器DMA的工作方法,首先由FPGA/CPLD与接口的高速A/D等器件进行高速数据采样,并将数据暂存于SRAM中,采样结束后,通过切换,使单片机与SRAM以总线方式进行数据通信,以便发挥单片机强大的数据处理能力。

1.设计思路 对单片机与FPGA/CPLD以总线方式通信的逻辑设计, 应详细了解单片机的总线读/写时序,根据时序图来设计逻辑结构。图6.9是MCS-51系列单片机的时序图,其时序电平变化速度与单片机工作时钟频率有关。

图6.9 MCS-51单片机总线接口方式工作时序

2. VHDL源程序 LIBRARY IEEE; --MCS-51单片机读/写电路 USE IEEE.STD_LOGIC_1164.ALL; ENTITY MCS_51 IS PORT( --与8031接口的各端口定义: P0:INOUT STD_LOGIC_VECTOR(7 DOWNTO 0); --双向地址/数据口 P2:IN STD_LOGIC_VECTOR(7 DOWNTO 0); --高8位地址线 RD,WR:IN STD_LOGIC; --读、写允许

ALE:IN STD_LOGIC; -- 地址锁存 READY:IN STD_LOGIC; --待读入数据准备就绪标志位 AD_CS:OUT STD_LOGIC; --A/D器件片选信号 DATAIN1:IN STD_LOGIC_VECTOR(7 DOWNTO 0); --单片机待读回信号 LATCH1:IN STD_LOGIC; --读回信号锁存 DATOUT1:OUT STD_LOGIC_VECTOR(7 DOWNTO 0); --锁存输出数据1 DATOUT2:OUT STD_LOGIC_VECTOR(7 DOWNTO 0)); --锁存输出数据2 END ENTITY MCS_51;

ARCHITECTURE ART OF MCS_51 IS SIGNAL LATCH_ADDRES:STD_LOGIC_VECTOR(7 DOWNTO 0); SIGNAL LATCH_OUT1:STD_LOGIC_VECTOR(7 DOWNTO 0); SIGNAL LATCH_OUT2:STD_LOGIC_VECTOR(7 DOWNTO 0); SIGNAL LATCH_IN1:STD_LOGIC_VECTOR(7 DOWNTO 0); SIGNAL WR_ENABLE1:STD_LOGIC; SIGNAL WR_ENABLE2:STD_LOGIC;

BEGIN PROCESS ( ALE ) IS --低8位地址锁存进程 IF ALE'EVENT AND ALE= '0' THEN LATCH_ADDRES<=P0; --ALE的下降沿将P0口的低8位地址 END IF; --锁入锁存器LATCH_ADDRES中 END PROCESS;

PROCESS(P2,LATCH_ADDRES) IS --WR写信号译码进程1 BEGIN IF ( LATCH_ADDRES= "11110101") AND ( P2= "01101111" ) THEN WR_ENABLE1<=WR; --写允许 ELSE WR_ENABLE1<= '1'; END IF ; --写禁止 END PROCESS; PROCESS ( WR_ENABLE1 ) IS --数据写入寄存器1

BEGIN IF WR_ENABLE1'EVENT AND WR_ENABLE1 = '1' THEN LATCH_OUT1<= P0; END IF; END PROCESS; PROCESS (P2,LATCH_ADDRES ) IS --WR写信号译码进程2 IF ( LATCH_ADDRES= "11110011")AND(P2= "00011111" ) THEN WR_ENABLE2<= WR; --写允许 ELSE WR_ ENABLE2<= '1';END IF; --写禁止

END PROCESS; PROCESS (WR_ENABLE2 ) IS --数据写入寄存器2 BEGIN IF WR_ENABLE2'EVENT AND WR_ENABLE2= '1' THEN LATCH_OUT2<=P0; END IF; PROCESS(P2,LATCH_ADDRES,READY,RD) IS --8031对PLD中数据读入进程

BEGIN IF ( LATCH_ADDRES= "01111110" ) AND ( P2= "10011111" ) AND ( READY= '1') AND ( RD= '0' ) THEN P0<=LATCH_IN1; --寄存器中的数据读入P0口 ELSE P0<= "ZZZZZZZZ";END IF ; --禁止读数,P0口呈高阻态 END PROCESS; PROCESS(LATCH1 ) IS --外部数据进入CPLD进程

BEGIN IF LATCH1'EVENT AND LATCH1= '1' THEN LATCH_IN1<=DATAIN1; END IF; END PROCESS; PROCESS(LATCH_ADDRES) IS --A/D工作控制片选信号输出进程

IF ( LATCH_ADDRES= "00011110" ) THEN AD_CS<= '0'; --允许A/D工作 ELSE AD_CS<= '1'; END IF; -- 禁止A/D工作 END PROCESS; DATOUT1<=LATCH_OUT1; DATOUT2<=LATCH_OUT2; END ARCHITECTURE ART;

这是一个CPLD与8031单片机接口的VHDL电路设计。8031以总线方式工作,例如,由8031将数据5AH写入目标器件中的第一个寄存器LATCH_OUT1的指令是: MOV A,#5AH MOV DPTR,#6FF5H MOVX @DPTR,A 当READY为高电平时,8031从目标器件中的寄存器LATCH_IN1将数据读入的指令是: MOV DPTR,#9F7EH MOVX A,@DPTR

3. 硬件逻辑验证 请读者根据前述方法自行完成硬件逻辑验证工作。

6.8 交通灯信号控制器的设计 1.设计思路 欲设计一个由一条主干道和一条支干道的汇合点形成的十字交叉路口的交通灯控制器,具体要求如下: 6.8 交通灯信号控制器的设计 1.设计思路 欲设计一个由一条主干道和一条支干道的汇合点形成的十字交叉路口的交通灯控制器,具体要求如下: (1) 主、支干道各设有一个绿、黄、红指示灯,两个显示数码管。 (2) 主干道处于常允许通行状态,而支干道有车来才允许通行。当主干道允许通行亮绿灯时,支干道亮红灯。而支干道允许通行亮绿灯时,主干道亮红灯。

(3) 当主、支道均有车时,两者交替允许通行,主干道每次放行45 s,支干道每次放行25 s,在每次由亮绿灯变成亮红灯的转换过程中,要亮5 s的黄灯作为过渡,并进行减计时显示。整个交通控制器的内部逻辑结构原理如图6.10所示。

图6.10 交通控制器的内部逻辑结构原理图

2 VHDL源程序 --JTDKZ.VHD LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL;   ENTITY JTDKZ IS PORT(CLK,SM,SB:IN STD_LOGIC; MR,MY0,MG0,BR,BY0,BG0: OUT STD_LOGIC); END ENTITY JTDKZ;

ARCHITECTURE ART OF JTDKZ IS TYPE STATE_TYPE IS(A,B,C,D); SIGNAL STATE: STATE_TYPE; BEGIN CNT:PROCESS(CLK) IS VARIABLE S:INTEGER RANGE 0 TO 45; VARIABLE CLR,EN:BIT;

BEGIN IF(CLK'EVENT AND CLK='1')THEN IF CLR='0'THEN S:=0; ELSIF EN='0' THEN S:=S; ELSE S:=S+1; END IF; CASE STATE IS WHEN A=>MR<='0'; MY0<='0';MG0<='1';BR<='1'; BY0<='0'; BG0<='0'; IF(SB AND SM)= '1' THEN IF S=45 THEN STATE<=B;CLR:= '0'; EN:= '0';

ELSE STATE<=A; CLR:= '1'; EN:= '1'; END IF; ELSIF(SB AND (NOT SM))= '1' THEN STATE<=B;CLR:= '0';EN:= '0'; WHEN B=>MR<='0'; MY0<='1';MG0<='0';BR<='1'; BY0<='0'; BG0<='0'; IF S=5 THEN STATE<=C;CLR:= '0'; EN:= '0'; ELSE STATE<=B; CLR:= '1'; EN:= '1';

END IF; WHEN C=>MR<='1'; MY0<='0';MG0<='0';BR<='0'; BY0<='0'; BG0<='1'; IF(SM AND SB)= '1' THEN IF S=25 THEN STATE<=D;CLR:='0'; EN:= '0'; ELSE STATE<=C; CLR:= '1'; EN:= '1'; ELSIF SB='0' THEN STATE<=D;CLR:= '0'; EN:= '0';

END IF; WHEN D=>MR<='1'; MY0<='0';MG0<='0';BR<='0'; BY0<='1'; BG0<='0'; IF S=5 THEN STATE<=A;CLR:= '0'; EN:= '0'; ELSE STATE<=D; CLR:= '1'; EN:= '1'; END CASE; END PROCESS CNT; END ARCHITECTURE ART;

--CSKZ.VHD LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; USE IEEE.STD_LOGIC_UNSIGNED.ALL;   ENTITY CSKZ IS PORT(INA:IN STD_LOGIC; OUTA: OUT STD_LOGIC); END ENTITY CSKZ;

ARCHITECTURE ART OF CSKZ IS BEGIN PROCESS(INA) IS IF INA='1' THEN OUTA<='1'; ELSE OUTA<='0'; END IF; END PROCESS; END ARCHITECTURE ART;

--CNT45S.VHD LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; USE IEEE.STD_LOGIC_UNSIGNED.ALL;   ENTITY CNT45S IS PORT(SB,CLK,EN45:IN STD_LOGIC; DOUT45M,DOUT45B: OUT STD_LOGIC_VECTOR(7 DOWNTO 0)); END ENTITY CNT45S ;

ARCHITECTURE ART OF CNT45S IS SIGNAL CNT6B: STD_LOGIC_VECTOR(5 DOWNTO 0); BEGIN PROCESS(SB,CLK,EN45) IS IF SB='0' THEN CNT6B<=CNT6B-CNT6B-1; ELSIF(CLK'EVENT AND CLK= '1')THEN IF EN45='1' THEN CNT6B<=CNT6B+1;

ELSIF EN45='0' THEN CNT6B<=CNT6B-CNT6B-1; END IF; END PROCESS; PROCESS(CNT6B) IS BEGIN CASE CNT6B IS WHEN "000000"=>DOUT45M<="01000101";DOUT45B<="01010000"; WHEN "000001"=>DOUT45M<="01000100";DOUT45B<="01001001";

WHEN "000010"=>DOUT45M<="01000011";DOUT45B<="01001000";

WHEN "001101"=>DOUT45M<="00110010";DOUT45B<="00110111";

WHEN "011010"=>DOUT45M<="00011001";DOUT45B<="00100100";

WHEN "100110"=>DOUT45M<="00000111";DOUT45B<="00010010"; WHEN OTHERS=>DOUT45M<="00000000";DOUT45B<="00000000";

END CASE; END PROCESS; END ARCHITECTURE ART;   --CNT05S.VHD LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; USE IEEE.STD_LOGIC_UNSIGNED.ALL;

ENTITY CNT05S IS PORT(CLK,EN05M,EN05B:IN STD_LOGIC; DOUT5: OUT STD_LOGIC_VECTOR(7 DOWNTO 0)); END ENTITY CNT05S;   ARCHITECTURE ART OF CNT05S IS SIGNAL CNT3B: STD_LOGIC_VECTOR(2 DOWNTO 0); BEGIN PROCESS(CLK,EN05M,EN05B) IS

BEGIN IF(CLK'EVENT AND CLK= '1')THEN IF EN05M='1' 'THEN CNT3B<=CNT3B+1; ELSIF EN05B='1' THEN CNT3B<=CNT3B+1; ELSIF EN05B='0' THEN CNT3B<=CNT3B-CNT3B-1; END IF; END PROCESS; PROCESS(CNT3B) IS

BEGIN CASE CNT3B IS WHEN "000"=>DOUT5<="00000101"; WHEN "001"=>DOUT5<="00000100'; WHEN "010"=>DOUT5<="00000011"; WHEN "011"=>DOUT5<="00000010"; WHEN "100"=>DOUT5<="00000001"; WHEN OTHERS=>DOUT5<="00000000'; END CASE; END PROCESS; END ARCHITECTURE ART;

--CNT25S.VHD LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; USE IEEE.STD_LOGIC_UNSIGNED.ALL; ENTITY CNT25S IS PORT(SB,SM,CLK,EN25:IN STD_LOGIC; DOUT25M,DOUT25B: OUT STD_LOGIC_VECTOR(7 DOWNTO 0)); END ENTITY CNT25S;

ARCHITECTURE ART OF CNT25S IS SIGNAL CNT5B: STD_LOGIC_VECTOR(4 DOWNTO 0); BEGIN PROCESS(SB,SM,CLK,EN25) IS IF SB='0' THEN CNT5B<=CNT5B-CNT5B-1; ELSIF SM='0'' THEN CNT5B<=CNT5B-CNT5B-1; ELSIF(CLK'EVENT AND CLK= '1')THEN IF EN25='1' THEN CNT5B<=CNT5B+1; ELSIF EN25='0' THEN CNT5B<=CNT5B-CNT5B-1; END IF;

END IF; END PROCESS; PROCESS(CNT5B) IS BEGIN CASE CNT5B IS WHEN "00000"=>DOUT25B<="00100101";DOUT25M<="00110000"; WHEN "00001"=>DOUT25B<="00100100";DOUT25M<="00101001"; WHEN "00010"=>DOUT25B<="00100011";DOUT25M<="00101000"; WHEN "00011"=>DOUT25B<="00100010";DOUT25M<="00100111"; WHEN "00100"=>DOUT25B<="00100001";DOUT25M<="00100110";

WHEN "00101"=>DOUT25B<="00100000";DOUT25M<="00100101";

WHEN "10001"=>DOUT25B<="00001000";DOUT25M<="00010011"; WHEN OTHERS=>DOUT25B<="00000000";DOUT25M<="00000000";

END CASE; END PROCESS; END ARCHITECTURE ART;   --XSKZ.VHD LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; USE IEEE.STD_LOGIC_UNSIGNED.ALL;

ENTITY XSKZ IS PORT(EN45,EN25,EN05M,EN05B:IN STD_LOGIC; AIN45M,AIN45B,AIN25M,AIN25B,AIN05: IN STD_LOGIC_VECTOR(7 DOWNTO 0); DOUTM,DOUTB: OUT STD_LOGIC_VECTOR(7 DOWNTO 0)); END ENTITY XSKZ; ARCHITECTURE ART OF XSKZ IS BEGIN PROCESS(EN45,EN25,EN05M,EN05B,AIN45M,AIN45B,AIN25M,AIN25B,AIN05) IS

IF EN45=' 1' THEN DOUTM<=AIN45M(7 DOWNTO 0);DOUTB<=AIN45B(7 DOWNTO 0); ELSIF EN05M='1' THEN DOUTM<=AIN05(7 DOWNTO 0);DOUTB<=AIN05(7 DOWNTO 0); ELSIF EN25='1' THEN DOUTM<=AIN25M(7 DOWNTO 0);DOUTB<=AIN25B (7 DOWNTO 0); ELSIF EN05B='1'THEN DOUTM<=AIN05(7 DOWNTO 0);DOUTB<=AIN05(7 DOWNTO 0); END IF; END PROCESS; END ARCHITECTURE ART;

--YMQ.VHD LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; USE IEEE.STD_LOGIC_UNSIGNED.ALL;   ENTITY YMQ IS PORT(AIN4:IN STD_LOGIC_VECTOR(3 DOWNTO 0); DOUT7: OUT STD_LOGIC_VECTOR(6 DOWNTO 0)); END ENTITY YMQ;

ARCHITECTURE ART OF YMQ IS BEGIN PROCESS(AIN4) IS CASE AIN4 IS WHEN "0000"=>DOUT7<="0111111"; WHEN "0001"=>DOUT7<="0000110"; WHEN "0010"=>DOUT7<="1011011"; WHEN "0011"=>DOUT7<="1001111"; WHEN "0100"=>DOUT7<="1100110"; WHEN "0101"=>DOUT7<="1101101";

WHEN "0110"=>DOUT7<="1111101"; WHEN "0111"=>DOUT7<="0000111"; WHEN "1000"=>DOUT7<="1111111"; WHEN "1001"=>DOUT7<="1101111"; WHEN OTHERS=>DOUT7<="0000000"; END CASE; END PROCESS; END ARCHITECTURE ART;

--JTKZQ.VHD LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL;   ENTITY JTKZQ IS PORT(CLK,SM,SB:IN STD_LOGIC; MR,MG,MY,BY,BR,BG: OUT STD_LOGIC; DOUT1,DOUT2,DOUT3,DOUT4:OUT STD_LOGIC_VECTOR(6 DOWNTO 0)); END ENTITY JTKZQ;

ARCHITECTURE ART OF JTKZQ IS COMPONENT JTDKZ IS PORT(CLK,SM,SB:IN STD_LOGIC; MR,MY0,MG0,BY0,BG0,BR: OUT STD_LOGIC); END COMPONENT JTDKZ; ...... SIGNAL EN1,EN2,EN3,EN4:STD_LOGIC; SIGNAL S45M,S45B,S05,S25M,S25B:STD_LOGIC_VECTOR(7 DOWNTO 0); SIGNAL YM1,YM2,YM3,YM4:STD_LOGIC_VECTOR(3 DOWNTO 0);

BEGIN U1:JTDKZ PORT MAP(CLK=>CLK, SM=>SM, SB=>SB,MR=>MR,MY0=>EN2,MG0=>EN1, BR=>BR,BY0=>EN4,BG0=>EN3); U2:CSKZ PORT MAP(INA=>EN1,OUTA=>MG); U3:CSKZ PORT MAP(INA=>EN2,OUTA=>MY); U4:CSKZ PORT MAP(INA=>EN3,OUTA=>BG); U5:CSKZ PORT MAP(INA=>EN4,OUTA=>BY); U6:CNT45S PORT MAP(CLK=>CLK,SB=>SB, EN45=>EN1,DOUT45M=>S45M,DOUT45B=>S45B); U7:CNT05S PORT MAP(CLK=>CLK, EN05M=>EN2,DOUT5=>S05,EN05B=>EN4);

U8:CNT25S PORT MAP(CLK=>CLK,SM=>SM,SB=>SB,EN25=>EN3,DOUT25M=>S25M,DOUT25B=>S25B); U9:XSKZ PORT MAP(EN45=>EN1,EN05M=>EN2,EN25=>EN3,EN05B=>EN4, AIN45M=>S45M,AIN45B=>S45B,AIN25M=>S25M,AIN25B=>S25B,AIN05=>S05, DOUTM(3 DOWNTO 0)=>YM1,DOUTM(7 DOWNTO 4)=>YM2, DOUTB(3 DOWNTO 0)=>YM3,DOUTB(7 DOWNTO 4)=>YM4);

U10:YMQ PORT MAP(AIN4=>YM1,DOUT7=>DOUT1); END ARCHITECTURE ART;

3. 硬件逻辑验证 选择实验电路结构图NO.6,由5.2节的实验电路结构图NO.6和图6.10确定引脚的锁定。时钟脉冲CLK可接CLOCK1(1 Hz);主干道和支干道来车信号SM、SB分别接键3和键4;主干道和支干道红、黄、绿灯驱动信号MR、MY、MG和BR、BY、BG分别接D1~D3和D8~D6;DOUT1、DOUT2驱动数码管5和数码管6显示主干道定时时间;DOUT3、DOUT4驱动数码管7和数码管8显示支干道定时时间。

6.9 语音信箱控制系统的设计 1.设计思路 语音信箱控制系统用于控制对语音信箱的有关操作,允许用户发送信息、重阅信息、存储信息和擦除信息,状态转移图如图6.11所示。

图6.11 语音信箱控制器的状态转移图

2. VHDL源程序 PACKAGE VM_PACK IS TYPE T_VM_STATE IS(MAIN_ST,REVIEW_ST, REPEAT_ST,SAVE_ST, ERASE_ST,SEND_ST,ADDRESS_ST,RECORD_ST, BEGIN_REC_ST,MESSAGE_ST); TYPE T_KEY('1','2','3','4','5','6','7','8','9','*','#'); END PACKAGE VM_PACK; LIBRARY IEEE;

USE WORK.VM_PACK,ALL; USE IEEE.STD_LOGIC_1164.ALL; ENTITY CONTROL IS PORT(CLK,KEY:IN STD_LOGIC; PLAY,RECORD,ERASE,SAVE,ADDRESS:OUT STD_LOGIC); END ENTITY CONTROL; ARCHITECTURE ART OF CONTROL IS SIGNAL NEXT_STATE,CURRENT_STATE:T_VM_STATE;

BEGIN PROCESS(CURRENT_STATE,KEY) IS PLAY<= '0';SAVE <= '0';ERASE<= '0'; RECORD<= '0';ADDRESS<= '0'; CASE CURRENT_STATE IS WHEN MAIN_ST => --看信箱 IF ( KEY='1') THEN NEXT_STATE<=REVIEW_ST; --转到重阅

ELSIF (KEY ='2') THEN NEXT_STATE<=SEND_ST ; --转到发送 ELSE NEXT_STATE<=MAIN_ST; END IF; WHEN REVIEW_ST=> --重阅 IF (KEY='1')THEN NEXT_STATE<=REPEAT_ST; ELSIF(KEY='2') THEN NEXT_STATE<=SAVE_ST; ELSIF( KEY = '3') THEN NEXT_STATE <=ERASE_ST;

ELSIF( KEY = '#') THEN NEXT_STATE <=MAIN_ST; ELSE NEXT_STATE<=REVIEW_ST; END IF; WHEN REPEAT_ST => --重复 PLAY<= '1'; NEXT_STATE<=REVIEW_ST; WHEN SAVE_ST => --存信息 SAVE<= '1';

NEXT_STATE<=REVIEW_ST; WHEN ERASE_ST => --擦掉 ERASE<= '1'; WHEN SEND_ST => --发送 NEXT_STATE<=ADDRESS_ST; WHEN ADDRESS_ST => --寻址 ADDRESS<= '1'; IF (KEY='#')THEN NEXT_STATE<=RECORD_ST;

ELSE NEXT_STATE<=ADDRESS_ST; END IF ; WHEN RECORD_ST=> --记录 IF (KEY='5') THEN NEXT_STATE<=BEGIN_REC_ST; ELSE NEXT_STATE<=RECORD_ST; END IF; WHEN BEGIN_REC_ST => --开始录音

RECORD<= '1'; NEXT_STATE<=MESSAGE_ST; WHEN MESSAGE_ST=> --记录录音 IF (KEY='#')THEN NEXT_STATE<=SEND_ST; --发送到信箱 ELSE NEXT_STATE<=MESSAGE_ST; END IF; END CASE; END PROCESS;

PROCESS IS BEGIN WAIT UNTIL (CLK'EVENT AND CLK = '1'); CURRENT_STATE<=NEXT_STATE; END PROCESS; END ARCHITECTURE ART;

程序包VM_PACK含有对状态值的类型说明和语音信箱控制系统允许用的键盘。必须指出的是,状态是用来表示某些事件的全过程的,而事件的全过程又是由它所对应状态(如STATE1、STATE2和STATE3 等)来说明的,用状态描述将使模块的可读性更好。

3.硬件逻辑验证 请读者根据前述方法自行完成硬件逻辑验证工作。

6.10 PID控制器的设计 1.设计思路 要求设计一个PID控制器,对电机转速进行采样,与额定的转速进行比较,并通过微积分计算得到电机的控制电流,从而实现对电机转速的调整。通常,PID控制器用模拟电路实现,但数字电路的实现方案可以很方便地实现集成。

该PID控制器包括一个完成算术和逻辑功能的ALU以及一个存储状态变量和有关系数的存储器。其端口说明如图6.12所示。

图6.12 PID控制器示意图

PID控制器的电流计算公式为 Irefk=(Kp+Ek) + Ki×∫Ekdt + Kd×dEk/dt 采用近似的离散方式表示为 Irefk=(Kp+Ek) + Ki×∑Ekdt + Kd×dEk/dt

4.VHDL源程序 1) 浮点运算单元的源程序FPU.VHD PACKAGE OP_PKG IS --定义程序中将要用到的程序包 SUBTYPE INT3BIT IS INTEGER RANGE 0 TO 7; END PACKAGE OP_PKG;   PACKAGE SYNCHRO IS FUNCTION RISING_EDGE(SIGNAL SIG:BIT) RETURN BOOLEAN; END PACKAGE SYNCHRO;

PACKAGE BODY SYNCHRO IS FUNCTION RISING_EDGE(SIGNAL SIG:BIT) RETURN BOOLEAN IS BEGIN RETURN (SIG'EVENT AND SIG='1' AND SIG'LAST_VALUE = '0'); END FUNCTION RISING_EDGE; END PACKAGE BODY SYNCHRO;   USE WORK.OP_PKG.ALL; USE WORK.SYNCHRO.ALL;

ENTITY FPU IS -浮点运算单元FPU的实体说明 PORT(CLOCK : IN BIT; --同步时钟 RESET : IN BIT; --复位信号 INPUT1 : IN REAL; --操作数1 INPUT2 : IN REAL; --操作数2 SEL : IN BIT; --启动信号 COM : IN INT3BIT; --操作类型 OUTPUT : OUT REAL; --结果输出 OUTDONE : OUT BIT); --完成信号

END ENTITY FPU; ARCHITECTURE ART OF FPU IS BEGIN PROCESS IS VARIABLE TMP: REAL; VARIABLE IN1,IN2:REAL; PROCEDURE MUL(A,B : IN REAL) IS TMP := A * B; --此处应该为具体的求乘积算法,为简便起见用A * B代替 END PROCEDURE MUL;

PROCEDURE REP(A: IN REAL) IS BEGIN TMP := 1.0/A; --此处应该为具体的求倒数算法,为简便起见用1.0/A代替 END PROCEDURE REP; WAIT UNTIL CLOCK'EVENT AND CLOCK = '1' AND SEL = '1'; --等待调用 CASE COM IS --判断操作类型 WHEN 1 => OUTDONE <= '0'; --浮点乘法

IN1 := INPUT1; WAIT UNTIL RISING_EDGE(CLOCK); REP(IN1); OUTPUT <= TMP; OUTDONE <= '1'; WHEN 2 => OUTDONE <= '0'; --求倒数

IN1 := INPUT1; IN2 := INPUT2; WAIT UNTIL RISING_EDGE(CLOCK); MUL(IN1,IN2); OUTPUT <= TMP; OUTDONE <= '1'; WHEN 3 => OUTPUT <= INPUT1 + INPUT2; --浮点加法 OUTDONE <= '1';

WHEN 4 => OUTPUT <= INPUT1- INPUT2; --浮点减法 WAITUNTIL RISING_EDGE(CLOCK); OUTDONE <= '1'; WHEN 5 => OUTPUT <= TMP; OUTDONE <='1'; WHEN OTHERS => OUTDONE <= '1'; END CASE; END PROCESS; END ARCHITECTURE ART;

2) PID控制器的源程序PID.VHD LIBRARY WORK; USE WORK.SYNCHRO.ALL; USE WORK.OP_PKG.ALL; ENTITY PID IS PORT ( RESET:IN BIT; FSIGNIN:IN BIT; HOSTINTERRUPT:IN BIT;

POSITIONCHANGE:IN BIT; IREFKOUT :OUT REAL ); END ENTITY PID; ARCHITECTURE ART OF PID IS COMPONENT FPU IS PORT (CLOCK :IN BIT; RESET :N BIT; INPUT1 :IN REAL; INPUT2 :IN REAL; SEL :IN BIT;

COM :IN INT3BIT; OUTPUT :OUT REAL; OUTDONE :OUT BIT); END COMPONENT FPU;   SIGNAL SIG_IN1,SIG_IN2 :REAL; SIGNAL SIG_OUT : REAL; SIGNAL SIG_SEL,SIG_DONE :BIT; SIGNAL SIG_COM : INT3BIT; SIGNAL CLOCK : BIT; -- <= '1'; FOR ALL:FPU USE ENTITY WORK.FPU (ART);

BEGIN INST_FU : FPU PORT MAP(CLOCK => CLOCK,RESET => RESET,INPUT1 => SIG_IN1,INPUT2 => SIG_IN2, SEL => SIG_SEL,COM => SIG_COM,OUTPUT => SIG_OUT, OUTDONE => SIG_DONE);

PROCESS IS VARIABLE N,EK_1,IK,EK,KP,KI,KD,FREF: REAL; VARIABLE FK,DEK,IREFK, TEMP: REAL; VARIABLE DONE : BIT;

PROCEDURE MUL(A,B : IN REAL) IS BEGIN SIG_IN1 <= A; SIG_IN2 <= B; SIG_SEL <='1'; SIG_COM <= 2; WAIT UNTIL RISING_EDGE(CLOCK); SIG_SEL <='0'; RETURN; END PROCEDURE MUL;

PROCEDURE REP(A:IN REAL) IS BEGIN SIG_IN1 <= A; SIG_SEL <='1'; SIG_COM <= 1; WAIT UNTIL RISING_EDGE(CLOCK); SIG_SEL <='0'; RETURN; END PROCEDURE REP;

PROCEDURE WAITRESULT(X:OUT REAL; Y:OUT BIT) IS BEGIN X := SIG_OUT; Y := SIG_DONE; WAIT UNTIL RISING_EDGE(CLOCK); RETURN; END PROCEDURE WAITRESULT; TYPE ROM IS ARRAY(0 TO 4) OF REAL;

VARIABLE VAL_ROM : ROM := (2.0*2.0**(-20),2.0,3.0*2.0**(-20),4.0*2.0**(20),2.0*2.0** (-20)); PROCEDURE GETCONSTKP(X :OUT REAL) IS BEGIN X := VAL_ROM(0); END PROCEDURE GETCONSTKP; PROCEDURE GETCONSTKI(X :OUT REAL) IS

BEGIN X := VAL_ROM(1); END PROCEDURE GETCONSTKI; PROCEDURE GETCONSTKD(X:OUT REAL) IS X := VAL_ROM(2); END PROCEDURE GETCONSTKD; PROCEDURE GETFREF(X :OUT REAL) IS

BEGIN X := VAL_ROM(3); END PROCEDURE GETFREF; PROCEDURE GETN(X :OUT REAL) IS X := VAL_ROM(4); END PROCEDURE GETN; GETCONSTKP(KP); GETCONSTKI(KI); GETCONSTKD(KD);

GETFREF(FREF); IK :=0.0; EK := 0.0; IREFK := 0.0; --WAIT FOR 50 ns; WAIT UNTIL (HOSTINTERRUPT ='0'); WHILE (HOSTINTERRUPT ='0') LOOP WAIT UNTIL(POSITIONCHANGE ='1'); GETN(N);

REP(N); EK_1 := EK; --WAIT UNTIL(DONE ='1') WAITRESULT(FK,DONE); WHILE (DONE /='1') LOOP WAITRESULT(FK,DONE); END LOOP; IF(FSIGNIN ='0') THEN EK := FREF - FK; ELSE EK := FREF + FK; END IF; MUL(KP,EK); DEK := EK - EK_1;

WAITRESULT(IREFK,DONE); WHILE(DONE /='1'') LOOP WAITRESULT(IREFK,DONE); END LOOP; MUL(DEK,FK); WAITRESULT(TEMP,DONE); WHILE(DONE /='1') LOOP WAITRESULT(TEMP,DONE); END LOOP; MUL(TEMP,KD); IREFK := IREFK + TEMP;

MUL(EK,N); WAITRESULT(TEMP,DONE); WHILE(DONE /='1') LOOP WAITRESULT(TEMP,DONE); END LOOP; IK := IK + TEMP; MUL(IK,KI); WHILE (DONE /='1') LOOP WAITRESULT(TEMP ,DONE); END LOOP; -- IREFKOUT <= IREFK + TEMP;

IREFK := IREFK + TEMP; END LOOP; IREFKOUT <= IREFK; END PROCESS; CLOCK <= NOT CLOCK ; END ARCHITECTURE ART; 3.硬件逻辑验证 请读者根据前述方法自行完成硬件逻辑验证工作。

6.11 空调系统有限状态自动机的设计 1.设计思路 设计一个空调系统的有限状态自动机,它的两个输入端TEMP_HIGH 和TEMP_LOW分别与传感器相连,用于检测室内温度。其原理方框图如图6.13所示。

图6.13 空调有限状态自动机原理方框图

2.VHDL源程序 LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL;   ENTITY AIR_CONDITIONER IS PORT(CLK : IN STD_ULOGIC; TEMP_HIGH :IN STD_ULOGIC; TEMP_LOW : IN STD_ULOGIC; HEAT : OUT STD_ULOGIC; COOL : OUT STD_ULOGIC); END ENTITY AIR_CONDITIONER;

ARCHITECTURE ART OF AIR_CONDITIONER IS TYPE STATE_TYPE IS (JUST_RIGHT,TOO_COLD,TOO_HOT); ATTRIBUTE SEQUENTIAL_ENCODING : STRING; ATTRIBUTE SEQUENTIAL_ENCODINGOF STATE_TYPE :TYPE IS “00 01 10”; SIGNAL STVAR: STATE_TYPE; ATTRIBUTE STATE_VECTOR : STRING; ATTRIBUTE STATE_VECTOR OF STYLE_B:ARCHITECTURE IS “STVAR”;

BEGIN CONTROLLER1: PROCESS IS WAIT UNTIL CLK='1'; --REVISED BY DLS IF (TEMP_LOW='1') THEN STVAR<=TOO_COLD; ELSIF (TEMP_HIGH='1') THEN STVAR<=TOO_HOT; ELSE STVAR<=JUST_RIGHT; END IF;

CASE STVAR IS WHEN JUST_RIGHT=>HEAT<='0';COOL<='0'; WHEN TOO_COLD=>HEAT<='1';COOL<='0'; WHEN TOO_HOT=>HEAT<='0';COOL<='1'; END CASE; END PROCESS CONTROLLER1; END ARCHITECTURE ART; 3.硬件逻辑验证 请读者根据前述方法自行完成硬件逻辑验证工作。

6.12 闹钟系统的设计 6.12.1 闹钟系统的设计要求及设计思路 要求设计一个带闹钟功能的24小时计时器,计时器的外观如图6.14所示。

图6.14 计时器外观

该计时器设计要求完成如下功能: (1) 计时功能:这是本计时器设计的基本功能,每隔一分钟计时一次,并在显示屏上显示当前时间。 (2) 闹钟功能:如果当前时间与设置的闹钟时间相同,则扬声器发出蜂鸣声。 (3) 设置新的计时器时间:用户用数字键‘0’~‘9’输入新的时间,然后按 "TIME"键确认。

(4) 设置新的闹钟时间:用户用数字键“0”~“9”输入新的时间,然后按“ALARM”键确认。过程与(3)类似。

6.12.2 闹钟系统的控制器的设计 1.设计思路 控制器命名为ALARM_CONTROLLER,其外部端口如图6.15所示。各端口的作用如下:

图6.15 控制器的外部端口

(1) CLK为外部时钟信号,RESET为复位信号。 (2) 当KEY为高电平(KEY= '1')时,表示用户按下数字键(“0”~“9”)。 (3) 当ALARM_BUTTON为高电平时,表示用户按下“ALARM”键。 (4) 当TIME_BUTTON为高电平时,表示用户按下“TIME”键。 (5) 当LOAD_NEW_A为高电平时,控制(闹钟时间寄存器)加载新的闹钟时间值。

(6) 当LOAD_NEW_C为高电平时,控制(时钟计数器)设置新的时间值。 (7) 当SHOW_NEW_TIME为高电平时,控制(七段数码显示电路)显示新的时间值,即用户通过数字键输入的时间;否则,当SHOW_NEW_TIME为低电平时,根据SHOW_A信号的值控制显示当前时间或闹钟时间。

根据设计要求及端口设置,需要五个状态来实现: S0:表示电路初态即正常时钟计数状态,完成前面设计功能 (1) 的工作。 S1:接收键盘输入状态。在状态S0时用户按下数字键后进入此状态。在此状态下,显示屏上显示的是用户键入的数字。

S2:设置新的闹钟时间。在状态S1时用户按下ALARM键后进入此状态。 S3:设置新的计时器时间。在状态S1时用户按下TIME键后进入此状态。 S4:显示闹钟时间。在状态S0时用户直接按下ALARM键后进入此状态。

在此状态下,显示屏上显示的是所设置的闹钟时间。注意:在此状态下,用户按下ALARM键后,显示屏上保持显示闹钟时间,经过一段时间以后,再返回状态S0显示计时器时间。相应的状态转换及控制如表6.1所示。

表6.1 控制器状态转换及控制输出表

表6.1中没有显式说明的控制信号赋值,表示信号的值为 零。例如在状态S0,当信号KEY =‘1’时,SHOW_NEW_TIME信号的赋值为‘1’,而其他信号LOAD_NEW_A、LOAD_NEW_C和SHOW_A的值此时都赋为‘0’。另外,表中关于“超时”判断处理的处理细节见VHDL源程序中的有关部分。

2.VHDL源程序 --整个设计中将要用到的程序包定义程序P_ALARM.VHD LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; PACKAGE P_ALARM IS SUBTYPE T_DIGITAL IS INTEGER RANGE 0 TO 9; SUBTYPE T_SHORT IS INTEGER RANGE 0 TO 65535; TYPE T_CLOCK_TIME IS ARRAY (3 DOWNTO 0) OF T_DIGITAL; TYPE T_DISPLAY IS ARRAY (3 DOWNTO 0) OF

STD_LOGIC_VECTOR(6 DOWNTO 0); TYPE SEG7 IS ARRAY (0 TO 9) OF STD_LOGIC_VECTOR(6 DOWNTO 0); CONSTANT SEVEN_SEG: SEG7 := (

“0111111”, “0000110”, “1011011”, "1001111", "1100110", "1101101", "1111101", "0000111", "1111111', "1110011" );

TYPE KEYPAD9 IS ARRAY (0 TO 9) OF STD_LOGIC_VECTOR(9 DOWNTO 0); CONSTANT KEYNUMBER: KEYPAD9 := (

"0000000001", -- 0 "0000000010", -- 1 "0000000100", -- 2 "0000001000", -- 3 "0000010000", -- 4 "0000100000", -- 5 "0001000000", -- 6 "0010000000", -- 7 "0100000000", -- 8 "1000000000" -- 9 ); END PACKAGE P_ALARM;  

-- 控制器源程序ALARM_CONTROLLER.VHD LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; USE WORK.P_ALARM.ALL; ENTITY ALARM_CONTROLLER IS PORT( KEY :IN STD_LOGIC; ALARM_BUTTON :IN STD_LOGIC; TIME_BUTTON :IN STD_LOGIC; CLK :IN STD_LOGIC;

RESET :IN STD_LOGIC; LOAD_NEW_A :OUT STD_LOGIC; LOAD_NEW_C :OUT STD_LOGIC; SHOW_NEW_TIME :OUT STD_LOGIC; SHOW_A :OUT STD_LOGIC); END ENTITY ALARM_CONTROLLER; ARCHITECTURE ART OF ALARM_CONTROLLER IS TYPE T_STATE IS (S0, S1, S2, S3,S4); CONSTANT KEY_TIMEOUT :T_SHORT := 500;

CONSTANT SHOW_ALARM_TIMEOUT : T_SHORT := 500; SIGNAL CURR_STATE : T_STATE; SIGNAL NEXT_STATE : T_STATE; SIGNAL COUNTER_K : T_SHORT; SIGNAL ENABLE_COUNT_K : STD_LOGIC; SIGNAL COUNT_K_END : STD_LOGIC; SIGNAL COUNTER_A : T_SHORT; SIGNAL ENABLE_COUNT_A : STD_LOGIC; SIGNAL COUNT_A_END : STD_LOGIC; BEGIN

PROCESS(CLK,RESET) IS BEGIN IF RESET ='1' THEN CURR_STATE <= S0; ELSIF RISING_EDGE(CLK) THEN CURR_STATE <= NEXT_STATE; END IF; END PROCESS;

PROCESS(KEY, ALARM_BUTTON, TIME_BUTTON, CURR_STATE, COUNT_A_END,COUNT_K_END) IS BEGIN NEXT_STATE <= CURR_STATE; LOAD_NEW_A <= '0'; LOAD_NEW_C <= '0'; SHOW_A <= '0'; SHOW_NEW_TIME <= '0'; ENABLE_COUNT_K <= '0'; ENABLE_COUNT_A <= '0';

CASE CURR_STATE IS WHEN S0 => IF (KEY = '1') THEN NEXT_STATE <= S1; SHOW_NEW_TIME <= '1'; ELSIF (ALARM_BUTTON = '1') THEN NEXT_STATE <= S4; SHOW_A <= '1'; ELSE NEXT_STATE <= S0; END IF;

WHEN S1 => IF (KEY = '1') THEN NEXT_STATE <= S1; ELSIF (ALARM_BUTTON = '1') THEN NEXT_STATE <= S2; LOAD_NEW_A <= '1'; ELSIF (TIME_BUTTON = '1') THEN NEXT_STATE <= S3; LOAD_NEW_C <= '1'; ELSE IF (COUNT_K_END = '1') THEN NEXT_STATE <= S0;

ELSE NEXT_STATE <= S1; END IF; ENABLE_COUNT_K <= '1'; SHOW_NEW_TIME <= '1'; WHEN S2 => IF (ALARM_BUTTON = '1') THEN NEXT_STATE <= S2; LOAD_NEW_A <= '1'; NEXT_STATE <= S0;

WHEN S3 => IF (TIME_BUTTON = '1') THEN NEXT_STATE <= S3; LOAD_NEW_C <= '1'; ELSE NEXT_STATE <= S0; END IF; WHEN S4 => IF (KEY = '1') THEN NEXT_STATE <= S1;

ELSE NEXT_STATE <= S4; IF (COUNT_A_END = '1') THEN NEXT_STATE <= S0; SHOW_A <= '1';

END IF; ENABLE_COUNT_A <= '1'; WHEN OTHERS => NULL; END CASE; END PROCESS;

COUNT_KEY : PROCESS(ENABLE_COUNT_K, CLK) IS BEGIN IF (ENABLE_COUNT_K = '0') THEN COUNTER_K <= 0; COUNT_K_END <= '0'; ELSIF (RISING_EDGE(CLK)) THEN IF (COUNTER_K >= KEY_TIMEOUT) THEN COUNT_K_END <= '1'; ELSE

COUNTER_K <= COUNTER_K + 1; END IF; END PROCESS COUNT_KEY;   COUNT_ALARM : PROCESS(ENABLE_COUNT_A, CLK) IS BEGIN IF (ENABLE_COUNT_A = '0') THEN COUNTER_A <= 0;

COUNT_A_END <= '0'; ELSIF RISING_EDGE(CLK) THEN IF (COUNTER_A >= SHOW_ALARM_TIMEOUT) THEN COUNT_A_END <= '1'; ELSE COUNTER_A <= COUNTER_A + 1; END IF; END PROCESS COUNT_ALARM; END ARCHITECTURE ART;

6.12.3 闹钟系统的译码器的设计 1.设计思路 本模块的功能是将每次按下闹钟系统的数字键盘后产生的一个数字所对应的10位二进制数据信号转换为1位十进制整数信号,以作为小时、分钟计数的四个数字之一,如图6.16所示。其中,KEYPAD为输入端口,接收10位二进制数据信号;VALUE为输出端口,输出相应的1位十进制整数信号。输入数据与输出数据的译码关系见表6.2。

图6.16 电路系统示意图

表6.2 输入、输出数据的译码关系

2.VHDL源程序 LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; USE WORK.P_ALARM.ALL; ENTITY DECODER IS PORT(KEYPAD :IN STD_LOGIC_VECTOR(9 DOWNTO 0); VALUE :OUT T_DIGITAL); END ENTITY DECODER; ARCHITECTURE ART OF DECODER IS

BEGIN WITH KEYPAD SELECT VALUE <= 0 WHEN “0000000001”, 1 WHEN “0000000010”, 2 WHEN “0000000100”, 3 WHEN “0000001000”, 4 WHEN “0000010000”, 5 WHEN “0000100000”, 6 WHEN “0001000000”, 7 WHEN “0010000000”,

8 WHEN “0100000000”, 9 WHEN “1000000000”, 0 WHEN OTHERS; END ARCHITECTURE ART;

6.12.4 闹钟系统的移位寄存器的设计 1.设计思路 本模块的功能是在CLK端口输入信号的上升沿同步下,将KEY端口的输入信号移入NEW_TIME 端口的输出信号最低位,原有信息依次向左移,最高位信息丢失;RESET端口的输入信号对NEW_TIME端口输出信号进行异步清零复位。电路系统示意图如图6.17所示。

图6.17 移位寄存器电路示意图

2.VHDL源程序 LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; USE WORK.P_ALARM.ALL; ENTITY KEY_BUFFER IS PORT(KEY :IN T_DIGITAL; CLK :IN STD_LOGIC; RESET :IN STD_LOGIC; NEW_TIME:OUT T_CLOCK_TIME); END ENTITY KEY_BUFFER;

ARCHITECTURE ART OF KEY_BUFFER IS SIGNAL N_T:T_CLOCK_TIME; BEGIN SHIFT:PROCESS(RESET,CLK) IS IF (RESET = '1') THEN N_T <= (0,0,0,0); ELSIF (CLK'EVENT AND CLK = '1' )THEN FOR I IN 3 DOWNTO 1 LOOP N_T(I) <= N_T(I-1);

END LOOP; N_T(0) <= KEY; END IF; END PROCESS SHIFT; NEW_TIME <= N_T; END ARCHITECTURE ART;

6.12.5 闹钟系统的闹钟寄存器和时间计数器的设计 1.电路系统工作原理 闹钟寄存器模块的功能是在时钟上升沿同步下,根据LOAD_NEW_A端口的输入信号控制ALARM_TIME端口的输出;当控制信号有效(高电平)时,把NEW_ALARM_TIME端口的输入信号值输出;RESET端口输入信号对ALARM_TIME端口的输出进行异步的清零复位。图6.18是闹钟寄存器模块的示意图。

图6.18 闹钟寄存器示意图

闹钟系统的闹钟时间由闹钟寄存器保存和传递,而当前时间由时间计数器保存、传递并按分钟累加推进。这两个组件的功能和设计描述比较相似,它们之间的区别主要在于自动累加功能的有无和控制信号的优先作用次序。

图6.19 时间计数器示意图

时间计数器模块的功能是当RESET端口输入信号为高电平时,对CURRENT_TIME端口输出信号清零复位;当LOAD_NEW_C端口输入信号为高电平时,将NEW_CURRENT_TIME端口的输入信号输出给CURRENT_TIME端口。RESET端口的控制优先于LOAD_NEW_C端口。当这两个控制信号都无效时,在时钟上升沿同步下,对CURRENT_TIME端口输出信号累加1,并根据小时、分钟的规律处理进位。图6.19是时间计数器模块的示意图。

2.VHDL源程序 --时间计数器的源程序ALARM_COUNTER.VHD LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; USE WORK.P_ALARM.ALL; ENTITY ALARM_COUNTER IS PORT(NEW_CURRENT_TIME:IN T_CLOCK_TIME; LOAD_NEW_C:IN STD_LOGIC; CLK:IN STD_LOGIC;

RESET:IN STD_LOGIC; CURRENT_TIME:OUT T_CLOCK_TIME); END ENTITY ALARM_COUNTER; ARCHITECTURE ART OF ALARM_COUNTER IS SIGNAL I_CURRENT_TIME : T_CLOCK_TIME; BEGIN PROCESS(CLK,RESET,LOAD_NEW_C) IS VARIABLE C_T:T_CLOCK_TIME; IF RESET = '1' THEN

I_CURRENT_TIME <= (0,0,0,0); ELSIF LOAD_NEW_C ='1' THEN I_CURRENT_TIME <= NEW_CURRENT_TIME; ELSIF RISING_EDGE(CLK) THEN C_T := I_CURRENT_TIME; IF C_T(0) < 9 THEN C_T(0) := C_T(0) + 1;

ELSE C_T(0) := 0; IF C_T(1) < 5 THEN C_T(1) := C_T(1) + 1; C_T(1) := 0; IF C_T(3) < 2 THEN IF C_T(2) < 9 THEN C_T(2) := C_T(2) + 1; C_T(2) := 0; C_T(3) := C_T(3) + 1; END IF;

ELSE IF C_T(2) < 3 THEN C_T(2) := C_T(2) + 1; C_T(2) := 0; C_T(3) := 0; END IF; I_CURRENT_TIME <= C_T;

END PROCESS; CURRENT_TIME <= I_CURRENT_TIME; END ARCHITECTURE ART;   --闹钟寄存器的源程序ALARM_REG.VHD LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; USE WORK.P_ALARM.ALL; ENTITY ALARM_REG IS

PORT(NEW_ALARM_TIME:IN T_CLOCK_TIME; LOAD_NEW_A :IN STD_LOGIC; CLK :IN STD_LOGIC; RESET :IN STD_LOGIC; ALARM_TIME:OUT T_CLOCK_TIME); END ENTITY ALARM_REG; ARCHITECTURE ART OF ALARM_REG IS BEGIN PROCESS(CLK,RESET) IS

IF RESET = '1' THEN ALARM_TIME <= (0,0,0,0); ELSE IF RISING_EDGE(CLK) THEN IF LOAD_NEW_A = '1' THEN ALARM_TIME <= NEW_ALARM_TIME; ELSIF LOAD_NEW_A /= '0' THEN ASSERT FALSE REPORT“UNCERTAIN LOAD_NEW_ALARM CONTROL!” SEVERITY WARNING;

END IF; END PROCESS; END ARCHITECTURE ART;

6.12.6 闹钟系统的显示驱动器的设计 1.设计思路 本模块的功能是:当SHOW_NEW_TIME端口输入信号有效(高电平)时,根据NEW_TIME端口输入信号(时间数据),产生相应的四个七段数码显示器的驱动数据,并在DISPLAY端口输出该信号。

当SHOW_NEW_TIME端口输入信号无效(低电平)时,判断SHOW_A端口的输入信号,为高电平时,根据ALARM_TIME端口的输入信号(时间数据)产生相应的四个七段数码显示器的驱动数据,并在DISPLAY端口输出该信号;为低电平时,根据CURRENT_TIME端口的输入信号,对DISPLAY端口进行驱动。当ALARM_TIME 端口的输入信号值与CURRENT_TIME端口的输入信号值相同时,SOUND_ALARM端口的输出信号有效(高电平),反之无效。图6.20为显示驱动器示意图。

图6.20 显示驱动器示意图

2.VHDL源程序 LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; USE WORK.P_ALARM.ALL; ENTITY DISPLAY_DRIVER IS PORT(ALARM_TIME :IN T_CLOCK_TIME; CURRENT_TIME :IN T_CLOCK_TIME; NEW_TIME :IN T_CLOCK_TIME; SHOW_NEW_TIME:IN STD_LOGIC; SHOW_A :IN STD_LOGIC; SOUND_ALARM :OUT STD_LOGIC; DISPLAY:OUT T_DISPLAY);

END ENTITY DISPLAY_DRIVER; ARCHITECTURE ART OF DISPLAY_DRIVER IS SIGNAL DISPLAY_TIME:T_CLOCK_TIME; BEGIN CTRL:PROCESS(ALARM_TIME,CURRENT_TIME,NEW_TIME,SHOW_A,SHOW_NEW_TIME) IS

SOUND_LP: FOR I IN ALARM_TIME'RANGE LOOP IF NOT(ALARM_TIME(I) = CURRENT_TIME(I)) THEN SOUND_ALARM <= '0'; EXIT SOUND_LP; ELSE SOUND_ALARM <= '1'; END IF;

END LOOP SOUND_LP; IF SHOW_NEW_TIME = '1' THEN DISPLAY_TIME <= NEW_TIME; ELSIF SHOW_A = '1' THEN DISPLAY_TIME <= ALARM_TIME; ELSIF SHOW_A = '0' THEN DISPLAY_TIME <= CURRENT_TIME; ELSE

ASSERT FALSE REPORT “UNCERTAIN DISPLAY_DRIVER CONTROL!” SEVERITY WARNING; END IF; END PROCESS CTRL; DISP:PROCESS(DISPLAY_TIME) IS BEGIN

FOR I IN DISPLAY_TIME'RANGE LOOP DISPLAY(I) <= SEVEN_SEG(DISPLAY_TIME(I)); END LOOP; END PROCESS DISP; END ARCHITECTURE ART;

6.12.7 闹钟系统的分频器的设计 1.设计思路  本模块的功能是将CLK_IN端口输入的时钟信号分频后送给CLK_OUT端口;当RESET端口输入信号有效(高电平)时,CLK_OUT端口输出信号清零。图6.21为分频器示意图。

图6.21 分频器示意图

2.VHDL源程序 LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; USE WORK.P_ALARM.ALL; ENTITY FQ_DIVIDER IS PORT( CLK_IN:IN STD_LOGIC; RESET:IN STD_LOGIC; CLK_OUT:OUT STD_LOGIC );

END ENTITY FQ_DIVIDER; ARCHITECTURE ART OF FQ_DIVIDER IS CONSTANT DIVIDE_PERIOD : T_SHORT := 6000; BEGIN DIVIDE_CLK: PROCESS(CLK_IN,RESET) IS VARIABLE CNT : T_SHORT; IF (RESET = '1') THEN CNT := 0; CLK_OUT <= '0';

ELSIF RISING_EDGE(CLK_IN) THEN IF (CNT < (DIVIDE_PERIOD/2)) THEN CLK_OUT <= '1'; CNT := CNT + 1; ELSIF (CNT < (DIVIDE_PERIOD-1)) THEN CLK_OUT <= '0';

ELSE CNT := 0; END IF; END PROCESS DIVIDE_CLK; END ARCHITECTURE ART;

6.12.8 闹钟系统的整体组装 1.整体组装说明 前边已经完成了计时器各个组成部分的设计,下面把这些组成部分组装起来,形成完整的总体设计。该计时器命名为ALARM_CLOCK,其外部端口如图6.22所示。

图6.22 计时器的外部端口

各个输入/输出端口的作用如下: (1) CLK为外部时钟信号,RESET为复位信号。 (2) KEYPAD是一个10位信号,若其中某一位为高电平,则表示用户按下了相应下标的数字键。 (3) 当KEYDOWN为高电平时(KEYDOWN= '1'),表示用户按下某一数字键。 (4) 当ALARM_BUTTON为高电平时,表示用户按下ALARM键。 (5) 当TIME_BUTTON为高电平时,表示用户按下TIME键。

(6) DISPLAY实际上表示了四个七段数码显示管,用于显示时间,如12∶20。 (7) SOUND_ALARM用于控制扬声器发声,当SOUND_ALARM = '1'时,扬声器发出蜂鸣,表示到了设定的闹钟时间。 设计的总体结构图如图6.23所示。

图6.23 总体结构

下面再简要说明各组成部分的功能: (1) 译码器(DECODER) 可将KEYPAD信号转换为0~9的整型数,以直观地表示和处理用户输入的数字。 (2) 键盘缓冲器(KEY_BUFFER)是一个移位寄存器,暂存用户键入的数字,并且实现用户键入数字在显示器上从右到左的依次显示。这里需要注意的是,由图6.23可以看出,KEY_BUFFER的时钟端连接的是外部KEY_DOWN 信号。这表示用户每输入一个数字,KEY_BUFFER移位一次。

(3) 分频器(FQ_DIVIDER)将较高速的外部时钟频率分频成每分钟一次的时钟频率,以便进行时钟计数。 (4) 计数器(ALARM_COUNTER)实际上是一个异步复位、异步置数的累加器,通常情况下进行时钟累加计数,必要时可置入新的时钟值,然后从该值开始新的计数。 (5) 寄存器(ALARM_REG)用于保存用户设置的闹钟时间,是一个异步复位寄存器。

(6) 显示器(DISPLAY_DRIVER)根据需要显示当前时间、用户设置的闹钟时间或用户通过键盘输入的新的时间,同时判断当前时间是否已到了闹钟时间,实际上是一个多路选择器加比较器。 (7) 控制器(ALARM_CONTROLLER)是设计的核心部分,按设计要求产生相应的控制逻辑,以控制其他各部分的工作。

2.VHDL源程序 LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; USE IEEE.STD_LOGIC_UNSIGNED.ALL; USE WORK.P_ALARM.ALL; ENTITY ALARM_CLOCK IS PORT(KEYPAD : IN STD_LOGIC_VECTOR(9 DOWNTO 0); KEY_DOWN : IN STD_LOGIC; ALARM_BUTTON: IN STD_LOGIC; TIME_BUTTON : IN STD_LOGIC;

CLK : IN STD_LOGIC; RESET : IN STD_LOGIC; DISPLAY : OUT T_DISPLAY; SOUND_ALARM : OUT STD_LOGIC); END ENTITY ALARM_CLOCK; ARCHITECTURE ART OF ALARM_CLOCK IS COMPONENT DECODER IS PORT( KEYPAD :IN STD_LOGIC_VECTOR(9 DOWNTO 0); VALUE :OUT T_DIGITAL); END COMPONENT DECODER;

... SIGNAL S0 : T_DIGITAL; SIGNAL S1,S2,S3,S4,S5 : STD_LOGIC; SIGNAL S6,S7,S8 : T_CLOCK_TIME; BEGIN U1: DECODER PORT MAP(KEYPAD, S0); U2: KEY_BUFFER PORT MAP(S0, KEY_DOWN,RESET, S6); U3: ALARM_CONTROLLER PORT MAP(KEY_DOWN,ALARM_BUTTON,TIME_BUTTON,

CLK,RESET,S1,S2,S3,S4); U4: ALARM_COUNTER PORT MAP(S6,S2,S5,RESET,S8); U5: ALARM_REG PORT MAP(S6,S1,CLK,RESET,S7); U6: DISPLAY_DRIVER PORT MAP(S7,S6,S8,S3,S4,SOUND_ALARM,DISPLAY); U7: FQ_DIVIDER PORT MAP(CLK,RESET,S5); END ARCHIITECTURE ART;

6.12.9 闹钟系统的硬件验证 若用GW48型EDA实验开发系统进行硬件验证,考虑到实验开发系统提供的输入信号按键的有限,可将输入数字按键0~9改为一个按键,该按键的信号作为一个8421码信号发生器的输入,由8421码信号发生器输出数字0~9。同时,每输入完一个数字后应增加一个输入确认键。具体验证方案由读者自行完成。