Easy 51Pro 的原理与扩充

这篇文章将让你很快掌握如何扩充Easy 51Pro对器件的支持。当然首先你必须先了解Keil C(如果扩充Easy 51Pro串行编程器)或VC(如果扩充Easy Isp下载线)。本文只介绍基本原理,至于串口通讯的细节和程序界面的制作请看源代码,里面有详细的注释。如果你正在学习单片机与PC的串口通讯,那么这套资料将对你非常有用。

 

本人编程水平有限,如果你发现了任何问题,欢迎指正。可以Email通知我(nie_zq@163.net)。常见问题我会贴在留言版。如果你是真心的想扩充器件,那么我们可以用QQ讨论(QQ3813420)。如果你想用它作为商业用途,请先与本人联系。

 

首先介绍一下我常挂在嘴变的FID”。FID=Function IDentification”,我E文不是很好,所以只能取出个这样的名字。它标识一种器件的编程方法(包括读,写,擦等编程操作)。AT89C51AT89C52,AT89C55的编程方法是一样的,所以可以用同一个FID,我把他们的FID定义为0,还有AT89CS51AT89S52FID=2AT89C2051FID=1。编程方法实际上就是控制编程过程的程序吧,C语言里面的程序不是叫Function?

 

Easy 51Pro串行编程器的扩充

    编程器和上位机能协调的工作肯定是要有个通讯协议的。Easy 51Pro的通讯协议很简单。每次编程操作,上位机发给编程器18个字节,编程器完成编程操作后再回应上位机18个字节(读,写过程略有不同,请看源程序)。这18个字节是什么东西呢?

0

1

2-17

编程操作的标识

FID

该操作相关的数据

编程操作标识是如何定义的?可以从源程序找到答案。

 

              switch( ComBuf[0] )            //根据操作ID跳到不同的操作函数

              {

                     case 0x00:

                            RstPro();               //编程器复位

                            break;

                     case 0x01:

                            ReadSign();           //读特征字

                            break;

                     case 0x02:

                            Erase();                 //擦除器件

                            break;

                     case 0x03:

                            Write();                 //写器件

                            break;

                     case 0x04:

                            Read();                  //读器件

                            break;

                     case 0x05:

                            Lock();                 //写锁定位

                            break;

                     default:

                            SendData();

                            break;

              }

FID已经解释过的,但是如何通过FID调用到控制器件编程操作的子程序呢?还是用程序说话:

e51pro.h中定义了这样一个结构:

 

struct _prowork                          //定义编程器的一般操作

{

       void (*fpInitPro)();               //编程前的准备工作

       void (*fpReadSign)();           //读特征字

       void (*fpErase)();                 //擦除器件

       BOOL (*fpWrite)(BYTE);      //写器件

       BYTE (*fpRead)();               //读器件

       void (*fpLock)();                 //写锁定位

       void (*fpProOver)();            //编程结束后的工作

};

typedef struct _prowork ProWork;

ProWork        pw;                       //编程器一般操作

 

看见没有,里面都是一堆函数的指针。没办法,Keil C里面没有class,在struct里面弄一堆函数指针也别有一方风味。

在调用编程操作(就是最上面那一堆程序switch(ComBuf[0]){…})之前,还要先进行这一堆程序:

             

switch( ComBuf[1] )                   //根据FID设置 (ProWork)pw 中的函数指针

              {

                     case 0:                                //at89c51编程器

                            PreparePro00();//<<<<<<<<<<<<<<<<<<<<<<关键要看这里面的东西

                            break;

                     case 1:                                //at89c2051编程器

                            PreparePro01();

                            break;

                     case 2:                                //at89s51编程器

                            PreparePro02();

                            break;

                     //case 3:                              //扩充器件时,请继续向下添加

                     //     break;

                     default:

                            ComBuf[0]=0xff;

                            ComBuf[1]=0xff;          //表示无效的操作

                            break;

              }

 

看看AT89C51PRO.C中的PreparePro00()函数里面搞了些什么?

 

void PreparePro00()                                  //设置pw中的函数指针,让主程序可以调用上面的函数

{

       pw.fpInitPro=InitPro00;

       pw.fpReadSign=ReadSign00;

       pw.fpErase=Erase00;

       pw.fpWrite=Write00;

       pw.fpRead=Read00;

       pw.fpLock=Lock00;

       pw.fpProOver=ProOver00;

}

 

其中InitPro00(),ReadSign00()…..ProiOver00()这些函数都写在了AT89C51PRO.C中,他们实现了控制编程器对AT89C51编程的具体细节。例如,再看看擦除AT89C51和插除AT89S51Flash Rom是如何实现的。

 

void Erase00()//擦除AT89C51

{

       InitPro00();

//-----------------------------------------------------------------------------

       //根据器件的DataSheet,设置相应的编程控制信号

       P2_6=1;

       P2_7=0;

       P3_6=0;

       P3_7=0;

       Delay_ms(1);

       SetVpp12V();

       Delay_ms(1);

       P3_2=0;

       Delay_ms(10);

       P3_2=1;

       Delay_ms(1);

//-----------------------------------------------------------------------------

       ProOver00();

}

就是根据这个来的:

      

再看看AT89S51PRO.C中的:

 

void Erase02()//擦除AT89S51

{

       InitPro02();

//-----------------------------------------------------------------------------

       //根据器件的DataSheet,设置相应的编程控制信号

       OutBuf[0]=0xac;//<<<<<<<<<<<<<<<看下表中的红框

       OutBuf[1]=0x80;//<<<<<<<<<<<<<<<看下表中的红框

       SendInstrc(4);

       Delay_ms(500);    

//-----------------------------------------------------------------------------

       ProOver02();

}

根据这个来的:

 

Erase02()中看到调用了SendInstrc(4)这样一个函数,有必要解释一下

 

void SendInstrc(BYTE nByte)              //MOSI串行发送命令的同时用MISO接收相关数据

{

       BYTE n;

       for(n=0;n<nByte;n++)                 //发送nByte字节

       {

              ACC=OutBuf[n];

              SCK=0;

              MOSI=A_7;                         //SCK低电平时输出一位

              SCK=1;

              B_7=MISO;                         //SCK高电平时接收一位

              SCK=0;

              MOSI=A_6;

             

             

              MOSI=A_1;

              SCK=1;

              B_1=MISO;

              SCK=0;

              MOSI=A_0;

              SCK=1;

              B_0=MISO;

              SCK=0;

              InBuf[n]=B;

       }

}

贴个图来解释:

最后来看一个扩充器件的全过程:

1.  看懂器件手册上Programming的原理和过程细节。

2.  评估一下Easy 51Pro的硬件是否可以实现,包括编程电压,编程控制信号。一般可以用Isp编程的都没问题。

3.  让软件能识别出器件,这就要用传说中的“ChipManager”编辑了。用这个程序打开程序目录下的ChipList.chip文件,然后“增加器件”。也可以在空白列表上直接“增加器件”,然后保存为*.chip文件,再把这个文件合并到ChipList.chip,这就是使用“从文件导入”。

如果你发现编程方法和列表中的某FID一样,那么就直接用这个FID吧,这是最幸福的。注意:如果特征字没有3个字节,可以用ff补充。

4.  最关键的部分,要你编程解决问题了。如果器件能ISP的尽量用ISP吧。建一个*.c文件,里面实现这些函数:

#include <e51pro.h>

 

void InitProXX()                         //编程前的准备工作

{

}

 

void ProOverXX()                       //编程结束后的工作,设置合适的引脚电平

{

}

 

void ReadSignXX()                     //读特征字

{

}

 

void EraseXX()                           //擦除器件

{

}

 

BOOL WriteXX(BYTE Data)        //向器件写一个字节

{

}

 

BYTE ReadXX()                         //从器件读一个字节

{

}

 

void LockXX()                           //写锁定位

{

}

 

void PrepareProXX()                   //设置pw中的函数指针,让主程序可以调用上面的函数

{

       pw.fpInitPro=InitProXX;

       pw.fpReadSign=ReadSignXX;

       pw.fpErase=EraseXX;

       pw.fpWrite=WriteXX;

       pw.fpRead=ReadXX;

       pw.fpLock=LockXX;

       pw.fpProOver=ProOverXX;

}

XX”就是FID。其实你不必写太多程序,如果发现它的编程方法与AT89C51相似,那就直接复制AT89C51PRO.C中的源程序,修改一下即可。如果与AT89S51相似呢,那就更好办了:

 

void Erase02()//擦除器件

{

       InitPro02();

//-----------------------------------------------------------------------------

       //根据器件的DataSheet,设置相应的编程控制信号

       OutBuf[0]=0xac;//<<<<<<<<<<<<<<<<<<修改这个

       OutBuf[1]=0x80;//<<<<<<<<<<<<<<<<<<修改这个

       SendInstrc(4);//<<<<<<<<<<<<<<<<<<<<注意要用几个字节

       Delay_ms(500);    

//-----------------------------------------------------------------------------

       ProOver02();

}

 

最后把PrepareProXX()添交到e51Pro.C中:

///////////////////////////////////////////////////////////////////////////////////////////////////

//所支持的FID,请在这里继续添加

///////////////////////////////////////////////////////////////////////////////////////////////////

extern void PreparePro00();//FID=00:AT89C51编程器

extern void PreparePro01();//FID=01:AT89C2051编程器

extern void PreparePro02();//FID=02:AT89S51编程器

extern void PrepareProXX();//<<<<<<<<<<<<<<<<<<<<<<<<<<<添加到末尾

 

还有:

              switch(ComBuf[1])              //根据FID设置(ProWork)pw中的函数指针

              {

                     case 0:                         //at89c51编程器

                            PreparePro00();

                            break;

                     case 1:                         //at89c2051编程器

                            PreparePro01();

                            break;

                     case 2:                         //at89s51编程器

                            PreparePro02();

                            break;

                     //case 3:                       //扩充器件时,请继续向下添加

                     //     PrepareProXX();<<<<<<<<<<<<<<<<<<<<<<<<添加到末尾

                     //     break;

                     default:

                            ComBuf[0]=0xff;

                            ComBuf[1]=0xff;//表示无效的操作

                            break;

              }

 

5.测试你的程序,成功后把它贴出来与大家分享,可以先发个Email给我。