摘要:
随着电子技术的发展,可编程逻辑器件(PLD)的出现,使得电子系统的设计者利用EDA(电子设计自动化)软件,就可以独立设计自己的专用集成电路(ASIC)器件。可编程逻辑器件是一种半导体集成器件的半成品。在可编程逻辑器件的芯片中按一定方式(阵列形式或单元阵列形式)制作了大量的门、触发器等基本逻辑器件,对这些基本器件适当地连接,就可以完成某个电路或系统的功能。抢答器控制系统是工厂、学校和电视台等单位举办各种智力竞赛等娱乐活动中经常使用的重要基础设备之一。目前设计抢答器的方法很多,例如用传统的PCB板设计、用PIC设计或者用单片机设计。而用VHDL可以更加快速、灵活地设计出符合各种要求的抢答器,优于其他设计方法,使设计过程达到高度自动化。本课题设计的数字式竞赛抢答器基于VHDL语言、以EDA技术作为开发手段、采用CPLD(复杂的可编程逻辑器件)作为控制核心设计而成。与传统设计相比较,不仅简化了接口和控制,也提高了系统的整体性能和工作可靠性,具有电路简单、成本低廉、操作方便、灵敏可靠等优点。
关键词:PLD;EDA;抢答器
目 录
1 课题综述 1
1.1 课题意义 1
1.2 课题要求 1
2 系统分析 1
2.1 基本原理 1
2.2 系统设计原理框图 2
3 软件设计 2
3.1 抢答鉴别模块 2
3.2 数据选择模块 4
3.3 计时模块 5
3.4 报警模块 7
3.5 译码模块 7
3.6 计分模块 9
3.7 顶层文件 11
4 硬件调试 13
总 结 14
致 谢 15
参考文献 16
1 课题综述
1.1 课题意义
抢答器作为一种电子产品,早已广泛应用于各种智力和知识竞赛场合,但目前所使用的抢答器存在分立元件使用较多,造成每路的成本偏高,而现代电子技术的发展要求电子电路朝数字化、集成化方向发展,因此设计出数字化全集成电路的多路抢答器是现代电子技术发展的要求。
1.2 课题要求
设计一个可容纳4组参赛的数字式抢答器,每组设一个按钮,供抢答使用。抢答器具有第一信号鉴别和锁存功能,使除第一抢答者外的按钮不起作用。设置一个主持人“复位”按钮。主持人复位后,开始抢答,第一信号鉴别锁存电路得到信号后,有指示灯显示抢答组别,扬声器发出2~3秒的音响。设置一个计分电路,每组开始预置100分,由主持人记分,答对一次加10分,答错一次减10分。
2 系统分析
2.1 基本原理
本设计为四路数字式竞赛抢答器,所以这种抢答器要求有四路不同组别的抢答输入信号,并能识别最先抢答的信号,直观地通过数显和蜂鸣等方式显示出组别;对回答问题所用的时间进行计时、显示、超时报警、预置答题时间,同时该系统还应有复位、倒计时启动功能以及计分功能。
抢答过程:主持人按下系统复位键(rst),系统进入抢答状态,计时模块和计分模块输出初始信号给数码显示模块并显示出初始值。当某参赛组抢先将抢答键按下时,系统将其余三路抢答信号封锁,同时扬声器发出声音提示,组别显示模块送出信号给数码显示模块,从而显示出该抢答成功组台号,并一直保持到下一轮主持人将系统清零为止。主持人对抢答结果进行确认,随后,计时模块送出倒计时计数允许信号,开始回答问题,计时显示器则从初始值开始以计时,在规定的时间内根据答题的正误来确定加分或减分,并通过数码显示模块将成绩显示出来。计时至0时,停止计时,扬声器发出超时报警信号,以中止未回答完问题。当主持人给出倒计时停止信号时,扬声器停止鸣叫。若参赛者在规定时间内回答完为题,主持人可给出倒计时计数停止信号,以免扬声器鸣叫。主持人按下复位键,即rst为高电平有效状态,清除前一次的抢答组别,又可开始新的一轮的抢答。
此抢答器的设计中采用自顶向下的设计思路,运用VHDL硬件描述语言对各个模块进行层次化、系统化的描述,并且先设计一个顶层文件,再把各个模块连接起来。
2.2 系统设计原理框图
图2.1 系统原理框图
3 软件设计
将该任务分成几个模块进行设计,分别为:抢答器鉴别模块、数据选择模块、计时模块、报警模块、译码模块、计分模块,最后是撰写顶层文件。
3.1 抢答鉴别模块
在这个模块中主要实现抢答过程中的抢答功能,并能对超前抢答进行警告,还能记录无论是正常抢答还是超前抢答者的台号,并且能实现当有一路抢答按键按下时,该路抢答信号将其余过滤抢答封锁的功能。其中有六个抢答信号s0、s1、s2、s3;抢答状态显示信号states;抢答与警报时钟信号clk2;系统复位信号rst;警报信号tmp。
3.1.1 抢答鉴别模块源程序
LIBRARY IEEE;–抢答鉴别模块
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY qdjb IS
PORT(rst,clk2:IN STD_LOGIC;
s0,s1,s2,s3:IN STD_LOGIC;
states:BUFFER STD_LOGIC_VECTOR(3 DOWNTO 0);
tmp:OUT STD_LOGIC);
END qdjb;
ARCHITECTURE behv OF qdjb IS
SIGNAL st:STD_LOGIC_VECTOR(3 DOWNTO 0);
BEGIN
p1:PROCESS(s0,rst,s1,s2,s3,clk2)
BEGIN
IF rst=’0’ THEN tmp<=’0’;st<=”0000”;
ELSIF clk2’EVENT AND clk2=’1’ THEN
IF (s0=’1’ OR st(0)=’1’)AND NOT( st(1)=’1’ OR st(2)=’1’ OR st(3)=’1’ ) THEN
st(0)<=’1’;
END IF ;
IF (s1=’1’ OR st(1)=’1’)AND NOT( st(0)=’1’ OR st(2)=’1’ OR st(3)=’1’ ) THEN
st(1)<=’1’;
END IF ;
IF (s2=’1’ OR st(2)=’1’)AND NOT( st(0)=’1’ OR st(1)=’1’ OR st(3)=’1’ ) THEN
st(2)<=’1’;
END IF ;
IF (s3=’1’ OR st(3)=’1’)AND NOT( st(0)=’1’ OR st(1)=’1’ OR st(2)=’1’ ) THEN
st(3)<=’1’;
END IF ;
tmp<=s0 OR s1 OR s2 OR s3;
END IF ;
END PROCESS p1;
P2:PROCESS(states(0), states(1), states(2), states(3))
BEGIN
IF (st=”0000”) THEN states<=”0000”;
ELSIF (st<=”0001”) THEN states<=”0001”;
ELSIF (st<=”0010”) THEN states<=”0010”;
ELSIF (st<=”0100”) THEN states<=”0011”;
ELSIF (st<=”1000”) THEN states<=”0100”;
END IF;
END PROCESS p2;
END behv;
3.1.2 抢答鉴别模块仿真图
图3.1 抢答鉴别仿真图
3.1.3 抢答鉴别模块元件图
图3.2 抢答鉴别元件图
3.2 数据选择模块
在这个模块中主要实现抢答过程中的数据输入功能,输入信号a[3..0]、b[3..0]、c[3..0];计数输出信号s;数据输出信号y;计数脉冲clk2,实现a、b、c按脉冲轮流选通,在数码管上显示。
3.2.1 数据选择模块源程序
LIBRARY IEEE; –数据选择模块
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;
ENTITY sjxz IS
PORT (a,b,c:IN STD_LOGIC_VECTOR(3 DOWNTO 0);
clk2,rst:IN STD_LOGIC;
s:OUT STD_LOGIC_VECTOR(1 DOWNTO 0);
y:OUT STD_LOGIC_VECTOR(3 DOWNTO 0) );
END sjxz;
ARCHITECTURE behv OF sjxz IS
SIGNAL count: STD_LOGIC_VECTOR (1 DOWNTO 0);
BEGIN
S<=count;
PROCESS(clk2,rst)
BEGIN
IF(rst=’0’) THEN count<=”00”;
ELSIF(clk2’EVENT AND clk2=’1’) THEN
IF(count=”11”) THEN
count<=”00”;
ELSE count<=count+1;
END IF;
END IF;
CASE count IS
WHEN “00”=>y<=a;
WHEN “01”=>y<=”1111”;
WHEN “10”=>y<=b;
WHEN “11”=>y<=c;
WHEN OTHERS=>NULL;
END CASE;
END PROCESS;
END behv;
3.2.2 数据选择模块仿真图
图3.3 数据选择仿真图
3.2.3 数据选择模块元件图
图3.4 数据选择元件图
3.3 计时模块
3.3.1 计时模块源程序
LIBRARY IEEE; –计时模块
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY js IS
PORT(clk,rst,s,stop:IN STD_LOGIC;
warn:OUT STD_LOGIC;
ta,tb:BUFFER STD_LOGIC_VECTOR(3 DOWNTO 0));
END js;
ARCHITECTURE behv OF js IS
SIGNAL co:STD_LOGIC;
BEGIN
p1:PROCESS(clk,rst,s,stop,ta)
BEGIN
IF rst=’0’ OR stop=’1’ THEN ta<=”0000”;
ELSIF clk’EVENT AND clk=’1’ THEN co<=’0’;
IF s=’1’ THEN
IF ta=”0000” THEN ta<=”1001”;co<=’1’;
ELSE ta<=ta-1;
END IF;
END IF;
END IF;
END PROCESS p1;
p2:PROCESS(co,rst,s,stop,tb)
BEGIN
IF rst=’0’ OR stop=’1’ THEN tb<=”1001”;
ELSIF co’EVENT AND co=’1’ THEN
IF s=’1’ THEN
IF tb=”0000” THEN tb<=”1000”;
ELSE tb<=tb-1;
END IF;
END IF;
END IF;
END PROCESS p2;
END behv;
3.3.2 计时模块仿真图
图3.5 计时仿真图
3.3.3 计时模块仿真图
图3.6 计时元件图
3.4 报警模块
3.4.1 报警模块源程序
LIBRARY IEEE; –报警模块
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY alarm IS
PORT(clk,i:IN STD_LOGIC;
q:OUT STD_LOGIC);
END alarm;
ARCHITECTURE behv OF alarm IS
SIGNAL warn:STD_LOGIC;
SIGNAL n:INTEGER RANGE 0 TO 90;
BEGIN
q<= warn;
PROCESS(clk)
BEGIN
IF clk’EVENT AND clk=’1’ THEN
IF i=’0’ THEN warn <=’0’;
ELSIF(i=’1’AND n<=89) THEN warn<=NOT warn;n<=n+1;
ELSE warn<=’0’;
END IF;
END IF;
END PROCESS;
END behv;
3.4.2 报警模块仿真图
图3.7 报警仿真图
3.4.3 报警模块元件图
图3.8 报警元件图
3.5 译码模块
3.5.1 译码模块源程序
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 ymq;
ARCHITECTURE behv OF ymq IS
BEGIN
PROCESS(ain4)
BEGIN
CASE ain4 IS
WHEN “0000”=> dout7<=”1111110”; –0
WHEN “0001”=> dout7<=”0110000”; –1
WHEN “0010”=> dout7<=”1101101”; –2
WHEN “0011”=> dout7<=”1111001”; –3
WHEN “0100”=> dout7<=”0110011”; –4
WHEN “0101”=> dout7<=”1011011”; –5
WHEN “0110”=> dout7<=”1011111”; –6
WHEN “0111”=> dout7<=”1110000”; –7
WHEN “1000”=> dout7<=”1111111”; –8
WHEN “1001”=> dout7<=”1111011”; –9
WHEN OTHERS=> dout7<=”0000000”;
END CASE;
END PROCESS;
END behv;
3.5.1 译码模块仿真图
图3.9 译码仿真图
3.5.1 译码模块元件图
图3.10 译码元件图
3.6 计分模块
3.6.1 计分模块源程序
LIBRARY IEEE; –计分模块
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY jfq IS
PORT(rst:IN STD_LOGIC;
add:IN STD_LOGIC;
acc:IN STD_LOGIC;
chos:IN STD_LOGIC_VECTOR(3 DOWNTO 0);
aa2,aa1,aa0,bb2,bb1,bb0:OUT STD_LOGIC_VECTOR(3 DOWNTO 0);
cc2,cc1,cc0,dd2,dd1,dd0:OUT STD_LOGIC_VECTOR(3 DOWNTO 0));
END ENTITY jfq;
ARCHITECTURE behv OF jfq IS
BEGIN
PROCESS(rst,add,acc,chos) IS
VARIABLE points_a2,points_a1:STD_LOGIC_VECTOR(3 DOWNTO 0);
VARIABLE points_b2,points_b1:STD_LOGIC_VECTOR(3 DOWNTO 0);
VARIABLE points_c2,points_c1:STD_LOGIC_VECTOR(3 DOWNTO 0);
VARIABLE points_d2,points_d1:STD_LOGIC_VECTOR(3 DOWNTO 0);
BEGIN
IF (add’EVENT AND add=’1’) THEN
IF rst=’1’ THEN
points_a2:=”0001”; points_a1:=”0000”;
points_b2:=”0001”; points_b1:=”0000”;
points_c2:=”0001”; points_c1:=”0000”;
points_d2:=”0001”; points_d1:=”0000”;
ELSIF chos=”0001” THEN
IF points_a1=”1001” then points_a1:=”0000”;
IF points_a2=”1001” THEN points_a2:=”0000”;
ELSE points_a2:=points_a2+’1’;
END IF;
ELSE points_a1:=points_a1+’1’;
END IF;
ELSIF chos=”0010” THEN
IF points_b1=”1001” THEN points_b1:=”0000”;
IF points_b2=”1001” THEN points_b2:=”0000”;
ELSE
points_b2:=points_b2+’1’;
END IF;
ELSE Points_b1:=points_b1+’1’;
END IF;
ELSIF chos=”0100” THEN
IF points_c1=”1001” then points_c1:=”0000”;
IF points_c2=”1001” THEN points_c2:=”0000”;
ELSE points_c2:=points_c2+’1’;
END IF;
ELSE points_c1:=points_c1+’1’;
END IF;
ELSIF chos=”1000” THEN
IF points_d1=”1001” THEN points_d1:=”0000”;
IF points_d2=”1001” THEN points_d2:=”0000”;
ELSE points_d2:=points_d2+’1’;
END IF;
ELSE points_d1:=points_d1+’1’;
END IF;
END IF;
ELSIF (acc’EVENT AND acc=’1’) THEN
IF chos=”0001” THEN
IF points_a1=”0000” THEN points_a1:=”1001”;
IF points_a2=”0000” THEN points_a2:=”0000”;
ELSE points_a2:=points_a2-‘1’;
END IF;
ELSE points_a1:=points_a1-‘1’;
END IF;
ELSIF chos=”0010” THEN
IF points_b1=”0000” THEN points_b1:=”1001”;
IF points_b2=”0000” THEN points_b2:=”0000”;
ELSE points_b2:=points_b2-‘1’;
END IF;
ELSE points_b1:=points_b1-‘1’;
END IF;
ELSIF chos=”0100” THEN
IF points_c1=”0000” THEN points_c1:=”1001”;
IF points_c2=”0000” THEN points_c2:=”0000”;
ELSE points_c2:=points_c2-‘1’;
END IF;
ELSE points_c1:=points_c1-‘1’;
END IF;
ELSIF chos=”1000” THEN
IF points_d1=”0000” THEN points_d1:=”0000”;
IF points_d2=”1001” THEN points_d2:=”0000”;
ELSE points_d2:=points_d2-‘1’;
END IF;
ELSE points_d1:=points_d1-‘1’;
END IF;
END IF;
END IF;
aa2<=points_a2; aa1<=points_a1; aa0<=”0000”;
bb2<=points_b2; bb1<=points_b1; bb0<=”0000”;
cc2<=points_c2; cc1<=points_c1; cc0<=”0000”;
dd2<=points_d2; dd1<=points_d1; dd0<=”0000”;
END PROCESS;
END behv;
3.6.2 计分模块仿真图
图3.11 计分仿真图
3.6.3 计分模块元件图
图3.12计分元件图
3.7 顶层文件
3.7.1 顶层文件源程序
LIBRARY IEEE; –顶层文件
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY qiangdaqi IS
PORT(clk,clk2,s,s0,s1,s2,s3,s4,s5,stop,rst:IN STD_LOGIC;
n,k,q_out:OUT STD_LOGIC;
m:OUT STD_LOGIC_VECTOR(1 DOWNTO 0);
a,b,c,d,e,f,g:OUT STD_LOGIC);
END qiangdaqi;
ARCHITECTURE behv OF qiangdaqi IS
COMPONENT qdjb IS
PORT(clk2,rst:IN STD_LOGIC;
s0,s1,s2,s3,s4,s5:IN STD_LOGIC;
tmp:OUT STD_LOGIC;
states:OUT STD_LOGIC_VECTOR(5 DOWNTO 0));
END COMPONENT;
COMPONENT js IS
PORT(clk,rst,s,stop:IN STD_LOGIC;
warn:OUT STD_LOGIC;
ta,tb:BUFFER STD_LOGIC_VECTOR(5 DOWNTO 0));
END COMPONENT;
COMPONENT sjxz IS
PORT(clk2,rst:IN STD_LOGIC;
s:OUT STD_LOGIC_VECTOR(1 DOWNTO 0);
a,b,c:IN STD_LOGIC_VECTOR(3 DOWNTO 0);
y:OUT STD_LOGIC_VECTOR(3 DOWNTO 0));
END COMPONENT;
COMPONENT ymq IS
PORT(ain4: IN STD_LOGIC_VECTOR (3 DOWNTO 0);
dout7: OUT STD_LOGIC_VECTOR (6 DOWNTO 0));
END COMPONENT;
COMPONENT alarm IS
PORT(clk,i:IN STD_LOGIC;
q:OUT STD_LOGIC);
END COMPONENT;
SIGNAL states_out,ta_out,tb_out,y_out:STD_LOGIC_VECTOR(3 DOWNTO 0);
SIGNAL ledout:STD_LOGIC_VECTOR(6 DOWNTO 0);
SIGNAL w:STD_LOGIC;
BEGIN
a<=ledout(6);b<=ledout(5);c<=ledout(4);
d<=ledout(3);e<=ledout(2);f<=ledout(1);g<=ledout(0);
u1:qdjb PORT MAP(clk2=>clk2,rst=>s,s0=>s0,s1=>s1,s2=>s2,s3=>s3,tmp=>k,
states=>states_out);
u2:js PORT MAP(clk=>clk,rst=>rst,s=>s,stop=>stop,warn=>n,ta=>ta_out,tb=>tb_out);
u3:sjxz PORT MAP(clk2=>clk2,rst=>rst,s=>m,a=>states_out,b=>ta_out,c=>tb_out,y=>y_out);
u4:ymq PORT MAP(ain4=>y_out,dout7=>ledout);
u5:alarm PORT MAP(clk2=>clk2,s=>s,q_out=q_out);
END behv;
3.7.1 顶层文件仿真图
图3.12 顶层文件仿真图
4 硬件调试
按下rst键清零,按下s键,观察数码管是否开始倒计时,扬声器是否发出报警声,按下s0,观察数码管是否显示1和抢答的时间,再按s1,s2,s3均不改变显示,按下rst键,观察是否清零,再按s键,不按别的,直到计时时间到,观察是否显示00,扬声器是否发出报警。第一个按下键的小组,抢答信号判定电路通过缓冲输出信号的反馈将本参赛组抢先按下按键的信号锁存,并且以异步清零的方式将其他参赛组的锁存器清零,组别显示、计时和计分会保存到主持人对系统进行清零操作时为止。当rst=1时系统复位,使组别显示信号a=0000,各组的指示灯信号s0=0,s1=0,s2=0,s3=0当rst=0,即低电平有效,使其进入抢答鉴别状态,到CLK的上升沿到来时,以A组抢答成功为例,当输入信号为a=1,b=0,c=0,d=0,输出信号a=0001,即为鉴别出A组抢答成功,同时屏蔽其他组的输入信号,以免发生错误。
总 结
这次EDA课程设计了一个星期,在这期间学到了很多很多的东西,同时不仅可以巩固以前所学过的知识,而且学到了很多在书本上所没有学到过的知识。通过这次设计,进一步加深了对EDA的了解,让我对它有了更加浓厚的兴趣。特别是当每一个子模块编写调试成功时,心里特别的开心。但是在编写顶层文件的程序时,遇到了不少问题,特别是各元件之间的连接,以及信号的定义,总是有错误,在细心的检查下,终于找出了错误和警告,排除困难后,程序编译就通过了。
通过这次课程设计使我懂得了理论与实际相结合是很重要的,只有理论知识是远远不够的,只有把所学的理论知识与实践相结合起来,从理论中得出结论,才能真正为社会服务,从而提高自己的实际动手能力和独立思考的能力。在设计的过程中遇到问题,可以说是困难重重,这毕竟第一次做的,难免会遇到过各种各样的问题,同时在设计的过程中发现了自己的不足之处,对以前所学过的知识理解得不够深刻,掌握得不够牢固。
总的来说,这次设计的数字抢答器还是比较成功的,在设计中遇到了很多问题,最后在老师的辛勤的指导下,终于一一解决,有点小小的成就感,终于觉得平时所学的知识有了实用的价值,达到了理论与实际相结合的目的,不仅学到了不少知识,而且锻炼了自己的能力,使自己对以后的路有了更加清楚的认识,同时,对未来有了更多的信心。
致 谢
在本次EDA课程设计中,加深了对EDA的了解,让我对它有了更加浓厚的兴趣。特别是当每一个子模块编写调试成功时,心里特别的开心。但是在编写顶层文件的程序时,遇到了不少问题,特别是各元件之间的连接,以及信号的定义,总是有错误,在细心的检查下,终于找出了错误和警告,排除困难后,程序编译就通过了。遇到了很多问题,在老师和同学的帮助下,也都一一解决了。比如当调试出现错误的时候,小组成员都会积极提供帮助,最终解决问题,提高了开发效率。不管过程如何,真的要好好非常感谢提供帮助的老师和同学。
首先我要感谢在本次实训中的指导老师,马岱老师和顾相平老师,他们给予我的指导、提供给我的支持和帮助。这是我能顺利完成这次报告的主要原因,更重要的是老师帮我解决了许多技术上的难题,让我能把系统做得更加完善。在此期间,我不仅学到了许多新的知识,而且也开阔了视野,提高了自己的设计能力。然后我还要谢谢计算机工程学院安排的这次实训。经过这两周的实训,更加是锻炼了对所学知识的认知应用能力以及团队协作的能力,在老师的悉心指导下,认识了到实训的重要性,同时也感受到理论与实践之间的差距,对于单片机系统的应用有了更加深刻的认识。我还要实验室及图书馆所有工作人员给我们提供的良好环境。正是因为各位工作人员井然有序的坚守工作岗位,才使我能够方便的完成此次的实训。同时,我要好好谢谢我的同学。在我遇到困惑时,正是因为在同学们的热心相助,才使我解决了疑惑。在大家团结一致的情况下,才使本次的实训圆满的完成。谢谢各位同学。
最后再一次感谢所有在设计中曾经帮助过我的良师益友和同学。
参考文献
1 江国强.EDA技术与应用.北京:电子工业出版社社,2010.4
2 李国洪.EDA技术与实验. 北京:机械出版社,2009.1
3 周立功.EDA实验与实践.北京:北京航天航空大学出版社,2007.9
4 潘松.EDA技术实用教程.北京:科学出版社,2005.5
5 朱正伟.EDA技术与应用北京:清华大学出版社,2005.4