电子产品的更新换代越来越快,怎样缩短设计时间,快速推出产品,降低设计成本和提高系统整体性能是每个设计人员共同关心的问题。一种叫做在应用可编程(In Application Programming-IAP)的设计方案应运而生,它可以在现场(当原存在的代码正在运行时)重新写入运行代码。这种方案的优点是可以降低开发代码的时间、可在装配线上测试和改装产品、可在现场修正代码错误、可以容易地添加产品新功能甚至可以远程进行系统的升级。目前,实现在应用可编程一般有两种方法:一种方法是使用与单片机配套的专用芯片;另一种是采用新型的支持在应用可编程的单片机。本文介绍一种基于AT89C51单片机的在应用可编程的设计方案,它只占用AT89C51的UART,只需少数的几块芯片就能实现上述功能。特别适用于需要用UART进行通讯的测控网络的设计。
1 设计思路
基于8051核的单片机提供两个独立的地址空间,一个用于程序存储器,一个用于数据存储器。这种特殊的地址结构在任何情况下都不会将数据写入程序空间,保护程序代码不会被数据覆盖,但这种特性使单片机在应用可编程不能实现。如果采用一种方法“欺骗”系统使之误认为程序存储器即为数据存储器,则可向程序存储器中写数据了。“欺骗”系统的方法是在IAP期间暂时将程序存储器“重新分类”为数据空间而不是程序空间,然后在IAP完成后再将它重新分类为程序空间。这种方案需要一款存储器既可以当作数据存储器又能作为程序存储器。现在市面上的多种具有掉电保护功能的静态随机存储器既具有数据存储器的高读写速度又具有程序存储器的非挥发性。如DALLAS公司的DS1230Y-70是与通用RAM27256管脚兼容的,内嵌锂电池保护的非易失性存储器,读写速度为70ns,掉电状态下可以保存数据10年。
按照上述思路设计的具有在应用可编程能力的单片机系统结构框图如图1所示。该系统有以下几个特点:
(1)有三块RAM,其中RAM3是数据存储器, RAMA、RAMB既是数据存储器又是程序存储器,RAMA和RAMB采用DS1230Y-70静态RAM。RAMA和RAMB具有相同的地址,当其中一块作为程序存储器时,另一块是数据存储器。AT89C51的数据空间与地址空间分开的特性保证了这两块存储器不会冲突。
(2)增加了选择电路,用来将程序存储器和数据存储器“重新分类”,通过DN_CON控制信号线来选择是钭WR信号还是钭PSEN信号送入相应的静态RAM。
(3)增加了串行EEPROM 以保存重要的信息,如模块号及下载标志等。
AT89C51 具有4K的片内Flash存储器,可以存放引导程序。系统初始化、串口中断等程序作为引导程序,固化在AT89C51的Flash存储器中,而将主程序放在32KB的静态RAM程序存储器中。因此,该系统程序存储器的地址空间从0000h~03FFh和8000H~0FFFFH。而数据存储器地址从 0000H~0FFFFH,如图2所示。引导程序中将串口中断设定为最高优无级,当AT89C51接收到程序代码下载的命令后,将向 8000H~0FFFH的数据空间依次写入程序代码。当程序代码写结束时,改变DN_CON控制信号,使原来的数据存储器变为程序存储器,而原来的程序存储器变为数据存储器。在串口中断程序结束时,将堆栈中的串行中断返回指针指向8000H,并退出中断,使程序跳至8000H运行下载的程序代码。图2中串行EEPROM采用基于I2C总线的24C01芯片,用以存放一些关键的数据信息,加测控模块的站号、下载标志等。
2 选择电路的实现 选择电路如图3所示,74HC157是四路二选一芯片。当P1.0(DN_CON)为低电平时,A=Y,此时RAMA的RD接PSEN,WR接VCC;RAMB的RD接RD数据读出线,WR接WR数据写入线,RAMA作为程序存储器,RAMB作为数据存储器。反之,当P1.0为高电平时,B=Y,RAMB是程序存储器,RAMA是数据存储器。
4 上位机软件的编程 上位机软件可以采用Delphi开发工具编写基于Windows95/98/2000平台下的串行通讯程序。MSCOMM32.OCX控制是微软公司在VB 和VC开发软件中随带的串行通信控件,该控件屏蔽了通信过程中的底层操作,程序员应用时只需设置和监视该控件的属性和事件即可完成对串行口的初始化和数据的输入和输出工作。在Delphi5.0中已将它重新定义为TMSComm类。在应用可编程测控网络的设计中需要发送与接收控制字符,这些控制字符有可能包含ASCII值大于80H的字符,因此要求上位机软件既能接收二进制数据又能发送二进制数据。在TMSComm类中一项InputMode属性,当设置 InputMode=1时,数据是以二进制方式取回,而发送二进制数据则需要依照TMSComm类的规则通过动态数组和变体的方法实现。 下面是一个简单的发送和接收二进制数据的例子程序:mscomm1.Comport:=1; //操作对象为串口1mscomm1.Settings:='9600,N,8,1'; 设置串口参数mscomm1.Rthreshold:=1; //收到1个字节后触发串口事件mscomm1.inbuffercount:=0; //清串口接收缓冲区mscomm1.OutBufferCount:=0; //清串口发送缓冲区mscomm1.PortOpen:=true; //打开串口 发送例程:varMyFlexibleArray : array of byte; //定义动态数组Outputdata:variant; //定义变体BeginSetLength(MyFlexibleArray,1); //在使用动态数组前必须设置它的长度MyFlexibleArray[0]:=$AA; //将待发送二进制数放入数组outputdata :=myFlexibleArray; //将动态数组赋给变体mscomm1.Output:=outputdata; //将变体中的二进制数0AAH发出end;
评论排行