📄 otp_wu2441.c
字号:
#pragma small
#pragma CODE DEBUGSYMBOLS OBJECTEXTEND
#include <reg52.h>
#include <stdio.h>
#include <absacc.h>
//#include "lcddisplay.h"
#define DEBUG 1
#define NEW_OTP 1 //新旧版的不同应用
#define uchar unsigned char
#define uint unsigned int
#define ulong unsigned long
#define CTR_WORD XBYTE[0x8000]
#define DATA_WR XBYTE[0x8100]
#define DATA_RD XBYTE[0x8400]
#define RST_SYS XBYTE[0x8700]
#define KEY XBYTE[0x8500]
#define LED XBYTE[0X7000]
#define LCD_DATA XBYTE[0x8600]
#define LCD_COMM XBYTE[0x8601]
#define POWERMANG XBYTE[0x8200]
#define WORK_STATE XBYTE[0x8300]
#define TEST_LED XBYTE[0x8800]
#define FLASH_SDP0 XBYTE[0x2AAA]
#define FLASH_SDP1 XBYTE[0x5555]
#define ROMSIZE06 2048
#define Bodrate 0xFFDC /* FFDC相对于11.0592M晶振下9600波特率,
FFB8将9600的波特率降低一半,为4800*/
#define PROGRAM_MODE 0x05 /*0101,最高位控制12V,最低位控制6.5V*/
#define TEST_MODE 0x07 /*0111,12V电源打开,其他几个关闭*/
#define PRO_OVER 0x0f /*关闭编程电压*/
#define MERG_OVER 0X0F
#define MERG_START 0X0E
#define MERG_PRO 0X0D
#define MERG_VERIFY 0X0B
#define MERG_ADD 0X07
#define CODE_PRO 0XAA
#define OPTION_PRO 0X55
#define Scomm 0xee
#define Sdata 0xdd
#define not_ready 0x82
#define get_ready 0x81
#define ERROR 0x03
#define BUSY 0x05
#define DONE 0x06
#define first_page 1
#define second_page 2
/****************全局变量定义区*******************/
bit frame_flg;
bit wr_hl; /*这两个位变量用来标识当前数据是高字节还是低字节,为0表示低字节,1表示高字节
每帧数据接收完毕后,则判断帧头是否为DD,是则进入编程数据处理中,根据wr_hl作出相应动作,并将其取反*/
bit pro_done; /*每次操作前,将其置位,操作完成后复位*/
bit trans;
//bit serialtst;
bit old_first;
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;
uchar SERIAL_CNT; //计算每帧数据已接收到的个数
uchar WORKSTATE; /*此变量用来表示系统当前所处工作状态
空闲:0
查空:1
逐BYTE:2
全烧:3
每次更改WORKSTATE时需查询其值,如果WORKSTATE不为0,则不能改变其状态;
当收到结束命令的时候可以将其置为0*/
uchar SBUF_TEMP0,SBUF_TEMP1; //每帧数据为2,与SERIAL_CNT配合使用,如果数据接收速度过快,需要标识当前缓存是否已空。可以考虑一个结构体
uchar DATA_WR0,DATA_WR1;
uchar DATA_RD0,DATA_RD1;
//uchar cnt;
uchar cnt_t0;
uint CUR_ADDR; //用于记录当前操作地址
uchar xdata *flash_p = 0; //指向对FLASH的操作
void Delay(uint a)
{
while( a--) ;
}
/**********************************************************/
/* 系统初始化,硬件及所有DATA区的全局变量 */
/**********************************************************/
/****************全局变量定义区*******************/
void Init_All_Var(void)
{
frame_flg=0;
wr_hl=0;
pro_done=0;
trans=0;
old_first=0;
SERIAL_CNT=1;
WORKSTATE=0;
SBUF_TEMP0=0xff;
SBUF_TEMP1=0xff;
DATA_WR0=0xff;
DATA_WR1=0xff;
DATA_RD0=0xff;
DATA_RD1=0xff;
#if NEW_OTP
CUR_ADDR=0x0000; /*CUR_ADDR 总是指向待烧写的单元 */
#else
CUR_ADDR=0x0000; /*初始化过程会先将其+1,初始化以后其地址就变成真实地址0 */
#endif
P10=0;
P11=0;
P12=0; /*初始化为不能访问FLASH,在P10、P11、P12均为0的时候,地址译码74146方可进行译码,
如果需要访问FLASH,另行设置P10,P11,P12,而且需要在访问完毕后关闭对FLASH访问的使能*/
}
void Init_Hardware(void)
{
EX0=1;//外部中断0打开
IT0=1;//外部中断0为下降沿触发,IT0=0,则为低电平触发
EX1=0;//外部中断1关闭
IT1=1;//外部中断1为下降沿触发
//ET0=1;//定时器中断0打开
ET0=0;//定时器中断0关闭
ET1=0;//定时器中断1关闭,不作为串口波特率发生器,用定时器2作为波特率发生器
//TMOD=0x00;//设置工作方式
//TH0=0xFC; //装高八位计数初值
//TL0=0x03; //装低八位计数初值
IP=0x03; //外部中断0和定时器0定义为高优先级中断
EA=1; //允许中断
}
void Init_Timer0(void)
{
TMOD&=0xf0; /*改变定时器0的定时设置为16位全计数,每次中断差不多5ms*/
TMOD|=0x01; /*改变定时器1的定时设置为16位全计数,每次中断差不多5ms*/
TH0=0x0; /*波特率对应的时间重载常数 1200波特率为e5,4800为f9,9600为fc */
TL0=0x0; /*计算公式为: BAND=(1+SMOD)*Fosc/12/32/(256-T) */
//TR0=1; /*打开定时器中断*/
TR0=0; /*关闭定时器中断*/
}
#if 0
void Init_Timer1(void)
{
TMOD&=0x0f; /*改变定时器1的定时设置为自重载模式,以便于进行数据通讯,先清高四位与定时器相关的位*/
TMOD|=0x20; /*改变定时器1的定时设置为自重载模式,以便于进行数据通讯,之后加入高四位控制字*/
TH1=0xfd; /*波特率对应的时间重载常数 1200波特率为e5,4800为f9,9600为fc */
TL1=0xfd; /*计算公式为: BAND=(1+SMOD)*Fosc/12/32/(256-T) */
/* Fosc=12MHz,SMOD=0: T=256-(1+SMOD)*Fosc/12/32/BAND */
/* T=256-1M/32/BAND */
/* T=256-31250/BAND */
PCON&=0x7f; /*最高位SMOD=0时波特率不加倍,1时波特率加倍*/
TR1=0; /*打开定时器中断*/
}
#endif
void Uart_Init(void)
{
T2CON = 0x35; /*0b0011 0101 16位串行波特率发生器,
自动重装*/
TH2 = (unsigned char )(Bodrate>>8) ;
TL2 = (unsigned char )(Bodrate & 0xff);
RCAP2H = (unsigned char )(Bodrate>>8) ;
RCAP2L = (unsigned char )(Bodrate & 0xff);
TR2 = 1; // 启动时钟
SCON = 0x50; // 0b0111 1010 第一种工作方式
// 8位单机通信
ES = 1; // 允许通信中断
}
void Init_Serial(void) /*串口工作于方式1,(10位异步收发,由定时器控制)允许接受中断,并且波特率不加倍 */
{
SCON=0x50; /*将串行口设置成工作方式1,方式1为异步传送10位数据(1个起始位加8位数据加1个停止位,无奇偶校验位)*/
/*该方式下用于数据发送,发送波特率为: BAND=(1+SMOD)*Fosc/12/32/(256-T) */
/*打开接收允许,REN=1*/
ES=0; /*关、打开串口中断*/
RI=0; /*先将中断接受标志清掉,以避免无法正常接受*/
TI=0;
PS=0; /*串口中断设置为0,低优先级*/
ES=1; //*开中断,add by liu
}
/**********************************************************/
/* 系统初始化,硬件及所有DATA区的全局变量 */
/**********************************************************/
/**********编程电压控制**********/
void Power_Ctr(uchar powerS)
{
switch(powerS){
case PROGRAM_MODE:POWERMANG=PROGRAM_MODE;break;
case TEST_MODE:POWERMANG=TEST_MODE;break;
case PRO_OVER:POWERMANG=PRO_OVER;break;
}
}
/*******初始化系统工作状态********/
void Init_Worstate(void)
{
uchar i;
RST_SYS=0xff; /*CPU初始化完毕后,紧接着对逻辑部分进行长复位*///对应0x8700
Delay(24); /*逻辑部分长复位时间*/
RST_SYS=0x00; /*复位结束*/
WORK_STATE=BUSY;/*系统指示忙于初始化*/
Power_Ctr(PRO_OVER); /*关闭编程电压,待编程时再打开*/
CTR_WORD=0xF0; /*保证PROCLK为低电平*/
DATA_WR=0x00;
i=DATA_RD;
WORK_STATE=DONE;
}
/*****LOAD&地址加模式触发*****/
void Add_Tri(uchar a,uchar b)
{
Delay(3); /*稍微延时*/
CTR_WORD=0XF4; /*先将CTR1置为1*/
Delay(6);
CTR_WORD=0XF5; /*再将PROCLK给高*/
Delay(2);
DATA_WR=a; /*将数据a写入数据寄存器后,将会一直出现在OTP数据总线上*/
Delay(2);
CTR_WORD=0XF4; /*再将PROCLK给低,利用此处PROCLK的下降沿将数据LOAD到OTP中*/
Delay(2);
CTR_WORD=0XF5; /*再将PROCLK给高,此时该上升沿将触发OTP内部写地址单元的增加,而在WRITE的时候,将写到增加后的单元中去*/
Delay(2);
DATA_WR=b; /*将数据a写入数据寄存器后,将会一直出现在OTP数据总线上*/
Delay(2);
CTR_WORD=0XF4; /*再将PROCLK给低,利用此处PROCLK的下降沿将数据LOAD到OTP中*/
Delay(2);
CTR_WORD=0XF0; /*再将控制信号全部置低,进入空闲状态*/
Delay(6);
CUR_ADDR++;
}
void Add_Tri1()
{
Delay(3); /*稍微延时*/
CTR_WORD=0XF4; /*先将CTR1置为1*/
Delay(6);
CTR_WORD=0XF5; /*再将PROCLK给高*/
Delay(5);
CTR_WORD=0XF4; /*再将PROCLK给低,利用此处PROCLK的下降沿将数据LOAD到OTP中*/
Delay(2);
CTR_WORD=0XF5; /*再将PROCLK给高,此时该上升沿将触发OTP内部写地址单元的增加,而在WRITE的时候,将写到增加后的单元中去*/
Delay(5);
CTR_WORD=0XF4; /*再将PROCLK给低,利用此处PROCLK的下降沿将数据LOAD到OTP中*/
Delay(2);
CTR_WORD=0XF0; /*再将控制信号全部置低,进入空闲状态*/
Delay(8);
CUR_ADDR++;
}
/********CODE写模式触发********/
void Write_Tri(void)
{
Delay(3); /*稍微延时*/
CTR_WORD=0XF1; /*将PROCLK置高*/
Delay(1);
CTR_WORD=0XF0; /*将PROCLK置低,至此顺利产生一个正脉冲*/
Delay(3); /*100us的精确延时,延迟数据需要进行调整*/
CTR_WORD=0XFC; /*将控制信号翻转,防止编程时间过长,产生负面影响与结果*/
}
void Write_Tri1(uchar a)//byte by byte 重烧
{
Delay(3); /*稍微延时*/
CTR_WORD=0XF0;
Delay(2);
DATA_WR=a; /*重新录入高8位*/
Delay(2);
CTR_WORD=0XF1; /*将PROCLK置高*/
Delay(1);
CTR_WORD=0XF0; /*将PROCLK置低,至此顺利产生一个正脉冲*/
Delay(3); /*100us的精确延时,延迟数据需要进行调整*/
CTR_WORD=0XFC; /*将控制信号翻转,防止编程时间过长,产生负面影响与结果,切换成11状态*/
}
/*******OPTION写模式触发*******/
void Write_Option(void)
{
Delay(3); /*稍微延时*/
CTR_WORD=0XF2; /*将CTR2置高,准备烧写OPTION*/
Delay(1);
CTR_WORD=0XF3; /*将PROCLK置高*/
Delay(1);
CTR_WORD=0XF2; /*将PROCLK置低,至此顺利产生一个正脉冲*/
Delay(3); /*100us的精确延时,延迟数据需要进行调整*/
CTR_WORD=0XFC; /*将控制信号翻转,防止编程时间过长,产生负面影响与结果*/
}
/*********写下一个字节*********/
void Pro_Byte(uchar a,uchar b,uchar S_code_option) /*此功能一次完成数据的LOAD和PROGRAM
针对新的OTP一次LOAD一个WORD的方式,此函数入口的a和b可以分别为低字节和高字节
老版本的OTP一次LOAD一个BYTE的方式,由于老版本仅用于测试,可将其设计为兼容新版本一次LOAD一个WORD的方式
此时仅将函数入口的a和b都给当前要烧写的字节即可,相当于将同一个BYTE的数据LOAD了两次,实际上最终LOAD进去的为后面一个字节
此细节参考OTP烧录原理时序
*/
{
Add_Tri(a,b);
if(S_code_option == CODE_PRO) //如果输入参数为CODE_PRO,则烧写CODE区
Write_Tri();
else if(S_code_option == OPTION_PRO) //如果输入参数为OPTION_PRO,则烧写OPTION区
Write_Option();
Delay(3); /*触发以后延时一段时间,保证该步完整执行*/
}
void Write_Option1(uchar a)
{
Delay(3); /*稍微延时*/
CTR_WORD=0XF0;
DATA_WR=a;
Delay(2);
CTR_WORD=0XF2; /*将CTR2置高,准备烧写OPTION*/
Delay(1);
CTR_WORD=0XF3; /*将PROCLK置高*/
Delay(1);
CTR_WORD=0XF2; /*将PROCLK置低,至此顺利产生一个正脉冲*/
Delay(3); /*100us的精确延时,延迟数据需要进行调整*/
CTR_WORD=0XFC; /*将控制信号翻转,防止编程时间过长,产生负面影响与结果*/
}
/*******完整字接收并写入子程序******/
void Word_Pro(uchar S_COWW)
{
if(wr_hl==0){
DATA_WR0=SBUF_TEMP1; //如果wr_hl为0,则表明此帧数据为低字节数据
wr_hl=1; //将数据存入低字节数据缓冲后,将wr_hl置1,表示下一帧数据将是高字节
pro_done=0;
}
else{
DATA_WR1=SBUF_TEMP1; //如果wr_hl为1,则表明此帧数据为高字节数据
wr_hl=0; //将数据存入高字节数据缓冲后,将wr_hl置0,表示下一帧数据将是低字节
Pro_Byte(DATA_WR0,DATA_WR1,S_COWW); //此时需要触发一次写,
pro_done=1; /*一个字烧写完(需要两个frame_flg)后,将烧写完标志置1*/
}
}
/*****字节数据串行发送子程序*****/
void Outport(uchar i)
{
SBUF=i; /*准备发送的数据*/
while (TI==0); /*数据发送完毕自动把TI置1,此语句等待数据发送完毕*/
TI=0;
}
/*********CODE完整字读取操作********/
void Word_Read(void)
{
Delay(3);
CTR_WORD=0XF8; /*先将CTR0置为1*/
Delay(12);
CTR_WORD=0XF9; /*先将CTR0 和 PROCLK均置为1*///
Delay(2);
DATA_RD0=DATA_RD; /*将低字节数据读入单片机变量DATA_RD0中*///CS[4],读otp数据送51
Delay(2);
CTR_WORD=0XF8; /*读完低字节以后,将PROCLK置为0*/
Delay(2); /*稍微延时*/
CTR_WORD=0XF9; /*先将CTR0 和 PROCLK均置为1*/
Delay(2);
DATA_RD1=DATA_RD;/*将高字节数据读入单片机变量DATA_RD1中*/
Delay(2);
CTR_WORD=0XF8; /*读完低字节以后,将PROCLK置为0*/
Delay(2); /*稍微延时*/
CTR_WORD=0XF0; /*将控制信号全恢复为空闲状态*/
Delay(12);
}
/********OPTION完整字读取操作*******/
void Option_Read(void)
{
Delay(3);
CTR_WORD=0XFA; /*先将CTR0,CTR2置为1*/
Delay(12);
CTR_WORD=0XFB; /*先将CTR0 和 PROCLK均置为1*/
Delay(2);
DATA_RD0=DATA_RD;/*将低字节数据读入单片机变量DATA_RD0中*/
Delay(2);
CTR_WORD=0XFA; /*读完低字节以后,将PROCLK置为0*/
Delay(2); /*稍微延时*/
CTR_WORD=0XFB; /*将CTR0,CTR2 和 PROCLK均置为1*/
Delay(2);
DATA_RD1=DATA_RD;/*将高字节数据读入单片机变量DATA_RD1中*/
Delay(2);
CTR_WORD=0XFA; /*读完低字节以后,将PROCLK置为0*/
Delay(2); /*稍微延时*/
CTR_WORD=0XF0; /*将控制信号全恢复为空闲状态*/
Delay(12);
}
/*****开始模式触发*****/
void Start_Tri(void)
{
WORK_STATE=BUSY;// C51语言,翻译成汇编是将地址置为8300,8表示p2.7=1,//3等价CS[3]=0,然后将0X05送数据总线,busy那条线送低电平
Power_Ctr(PROGRAM_MODE); /*打开编程电压控制继电器,12V和6.5V */////往0x8200送0x05对应CS[2]=0,POWER_CTR[3:0]=0x05
Delay(3600);
Delay(3600);
Delay(3600);
Delay(3600);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -