单片机应用系统设计技术
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

第II章Proteus ISIS入门实例

本章将通过4个实例,分别介绍Proteus ISIS中绘制基本电路的方法、总线和虚拟仪器的运用、如何绘制子电路、如何设计模块元器件。

关于Proteus ISIS仿真电路的说明如下。

① 目前在Proteus 7 Professional中所有的80C51系列单片机使用的都是同一仿真模型:MCS8051.DLL,故在设计仿真电路时,选择AT89C52、AT89C51、80C32或P87C51FA等80C51单片机器件没有任何区别,其片内程序存储器足可以装载任何小于64KB的程序代码。扩展片外的程序存储器也无任何意义,无论或悬空,均使用片内ROM。实际上,80C51单片机系统目前也很少使用片外程序存储器。

② 在Proteus 7 Professional中设计80C51单片机系统原理图时,可以省略复位电路和时钟电路,默认复位有效,时钟频率可以通过CPU器件在单片机的属性中进行设置。为节省版面,除实例1外后续的电路中将省略复位电路和时钟电路,不考虑接VCC。但在设计实际系统中,必须有复位电路和时钟电路,需要接VCC,使用片内存储器

③ 单片机及外围电路的输入引脚悬空时,默认输入信号为低电平。

一、实例1:绘制基本电路的方法

本实例运用单片机AT89C52,通过按键控制点亮LED,实现流水灯(见图II.1)。具体过程为:设置一个触发按键,每按一次按键,灯就循序往下点亮,从而实现手控的流水灯的功能,所用的元器件清单见表II.1。

图II.1 实例1原理图

1.将所需的元器件添加到元器件列表

① 单击按钮,打开“Pick Devices”对话框。

表II.1 实例1原理图元器件清单

② 在“Keywords”框中输入“at89c52”,不区分大小写,如图II.2所示。在Results区中显示了两种类型的AT89C52,这个实例需要引脚型的,双击“AT89C52”项,将其添加至元器件列表区中。

图II.2 AT89C52的选取

③ 在“Keywords”框中输入res,选中“Match Whole Words”复选框,如图II.3所示。在“Results”区中获得与RES完全匹配的搜索结果。双击“RES”项,将“RES”(电阻)添加至元器件列表区中。依照表II.1的元器件清单,将所要用到的元器件添加到元器件列表区中,单击“OK”按钮,结束对象选择。

图II.3 电阻的选取

④ 单击元器件列表区中的元器件,它将会在导航窗口中显示出来,如图II.4所示。

图II.4 导航窗口显示所要用到的元器件

2.将元器件放置在原理图编辑窗口中

① 单击选取元器件

单击选取元器件列表区中的元器件放置在原理图编辑窗口中。若对象位置需要移动,将鼠标指针移到该对象上,单击,如果该对象的颜色变为红色,就表明该对象已被选中,按住左键拖动鼠标,将对象移至新位置后,松开左键,完成移动操作。

② 修改元器件的属性

要改变元器件的参数,可以双击该元器件,或从右键快捷菜单中选择“Edit Properties”命令,打开元器件的编辑对话框。如图II.5所示,是电阻属性对话框,可以修改元器件的参考号,也可以修改元器件的值。

图II.5 元器件编辑对话框

③ 块操作

很多元器件的参数值相同(如本实例中的电阻、LED),可以选择要复制的元器件或电路模块,单击“块复制”按钮,在原理图中单击,就能快速进行粘贴,也可以进行块移动、块旋转、块删除,操作基本与块复制相似。

④ 添加电源和接地引脚

单击工具箱中的按钮,选择POWER和GROUND,为电路添加电源和地。

⑤ 旋转元器件

右击元器件,将会弹出快捷菜单,可以选择如何旋转元器件,如图II.6所示。也可以用快捷键:“+”、“-”,旋转元器件。在放置元器件之前,可以使用工具箱中的“旋转”按钮,在导航窗口中进行旋转。如果原理图中要旋转的元器件较多,使用工具箱中的“旋转”按钮可以减少很多劳动量。

图II.6 右键快捷菜单

⑥ 添加文字标注

单击工具箱中的按钮,在原理图编辑窗口中添加文字标注。

