📄 jiance.c
字号:
//51串行烧写器的C51源程序代码,还是在4年前刚学C51不久时写的,结构化不太好,各位见笑了!
//不过程序运行还算稳定,前几天修改了一下,使其可以支持AT89S51,52。
//本烧写器的最大特点是,不用依赖上位机烧写软件,可以自行处理HEX文件数据并烧写,并且可以自动识别芯片。
//将intel格式的HEX文件用9600bps发送至本烧写器,发送完就烧写完了,并且还会返回各种工作状态提示。
//作者聂小猛(丁丁),www.mcu51.com(51单片机世界)网站创始人,51大虾论坛版主。
//本源代码保留版权,用户购买过本站的51仿真器者可以免费获得本源代码和电路图自制和研究烧写器,
//未经作者本人书面允许,任何人不得公布到公共场合和用作商业用途!
#include <reg52.h>
#define uchar unsigned char
#define uint unsigned int
//*********************************
//外部调用的串口函数
extern char getbyte(void);//从接收缓冲区取一个byte,如不想等待则在调用前检测inbufsign是否为1。
extern putbyte(char c);//放入一个字节到发送缓冲区
extern putstring(uchar *puts);//发送一个字符串到串口
extern puthex(uchar c);//发送一个字节的hex码,分成两个字节发。
extern putchar(uchar c,uchar j);//输出一个无符号字符数的十进制表示,必须标示小数点的位置,自动删除前面无用的零
#define CR putstring("\r\n")//发送一个回车换行
extern void delay(unsigned char d);
extern bit inbufsign;
extern void serial_init (void);
//******************************
#define ea5v P35=1 //EA=5V
#define ea5v_ P35=1;P22=0
#define ea12v_ P35=0;P22=0
#define ea12v P35=0 //EA=12V
#define ea0v_ P22=1
sbit ale=P3^4; //定义管脚
sbit psen=P3^3;
sbit P30=P3^2;
sbit P33=P3^2;
sbit P36=P3^6;
sbit P37=P3^7;
sbit P35=P3^5;
sbit P01=P0^1;
sbit P00=P0^0;
sbit P26=P2^6;
sbit P27=P2^7;
//2051
sbit P22=P2^2;
sbit P33_=P0^6;
sbit P34_=P0^7;
sbit P35_=P2^0;
sbit P37_=P2^1;
sbit P32_=P0^5;
sbit xtal=P0^4;
sbit gnd2051=P3^2;
bit is2051;
uchar idata id,id0,id1; //定义芯片型号
uchar idata add_all; //定义烧写种类winbond=1,atmel51=2,atmel2051=3
//******************************************************
//测试芯片的id
testid(void)
{
id1=0;id0=0;id=0;
//if atmel
P2=0x00;psen=0;ale=1;ea5v;P26=0;P27=0;P33=0;P36=0;P37=0;P0=0x31;P1=0xff;P1=0xff;P1=0xff;P1=0xff;P1=0xff;P1=0xff;
if (P1!=0xff && P1!=0x00 && P1!=0x78 && P1!=0x84)
{
id=P1;
P0=0x30;P1=0xff;P1=0xff;P1=0xff;id0=P1;
P0=0x32;P1=0xff;P1=0xff;P1=0xff;id1=P1;
}
//if 89s52
if (id0==0xff||id0==0x00)
{
P2=0;P0=0;P1=0xff;P1=0xff;P1=0xff;id0=P1;
P2=1;P0=0;P1=0xff;P1=0xff;P1=0xff;id=P1;
P2=2;P0=0;P1=0xff;P1=0xff;P1=0xff;id1=P1;
}
//if winbond
if (id0==0xff || id0==0x00)
{
psen=1;ale=0;ea5v;P30=1;P36=0;P37=0;P00=1;P1=0xff;P1=0xff;P1=0xff;P1=0xff;P1=0xff;P1=0xff;P1=0xff;P1=0xff;P1=0xff;P1=0xff;P1=0xff;P1=0xff;
if (P1!=0xff && P1!=0x00 && P1!=0x78 && P1!=0x84)
{
id=P1;P00=0;P1=0xff;P1=0xff;P1=0xff;P1=0xff;P1=0xff;P1=0xff;P1=0xff;P1=0xff;P1=0xff;P1=0xff;P1=0xff;P1=0xff;id0=P1;
}
}
//if 2051
if (id==0xff || id==0x00)
{
gnd2051=0;xtal=0;ea0v_;ea5v_;P33_=0;P34_=0;P35_=0;P37_=0;P32_=1;P1=0xff;P1=0xff;P1=0xff;P1=0xff;P1=0xff;P1=0xff;P1=0xff;id0=P1;;
xtal=1;xtal=0;P1=0xff;P1=0xff;P1=0xff;P1=0xff;P1=0xff;P1=0xff;P1=0xff;id=P1;
}
if (id==0x84 || id==0x88 || id0==0x78)
{
is2051=1;id0=0x1e;
if (id==0x84) id=0x21;
if(id0==0x78)id0=0x1e;
if (id==0x88) id=0x11;
}
else is2051=0;
}
//************************************
//************************************
secrity(void)
{
char c;
testid();
switch(id0)
{
case 0xda: //winbond
c=getbyte();
psen=1;ale=0;ea12v;P2=0xff;P0=0xff;
switch(c)
{
case '1':
P30=0;P36=0;P37=1;P1&=0xfe;delay(5);
break;
case '2':
P30=0;P36=0;P37=1;P1&=0xfc;delay(5); //fd
break;
case '3':
P30=0;P36=0;P37=1;P1&=0xf8;delay(5); //fb
break;
}
P30=0;P36=1;P37=0;ea5v;
break;
case 0x1e: //atmel芯片的处理
if(!is2051 && id1!=0x06) //因为不知为何擦除时总是擦除不了AT89S51的加密位,因此该芯片不加密
{
psen=0;ale=1;ea12v;//atmel
c=getbyte();
switch(c)
{
case '1':
P26=1;P27=1;P33=1;P36=1;P37=1;ale=0;delay(1);ale=1;
break;
case '2':
P26=1;P27=1;P33=1;P36=0;P37=0;ale=0;delay(1);ale=1;
P26=1;P27=1;P33=1;P36=1;P37=1;ale=0;delay(1);ale=1;
break;
case '3':
P26=1;P27=1;P33=1;P36=1;P37=1;ale=0;delay(1);ale=1;
P26=1;P27=1;P33=1;P36=0;P37=0;ale=0;delay(1);ale=1;
P26=1;P27=0;P33=1;P36=1;P37=0;ale=0;delay(1);ale=1;
break;
}
delay(50);
}
else //2051
{
gnd2051=0;xtal=0;ea12v_;P32_=1;
c=getbyte();
switch(c)
{
case '1':
P33_=1;P34_=1;P35_=1;P37_=1;P32_=0;delay(1);P32_=1;
break;
case '2':
case '3':
P33_=1;P34_=1;P35_=1;P37_=1;P32_=0;delay(1);P32_=1;
P33_=1;P34_=1;P35_=0;P37_=0;P32_=0;delay(1);P32_=1;
break;
}
}
break;
}
putbyte(c);//显示加密等级
putstring("Secrity ok!");
}
//******************************************************
//将两个HEX字节转换成一个字节 (2 hexbytes = 1 byte)
uchar code hex_c[]={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,0,10,11,12,13,14,15};
uchar hextochar(uchar c0,c1)
{
return((hex_c[c0-0x30]<<4)+hex_c[c1-0x30]);
}
//******************************************************
//显示芯片的id及型号
void showid(void)
{
CR;
testid();
switch(id0)
{
case 0x1e: //atmel
putstring("It's AT8");
if (id==0x80 && id1==0x02) {add_all=0x20;putstring("0F52.");}
if (id==0x80 && id1==0x01) {add_all=0x10;putstring("0F51.");}
if (id==0x87 && id1==0x02) {add_all=0x20;putstring("7F52.");}
if (id==0x87 && id1==0x01) {add_all=0x10;putstring("7F51.");}
if (id==0x52 && id1==0xff) {add_all=0x20;putstring("9C52.");}
if (id==0x51 && id1==0xff) {add_all=0x10;putstring("9C51.");}
if (id==0x52 && id1==0x06) {add_all=0x20;putstring("9S52.烧写之前请手动按'e'擦除芯片。");}
if (id==0x51 && id1==0x06) {add_all=0x10;putstring("9S51.烧写之前请手动按'e'擦除芯片。");}
if (is2051) {add_all=0x08;putstring("9CX051.");}
break;
case 0xda://winbond
putstring("It's W7");
if (id==0x62 ) {add_all=0x80;putstring("7E58.");}
else if (id==0x61 ) {add_all=0x80;putstring("8E58.");}
else {add_all=0x40;putstring("8E5X.");}
break;
default:
putstring(" 没有放芯片.ID=");
puthex(id0);puthex(id);puthex(id1);CR;
}
putstring("ID=");puthex(id0);puthex(id);puthex(id1);CR;//显示出ID
putstring("\r\n按'`'读,传输文件写,按'h'帮助.\r\n"); //显示提示
}
//******************************************************
//******************************************************
//读取EPROM中的内容
sbit P10=P1^0;sbit P11=P1^1;sbit P12=P1^2;sbit P13=P1^3;sbit P14=P1^4; sbit P15=P1^5;sbit P16=P1^6; sbit P17=P1^7;
sbit B0=B^0;sbit B1=B^1;sbit B2=B^2;sbit B3=B^3;sbit B4=B^4;sbit B5=B^5;sbit B6=B^6;sbit B7=B^7;
void readeprom(void)
{
uint idata address; //定义当前读取字节地址
uchar idata i;
CR;putstring("开始读,任何键中断。");
showid();
//根据芯片类型设置读取环境
switch(id0)
{
case 0xda:
psen=1;ale=0;ea5v;P30=0;P36=0;P37=0;
break; //winbond
case 0x1e:
if (!is2051)
{
psen=0;ale=1;ea5v;P26=0;P27=0;P33=0;P36=1;P37=1;//atmel
}
else
{
gnd2051=0;xtal=0;ea0v_;ea5v_;P33_=0;P34_=0;P35_=1;P37_=1;P32_=1;//2051
}
break;
default:
putstring("\r\n不能读取,没有芯片。\r\n");
return; //无芯片返回
}
//开始读取地址为0
address=0; CR;
do
{
putstring(":10"); //输出一行字节数,固定为16个
puthex(address>>8);puthex(address);puthex(0); //输出行首地址
for(i=0;i!=16;i++) //读取十六个字节
{
if (!is2051)
{
P2=address>>8;P0=address; //置地址
P1=0xff;delay(1); //置输入及延时
puthex(P1); //输出读取的字节
address++;
}
else //2051
{
P1=0xff;delay(1); //置输入及延时
B7=P10;B6=P11;B5=P12;B4=P13;B3=P14;B2=P15;B1=P16;B0=P17;
puthex(B); //输出读取的字节
address++; //地址加一
xtal=1;xtal=1;xtal=0; //
}
}
CR; //回车换行
if (address%256==0)//每256字节检测一次已经读取的大小,根据芯片型号判断是否读取结束
{
if ((address/256)==add_all) goto endread;
}
}while(!inbufsign); //读取过程中有键按下中断读取
getbyte(); //取掉该字节,以免影响其他操作
endread:
putstring(":00000001FF\r\n"); //发出结束行
}
//*************************
//解密早期的AT89C51
jiemi()
{ }
/*
uchar i=1,j=0;
return;
CR;
do
{
psen=0;P26=1;P27=0;P36=0;P37=0;ea12v;ale=0;//ale=0;ale=0;ale=0;
do{j++;} while(j!=i);
ea5v;ale=1;j=0;
psen=0;ale=1;ea5v;P26=0;P27=0;P36=1;P37=1;delay(2);P0=0;P2=0;
putchar(i,1);i++;CR;
if (i==255) P1=0;
}while(P1==0xff);
i=0;
do
{
psen=0;P26=1;P27=0;P36=0;P37=0;ea12v;ale=0;ale=0;ale=0;ale=0;
ale=0;ale=0;ale=0;ale=0;ale=0;ale=0;ale=0;ale=0;ale=0;ale=0;ale=0;
ale=0;ale=0;ale=0;ale=0;ale=0;ale=0;ale=0;ale=0;ale=0;ale=0;ale=0;
ale=0;ale=0;ale=0;ale=0;ale=0;ale=0;ale=0;ale=0;ale=0;ale=0;ale=0;
ale=1;ea5v; delay(10);
putchar(i,1);i++;CR;
}while(i!=5);
readeprom();
}
*/
//******************************************************
//写EPROM
void writeeprom(void)
{
uchar idata c1,c0,i,n_of_line;
bit issecrit; //定义输入字节、每行个数
uint j;
union {uint addrhl;struct {uchar h,l;}addr;} idata address; //定义现在写入的地址
union {uint addrhl;struct {uchar h,l;}addr;} idata addressall; //定义已经写入的总数
unsigned char free[8]; //定义行首处理空间
unsigned char idata *freep; //定义指向该数组的指针
freep=free;CR;CR;testid(); //开始烧写,指针指向底部
start:
addressall.addrhl=0; //已经写入的总数清0
switch(id0) //根据芯片类型设置烧写环境
{
case 0xda: //winbond
psen=1;ale=0;P30=1;P36=0;P37=1;ea12v;delay(150);//swap 20ms
P30=0;P36=0;P37=1;delay(5);//write 10ms
P30=0;P36=1;P37=0;delay(5);
break;//verify
case 0x1e: //atmel
if (!is2051 && id1!=0x06) //51,swap 8ms,89S51不擦除,因为需要手动擦除
{
psen=0;P26=1;P27=0;P33=1;P36=0;P37=0;ea12v;ale=0;delay(150);ale=1;
}
else //2051
{
gnd2051=0;xtal=0;P32_=1;ea0v_;ea5v_;ea12v_;P33_=1;P34_=0;P35_=0;P37_=0;P32_=0;delay(20);P32_=1;
}
break;
default: //因为有些芯片加密后就读不出型号,所有对读不出的强行擦除再试读一次
issecrit=1; //无芯片不烧写
psen=0;P26=1;P27=0;P33=1;P36=0;P37=0;ea12v;ale=0;delay(80);ale=1; //if atmel swap 8ms
testid();
if (id0==0x1e)//psen=0;P26=1;P27=0;P36=0;P37=0;ea12v;ale=0;
break; //
psen=1;ale=0;P30=1;P36=0;P37=1;ea12v;delay(200);//if winbond swap 20ms
testid();
if (id0==0xda) //psen=1;ale=0;P30=0;P36=1;P37=0;ea12v;
break; //
putstring("\r\n没有芯片!");
do
{
delay(20);//等待文件传输完毕 (2ms)
if (inbufsign) getbyte(); //缓冲区不空取数据
}while(inbufsign); //2vms 之内无数据表示传输完毕
return; //返回
}
if (issecrit && (id0==0x1e || id0==0xda))
{
issecrit=0;
goto start;
}
//开始烧写芯片啦!
for(i=0;i!=8;i++) //读取第一行的行首,8字节
{
*freep=getbyte();
freep++;
}
n_of_line=hextochar(free[0],free[1]); //分析行首,解出行字节总数及行首址
address.addr.h=hextochar(free[2],free[3]); //高位地址
address.addr.l=hextochar(free[4],free[5]); //底位地址
do //大循环,行总数为0时停止,此时文件结束
{
if (!is2051)
{
do //小循环,每行一个循环
{
c1=getbyte();c0=getbyte(); //取两个HEX数据
c0=hextochar(c1,c0);P1=c0; //算出该字节并送往端口
P2=(P2&0xc0) | address.addr.h;P0=address.addr.l; //置地址到端口
addressall.addrhl++; //已经写入的地址加1
i=0;
//do
//{ //if bad write 3 times cycle
switch(id0) //根据芯片类型设置写环境
{
case 0xda: //winbond
P30=0;P36=0;P37=1;delay(1);//write 100us
P30=0;P36=1;P37=0;P1=0xff;P1=0xff;P1=0xff;delay(5);
break;//verify
case 0x1e: //atmel
psen=0;ale=1;P26=0;P27=1;P33=1;P36=1;P37=1;ea12v;ale=0;delay(10);ale=1;
delay(5); //1ms
ea5v;P26=0;P27=0;P33=0;P36=1;P37=1;P1=0xff;delay(1);//5ms
break;//verify
}
//}while(++i!=3 && c0!=P1); //if unssucceed write 3 times
//对刚写入的一个字节校验。 id!=0x61是78E58,不检查
//注:这种检验方式对地址线错误无法校验。如果属于地址线错误必须全部读出校验。本烧写器不提供这样方式。
if( id!=0x61 && c0!=(c1=P1))
{
putstring("\r\n校验错误!");//校验错输出地址等
puthex(c0);puthex(c1);putstring("在");puthex(address.addr.h);puthex(address.addr.l);putstring("H\r\n");
putstring("\r\n请检查芯片.");
do
{
delay(20);//wait the rubbish of hex file over (2ms)
if (inbufsign) getbyte();
}while(inbufsign);
return;
}
address.addrhl++;//现在写入的地址加1
n_of_line--; //该行剩下的字节减一
}while(n_of_line!=0); //写完一行退出该循
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -