📄 otp_wu2441.c
字号:
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 + -