将所有的元器件按理想位置摆好,如图II.7所示。

图II.7 连线前的原理图

3.进行元器件的连线,完成原理图的绘制

① 在原理图绘制过程中,有时连线上会出现交叉点,若出现的是实心小黑圆点,则表明导线连通,否则表明导线无连通关系。要让两根交叉线接通,也可以通过工具箱中的“连接点”按钮进行连接。

② Proteus ISIS具有自动连线功能。只要选择一根连线的起始端点和末端点,它将会自动寻找合适路径进行连接。使用上方工具栏中的“自动连线”按钮,可以实现自动连线功能的开启和关闭。

③ Proteus ISIS具有自动布线功能,当要连接的多组元器件的位置平行时,只要连接一组元器件,然后双击元器件组的起始端点,它将会自动连接末端点。例如,连接了图II.7中的R1与D8之后,只要双击R2、R3等,就会自动连接D7、D6等。连接分支与总线时,用此方法会很方便。

④ 如果一根线连接错误,可以在连线上右击,在快捷菜单(如图II.8所示)中选择“Delete Wire”。也可以右键双击,取消此连线。当然,也可以选择该连线,按“Delete”键。

图II.8 删除错误连线

完成各个对象间的连线后,就完成了原理图的绘制。

4.参考程序

            #include <REG52.h>               /*片内寄存器定义所在头文件*/
            sbit key=P2^0;                   /*定义触动开关接P2.0引脚*/
            void main (void)
            {
            unsigned char x;                 /*定义显示位*/
                x=1;                         /*初始化灯状态,指示显示红灯D1*/
                /*循环按键,使灯循环点亮*/
                while(1)
                {
                P1=~x;                      /*LED共阳极,取反由P1显示显示位*/
                x=x<<1;                      /*循环左移,指示下一个显示位*/
                while(key);                  /*判断是否有按键按下*/
                while(!key);                 /*判断按键是否释放*/
                      if(x<128)
                        continue;            /*判断是否显示到最后一位,没有,继续显示其他位*/
                      else
                      {
                        P1=~x;              /*显示最后一位*/
                      while(key);            /*判断是否有按键按下*/
                        while(!key);         /*判断按键是否释放*/
                        x=1;                 /*初始化灯状态,从D1等重新开始显示*/
                      }
                }
            }

5.在μVision 3中运行该程序

在μVision 3中建立工程,并添加参考程序,然后进行相应的设置(见第I章中相关内容),编译链接。如果程序没有错误的话,结果如图II.9所示。

图II.9 μVision 3的编译链接结果

6.修改AT89C52属性,并加载程序文件

双击仿真电路中U1,弹出AT89C52的编辑对话框,如图II.10所示,可以选择HEX文件的路径和晶振频率。

图II.10 AT89C52的编辑对话框

7.调试运行

可采用下面两种方法之一调试程序。

① 直接在Proteus ISIS环境中单击“运行”按钮,可以看到元器件的两边会出现两个小点,表示元器件两边电平的变化,红色表示高电平,蓝色表示低电平,灰色表示未接入信号或者为高阻态。其运行状态的窗口如图II.11所示。由于AT89C52单片机的P1、P2、P3口在内部上拉,当软件没有控制其输出时,引脚显示红色表示为高电平,P0口为开路输出,故显示灰色表示高阻态。

图II.11 实例1仿真效果

② 直接在μVision 3 IDE中单击按钮,也可打开Proteus ISIS仿真电路,此时可使用μVision 3 IDE的各种调试手段。其调试功能远比Proteus ISIS强大。

二、实例2:总线和虚拟仪器的使用

本例运用Proteus ISIS中脉冲发生器产生的1HZ方波,输入单片机AT89C52中,由AT89C52将脉冲发生器产生的方波的个数通过LED显示出来;同时,AT89C52将脉冲发生器产生的方波转化为0.5Hz的方波,0.5Hz方波的个数通过虚拟终端显示出来。本实例还用到示波器,将两种方波进行对比,如图II.12所示。所用的元器件清单见表II.2。

图II.12 实例2原理图

表II.2 实例2原理图元器件清单

1.将所需元器件添加在元器件列表中

