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

📄 otp_wu2441.c

📁 51单片机的控制程序.是一个烧写器的控制程序.语言采用的是c51
💻 C
📖 第 1 页 / 共 2 页
字号:
	CTR_WORD=0xF0;							/*所有控制信号置为0,准备开始工作*///地址8000,CS[0]=0,锁存51低4位到ctrout
	Delay(6);
	CTR_WORD=0xF1;							/*第一个PROCLK*/
	Delay(6);
	CTR_WORD=0xF0;							/*第二个PROCLK*/
	Delay(6);
	CTR_WORD=0xF1;							/*第二个PROCLK*/
	Delay(6);
	CTR_WORD=0xF0;							/*第三个PROCLK*/
	Delay(6);
	CTR_WORD=0xF1;							/*第三个PROCLK*/
	Delay(6);
	CTR_WORD=0xF0;							/*第四个PROCLK*/
	Delay(6);
	CTR_WORD=0xF1;							/*第四个PROCLK*/
	Delay(6);
	CTR_WORD=0xF0;							/*4个脉冲结束后,置为0状态*/
	Delay(120);									/*确保足够的复位时间,使OTP内部充分复位*/
	Delay(120);									/*确保足够的复位时间,使OTP内部充分复位*/
	Delay(240);									/*确保足够的复位时间,使OTP内部充分复位*/

	CTR_WORD=0XF4;		/*将CTR1置高,准备往数据总线上写0*/
	Delay(6);
	DATA_WR=0x00;			/*将数据0x00写入数据寄存器,由于此时CTR0为低,所以在OTP数据总线上将会出现0*///地址8100,51数据送otp总线
	Delay(12);
	CTR_WORD=0XF0;		/*再将控制信号全部置低,进入空闲状态*/
  Delay(240);				/*确保足够的复位时间,使OTP内部充分复位*/
	}

//分页读取FLASH中的CODE数据
//入口参数page为要读取的页,指针p为要读区的单元
//如果要读取的页和单元合法,则函数返回读取结果,
//否则如果有必要可将返回类型设置成int型(有符号int型),当入口参数不合法的时候,可返回-1,不过此设计基本不会出现错误的情况,所以无需此设计
uchar		FLASH_READ(uchar	page,uchar	*p)
{
	uchar	flash_data;
	if(page	==	first_page){
		P12=1;
		P11=0;
		P11=0;
	}
	else	if(page	==	second_page){
		P12=1;
		P11=0;
		P11=1;
	}
	else	return	1;
	flash_data=*p;
	P12=0;
	P11=0;
	P11=0;
	return	flash_data;
}

//脱机烧写
void	OFFLINE_PRO(uchar	a,uchar	b)
{
	if(CUR_ADDR>=ROMSIZE06)
		Pro_Byte(a,b,OPTION_PRO);
	else
		Pro_Byte(a,b,CODE_PRO);

	if(CUR_ADDR>=(ROMSIZE06+2))	{
		Power_Ctr(PRO_OVER);//关闭编程电压
		WORK_STATE=DONE;		//打开绿灯指示结束
		flash_p=0;		//将FLASH读取指针归0
		WORKSTATE=0;
		P15=1;	//关闭244w
		P15=1;	//关闭244w
	}
}

/******完整字读取并送上位机******/
void	Word_Back(uchar	S_COW)
{
	P15=1;	//读,打开244w
	P16=0;	//读,打开244w
	if(S_COW	==	CODE_PRO)
			Word_Read();		/*将数据读入DATA_RD数组*/
	else	if(S_COW	==	OPTION_PRO)
			Option_Read();
	Outport(DATA_RD0);
	Outport(DATA_RD1);
}
/********发送命令子程序********/
void	Serial_Trans(uchar	frame,uchar	cont)
{
	Outport(frame);
	Outport(cont);
}


void	Serial_Trans1(uchar	frame,uchar	cont,uchar cont1)
{
	Outport(frame);
	Outport(cont);
	Outport(cont1);
}



void	ByteBy_Back(uchar	S_COB)
{
	if(S_COB	==	CODE_PRO)
			Word_Read();		/*将数据读入DATA_RD数组*/
	else	if(S_COB	==	OPTION_PRO)
			Option_Read();
	Serial_Trans1(Sdata,DATA_RD0,DATA_RD1);
	
}


/****************************/
/*					逐BYTE烧写				*/
/****************************/
void	ByteBy_Comm(void)						/*--------WORKSTATE!=0状态下的命令处理-------*/
{															/*------不同状态下的命令处理过程是不一样的------*/
	switch(SBUF_TEMP1){
	case	0x11:break;								/*该状态下不可能再收到0x11命令了						*/
	case	0x12:
							if(CUR_ADDR>=ROMSIZE06)
							{
									  P16=1;	//
	                  P15=0;	//写,打开244w
								 Write_Option1(DATA_WR1);
								 			P15=1;	//
								 			Delay(2);
			                P16=0;	//读,打开244w
									ByteBy_Back(OPTION_PRO);
								}
							else
								{
										  P16=1;	//
	                       P15=0;	//写,打开244w
									Write_Tri1(DATA_WR1);
												P15=1;	//
												Delay(2);//断开总线,以免直接切换产生冲突
												
			                  P16=0;	//读,打开244w
									ByteBy_Back(CODE_PRO);
								}
							break;		/*数据再读一次,送回上位机									*/
	case	0x13:	WORKSTATE=0;
							Power_Ctr(PRO_OVER);
							WORK_STATE=DONE;		//打开绿灯指示结束
							break;		/*如果收到结束命令,则将WORKSTATE置0,下一次循环即进入WORKSTATE=0的状态*/
	default:Serial_Trans(Scomm,not_ready);		/*此时为一次全烧写状态,如果收到结束以外的其他命令,则告之上位机,系统处于忙状态*/
	}
}

void	ByteBy_Data(void)		/*此状态下发过来的数据都是要求将其写入OTP,然后读回给上位机*/
{
	#if		NEW_OTP
	  P16=1;	//
	  P15=0;	//写,打开244w
		if(CUR_ADDR>=ROMSIZE06)
				Word_Pro(OPTION_PRO);
		else
				Word_Pro(CODE_PRO);					//此函数由两块构成,每接收一帧数据,执行一块,接收完两帧数据,才会完整执行一边,烧写一个WORD/
	#else
		if(CUR_ADDR	==	0){
				if(old_first	==	0)
						old_first=1;
				else	if(old_first==1){
						old_first=0;
						CUR_ADDR=1;
						Serial_Trans(Sdata,0xFF);
						Serial_Trans(Sdata,0xFF);
				}
		}
		else	if(CUR_ADDR>=ROMSIZE06)
				Word_Pro(OPTION_PRO);
		else
				Word_Pro(CODE_PRO);					//此函数由两块构成,每接收一帧数据,执行一块,接收完两帧数据,才会完整执行一边,烧写一个WORD/
	#endif
	if(pro_done==1){		/*一个WORD烧写完后,回将pro_done置位,表明烧写结束,可以读回*/
			pro_done=0;
			P15=1;	//
			P16=0;	//读,打开244w
			if(CUR_ADDR>=ROMSIZE06)
					ByteBy_Back(OPTION_PRO);
			else
					ByteBy_Back(CODE_PRO);
	}
}
/*********逐BYTE帧处理*********/
void	ByteBy_Frame(void)			/*每一帧调用一次,两帧数据结束后,将已写数据读回*/
{
	switch(SBUF_TEMP0){
		case	Scomm:ByteBy_Comm();break;
		case	Sdata:ByteBy_Data();break;
	}
}

/****************************/
/*				全烧写处理					*/
/****************************/
void	AllPro_Comm(void)				/*--------WORKSTATE!=0状态下的命令处理--------*/
{															/*------不同状态下的命令处理过程是不一样的------*/
	switch(SBUF_TEMP1){
	case	0x13:	WORKSTATE=0;
							Power_Ctr(PRO_OVER);
							WORK_STATE=DONE;		//打开绿灯指示结束
							break;		/*如果收到结束命令,则将WORKSTATE置0,下一次循环即进入WORKSTATE=0的状态*/
	default:Serial_Trans(Scomm,not_ready);		/*此时为一次全烧写状态,如果收到结束以外的其他命令,则告之上位机,系统处于忙状态*/
	}
}

void	AllPro_Data(uchar	S_CO)
{
	Word_Pro(S_CO);
}
/*********全烧写帧处理**********/
void	AllPro_Frame(void)
{
	switch(SBUF_TEMP0){
		case	Scomm:AllPro_Comm();break;
		case	Sdata:
					
					P16=1;	//
					P15=0;	//写,打开244w
									if(CUR_ADDR>=ROMSIZE06)
											AllPro_Data(OPTION_PRO);
									else
											AllPro_Data(CODE_PRO);

								  break;
	}
}


/****************************/
/*				空闲状态处理				*/
/****************************/
void	Spare_Comm(void)						/*--------WORKSTATE==0状态下的命令处理--------*/
{															/*------不同状态下的命令处理过程是不一样的------*/
	/*先进行相应初始化*/
	wr_hl=0;		/*高低字节标志清为低字节*/
	pro_done=0;	/**/
	CUR_ADDR=0;
	switch(SBUF_TEMP1){
	case	0x01:Serial_Trans(Scomm,get_ready);break;/*准备好则给出回应,即预通信add by ljw,发EE 81
	//case	0x02:break;	/*Command为0x02、0x03、		//(注释操作为WORKSTATE==1的操作)全查,将OTP ROM数据依次读出送上位机*/
	//case	0x03:break;	/*0x04时,仅将WORKSTATE		//(注释操作为WORKSTATE==1的操作)一次读一个,上位机给一次命令,读一次,读完等待上位机命令*/
	//case	0x04:break;	/*置为1即可								//(注释操作为WORKSTATE==1的操作)读rom,不加*/
	case	0x02:WORKSTATE=1;	Start_Tri();					/*Command为0x02时,仅将WORKSTATE置2,进行一次全查验		//(注释操作为WORKSTATE==1的操作)全查,将OTP ROM数据依次读出送上位机*/
													break;

	case	0x11:WORKSTATE=2;Start_Tri();Serial_Trans(Scomm,0x91);break;	/*空闲状态下,收到此命令后,执行逐BYTE烧写的初始化*/
	case	0x12:WORKSTATE=2;break;	/*------------空闲状态下应该不会直接发此命令,不必过虑------------*/
	case	0x21:WORKSTATE=3;Start_Tri();Serial_Trans(Scomm,0xA1);break;	/*空闲状态下收到此命令后,执行全烧写的初始化*/
	default:Serial_Trans(Scomm,get_ready);
	}
}

void	Spare_Frame()
{
	switch(SBUF_TEMP0){
	case	Scomm:Spare_Comm();break;       /*接收到命令*/
	case	Sdata:break;                    /*接收到数据*/
	}
}
/********************************************************/
/*										外部中断0用作按键										*/
/**/
/********************************************************/
/*******************外部中断0,键盘中断********************/
void 	Ex_Intr(void)		interrupt 0       using 0
{
uchar a,b;
 EA=0;
 a=KEY;
 Delay(1000);
 b=KEY;
 if(a==b)
     {

     	#if		DEBUG
     			b<<=4;
     			b^=0xff;	//将高4位取反
     			b&=0xf0;	//低4位清0,高4位保留
     			//P1&=0x0f;	//高4位清0,低4位保留
     			//P1|=b;

     	#endif

      switch(a)
           {
            case 1: 	WORKSTATE=4;
            					Start_Tri();//打开编程电压,指示
            					#if	NEW_OTP
	            					flash_p+=2;
	            				#else
	            					flash_p++;
	            				#endif
					  					//WORK_STATE=DONE;
            					break;
            case 2:  	WORK_STATE=BUSY;break;
            case 3:  	WORK_STATE=ERROR;break;
            case 4:  break;
            case 5:  break;
            case 6:  break;
            case 7:  break;
            case 8:  break;
            case 9:  break;
            case 10: break;
            case 11: break;
            case 12: WORK_STATE=0xff;break;
            case 13: break;
            case 14: break;
            case 15: break;
            case 16: break;
            case 17: break;
            case 18: break;
            case 19: break;
            case 20: break;
            case 21: break;
            case 22: break;
            case 23: break;
            case 24: break;
            default: break;
           }
     }
  EA=1;

}

/**********************************************************/
/*************           中断2:定时器0          **********/
/*************         用P11来闪烁LED检测        **********/
/**********************************************************/

void time0(void) interrupt 1      using 2
{

TR0=0;
TH0=0X00;
TL0=0X00;
#if      DEBUG
cnt_t0++;    //如果初始化为0或者未对cnt赋初始值,则cnt初始化为0,此时将会从255开始减
if(cnt_t0>=12)
        {
        	cnt_t0=0;
					WORK_STATE=0XFF;
	       	P13^=1;
        }
#endif
TR0=1;
}

/********************************************************/
/*									串口中断设置为接收中断							*/
/********************************************************/
/*******************串口中断,接收数据*******************/
void 	Intr4(void)	interrupt 4       using 3
{
	if(RI==1){//接受到一数据(此处一个字节)时硬件置位,必须由软件清零。add by liu
		RI=0;
		switch(SERIAL_CNT){//串口接收数据计数,主要用于判断奇。偶,一帧数据含两字节,初始化为1
			case	1:SBUF_TEMP0=SBUF;break;//第一字节放temp0
			case	2:SBUF_TEMP1=SBUF;SERIAL_CNT=0;frame_flg=1;break;//第二字节放temp1,同时
		}
		SERIAL_CNT++;
	}
	//else	if(TI==1)	TI	=	0;
}


//////////////////////////////////////////////////////////////////
// 定时器CT2中断服务程序										//
//////////////////////////////////////////////////////////////////
void timer2Int(void) interrupt 5
{
	TF2 = 0;							// 溢出标志必须由软件清零
	EXF2 = 0;
}



void	main()
{
		uchar		flash_d0,flash_d1;
		#if	DEBUG
        P13=0;
        P14=0;
        P15=1;
        P16=1;
				P17=0;
        cnt_t0=0;
    #endif
	Init_All_Var();
	Init_Serial();
  Init_Timer0();
	//Init_Timer1();
	Uart_Init();
	Init_Hardware();
	Init_Worstate();

	while(1){

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

			//P1^=0xf8;	//低3位不动
		//	P14^=1;//异或,此处相当于取反,示波器察看输出方波,我理解为单篇机测试,看是否运行。
		//	P15^=1;//老版里就有测试程序,这是其中的一段
		//	P16^=1;
			P17^=1;
			//////////////////////////////////////////////

			if(frame_flg==1){//每接收到两个字节后frame_flg=1了。
					frame_flg=0;
					switch(WORKSTATE){//初始化为0
							case	0:Spare_Frame();break;		/*仅在WORKSTATE==0的时候,可以根据收到命令来改变WORKSTATE,进行工作状态切换
																						其他状态下,收到的命令仅进行相应工作的动作,如果收到该工作状态以外的命令,则回应not_ready*/
							//case	1:FreeChk_Frame();break;	/*各个内部操作用状态指示,在一次frame_flg下完成*/
							case	2:ByteBy_Frame();break;
							case	3:AllPro_Frame();break;
					}
			}

			//---------读OTP---------
			//实际协议中的读、查空、校验是在上位机中进行区分,对应的下位机功能则全有读来实现
			//即这三个功能中,下位机所需要做的动作仅仅是将OTP的数据读出,并发给上位机
			if(WORKSTATE==1){
									//调用Start_Tri时已经打开BUSY指示,不用重复打开

				Add_Tri1();                     //对新片先进行地址加
				if(CUR_ADDR>=ROMSIZE06+1)
				     {
				     	      if(CUR_ADDR<ROMSIZE06+2)
						    Word_Back(OPTION_PRO);
				     }
				else
						Word_Back(CODE_PRO);
				//Add_Tri(0xff,0xff);	/*读完一个WORD后,需要将地址加1,保证顺序读*/
				if(CUR_ADDR>=(ROMSIZE06+2))	{
					Power_Ctr(PRO_OVER);//关闭编程电压
					WORK_STATE=DONE;		//打开绿灯指示结束
					WORKSTATE=0;
					P15=1;	//
			                P16=1;	//
				}
			}


	}
}








⌨️ 快捷键说明

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