📄 at88scxx.c
字号:
#include<reg52.h>
#include<intrins.h>
#define _Nop()_nop_() // 延时1us
sbit SDA=P1^3; // 定义SDA
sbit SCL=P1^2; // 定义SCL
sbit pwr=P3^5; // 供电
unsigned char GPA[20]; //GPA 单元使用频率高,应直接寻址
unsigned char rwdata[0x14];//min=0x04(不读写) max=0x0c(读最大字节数为0x20H,写最大为0x10H)
//前4字节用做命令,数据存放在rwdata[0x04]=>rwdata[0x13]
//参数也可分配成0x0C,但后面一次只能读写8字节数据
//所有从器件解密出的数据和写入器件的数据暂放在此
//******************请填写GC************************************
//GC_TABLE:
unsigned char code GC0[]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};//GC0
unsigned char code GC1[]={0x00,0x00,0x06,0x09,0x02,0x06,0x16,0x00};//GC1
unsigned char code GC2[]={0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11};//GC2
unsigned char code GC3[]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};//GC3
//******************请填写PASSWORD************************************
//PASSWORD_TABLE:
unsigned char code PW_WRITE0[]={0x80,0x00,0x00};//WRITE PASSWORD 0
unsigned char code PW_READ0[]= {0x00,0x00,0x00};//READ PASSWORD 0
unsigned char code PW_WRITE1[]={0x11,0x00,0x11};//WRITE PASSWORD 1
unsigned char code PW_READ1[]= {0x00,0x00,0x00};//READ PASSWORD 1
unsigned char code PW_WRITE2[]={0x00,0x00,0x00};//WRITE PASSWORD 2
unsigned char code PW_READ2[]= {0x00,0x00,0x00};//READ PASSWORD 2
unsigned char code PW_WRITE3[]={0x00,0x00,0x00};//WRITE PASSWORD 3
unsigned char code PW_READ3[]= {0x00,0x00,0x00};//READ PASSWORD 3
unsigned char code PW_WRITE4[]={0x22,0x22,0x22};//WRITE PASSWORD 4
unsigned char code PW_READ4[]= {0x22,0x22,0x22};//READ PASSWORD 4
unsigned char code PW_WRITE5[]={0x00,0x00,0x00};//WRITE PASSWORD 5
unsigned char code PW_READ5[]= {0x00,0x00,0x00};//READ PASSWORD 5
unsigned char code PW_WRITE6[]={0x00,0x00,0x00};//WRITE PASSWORD 6
unsigned char code PW_READ6[]= {0x00,0x00,0x00};//READ PASSWORD 6
unsigned char code PW_WRITE7[]={0xdd,0x42,0x97};//WRITE PASSWORD 7
unsigned char code PW_READ7[]= {0x00,0x00,0x00};//READ PASSWORD 7
void SMSTART(void);//功能:启动I2C
void SMSTOP(void); //功能:停止I2C
void delay_ms(); //功能:延时1ms
void IIC_Initial(void);//上电后初始化IIC
void Wait_For_AckPolling(void);
//功能:检查所发送的命令是否已被执行
//只有当AckPolling_return=1或bytecounter=0时,该程序才退出
void GPA_CLOCK(unsigned char Datain,unsigned char times);
//GPA函数
//入口:Data_in
//出口:GPA[0]:GPA_byte
//参数:times GPA函数计算的次数
void read(rd);
//功能:对at88scxx I2C读操作函数
//本程序中以read(rwdata)调用;
//入口:rwdata数组
//出口:rwdata数组
//rd数组长度可改
//cmd_send_counter发送命令次数,超出8次,本函数退出,并认为I2C线路上无器件
void write(SDATA);
//功能:对at88scxx I2C写操作函数
//本程序中以write(rwdata)调用;
//入口:rwdata数组
//出口:rwdata数组
//rd数组长度可改
//cmd_send_counter发送命令次数,超出8次,本函数退出,并认为I2C线路上无器件
unsigned char AUTHENTICATION(unsigned char GC_select);
//双向认证函数
//入口:GC_select:选择密钥套数
//出口:AAC: 认证结果
//过程:
//1.从器件读出CIx,产生随机数Q0,计算密钥;计算出Q1,将Q0、Q1发送给器件,计算出新的CIx,SKx
//2.用读回的CIx与计算出的CIx比较
//3.用计算出的SKx替代GCx,重复1过程
//AAC:认证错误计数器.AAC!=0xff表示双向认证未通过或无器件
//需产生随机数则应在程序里修改
unsigned char verify_write_password(unsigned char pw_select);
//校验写密码组主函数,正确校验了写密码后开放读写
//pw_select:密码套数选择
//PAC:密码校验错误计数器.PAC!=0xff表示认证未通过或无器件
void set_user_zone(unsigned char zone);
//选择用户区
//zone:用户区序号
void read_user_zone(unsigned char rd_high_addr,unsigned char rd_low_addr,unsigned char rd_number);
//读出用户区密文数据,并解出明文数据
//rd_high_addr 用户区高字节地址
//rd_low_addr 用户区低字节地址
//rd_number 读取密文数据及解出明文数据的个数
//解密出的明文数据存放在rwdata[0x04]=>rwdata[0x13]
void read_config_zone(unsigned char rd_high_addr,unsigned char rd_low_addr,unsigned char rd_number);
//当rd_low_addr往后不应滚动到0xb0
//如想读 0xb0<rd_low_addr<0xef 单元则应重新调用
void encrypto_data(unsigned char encryptodatanumber);
//对明文数据进行加密
//encryptodatanumber加密数据的个数
//需加密的明文数据存放在 rwdata[4]至rwdata[0x13]
void write_user_zone(unsigned char wr_high_addr,unsigned char wr_low_addr,unsigned char wr_number);
//功能:把已加密了的密文数据写到器件
//wr_high_addr 用户区高字节地址
//wr_low_addr 用户区低字节地址
//wr_number 写入数据的个数
//将存放在 rwdata[4]至rwdata[0x13]明文数据写入器件
void send_checksum();
//功能:发送校验和到器件(以密文形式写入数据后,需发送校验和)
void write_config_zone(unsigned char wr_high_addr,unsigned char wr_low_addr,unsigned char wr_number);
//当rd_low_addr往后不应滚动到0xb0
//如想读 0xb0<rd_low_addr<0xef 单元则应重新调用
//熔丝断后不可写
//****************明文读写部分******************************
unsigned char verify_sc_plaintext(unsigned char sc_first_byte,unsigned char sc_second_byte,unsigned char sc_third_byte);
//功能:校验安全密码(传输密码),该密码位置在write7_password
//在器件熔丝未断前,校验安全密码成功后,可以对器件配置区,用户区的随意读写
//sc_firsr_byte 密码的第1个字节数据
//sc_second_byte 密码的第2个字节数据
//sc_third_byte 密码的第3个字节数据
//如verify_sc_plaintext(0xDD,0x42,0x97)
//0xDD,0x42,0x97分别为密码的第123个字节数据
void set_user_zone_plaintext(unsigned char zonep);
//选择用户区(明文)
//zonep:用户区序号
void read_paintext(unsigned char rd_cmd,unsigned char A1,unsigned char A2,unsigned char N);
//读操作(明文)
//rd_cmd:0xb2 读用户区 /0xb6 读配置区 /0xb6 0x01 0x00 0x01 读熔丝
//A1 :高字节地址
//A2 :地字节地址
//N :读取数据个数
void write_paintext(unsigned char wr_cmd,unsigned char A1,unsigned char A2,unsigned char N);
//写操作(明文)
//rd_cmd:0xb0 写用户区 /0xb4 写配置区 /0xb4 0x01 ID 0x00 写熔丝
//A1 :高字节地址
//A2 :地字节地址
//N :写数据个数
//注意:烧断熔丝时只能从ID=0x06=>0x04=>0x00
////////////////////////////////////////
void main()
{
unsigned char j;
unsigned char AAC; //AAC=0xFF则表明校验GCx正确
unsigned char PAC; //PAC=0xFF则表明校验PWx正确
pwr=0; //上电
AAC=0;
PAC=0;
IIC_Initial();
//goto MTZ_Test;
//goto Set_AAC_PAC_FF;
//goto RW_Config_User_Zone_Plaintext;
//goto RW_User_Zone_Encryptoed;
//goto RW_Config_Zone_Encryptoed;
////////////////////密文读写部分////////////////////////////////////////
RW_User_Zone_Encryptoed:
AAC=AUTHENTICATION(0x02); //0x02使用02套密钥/
PAC=verify_write_password(0x04);//0x04使用04套密码,只读可用verify_read_password(pw_select)
set_user_zone(0x00); //0x00进入00H用户区
read_user_zone(0x00,0x00,0x10); //解密出的明文数据存放在rwdata[0x04]=>rwdata[0x13]
//read_user_zone(rd_high_addr,rd_low_addr,rd_number)
//rd_high_addr:对于0104恒为0x00
//rd_low_addr:读0104用户区的首地址
//rd_number:读出的数据字节数
//如read_user_zone(0x00,0x00,0x10)则读解0104下0x00H-0x0fH单元
read_user_zone(0x00,0x10,0x10);
for(j=0x04;j<0x0c;j++)
{rwdata[j]=0x85;}
for(j=0x0c;j<0x14;j++)
{rwdata[j]=0x66;} //明文数据存放在 rwdata[4]至rwdata[0x13]
write_user_zone(0x00,0x00,0x10);//write_user_zone(wr_high_addr,wr_low_addr,wr_number)
for(j=0x04;j<0x0c;j++)
{rwdata[j]=0x28;}
for(j=0x0c;j<0x14;j++)
{rwdata[j]=0x66;} //明文数据存放在 rwdata[4]至rwdata[0x13]
write_user_zone(0x00,0x10,0x10);//write_user_zone(wr_high_addr,wr_low_addr,wr_number)
//wr_high_addr:对于0104恒为0x00
//wr_number:写入0104的数据字节数
//如write_user_zone(0x00,0x00,0x10)则把数据写到0104下0x00H-0x0fH单元
set_user_zone(0x00); //再调用命令操作防止写数据掉电丢失
pwr=1; //芯片下电,释放SDA SCL,RAM单元以做其他用
while(1);
////////////////密文方式读写配置区///////////////////////////////////////////
RW_Config_Zone_Encryptoed:
AAC=AUTHENTICATION(0x02); //0x02使用02套密钥/
PAC=verify_write_password(0x07);//0x07使用07套密码,开放所有权限
for(j=0x04;j<0x0c;j++)
{rwdata[j]=0x28;}
for(j=0x0c;j<0x14;j++)
{rwdata[j]=0x66;}
write_config_zone(0x00,0x40,0x10);//熔丝断后不可写
read_config_zone(0x00,0x40,0x10);
for(j=0x04;j<0x0c;j++)
{rwdata[j]=0x18;}
for(j=0x0c;j<0x14;j++)
{rwdata[j]=0x16;}
write_config_zone(0x00,0xb0,0x10); //low_addr+ wr_number不应超过B0,若要读写 0xb0后应另起一行
read_config_zone(0x00,0xb0,0x10);
for(j=0x04;j<0x0c;j++)
{rwdata[j]=0x58;}
for(j=0x0c;j<0x14;j++)
{rwdata[j]=0x56;}
write_config_zone(0x00,0xb0,0x10); //low_addr+ wr_number不应超过B0,若要读写 0xb0后应另起一行
read_config_zone(0x00,0xb0,0x10);
while(1);
//////////////////明文读写部分,可执行F1算法/////////////////////////////
/////////////////////////////////////////////////////////////
MTZ_Test:
rwdata[4]=0x88;
rwdata[5]=0x66; //明文写
write_paintext(0xb4,0x00,0x0a,0x02); //write_paintext(0xb0 或 0xb4,A1,A2,N)
read_paintext(0xb6,0x00,0x0a,0x02); //明文读
//读回rwdata[4]=0x85;rwdata[5]=0x66;则表明通讯测试成功
while(1);
///////////////////////////////////////////////////////////
Set_AAC_PAC_FF://恢复设置 ACC PAC
rwdata[4]=0xff;
write_paintext(0xb4,0x00,0x70,0x04); //write_paintext(0xb0 或 0xb4,A1,A2,N)
read_paintext(0xb6,0x00,0x70,0x10); //明文读
rwdata[4]=0xff;
write_paintext(0xb4,0x00,0xd0,0x01); //write_paintext(0xb0 或 0xb4,A1,A2,N)
read_paintext(0xb6,0x00,0xd0,0x01); //明文读
while(1);
////////////////////////////////////////////////////////////
RW_Config_User_Zone_Plaintext://明文读写配置区或用户区或熔丝
PAC=verify_sc_plaintext(0xDD,0x42,0x97);//校验SC
set_user_zone_plaintext(0x03); //选区
read_paintext(0xb2,0x00,0x00,0x10); //明文读
//read_paintext(0xb2 或 0xb6,A1,A2,N)
rwdata[4]=0x85;
rwdata[5]=0x66; //明文写
rwdata[6]=0x28;
rwdata[7]=0x66;
write_paintext(0xb0,0x00,0x00,0x04); //write_paintext(0xb0 或 0xb4,A1,A2,N)
//如以明文写用户区,则AR PR应为0xFF
read_paintext(0xb2,0x00,0x00,0x10); //明文读
while(1);
}
//******************delay_ms*********************************
//功能:延时1ms
//*****************************************************************
void delay_ms()
{
unsigned char j;
for(j=0x00;j<255;j++)
{
_Nop();_Nop();_Nop();
}
}
//***********************IIC_Initial***********************************
//功能:上电后初始化IIC
//*****************************************************************
void IIC_Initial(void)
{SDA=1;_Nop();_Nop();_Nop();
SCL=1;_Nop();_Nop();_Nop();SCL=0;_Nop();_Nop();_Nop();
SCL=1;_Nop();_Nop();_Nop();SCL=0;_Nop();_Nop();_Nop();
SCL=1;_Nop();_Nop();_Nop();SCL=0;_Nop();_Nop();_Nop();
SCL=1;_Nop();_Nop();_Nop();SCL=0;_Nop();_Nop();_Nop();
SCL=1;_Nop();_Nop();_Nop();SCL=0;_Nop();_Nop();_Nop();//先打出5个CLK
}
//***********************SMSTART***********************************
//功能:启动I2C
//*****************************************************************
void SMSTART(void)
{SCL=1;_Nop();_Nop();_Nop();
SDA=1;_Nop();_Nop();_Nop();
SDA=0;_Nop();_Nop();_Nop();
SCL=0;_Nop();_Nop();_Nop();
}
//************************SMSTOP***********************************
//功能:停止I2C
//*****************************************************************
void SMSTOP(void)
{
SCL=1;_Nop();_Nop();_Nop();
SDA=0;_Nop();_Nop();_Nop();
SDA=1;_Nop();_Nop();_Nop();
SCL=0;_Nop();_Nop();_Nop();
}
//************************AckPolling*******************************
//功能:检查所发送的命令是否已被执行
//只有当AckPolling_return=1或bytecounter=0时,该程序才退出
//*****************************************************************
void Wait_For_AckPolling(void)
{
unsigned char AckPolling_return;
unsigned char temp, bitcounter;
unsigned char bytecounter;
SMSTART();
temp=0xb6;
bytecounter=0xff;//如CPU速度过快须加大其值
AckPolling_return=0;
do{
for(bitcounter=0;bitcounter<8;bitcounter++)
{
if ((temp&0x80)==0x80)
{SDA=1;}
else
{SDA=0;}
_Nop();_Nop();_Nop();
SCL=1;_Nop();_Nop();
SCL=0;_Nop();_Nop();
temp=temp<<1;
}
SDA=1;_Nop();_Nop();
SCL=1;_Nop();_Nop();
bytecounter--;
if(SDA==0)
{SCL=0;AckPolling_return=1;}
else
{SCL=0;AckPolling_return=0;SMSTART();temp=0xb6;}
if(AckPolling_return==1)
{break;}
}while(bytecounter>0);
SMSTOP();
}
//*********************GPA_CLOCK************************************
//GPA函数
//入口:Data_in
//出口:GPA[0]:GPA_byte
//参数:times GPA函数计算的次数
//*****************************************************************
void GPA_CLOCK(unsigned char Datain,unsigned char times)
{
unsigned char t;
unsigned char d;
unsigned char din_gpa;
unsigned char Ri;
unsigned char R_Sum;
unsigned char Si;
unsigned char S_Sum;
unsigned char Ti;
unsigned char T_Sum;
for(t=0x00;t<times;t++)
{
din_gpa=Datain ^ GPA[0];
Ri= din_gpa&0x1f;
Si= ((din_gpa&0x0f)<<3)+((din_gpa&0xe0)>>5);
Ti=(din_gpa&0xf8)>>3;
//r元素
if(((GPA[4])+((GPA[1]&0x0f)<<1)+((GPA[1]&0x10)>>4))>31)
{R_Sum=((GPA[4])+((GPA[1]&0x0f)<<1)+((GPA[1]&0x10)>>4))-31;}
else
{R_Sum=((GPA[4])+((GPA[1]&0x0f)<<1)+((GPA[1]&0x10)>>4));}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -