由Proteus仿真入门单片机学习
1 引言
对于单片机的学习,由于其比较抽象,特别是在编写程序时,完全只是凭借程序员周密的逻辑思维来进行程序设计,为了让程序设计员更好的理解和调试其所设计的程序,所有单片机生产厂家都针对他们的单片机系列设计生产了相应的仿真器。然而这些仿真器的价格却不菲,无凝这是初次学习单片机时重要考虑的因素。而目前随着我国电子技术的飞速发展,我们所有生活上所用到、见到的电子产品都离不开单片机的身影,这也愈加激起我们对单片机的学习热情。然而在具体学习这门技术时,特别是高校教学时,因为实验设备不够和教学课时少等原因,往往都是采用纯理论性的或集体性的实验。而通过这种学习之后,以我个人在校学习时的经历和对一些高校学生的了解,大部分学习者最终都是知识考试过了关,却什么都不会。针对这一现象,在此本文提倡运用仿真的方法结合具体的设计来学习单片机知识。
目前国外很多软件设计公司都针对单片机的学习而设计了许多仿真软件,这使得单片机学习者只需要一台个人电脑就可以完成单片机程序的设计和调试,大大降低了我们的学习成本,方便了我们的学习。其中,Proteus[1]是由英国Labcenter 公司开发的具有硬件电路分析、实物仿真软件和程序仿真功能的仿真软件。通过软件安装在个人电脑后,可以实现了单片机和SPICE 电路相结合的仿真。在此运用该仿真软件,设计以AT89C2051[2]的P1 口输出正弦波为目的的硬件电路和相应程序,通过这一具体的项目设计,把理论与实践结合起来,以期引导入门单片机学习。
2设计Proteus里的仿真电路
为了对单片机内部程序运行时有感性上的理解,在此利用Proteus7 Professional 下的ISIS7 Professional 仿真电路设计软件设计了如下图1 所示的电路,该电路所预达到的功能是通过单片机AM89C2051 的P10-P17 口输出准正弦波并通过虚拟示波器显示出来,为了避免可能由电路元器件引起后面的调试工作,电路所有采用的元器件都采用软件自带的标准库里的元器件。
图1 Proteus 中基于AT89C2051 单片机的准正弦波电路
图1 所示电路的核心部件是信号处理器U1,双击它时可对它进行相应的设定,完成相应的设定后其功能就完全可以用来履行已烧入程序代码的CPU 的功能;时钟电路有晶体振荡器Y1 和瓷片电容C7、C8 组成;信号由U1 的P10-P17 这8 个输出口输出,信号再经过上来电阻RP1、R1-R8 分压输出和通过电压跟随器电路转化成近似于正弦波信号。
电阻R1 至R8 满足如下方程:
于是得出S0-S8 分别约为:0、0.0381、0.1464、0.3087、0.5、0.6913、0.8536、0.7619和1。S(n)值确定后,作出S(n)的值在EXCEL 里折线图如图2 所示,从图表中可以看出其形状类似于正弦信号在-90°到+90°象限内的波形。再依据以上结果,由式(3)可计算出R1-R8 的阻值关系,并按照常用电阻阻值规则,可取定如图1 电路图所示电阻阻值。
图2 S(n)的在Excel 里的折线图
3 设计相应程序
参照前面所设计电路,利用时间中断程序来产生频率为1KHz 的正弦波,所设计程序源代码及相关注释如下:
3.1定义P1端口的输出值
首先定义P1 端口的输出,P1 端口将按照数组P1_out[ ]给出的值不停的输出,也类似于P1 端口的P10 置“1”其他端口置“0”后不停的左移和右移。之所以该数组的大小为16是因为将输出正弦波周期在时域上分成16 等分。
code char P1_out[16]=
{0x00,0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01,0x02,0x04,0x06,0x10,0x20,0x40,0x80};
3.2初始化时钟中断0和1
在此程序中主要是初始化有关时钟中断寄存器。
void int_init(void)
{ EA=0;//关闭所有中断,以保证在调用此子程序时中断不会发生
TMOD=0x11; //#00000001B ;定义时钟中断0 为16 位时钟发生器
TCON=0x50; //#00010000B ; 使能时钟中断0
IE=0x0a; //#00000010B ; 运行时钟中断0
IP=0x02; //#00000010B ; 时钟中断0 优先
TL0= (65535-1000/16);
TH0= ((65535-1000/16)>>8); /*初始化时钟中断0 的计数寄存器,系统时钟12MHz, 所以中断计数时间为1us,中断发生时间为1000/16X1us=1/16ms, 频率为16KHz,除以16 是因为一个周期被分成16 等分*/
EA=1; //允许中断发生
}
3.3主程序
#include
#include
#include
void main(void)
{
static short P1_out_cnt=0; //定义对P1 口输出时计数
int_init(); //调用中断初始化子程序
while(1) //下面为一个无限循环
{
_nop_();
}
}
3.4时钟中断子程序
void timer_0 (void) interrupt 1 using 1
{ TL0= (65535-1000/16);
TH0= ((65535-1000/16)>>8); //重置时钟中断0 的时间计数寄存器值
P1=P1_out[P1_out_cnt]; //P1 口按数组给定值输出
P1_out_cnt++; //指向数组中下一个值
P1_out_cnt=0x0f; //00001111B,保证0≤P1_out_cnt≤15
}
- Windows CE 进程、线程和内存管理(11-09)
- RedHatLinux新手入门教程(5)(11-12)
- uClinux介绍(11-09)
- openwebmailV1.60安装教学(11-12)
- Linux嵌入式系统开发平台选型探讨(11-09)
- Windows CE 进程、线程和内存管理(二)(11-09)