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

📄 ispl20.c

📁 一个基于单片机系统的ISP的源代码
💻 C
字号:
#pragma CD DB SB OE OT(8,SPEED) OR
#include	<reg52.h>
#include	<absacc.h>
#include	<intrins.h>
#include	<string.h>
#include	<ctype.h>

sfr CHPCON=0xBF;
sfr CHPENR=0xF6;
sfr SFRAL =0xC4;
sfr SFRAH =0xC5;
sfr SFRFD =0xC6;
sfr SFRCN =0xC7;

#define uchar	unsigned char
#define uint	unsigned int

//------常量
#define TIMEL_1MS		0X67//1ms低字节
#define TIMEH_1MS		0XFC//1ms高字节
#define BAUD_RATE		0XFD//波特率9.6k
static uchar code ascii[]={"0123456789ABCDEF"};
static uchar code hex[80]=
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
 0,1,2,3,4,5,6,7,8,9,0,0,0,0,0,0,
 0,10,11,12,13,14,15};//ASCII码转16进制表

#define EOC	'<'//帧头
#define EOF	'>'//帧尾

sbit	bIspEnIn=P1^2;//ISP使能 0进入ISP
sbit    bLed=P1^6;//灯
sbit    bKillDogOut=P1^7;

static bit g_bInt;//中断发生标志1表示发生过中断
static bit bRcv;//串口接收标志 1收到一帧
static bit bLoad;//代码下载标志 1下载中
static union
{
  uchar a[2];//a[0]存高字节,a[1]存低字节
  uint ui;
} CLOCK;//系统时钟1ms
static struct
{
	uchar aucA[64];
	uchar ucAind;
} RE_BUFF;
static enum
{
	NONE=0,//没有错误
	BLANK_CHECK_ERR,
	PROG_FAIL,
	OVERFLOW
}enError;

static void initializtion(void);
static uint read_clock(void);
static void my_printf(uchar *p);
static void isp_exit(void);
static void isp_erase(void);
static void isp_prog(uchar sfrah,uchar sfral,uchar len);
static void process_comm_data(void);
static void asc_to_hex(uchar *p1,uchar *p2,uchar len);
static void hex_to_asc(uchar *p1,uchar *p2,uchar len);
static bit verify_sum(uchar *p,uchar len);//返回1表示正确,0错误
//-----------主程序
void main(void)
{
	void initializtion(void);

	static uint uiTLed;

	initializtion();
	while(1)
	{
		bKillDogOut=!bKillDogOut;
		//if(bIspEnIn)isp_exit();
		//else led();
		if( (read_clock()-uiTLed)>500 )
		{
			uiTLed=read_clock();
			bLed=!bLed;
		}
		process_comm_data();
    }
}
//------------------------------------------------
void initializtion(void)//初始化
{
	uchar t;
	uchar a[5];

	CHPENR =0;

	IE=0;TCON=0;
	TMOD=0X21;//定时器0模式1定时器1模式2
    TL1=TH1=BAUD_RATE;

    T2CON=0;//定时器2模式:自动重装载定时器
    RCAP2L=TIMEL_1MS;RCAP2H=TIMEH_1MS;

    SCON=0X50;PCON=0;//串行通讯模式1,SM2=0,REN=1,波特率不倍增
    TR1=1;TR2=1;//启动定时器1,2

	my_printf("4k LDROM program V2.0\r");
//=====================================================
//MOV CHPENR, #87H ; CHPENR = 87H, CHPCON WRITE ENABLE.
//MOV CHPENR, #59H ; CHPENR = 59H, CHPCON WRITE ENABLE.
//MOV A, CHPCON
	CHPENR = 0x87;
	CHPENR = 0x59;
	t=CHPCON;
//ANL A, #80H
//CJNE A, #80H, UPDATE_32K ; CHECK F04KBOOT MODE ?
	my_printf("CHPCON=");
	a[0]=ascii[t>>4];a[1]=ascii[t&0x0f];
	a[2]='\r';a[3]=0;
   	my_printf(a);

	t&=0x80;
	if(t==0x80)
	{
//MOV CHPCON, #03H ; CHPCON = 03H, ENABLE IN-SYSTEM PROGRAMMING.
//MOV CHPENR, #00H ; DISABLE CHPCON WRITE ATTRIBUTE
		CHPCON =0x03;
		CHPENR=0;
//MOV TCON, #00H ; TCON = 00H, TR = 0 TIMER0 STOP
//MOV TMOD, #01H ; TMOD = 01H, SET TIMER0 A 16BIT TIMER
//MOV IP, #00H ; IP = 00H
//MOV IE, #82H ; IE = 82H, TIMER0 INTERRUPT ENABLED
		IP=0;
		EA=1;ET0=1;
//MOV R6, #F0H
//MOV R7, #FFH
//MOV TL0, R6
//MOV TH0, R7
		TL0=0xf0;TH0=0xff;
//MOV TCON, #10H ; TCON = 10H, TR0 = 1, GO
//MOV PCON, #01H ; ENTER IDLE MODE
		TR0 = 1;
		PCON=0x01;
	}
//=====================================================

	EA=1;ET2=1;ES=1;//开定时器2中断 开串口中断

	/*isp_erase();
	switch(enError)
	{
		case NONE:
		break;
		case BLANK_CHECK_ERR:
			enError=NONE;
			my_printf("Error1:Blank check err\r");
		break;
		default:enError=NONE;break;
	}
	*/
	my_printf("Waiting download Hex file...\r");
}
//---------------------初始化程序结束