将用到的元器件添加到元器件列表区中,注意:本实例用到的AT89C52是总线型的,所以这次选取元器件时选择AT89C52.BUS。

2.总线的画法

① 放置总线

从工具箱中选择“总线”按钮,在要画总线的一端单击,然后拖动鼠标,在总线需要拐点的地方右击,改变总线的走向,在总线的终点处双击,结束总线的放置,如图II.13所示。

图II.13 总线的放置

② 放置总线分支

总线分支就是总线的各个引线,引线用于连接元器件的各个引脚。当连接各个元器件的引脚时,粗线会自动变成细线。

连接方法为:单击“自动布线器”按钮使之处于选中状态(为画斜线做准备),然后单击元器件的一个引脚,拖动鼠标,在距总线一个背景栅格时,按住“Ctrl”键的同时单击,在与原来方向垂直的方向上移动鼠标,移动一个背景栅格,可以将细线画成与总线成45°的斜线,单击,完成了一条总线分支的绘制。画其他分支时,因为路径相似,可以运用Proteus的自动布线功能,只要在每个引脚上双击,Proteus就会自动完成其余总线分支的绘制。绘制结果如图II.14所示。

图II.14 总线分支的绘制结果

③ 添加总线终端

为了保证总线的电气导通,一般要添加一个总线终端,总线终端可以从终端模式中找到。进入终端模式,选择最后一项“BUS”,然后在原理图编辑窗口中画出一个总线终端,与总线相连。

双击总线终端,进入终端编辑对话框,如图II.15所示,在“String”框中填入P2[0..7],中间的两点表示从0到7。总线终端的命名可以与单片机的总线名相同,也可以不同。

图II.15 终端编辑对话框

④ 添加网络标签

添加网络标签是为了实现总线分支的电气识别。从工具箱中找到网络标签的图标,把鼠标指针指向要放置标签的总线分支上,在鼠标指针处将会出现一个“×”号,单击,将会出现标签编辑对话框,如图II.16所示。在“String”下拉列表中可以看到P20、P21等标号,这是因为已经添加了总线终端。选择合适的标号,就可以与总线同标号的电气线进行连接。

图II.16 标签编辑对话框

如果没有添加总线终端,则必须自己输入网络标签,如图II.17所示,就是一个例子。可以先在标签属性对话框中输入总线一端的网络标签,然后从“String”下拉列表中选择另一端网络标签。

图II.17 手动添加标签

也可以对网络标签进行连续的添加,选择菜单命令“Tool”→“Property Assignment Tool”或按快捷键A,将会弹出属性设置工具对话框,如图II.18所示。在“String”框中输入属性及属性关键字,将它改为“net=P2#”;在“Count”框中输入关键字P2计数的初值,默认为0;在“Increment”框中输入网络标签的增量,为1。设置完后,第一次单击总线分支时,标签将从P20开始,每单击一次,依次递增。用这种方法,很容易实现连续标注。

图II.18 属性设置工具对话框

添加网络标签后如图II.19所示。

图II.19 添加网络标号

3.虚拟示波器和虚拟激励源的使用

① 单击工具箱中的按钮,可以看到很多虚拟仪器,如OSCILLOSCOPE(示波器)、LOGIC ANALYSER(逻辑分析仪)等。选择“OSCILLOSCOPE”,添加到原理图编辑窗口中,如图II.20所示。虚拟示波器有A、B、C、D共4个接线端,可以同时测量4路输入信号。

图II.20 虚拟示波器

② 单击工具箱中的按钮,同样可以看到很多激励源,如DC(直流信号发生器)、SINE(正弦波信号发生器)等。选择“PULSE”,即脉冲激励信号,添加到原理图编辑窗口中,如图II.21所示。脉冲激励信号名默认为“?”,当与其他元器件、电路连上后,它的名字会自动更改为已标注的导线名、总线名,或者与该导线连接的设备引脚名。

图II.21 脉冲激励信号

③ 将脉冲信号接到示波器的A通道,如图II.22所示,双击脉冲信号的图标,将出现如图II.23所示的脉冲信号属性设置对话框。

图II.22 脉冲信号与示波器的接法

图II.23 脉冲信号属性设置对话框

④ 本实例将脉冲信号的频率设为1Hz,将幅度设为5V(由AT89C52单片机判断高、低电平)。单击按钮开始仿真,弹出如图II.24所示的示波器运行界面。

图II.24 示波器的运行界面

该示波器可以同时显示4路输入信号,可以通过旋转按钮修改显示波形的大小和位置。由于本实例示波器只有A通道接入了脉冲信号,因此图II.24中只显示A通道的脉冲信号。

4.虚拟终端的使用

单击工具箱中的按钮,选择“VIRTUAL TERMINAL”,即虚拟终端,添加到原理图编辑窗口中,如图II.25所示。从图中可以看出,虚拟终端有4个接线端。

图II.25 虚拟终端

RXD:数据接收端。

TXD:数据发送端。

RTS:请求发送信号。

CTS:清除传送,是对RTS的响应信号。

读取信号时,一般将RTS和CTS短接。

双击虚拟终端图标,将会弹出虚拟终端的编辑对话框,如图II.26所示。

图II.26 虚拟终端的编辑对话框

波特率要根据单片机的数据传输速率进行设置,如果不匹配,终端将不会显示,或出现乱码错误。其他设置要根据单片机串行口通信的方式,进行相应设置。本实例的具体设置如图II.26所示。

5.添加电压探针

单击工具箱中的按钮,按照原理图,在示波器引脚线上和总线上添加电压探针。连到单个信号线上的电压探针测试的是高、低电平的周期性变化,连到总线上的探针显示的是总线数据。

6.参考程序

            #include <REG52.H>                   /*片内寄存器定义所在头文件*/
            #include <stdio.h>                   /*输入输出函数库*/
            #define uchar unsigned char          /*为字符数据类型定义新名字为uchar*/
            sbit pulse_in=P1^1;                  /*定义脉冲输入接P1.1引脚*/
            sbit pulse_out=P1^0;                /*定义脉冲输出接P1.0引脚*/
            void initUart(void);                 /*初始化串行口波特率,使用定时器2*/
            /*********** main C **************/
            void main (void)
            {
                unsigned char i,j;               /*定义7段数码管与虚拟终端的输出变量*/
                i=0;                             /*初始化数码管的输出值为0*/
                j=0;                             /*初始化虚拟终端的输出值为0*/
                initUart();                      /*为了使用printf语句,初始化串行口*/
                /*脉冲信号发生器与单片机转换的脉冲输出*/
                while(1){
                        P2=i;                    /*显示脉冲信号发生器脉冲的个数*/
                        while(!pulse_in);        /*等待脉冲的高电平状态*/
                        pulse_out=0;             /*将脉冲输出设置为低电平*/
                      while(pulse_in);           /*等待脉冲的低电平状态*/
                        i++;                     /*记录脉冲信号发生器脉冲的个数*/
                        P2=i;                    /*显示脉冲信号发生器脉冲的个数*/
                      while(!pulse_in);          /*等待脉冲的高电平状态*/
                        pulse_out=1;             /*将脉冲的输出设置为高电平*/
                      while(pulse_in);           /*等待脉冲的低电平状态*/
                        i++;                     /*记录脉冲信号发生器脉冲的个数*/
                      j++;                       /*记录单片机输出脉冲的个数*/
                        printf("current data-out of port: 0%BX\n",j);
                      /*从虚拟终端显示单片机输出脉冲的个数*/
                    }
            }
            /********** 初始化串行口波特率 ************/
            void initUart(void)                  /*初始化串行口波特率,使用定时器2*/
            {
            /* Setup the serial port for 9600 baud at 11.0592MHz */
                SCON=0x50;  //串行口工作在方式1
                RCAP2H=(65536-(3456/96))/256;    /*设置计数初值,高字节*/
                RCAP2L=(65536-(3456/96))%256;    /*设置计数初值,低字节*/
                T2CON=0x34;                      /*设置中断请求标志位*/
    TI =1;                                     /*置位TI*/
            }

7.观察结果

从图II.27可以看出,电压指针显示的是总线上的数据,示波器上A通道和B通道显示的波形周期恰好是两倍的关系,虚拟终端和LED显示的脉冲个数也是两倍的关系。

图II.27 实例2仿真效果

三、实例3:绘制子电路

在Proteus ISIS中用一个子电路可以把部分电路封装起来,这样可以实现电路图功能的模块化,也可以节省原理图编辑窗口的版面空间。图II.28是一个多开关控制灯原理图,按K1时,一个灯亮,按K2时,两个灯亮,……,按K8时,8个灯亮,按下多个按键时,全灭。现在将虚线围成的电路设计成子电路,所用的元器件清单见表II.3。

图II.28 实例3原理图

表II.3 实例3原理图元器件清单

1.将所用元器件添加到元器件列表区中

新建一个ISIS设计文档,将表II.3中给出的元器件添加到元器件列表区中。

2.创建子电路

① 画出子电路外形

单击工具箱中的按钮,在下拉列表中选择“DEFAULT”项,在原理图编辑窗口中按住左键,画出一个子电路模块如图II.29所示,然后依次选择“INPUT”和“BUS”项,在外框线上单击,添加输出端口和总线端口,如图II.30所示。

图II.29 子电路图模块

图II.30 添加端口后的子电路图模块

② 编辑图框和端口的名称

双击图框,或者从右键快捷菜单中选择“Edit Properties”命令,将会出现如图II.31所示的对话框,在“Name”(实体名称)框中输入“I/O”,表示基本的输入/输出;在“Circuit”(电路名称)框中输入“CR-LED”,表示这是一个控制LED的电路。

图II.31 子电路编辑对话框

双击端口,打开如图II.32所示的对话框,在“String”框中填写端口的名称,端口的名称必须与子电路的逻辑终端的名称一致。如果编辑的引脚有上画线,则在名称前面输入$,如OE,输入$OE即可。总线也可以通过此方法来命名,设置属性。

图II.32 端口编辑对话框

将输出端口依次设置为:P1.0, P1.1, …, P1.7,将输入总线设置为C[0..7],画出的子电路图如图II.33所示。

图II.33 子电路图模块

③ 编辑子电路

画好上述子电路之后,右击该图,选择“Goto Child Sheet”命令,如图II.34所示,或按快捷键Ctrl+C,这时,ISIS将会加载一个空白子图页。

图II.34 快捷菜单

单击工具箱中的按钮,将会列出所有终端,选择“OUTPUT”项,在空白页上有序地画上8个输出端;然后选择“BUS”项,画出一个总线终端。双击这些终端,为其命名,如图II.35所示。

图II.35 端口编辑对话框

注意,这些终端的名称必须与子电路框图上的名称保持一致。根据端口,画出子电路图。如果子电路需要电源,可以选择终端模式下的“POWER”项,添加电源。通过元器件的布局和连线,由此得到子电路图,如图II.36所示。

图II.36 子电路图

④ 返回主设计图

子电路编辑完后,选择菜单命令“Design”→“Goto Sheet”,打开如图II.37所示的对话框。选择“Root sheet1”,单击“OK”,返回主设计图。也可以在空白处右击,从快捷菜单中选择“Exit to Parent Sheet”返回主设计图,如图II.38所示。

图II.37 返回主设计图

图II.38 快捷菜单

⑤ 编辑子电路属性

单击子电路图框,进入子电路的编辑对话框,可以对电路属性进行编辑,如图II.39所示。可以在“Properties”框中输入U2=AT89C52,说明定义的电路图所用的元器件是AT89C52。

图II.39 子电路的编辑对话框

然后单击“OK”按钮完成对子电路的设计。

3.画出总电路图

通过以上步骤,完成了一个子电路的设计,现将该子电路图连接到总电路图中,如图II.40所示。

图II.40 包含子电路的总电路图

