⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 jiance.c

📁 这是关于DX516仿真器的资料
💻 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 + -