//------------------------------------
void my_printf(uchar *p)//串口输出
{
	//TI=1;
	while( (*p)!='\0' )
	{
		//while(!TI);
		//TI=0;
		SBUF=(*p);p++;
		while(!TI);TI=0;
	}
	//while(!TI);TI=0;
}
//--------------------------------------
static uint read_clock(void)
{
	uint tt;

	do
	{
		g_bInt=0;
		tt=CLOCK.ui;
	}
	while(g_bInt);
	return(tt);
}
//--------------------------------------
/*PC通讯协议
1.9600 Baud Rate,主从方式,PC主;
2.命令用ASCII码通讯,非定长帧,最长64;
3.帧头<,帧尾>,无校验和;
4.帧格式:帧头+命令+参数+帧尾;
5.代码用16进制下载,进入下载用Prog命令,退出用长度=64;

6.单片机4k程序模式时PC发命令:
	1)Handshake		握手			应答4k LDROM program+程序版本号
	2)Erase			擦除			应答Erase
									擦除错误应答Error1:Blank check err
	3)Prog			下载代码		应答Prog,准备接收代码
		代码格式:长度(1byte)+首地址(2byte)+类型(1byte)+代码(nbyte)+校验和(1byte)
		如果长度=59 表示下载结束
									应答:
									校验错误应答Error2:Verify err
									编程失败应答Error3:Prog fail
									长度错误应答Error4:Overflow 16
									超时应答Error5:Load over time
									编程继续应答Next
									编程结束应答Prog end
	4)Exit ISP		退出ISP			系统软复位,应答Be going to exit ISP mode...

7.单片机32k程序模式时PC发命令:
	1)Handshake 握手	应答32k ADROM program+程序版本号
	2)Enter ISP 进入ISP	应答Be going to ISP mode...
*/
static void process_comm_data(void)
{
	//uchar i;
	//uchar a[3];
	static uint uiTLoad;
	static enum {ORIGIN,LOADING}enStp;

	switch(enStp)
	{
	case ORIGIN:
		if(bRcv)
		{
			bRcv=0;//允许串口接收

			if( strncmp(RE_BUFF.aucA,"Handshake",9)==0 )my_printf("4k LDROM program V2.0\r");
			else if( strncmp(RE_BUFF.aucA,"Prog",4)==0 )
			{
				bLoad=1;
				uiTLoad=read_clock();enStp=LOADING;
				my_printf("Prog\r");
				//isp_erase();
			}
			else if( strncmp(RE_BUFF.aucA,"Erase",5)==0 )
			{
				my_printf("Erase\r");isp_erase();
			}
			else if( strncmp(RE_BUFF.aucA,"Exit ISP",8)==0 )isp_exit();
			else;
		}
	break;
	case LOADING:
		if( (read_clock()-uiTLoad)>3000 )//下载超时
		{
			bLoad=0;
			enStp=ORIGIN;
			my_printf("Error5:Load over time\r");
		}
		else if(bRcv)
		{

			/*for(i=0;i<RE_BUFF.aucA[0]+5;i++)
			{
				hex_to_asc(&RE_BUFF.aucA[i],a,1);
				a[2]=0;
				my_printf(a);
			}
			my_printf("\r");*/

			bRcv=0;

			if( !verify_sum(RE_BUFF.aucA,RE_BUFF.aucA[0]+5) )
			{
				bLoad=0;
				enStp=ORIGIN;
				my_printf("Error2:Verify err\r");
			}
			else if( RE_BUFF.aucA[0]==59 )
			{
				bLoad=0;
				enStp=ORIGIN;
				my_printf("Prog end\r");
			}
			else
			{
				isp_prog(RE_BUFF.aucA[1],RE_BUFF.aucA[2],RE_BUFF.aucA[0]);//编程
				if(enError==NONE)my_printf("Next\r");
			}

			uiTLoad=read_clock();
			//bRcv=0;
		}
		else;
	break;
	default:enStp=ORIGIN;break;
	}
	//=====================
	switch(enError)
	{
	case NONE:
	break;
	case BLANK_CHECK_ERR:
		enError=NONE;
		my_printf("Error1:Blank check err\r");
	break;
	case PROG_FAIL:
		enError=NONE;
		my_printf("Error3:Prog fail\r");
	break;
	case OVERFLOW:
		enError=NONE;
		my_printf("Error4:Overflow 16\r");
	break;
	default:enError=NONE;break;
	}
}
//--------------------------------------
/*static void asc_to_hex(uchar *p1,uchar *p2,uchar len)
{
	uchar i;
	uchar t,t1;

	for(i=0;i<len;i++)
	{
		t=hex[(*p1)];t=t<<4;
		p1++;
		t1=hex[(*p1)];
		p1++;
		(*p2)=t|t1;p2++;
	}
}*/
//--------------------------------------
/*static void hex_to_asc(uchar *p1,uchar *p2,uchar len)
{
	uchar i;

	for(i=0;i<len;i++)
	{
		(*p2)=ascii[(*p1)>>4];p2++;
		(*p2)=ascii[(*p1)&0x0f];
		p1++;
	}
}*/
//--------------------------------------
static bit verify_sum(uchar *p,uchar len)//校验和程序
{
    uchar i,sum=0;

    for(i=0;i<len;i++)
	{
		sum+=*p;
		p++;
	}
	if(sum==0)return(1);
	else return(0);
}
//--------------------------------------
void timer2_int() interrupt 5//1ms定时器2中断
{
    g_bInt=1;
    CLOCK.ui++;
    TF2=0;
}
//--------------------------------------
void timer0() interrupt 1//
{
	TR0=0;
	TL0=0;
	TH0=0;
}
//--------------------------------------
void uart_int() interrupt 4 using 3//串口中断
{
	static uchar ucCodeLong;
	static enum {ORIGIN,ORDER,LOADING}enStp;

	g_bInt=1;
	if(TI);
	else if(RI)
	{
		RI=0;

		switch(enStp)
		{
		case ORIGIN:
			if( bLoad&&(!bRcv) )//代码?
			{
				ucCodeLong=SBUF;
				RE_BUFF.aucA[0]=ucCodeLong;
				ucCodeLong+=5;
				//长度:	长度(1byte)+首地址(2byte)+类型(1byte)+代码(nbyte)+校验和(1byte)
				if(ucCodeLong<=64)
					{RE_BUFF.ucAind=1;enStp=LOADING;}
				else bLoad=0;//错误复位
			}
			else if( (SBUF==EOC)&&(!bRcv) )//命令?
			{
				RE_BUFF.ucAind=0;
				enStp=ORDER;
			}
			else;
		break;
		case ORDER://收命令
			if(SBUF==EOF){bRcv=1;enStp=ORIGIN;}
			else
			{
				RE_BUFF.aucA[RE_BUFF.ucAind]=SBUF;
				RE_BUFF.ucAind++;
				RE_BUFF.ucAind&=0x3f;
			}
		break;
		case LOADING://收代码
			RE_BUFF.aucA[RE_BUFF.ucAind]=SBUF;
			RE_BUFF.ucAind++;
			if(RE_BUFF.ucAind>=ucCodeLong)
			{
				bRcv=1;enStp=ORIGIN;
			}
		break;
		default:enStp=ORIGIN;break;
		}
	}
	else TI=RI=0;
}
//--------------------------------------
void isp_erase(void)
{
	uchar i,j;
	uchar t0;
	uchar a[9];

	IE=0;
	TR0=0;
	//===========擦除=============
//MOV CHPENR, #00H ; DISABLE CHPCON WRITE-ATTRIBUTE
	CHPENR=0;
//MOV TCON, #00H ; TCON = 00H , TR = 0 TIM0 STOP
//MOV IP, #00H ; IP = 00H
	IP=0;
//MOV IE, #82H ; IE = 82H, TIMER0 INTERRUPT ENABLED
	EA=1;ET0=1;
//MOV TMOD, #01H ; TMOD = 01H, MODE1
//MOV R6, #E0H ; SET WAKE-UP TIME FOR ERASE OPERATION, ABOUT 15 mS. DEPENDING
//; ON USER'S SYSTEM CLOCK RATE.
//MOV R7, #B1H
//MOV TL0, R6
//MOV TH0, R7
	TL0=0xe0;TH0=0x61;//TH0=0xb1;
//ERASE_P_4K:
//MOV SFRCN, #22H ; SFRCN(C7H) = 22H ERASE 32K
	SFRCN=0x22;
//MOV TCON, #10H ; TCON = 10H, TR0 = 1,GO
	TR0 = 1;
//MOV PCON, #01H ; ENTER IDLE MODE (FOR ERASE OPERATION)
	PCON=0x01;
	//===========查空=============
//;* BLANK CHECK
//MOV SFRCN, #0H ; READ 32KB APROM MODE
	SFRCN=0;
//MOV SFRAH, #0H ; START ADDRESS = 0H
//MOV SFRAL, #0H
//MOV R6, #FEH ; SET TIMER FOR READ OPERATION, ABOUT 1.5 uS.
//MOV R7, #FFH
//MOV TL0, R6
//MOV TH0, R7
//BLANK_CHECK_LOOP:
//SETB TR0 ; ENABLE TIMER 0
//MOV PCON, #01H ; ENTER IDLE MODE
//MOV A, SFRFD ; READ ONE BYTE
//CJNE A, #FFH, BLANK_CHECK_ERROR
	for(i=0;i<=0x7f;i++)
	{
		bKillDogOut=!bKillDogOut;
		SFRAH=i;
		//for(j=0;j<0xff;j++)
		j=0;
		do
		{
			SFRAL=j;
			TL0=0xfe;TH0=0xff;//1.5us
			TR0=1;PCON=0x01;
			t0=SFRFD;
			if(t0!=0xff)
			{
				a[0]=ascii[i>>4];a[1]=ascii[i&0x0f];
				a[2]=ascii[j>>4];a[3]=ascii[j&0x0f];
				a[4]='-';
				a[5]=ascii[t0>>4];a[6]=ascii[t0&0x0f];
				a[7]='\r';a[8]=0;
		    	my_printf(a);

		    	enError=BLANK_CHECK_ERR;break;
			}
			j++;
		}while(j>0);
		if(enError==BLANK_CHECK_ERR)break;
	}

//INC SFRAL ; NEXT ADDRESS
//MOV A, SFRAL
//JNZ BLANK_CHECK_LOOP
//INC SFRAH
//MOV A, SFRAH
//CJNE A, #80H, BLANK_CHECK_LOOP ; END ADDRESS = 7FFFH
//JMP PROGRAM_32KROM
	//=====================
	EA=1;ET2=1;ES=1;//恢复定时器2中断 串口中断
}
//--------------------------------------
static void isp_prog(uchar sfrah,uchar sfral,uchar len)
{
	uchar i;

	IE=0;TR0=0;
	if(len>16){len=0;enError=OVERFLOW;}//最长16byte
/*
PROGRAM_32KROM:
MOV DPTR, #0H ; THE ADDRESS OF NEW ROM CODE
MOV R2, #00H ; TARGET LOW BYTE ADDRESS
MOV R1, #00H ; TARGET HIGH BYTE ADDRESS
MOV DPTR, #0H ; EXTERNAL SRAM BUFFER ADDRESS
MOV SFRAH, R1 ; SFRAH, TARGET HIGH ADDRESS
MOV SFRCN, #21H ; SFRCN(C7H) = 21 (PROGRAM 32K)
MOV R6, #BEH ; SET TIMER FOR PROGRAMMING, ABOUT 50 uS.
MOV R7, #FFH
MOV TL0, R6
MOV TH0, R7
PROG_D_32K:
MOV SFRAL, R2 ; SFRAL(C4H) = LOW BYTE ADDRESS
MOVX A, @DPTR ; READ DATA FROM EXTERNAL SRAM BUFFER. BY ACCORDING USER?
; CIRCUIT, USER MUST MODIFY THIS INSTRUCTION TO FETCH CODE
MOV SFRFD, A ; SFRFD(C6H) = DATA IN
MOV TCON, #10H ; TCON = 10H, TR0 = 1,GO
MOV PCON, #01H ; ENTER IDLE MODE (PRORGAMMING)
INC DPTR
INC R2
CJNE R2, #0H, PROG_D_32K
INC R1
MOV SFRAH, R1
CJNE R1, #80H, PROG_D_32K
*/
	EA=1;ET0=1;
	SFRCN=0x21;
	/*SFRAH=sfrah;SFRAL=sfral;
	for(i=0;i<=0x7f;i++)
	{
		bKillDogOut=!bKillDogOut;
		SFRAH=i;
		j=0;
		do
		{
			SFRAL=j;
			TL0=0xbe;TH0=0xff;//50us
			SFRFD=j;
			TR0=1;PCON=0x01;
			j++;
		}while(j>0);
	}*/
	for(i=0;i<len;i++)
	{
		SFRAL=sfral+i;
		if( (sfral+i)>255 )SFRAH=sfrah+1;
		else SFRAH=sfrah;
		SFRFD=RE_BUFF.aucA[4+i];
		TL0=0xbe;TH0=0xff;//50us
		TR0=1;PCON=0x01;
	}

	SFRCN=0;//校验
	for(i=0;i<len;i++)
	{
		SFRAL=sfral+i;
		if( (sfral+i)>255 )SFRAH=sfrah+1;
		else SFRAH=sfrah;
		TL0=0xfe;TH0=0xff;//1.5us
		TR0=1;PCON=0x01;
		if(SFRFD!=RE_BUFF.aucA[4+i])
			{enError=PROG_FAIL;break;}
	}

	EA=1;ET2=1;ES=1;//恢复定时器2中断 串口中断
}
//--------------------------------------
static void isp_exit(void)
{
	my_printf("Be going to exit ISP mode...\r");
	//MOV CHPENR, #87H ; CHPENR = 87H
	CHPENR =0x87;
	//MOV CHPENR, #59H ; CHPENR = 59H
	CHPENR =0x59;
	//MOV CHPCON, #83H ; CHPCON = 83H, SOFTWARE RESET.
	CHPCON =0x83;
}
//--------------------------------------

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -