|
![](static/image/common/ico_lz.png)
楼主 |
发表于 2010-3-21 23:54:05
|
显示全部楼层
//小程序就不另外头文件了,都写一个文件里,凑合着用吧.....
#include <STC11F04E.h> //你包含2051的头文件即可
#include <string.h>
#define byte unsigned char
#define word unsigned int
#define dword unsigned long
#define SetBit(byte,bit) (byte|=(1<<bit))
#define ClrBit(byte,bit) (byte&=~(1<<bit))
sbit LED1 = P3^2;
sbit LED2 = P3^3;
sbit LED3 = P3^4;
sbit LED4 = P3^5;
byte sMcuId[7]; //处理器序列号;
byte code sMcuIdFlash[7] _at_ 0x300; //FLASH中于存的MCU序列号;
word code wMainFuncAddOnFlash _at_ 0x320; //(800) 存放在Flash中Main函数的入口地址,便于量产软件识别;
word code wGetIdFuncAddOnFlash _at_ 0x3e8; //(1000)作用同上;
//..... //可以定义N个要校验的主要函数;
word code wMainCrc16 _at_ 0x380; //从MAIN开始50Byte 数据的CRC16验证码存放地。
word code wGetIdCrc16 _at_ 0x400; //从取ID号入口函数开始以后50 Byte的CRC校验码;
//...... //N个主要函数代码的校验码;
byte iCheckStatus; //校验结果;
byte iCheckIndex=0; //校验次序;
byte iCommandIndex=0; //主程序里的命令序列;
word wKeyTimer=0; //按键处理记时;
byte iKeyData=0;
union unionIntAddr //系统联合体,共8byte; 用于串口返回;
{
struct strSysStru
{
word wMainFuncAddr; //入口地址;
word wCRC16A; //从0开始的50B校验码;
word wGetIdFuncAddr;
word wCRC16B; //取MCU ID函数校验码;
} struSys;
byte sUionBuff[8]; //用于向串口发数据;
} untest;
//---------CRC16校验计算-----------
word CRC16Check(byte * buf, byte len)
{
word crc=0x0000;
word c,i;
while(len!=0)
{
c=*buf;
for(i=0;i<8;i++)
{
if((crc ^ c) & 1)
crc=(crc>>1)^0xa001;
else
crc>>=1;
c>>=1;
}
len--;
buf++;
}
return crc;
}
void InitIoPort()
{
P1=0XFF;
}
//串口发送函数,为了使程序易读些,就不用中断发送了;
void Send1Byte(byte iSendData)
{
TI=0;
//ACC=iSendData;
//TB8=P;//Odd_Checkout(i); //校验位;
SBUF = iSendData;
while(!TI)
{
;
}
TI=0;
}
//向串口发送缓冲区iNum个字节内容;
void SendBuffer(byte *sBuffer,byte iNum)
{
byte i;
for(i=0;i<iNum;i++)
{
Send1Byte(*sBuffer);
sBuffer++;
}
return;
}
//取得序列号或OSCCAL;
void GetMcuIdNo()
{
byte idata *idata_point;
idata_point = 0xF1;
memset(sMcuId,0,7);
memcpy(sMcuId,idata_point,7);
}
//将MCU ID发给串口;
void SendMcuIdNo()
{
SendBuffer(sMcuId,7);
return;
}
void MainCheck()
{
//校验00开始到50的FLASH是否被改动过
byte code *sData;
word wTemp=0;
sData=0; //将sData指针指向FLASH的0位置;
wTemp=CRC16Check(sData,50); //算出校验值
untest.struSys.wCRC16A=wTemp;
//调试用,将校验码发到串口上;
SendBuffer(untest.sUionBuff,4);
if(wTemp!=wMainCrc16) //比较校验值;数据有误;
{
SetBit(iCheckStatus,0); //防盗版标志;
//可以不立即爆发,
return ;
}
ClrBit(iCheckStatus,0); //防盗版标志;
return ;
}
//校验比对序列号;
void GetIdCheck()
{
if(memcmp(sMcuId,sMcuIdFlash,7)>0)
{
//序列号不一致;
ClrBit(iCheckStatus,1); //防盗版标志;
return;
}
//发送GetIdCheck函数入口地址,及校验码
//注,此处不对代码进行校验了,与主函数校验方式一样
//......
SendBuffer(untest.sUionBuff+4,4);
SetBit(iCheckStatus,1);
return;
}
//按键处理程序,可根据自己喜好改用其它方式检测;
//此法优点在于无需等待消抖,不占处理器时间;
byte CheckKey()
{
byte iKeyTemp;
P1=0XFF;
iKeyTemp=P1;
iKeyTemp=(~iKeyTemp)&0x0f;
if(iKeyTemp==0)
{
wKeyTimer=0; //清相同按键记时;
return 0; //无按键
}
if(iKeyTemp==iKeyData) //有按键,且和上次检测相同;
{
wKeyTimer++;
if(wKeyTimer>800) //按下此键超过一定时间,视为有效
{
wKeyTimer=800;
return iKeyData;
}
}
else
{
iKeyData=iKeyTemp;
wKeyTimer=0;
}
return iKeyData;
}
void DoFunc1()
{
//点亮第一个灯;当然,你的程序可不只是点灯;
LED1 = 0;
return;
}
void DoFunc2()
{
LED2=0;
return;
}
void DoFunc3()
{
LED3=0;
return;
}
void DoFunc4()
{
LED4=0;
return;
}
void DoFunc5()
{ //熄灯;
P3=0xff;
return;
}
void main()
{
GetMcuIdNo(); //取得序列号;
//取得主函数的入口地址;
untest.struSys.wMainFuncAddr =(word)&MainCheck;
//取得取CPU ID号函数的入口地址;
untest.struSys.wGetIdFuncAddr=(word)&GetIdCheck;
InitIoPort();
//初始化寄存器;用到串口,返回各函数地址,便于量产;
SCON=0xd0; //串行口0 工作在方式3 不倍频;
PCON=PCON|0X80;
//CLK_DIV=0;
//AUXR=0X0;
IT1=1;
TMOD=0x21;
TH1=0xfa;
TL1=0xFa;
ES=1;
TR1=1;
EA=1; //开放中断
//将序列号发到串口;
SendMcuIdNo();
while(1)
{
iCommandIndex=CheckKey();
switch(iCommandIndex) //此处多用SWITCH不用IF语句,因为反编后IF思路非常清晰,对加密并不利。
{
case 1:
DoFunc1(); //以下点灯
break;
case 2:
DoFunc2();
break;
case 4:
DoFunc3();
break;
case 8:
DoFunc4();
break;
default: //只是做个范例,组合键就免了
DoFunc5();
break;
}
switch(iCheckIndex)
{
case 0: //执行第一次校验,Main主函数校验;
MainCheck();
iCheckIndex=1;
break;
case 1:
GetIdCheck();
iCheckIndex=2;
break;
//......还有一些校验,不写了;
}
}
} |
|