4.参考程序

            #include <REG52.H>
            #define PORT_OUT P1                               /*定义P1为输出口*/
            #define PORT_IN P2                                /*定义P2为输入口*/
            unsigned char state[8]={0x01,0x03,0x07,0x0f,0x1f,0x3f,0x7f,0xff,};
            /*存放LED灯不同按键状态对应的P1口的输出值*/
            void main(void)
            {
            unsigned char i;                                  /*定义存放按键值的变量*/
                while(1)
                {
                      i=~PORT_IN;                            /*取按键值*/
                      switch(i)                               //判断是第几个按键按下,然后就亮几个灯
                      {  /* 共阳极数码管,所以状态取反*/
                        case 1: PORT_OUT =~state[0];break;   /*按键S1亮1个灯*/
                        case 2: PORT_OUT =~state[1];break;   /*按键S2亮2个灯*/
                        case 4: PORT_OUT =~state[2];break;   /*按键S3亮3个灯*/
                        case 8: PORT_OUT =~state[3];break;   /*按键S4亮4个灯*/
                        case 16: PORT_OUT =~state[4];break;  /*按键S5亮5个灯*/
                        case 32: PORT_OUT =~state[5];break;  /*按键S6亮6个灯*/
                        case 64: PORT_OUT =~state[6];break;  /*按键S7亮7个灯*/
                        case 128: PORT_OUT =~state[7];break; /*按键S8亮8个灯*/
                        default:PORT_OUT =0xff;break;         /*多个按键按下时,全灭*/
                      }while(i==~PORT_IN||PORT_IN==0xff);    /*判断是否有新按键按下,没有则等待*/
                }
            }

5.观察结果

从如图II.41所示的仿真图可以看到,按下S6按键时,发光二极管有6个灯亮。

图II.41 实例3仿真效果

四、实例4:模块元器件的设计

模块元器件的封装,是指将一个电路图封装成一个特殊的元器件,这样可以简化电路的设计,节省原理图编辑窗口的空间,也增强了电路的层次性。图II.42所示是一个交通灯的原理图。具体过程为:初始态为4个路口的红灯全亮,之后,南北路口的绿灯亮,东西路口的红灯亮,南北路口方向通车。延时一段时间后,南北路口的绿灯熄灭,黄灯开始闪烁。闪烁2次后,南北路口红灯亮,而同时东西路口的绿灯亮,东西路口方向开始通车。延时一段时间后,东西路口的绿灯熄灭,黄灯开始闪烁。闪烁2次后,再切换到南北路口方向,重复以上过程。

图II.42 实例4原理图

现在将图II.42中虚线围起来的部分设计成一个模块元器件。由图可知,此部分电路共有8个输入端口,12个输出端口。元器件清单见表II.4。

表II.4 实例4原理图元器件清单

1.将所用元器件添加到元器件列表区中

新建一个ISIS设计文档,将表II.4中给出的元器件添加到元器件列表区中。

2.创建模块元器件

① 绘制模块元器件外形

单击工具箱中的按钮,下拉列表中列出了各种图形类型,有画元器件的“COMPONENT”,画子电路的“SUBCIRCUIT”,画端口的“PORT”等。本实例选择画元器件的“COMPONENT”项,在原理图编辑窗口中按住左键拖动,画出元器件的外形,如图II.43所示的方框。

② 添加引脚

单击工具箱中的按钮,下拉列表中会列出各种引脚类型,选择“DEFAULT”项,然后在原理图编辑窗口中单击,将会出现如图II.43所示的引脚,按“+”键或“-”键,可以调整引脚的方向,将引脚放置在元器件外的适当位置。注意,一般习惯将引脚放置在元器件的两边,且在没有“×”的一端连接元器件。如图II.43所示,有8个输入端口,12个输出端口。

图II.43 模块元器件的外形

③ 引脚的设置

将鼠标指针放在引脚上,引脚将会变红,按Ctrl+E组合键,或者右击引脚,从快捷菜单中选择“Edit Properties”命令,打开引脚编辑对话框,如图II.44所示。模块元器件的引脚类型见表II.5。

图II.44 引脚编辑对话框

表II.5 模块元器件的引脚类型

在Pin Name(引脚名称)框中输入“D1”,在Electrical Type区中选择“IP”。然后,单击“Next”按钮,进入下个引脚的编辑。Electrical Type区,将左边的引脚都设置为“IP”,将右边的引脚设置为“OP”,与实际电路相对应。要输入“OE”,表示低电平有效,则在Pin Name框中输入“$OE”,$表示上画线。编辑完引脚属性后的图如图II.45所示。

图II.45 模块元器件

④ 设置图块属性

将鼠标指针放在图块上,方框变成红色,右击,从快捷菜单中选择“Edit Properties”命令(也可以用快捷键Ctrl+E),打开如图II.46所示的编辑对话框,取消选中各项的“Follow Global”,可以设置图块的线性、填充色等,也可以采用默认设计。

图II.46 图块编辑对话框

⑤ 在图形上设置标注

单击工具箱中的按钮,在下拉列表中选择“COMPONENT”项,然后在图块上单击,将会出现如图II.47所示的对话框,在String框中输入“74HCCIRCUIT”。

图II.47 标注编辑对话框

在Font Attributes区中可以设置字体的格式和位置,设置完以后,单击“OK”按钮。如果想对引脚也进行标注,单击工具箱中的按钮,在下拉列表框中选择“PIN”项,单击图块的引脚,对引脚进行标注。

图II.48完成了对图块的标注,74HCCIRCUIT表示这是一个含有74HC系列芯片的子电路。

图II.48 编辑完成的模块元器件

⑥ 将模块元器件存入元器件库

按住左键拖动鼠标,画出方框选中模块,选择菜单命令“Library”→“Make Device”,或者右击,从快捷菜单中选择“Make Device”命令,打开如图II.49所示的对话框。

图II.49 元器件属性对话框

在“Device Name”框中输入“74HCCIRCUIT”,在“Reference Prefix”框中输入“U”,在“External Model”框中输入“74HCCIRCUIT”,然后一直单击“Next”按钮,直到出现如图II.50所示的对话框。

图II.50 元器件存入元器件库

单击“Device Category”(元器件库)旁边的“New”按钮,打开如图II.51所示的对话框。新建一个名为“USE”的库,单击“OK”按钮,刚刚设计的元器件被放在这个库里面。

图II.51 新建一个库

通过以上步骤,完成了一个模块元器件的设计工作。下面将介绍如何为模块元器件设计子电路。

⑦ 取出模块元器件,进行相应的设置

单击工具箱中的按钮,然后单击按钮,进入元器件库。在“Keywords”框中输入“74HCCIRCUIT”,如图II.52所示。在“Category”框中可以看到刚建立的类“USE”,单击“USE”项,在右侧列表框中可以看到刚制作的模块元器件,双击它,使之出现在元器件列表区中。

图II.52 拾取模块元器件

将元器件列表区中设计的模块元器件放在原理图编辑窗口中。将指针放在元器件上,右击,在快捷菜单中选择“Edit Properties”命令或按快捷键“Ctrl+E”,进入元器件编辑对话框,如图II.53所示。对“Component Reference”和“Component Value”可以修改,但注意“Component Reference”不要和其他元器件重名。选中“Attach hierarchy module”复选框,表示附加层次模块,可以增加子电路。单击“OK”按钮完成设置。

图II.53 元器件编辑对话框

⑧ 画子电路

将指针放在模块元器件上,右击,从快捷菜单中选择“Goto Child Sheet”命令,或者按快捷键Ctrl+C,打开一个空白页。从工具箱中选择按钮,从下拉列表中选择“INPUT”,在原理图编辑窗口中画8个端口;选择“OUTPUT”,画出12个输出端口。然后单击端口符号,进入端口编辑对话框,对端口进行命名。注意子电路的端口名必须与模块元器件的引脚名一致。按照图II.42虚线框内的电路,进行连线,可以得到如图II.54所示的子电路。最后返回主设计图。

图II.54 模块元器件子电路图

3.画总电路

通过以上步骤,完成了一个模块元器件的设计,现在按照图II.42将子电路图连入总电路图中,可以得到如图II.55所示的电路图。整个界面看起来简洁了很多。为了进一步表现交通灯的特点,把图II.55改造为总线连接的总电路图,如图II.56所示。

图II.55 含模块元器件的总电路图

图II.56 总线连接的总电路图

4.参考程序

主程序模块main.c:

            #include <REGX52.H>                  /* special function register declarations */
            #include <stdio.h>                   /* prototype declarations for I/O functions */
            #include <intrins.h>
            #include <Absacc.h>
            #include <string.h>
            #include <ctype.h>
            #define byte unsigned char
            #define uchar unsigned char
            #define word unsigned int
            #define uint unsigned int
            #define ulong unsigned long
            #define BYTE    unsigned char
            #define WORD    unsigned int
            #define TRUE  1
            #define FALSE 0
            #define PORT_OUT P2                  /*定义P2为输出口*/
            #define LE P2_6                      /*定义锁存器使能引脚接P2.6引脚*/
            #define OE P3_6                      /*定义锁存器使能引脚接P3.6引脚*/
            #define YELLOW_1 P2_1                /*东西方向的黄灯接P2.1引脚*/
            #define YELLOW_2 P2_4                /*南北方向的黄灯接P2.4引脚*/
            unsigned char state[5]={0x36,0x33,0x35,0x1e,0x2e};/*存放P2口的输出,对应的状
                                    态为:东西南北都为红灯;东西红灯,南北绿灯;东西红灯,南北黄灯;
                                    东西绿灯,南北红灯;东西黄灯,南北红灯*/
            void initUart(void);                 /*初始化串行口*/
            void time(unsigned int ucMs);        //延时单位:ms
            void main(void)
            {
                unsigned char counter=0x0;
                /*灯状态值数组的索引,与前面定义的灯的状态值数组state结合使用*/
                int times=2000;                 /*存放延时数值,单位为毫秒*/
                initUart();
                OE=0x0;                         /*使能锁存器的输出*/
                P2=state[0];                    /*初始化灯的状态为东西南北都为红灯*/
                LE=0x1;                         /*使能锁存器的锁存引脚*/
                while(TRUE)
                {
                      time(times);                /*延时以使灯的状态保持一定时间*/
                      P2=state[counter++];       /*输出灯的状态并将索引指向灯的下一状态*/
                      LE=0x1;                    /*使能锁存器以锁存灯的下一状态的值*/
                      if(counter==3 || counter==5)/*当前东西或南北为黄灯时,使黄灯闪烁*/
                      {
                        times=500;               /*闪烁时延时间隔为500毫秒*/
                        time(300);                /*延时300毫秒*/
                        YELLOW_1=0x1;            /*灭黄灯1*/
                        YELLOW_2=0X1;            /*灭黄灯2*/
                        time(300);                /*延时300毫秒*/
                        if(counter==3)
                            YELLOW_1=0x0;        /*亮黄灯1*/
                        else
                            YELLOW_2=0x0;        /*亮黄灯2*/
                      }
                      else
                        times=2000;              /*非黄灯状态,延时2秒*/
                      if(counter>4)
                        counter=0x1;             /*索引越界时重新赋值为1*/
                }
            }
            /*********************************************************
            *  函数说明:延时5us,晶振改变时只需要改变这一个函数!
                1.对于11.0592MHz晶振而言,需要2个_nop_();
                2.对于22.1184MHz晶振而言,需要4个_nop_();
            *  入口参数:无
            *  返回:无
            *  创建日期:20010623
            *  作者:张齐
            *********************************************************/
            void delay_5us(void)                 //延时5us,晶振改变时只改变这一个函数
            {
                _nop_();
                _nop_();
                //_nop_();
                //_nop_();
            }
            /************ delay_50us ***************/
            void delay_50us(void)                //延时50us
            {
                unsigned char i;
                for(i=0;i<4;i++)
                {
                      delay_5us();
                }
            }
            /******** 延时100us ******************/
            void delay_100us(void)               //延时100us
            {
                delay_50us();
                delay_50us();
            }
            /*********** 延时单位:ms *******************/
            void time(unsigned int ucMs)        //延时单位:ms
            {
                unsigned char j;
                while(ucMs>0){
                      for(j=0;j<10;j++) delay_100us();
                      ucMs--;
                }
            }
            /********** 初始化串行口波特率 ************/
            void initUart(void)                 /*初始化串行口波特率,使用定时器2*/
            {
            /* Setup the serial port for 9600 baud at 11.0592MHz */
                SCON=0x50;                    //串行口工作在方式1
                RCAP2H=(65536-(3456/96))>>8;
                RCAP2L=(65536-(3456/96))%256;
                T2CON=0x34;
                TI =1;                        /* 置位TI*/
            }

注:程序中无法输入希文μ,因此用us表示微秒,以下不再说明。

5.观察结果

由图II.57可以看出,现在交通灯的状态为:南北绿灯可以通行,东西红灯禁止通行。

图II.57 实例4仿真效果