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

📄 ic_c.c

📁 51系列单片机的汇编程序包
💻 C
字号:
/******************************************
; 程序名称:SLE4442 逻辑加密存储卡读写程序
;
; 程序功能:首先对IC卡20~2Fh应用数据区16个
;           单元写数据,再将其读到片外数据
;           区2000h为起始地址的单元。
; 运行结果:2000 = 80,81,82...8F
******************************************/

#include <reg51.h>
#include <intrins.h>

#define uchar unsigned char
#define uint  unsigned int

uchar LedBuf[8];               /*显示缓冲区*/
uchar xdata *CS8255 = 0xffff;
uchar xdata *OUTSEG = 0xfffc;  /*字形控制口*/
uchar xdata *OUTBIT = 0xfffd;  /*字位控制口*/
uchar code Led_ICError[8] = {0xf9,0xc6,0xff,0x86,0xaf,0xaf,0xa3,0xaf};
uchar code Led_ICGood[8]  = {0xff,0xf9,0xc6,0xff,0xc2,0xa3,0xa3,0xa1};
uchar code Led_NoIC[8]    = {0xc8,0xc0,0xff,0xf9,0xc6,0xff,0xf9,0xc8};

/* 延时5us宏定义 */
#define Delay5us() _nop_();_nop_();_nop_();_nop_();_nop_()

/* 延时10us宏定义 */
#define Delay10us() _nop_();_nop_();_nop_();_nop_();_nop_();\
                    _nop_();_nop_();_nop_();_nop_();_nop_()

/* IC卡常数 */
/*---------------------------------------------
此处为IC卡保护区00~03单元的值,用于识别卡,这四个
字节是SLE4442的标识,如果IC卡保护区00~03单元的值
不是这四个字节,表明该卡不是SLE4442卡或卡已损坏
---------------------------------------------*/
#define IDENTIFY1 0xA2
#define IDENTIFY2 0x13
#define IDENTIFY3 0x10
#define IDENTIFY4 0x91

/* IC卡引脚位定义 */
sbit IO  = P1^0;        /*数据*/
sbit CLK = P1^1;        /*脉冲*/
sbit RST = P1^2;        /*复位*/

/* IC卡状态指示 */
sbit IC_INS = P1^3;     /*插入正确*/
sbit IC_WRS = P1^4;     /*写操作*/
sbit IC_RDS = P1^5;     /*读操作*/

uchar bdata ibase;      /*定义位寻址单元,用于发送与接收一个字节*/
sbit mybit0 = ibase^0;
sbit mybit1 = ibase^1;
sbit mybit2 = ibase^2;
sbit mybit3 = ibase^3;
sbit mybit4 = ibase^4;
sbit mybit5 = ibase^5;
sbit mybit6 = ibase^6;
sbit mybit7 = ibase^7;

/************************************************
函数名称:Readchar()
功    能:读一个字节
输    入: 无
输    出:所得的字节的值
************************************************/
uchar Readchar(void)
{
  CLK=0; Delay5us(); mybit0=IO; CLK=1; Delay5us();  /*一个脉冲接收1 bit*/
  CLK=0; Delay5us(); mybit1=IO; CLK=1; Delay5us();  /*一个脉冲接收1 bit*/
  CLK=0; Delay5us(); mybit2=IO; CLK=1; Delay5us();  /*一个脉冲接收1 bit*/
  CLK=0; Delay5us(); mybit3=IO; CLK=1; Delay5us();  /*一个脉冲接收1 bit*/
  CLK=0; Delay5us(); mybit4=IO; CLK=1; Delay5us();  /*一个脉冲接收1 bit*/
  CLK=0; Delay5us(); mybit5=IO; CLK=1; Delay5us();  /*一个脉冲接收1 bit*/
  CLK=0; Delay5us(); mybit6=IO; CLK=1; Delay5us();  /*一个脉冲接收1 bit*/
  CLK=0; Delay5us(); mybit7=IO; CLK=1; Delay5us();  /*一个脉冲接收1 bit*/
  return(ibase);  /*返回读得的一个字节*/
}

/************************************************
函数名称:SendByte()
功    能:把一个字节的数据由低到高位依次发送出去
输    入:uchar sendchar -- 要发送的字节
输    出;无
************************************************/
void SendByte(uchar sendchar)
{
  uchar i;
  ibase = sendchar;
  for(i=8; i>0; i--)    /*8个比特发送8次*/
  {
    CLK = 0;
    Delay5us();
    IO  = mybit0;       /*一个脉冲发送一个比特mybit0*/
    CLK = 1;
    Delay5us();
    ibase >>= 1;        /*将下次要发送的比特位移到mybit0*/
  }
}

/************************************************
函数名称:RstCard()
功    能:使IC卡SLE4442复位
输    入:无
输    出:0 -- 复位成功
          1 -- 复位失败,卡为无效卡或卡已损坏
************************************************/
uchar RstCard(void)
{
  uchar i;
  uchar ReadBuf[4];

  IO  = 1;              /*IO引脚置高电平*/
  RST = 0;              /*RST引脚置低电平*/
  CLK = 0;              /*CLK 引脚置低电平*/

  /*下面在一个RST脉冲期间产生一个CLK脉冲*/
  Delay10us(); RST = 1;
  Delay5us();  CLK = 1;
  Delay5us();  CLK = 0;
  Delay5us();  RST = 0;

  for(i=0; i<4; i++) ReadBuf[i] = Readchar();  /*接收复位响应值*/

  CLK = 1;
  Delay5us();
  CLK = 0;
  IO  = 1;              /*置CLK和IO为复位时序图复位完成时的状态*/

  if((ReadBuf[0]==IDENTIFY1) && (ReadBuf[1]==IDENTIFY2)&&
     (ReadBuf[2]==IDENTIFY3) && (ReadBuf[3]==IDENTIFY4))
  {
    return 0;           /*复位值正确,返回复位成功*/
  }
  else
  {
    return 1;           /*复位值错误,返回复位失败*/
  }
}

/************************************************
函数名:SendCommand()
功  能:根据不同的参数把命令字发给IC卡
参  数:uchar command  -- 命令字;
        uchar Address  -- 地址;
        uchar senddata -- 数据
返回值:无
************************************************/
void SendCommand(uchar command,uchar Address,uchar senddata)
{
  IO  = 1;              /*产生开始状态*/
  CLK = 0; Delay5us();
  CLK = 1; Delay10us();
  IO  = 0; Delay10us();
  CLK = 0;

  SendByte(command);    /*发送命令*/
  SendByte(Address);
  SendByte(senddata);

  CLK = 0;              /*产生停止状态*/
  IO  = 0; Delay5us();
  CLK = 1; Delay5us();
  IO  = 1; Delay5us();
}

/************************************************
函数名称:SendClock()
功    能:发送处理脉冲
输    入:无
输    出:无
************************************************/
void SendClock(void)
{
  CLK = 0; Delay10us(); /*产生一个脉冲,做为处理的工始*/
  CLK = 1; Delay10us();

  /*不断产生处理脉冲,驱动IC卡内部处理,直到IC卡将IO口拉为高电平*/
  do
  {
    CLK = 0; Delay10us();
    CLK = 1; Delay10us();
  } while(IO == 0);
}

/************************************************
函数名称:ReadCm()
功    能:从主存储器中读出数据块并存入ReadBuf中
输    入:uchar StarAddr -- 开始地址(0-255)
          uchar ByteNum  -- 要读出的字节数(1-256)
          uchar *RecBuf  -- 接收数据缓冲区
输    出: 0 -- 读成功
          1 -- 表示无效卡或者卡损坏
************************************************/
uchar ReadCm(uchar StarAddr,uchar ByteNum,uchar *RecBuf)
{
  uchar i;

  if(RstCard() == 1)    /*使卡复位*/
    return 1;           /*如果复位失败返回1*/

  SendCommand(0x30,StarAddr,0x00); /*发送读主存命令*/

  for(i=0; i<ByteNum; i++)
  {
    *RecBuf = Readchar(); /*从主存中读出ByteNum个字节并存入RecBuf中*/
    RecBuf++;
  }
  return 0;
}

/************************************************
函数名称: WriteCm()
功    能: 把存在WriteBuf中的ByteNum个字节的数据存入主存储器中
输    入: uchar StarAdr   -- 开始地址(0-255)
          uchar ByteNum   -- 要写入的字节数(1-256)
          uchar *WriteBuf -- 写入数据缓冲区
输    出: 0 -- 写成功
          1 -- 表示无效卡或者卡损坏
注    意:要校验密钥正确,才能对卡的主存储器写入数据
************************************************/
uchar WriteCm(uchar StarAdr,uchar ByteNum,uchar *WriteBuf)
{
  uchar i;

  if(RstCard() == 1)    /*使卡复位*/
    return 1;           /*如果复位失败返回1*/

  for(i=0; i<ByteNum; i++)
  {
    SendCommand(0x38,StarAdr,*WriteBuf); /*发送写主存储区命令*/
    SendClock();        /*发送处理脉冲*/
    StarAdr++;          /*写入字节地址加1*/
    WriteBuf++;         /*写入缓冲区指针加1*/
  }
  return 0;
}

/************************************************
函数名称:ReadPm()
功    能:读保护存储器,并把保护存储器的4字节的内容存在RecBuf中
输    入:uchar *RecBuf -- 接收数据缓冲区,长度为4个字节
输    出:0 -- 读成功
          1 -- 表示无效卡或者卡损坏
************************************************/
uchar ReadPm(uchar *RecBuf)
{
  uchar i;

  if(RstCard() == 1)    /*使卡复位*/
    return 1;           /*如果复位失败返回1*/

  SendCommand(0x34,0x00,0x00); /*读保护存储器命令*/

  IO = 1;               /*置IO口为输入状态*/
  Delay10us();          /*延时10us*/

  for(i=0; i<4; i++)    /*读保护存储器4个字节*/
  {
    *RecBuf=Readchar();
    RecBuf++;           /*接收缓冲区指针加1*/
  }

  SendClock();          /*发送处理脉冲*/

  return 0;
}

/************************************************
函数名称:WritePm()
功    能:写保护数据存储器
输    入:uchar StartAdr  -- 起始地址(0-31)
          uchar ByteNum   -- 写入的字节数(1-32)
          uchar *WriteBuf -- 写入数据缓冲区
输    出:0 -- 写成功
          1 -- 表示无效卡或者卡损坏
注    意: 首先校验密钥正确,才能对卡的护存储器写
          入数据,其次写入的数据必须与卡中对应的
          数据相等才能写入
************************************************/
uchar WritePm(uchar StartAdr,uchar ByteNum,uchar *WriteBuf)
{
  uchar i;

  if(RstCard() == 1)    /*使卡复位*/
    return 1;           /*如果复位失败返回1*/

  for(i=0; i<ByteNum; i++)
  {
    SendCommand(0x3c,StartAdr,*WriteBuf); /*写入一个字节*/
    SendClock();        /*发送写命令处理脉冲*/
    StartAdr++;         /*写入字节地址加1*/
    WriteBuf++;         /*写入缓冲区指针加1*/
  }
  return 0;
}

/************************************************
函数名称:ReadPsw()
功    能:读加密存储器
输    入:uchar *Psw  --- 用于装读到的加密存储器内容,长度为4个字节
          Psw第一字节:错误计数器值
          Psw第二字节到第四字节:卡的密码值
输    出:0 -- 读成功
          1 -- 表示无效卡或者卡损坏
注    意: 必须校验密码正确才能读到正确的密钥值,否则读到的密码值为00 00 00
************************************************/
uchar ReadPsw(uchar *Psw)
{
  uchar i;

  if(RstCard() == 1)    /*使卡复位*/
    return 1;           /*如果复位失败返回1*/

  SendCommand(0x31,0,0);/*读加密存储器命令*/

  for(i=0; i<4; i++)    /*读加密存储器的四个字节*/
  {
    *Psw = Readchar();
    Psw++;
  }
  return 0;
}

/************************************************
函数名称:CheckPsw()
功    能:校验密码,把Psw中1,2,3字节的内容分别与加密存储器的1,2,3字节比较
输    入:uchar *Psw -- 待校验的密码值,长度为3个字节
输    出: 3 -- 核对密码成功
          0 -- 卡已报废
          1 -- 只剩一次校验机会,校验密码失败
          2 -- 只剩二次校验机会,校验密码失败
          4 -- 卡为无效卡或已损坏
************************************************/
uchar CheckPsw(uchar *Psw)
{
  uchar ReadBuf[4], i;

  if(ReadPsw(ReadBuf)==1) /*读加密存储器*/
    return 4;

  if(ReadBuf[0]==0x07)
  {
    SendCommand(0x39,0,0x03); /*将EC写为0x03*/
    SendClock();        /*发送处理脉冲*/
  }
  else if(ReadBuf[0]==0x06 || ReadBuf[0]==0x05 || ReadBuf[0]==0x03)
  {
    SendCommand(0x39,0,0x01); /*将EC写为0x01*/
    SendClock();        /*发送处理脉冲*/
  }
  else if(ReadBuf[0]==0x01 || ReadBuf[0]==0x02 || ReadBuf[0]==0x04)
  {
    SendCommand(0x39,0,0x00); /*将EC写为0x00*/
    SendClock();        /*发送处理脉冲*/
  }

  SendCommand(0x33,1,Psw[0]); SendClock(); /*校验密码的第一个字节*/
  SendCommand(0x33,2,Psw[1]); SendClock(); /*校验密码的第二个字节*/
  SendCommand(0x33,3,Psw[2]); SendClock(); /*校验密码的第三个字节*/

  SendCommand(0x39,0,0x07);   SendClock(); /*擦除错误计数器*/

  SendCommand(0x31,0,0);/*读加密存储器命令*/

  for(i=0;i<4;i++) ReadBuf[i]=Readchar();  /*读加密存储器的四个字节*/

  if(ReadBuf[0]==0x07) return 3;           /*剩下3次校验机会,校验密码成功*/
  else if(ReadBuf[0]==6 || ReadBuf[0]==5 || ReadBuf[0]==3) return 2;
                                           /*剩下2次校验机会,校验密码失败*/
  else if(ReadBuf[0]==4 || ReadBuf[0]==2 || ReadBuf[0]==1) return 1;
                                           /*剩下1次校验机会,校验密码失败*/
  else return 0;                           /*无校验机会,卡报废*/
}

/************************************************
函数名称:SetPsw()
功    能:修改加密存储器中的密码
输    入:NewPsw -- 新密码缓冲区,长度为3个字节
输    出:0 -- 读成功
          1 -- 表示无效卡或者卡损坏
注    意: 必须校验密码成功后才能修改密码,否则密码写不进卡中
************************************************/
uchar SetPsw(uchar *NewPsw)
{
  uchar i;

  if(RstCard() == 1)    /*使卡复位*/
    return 1;           /*如果复位失败返回1*/

  for(i=0; i<3; i++)
  {
    SendCommand(0x39,i+1,*NewPsw); /*发送新的密码值*/
    SendClock();        /*发送处理脉冲*/
    NewPsw++;           /*密码值缓冲区指针加1*/
  }
  return 0;
}

/* 程序延时 */
void Delay(uint count)
{
  uchar i;
  while(count-- != 0) for(i=0;i<120;i++);
}

/* LED显示函数 */
void DispLed(uchar LedPtr[8])
{
  uchar i, pos=0x80;
  for(i=0; i<8; i++)
  {
    *OUTSEG = LedPtr[i];
    *OUTBIT = pos;
    Delay(2);
    pos>>=1;
  }
}

main()
{
  uchar ReadBuf[16];    /*读数据缓冲区*/
  uchar WriteBuf[16];   /*写数据缓冲区*/
  uchar i;
  uchar retw, retr;
  uchar psw[3] = {0xff,0xff,0xff}; /*IC卡初始密码: FF FF FF*/
  uchar xdata *PTR = 0x0080   ;0x2000           ;片内地址; /*片外RAM地址指针*/

  *CS8255 = 0x88;
  
  while(IC_INS) DispLed(Led_NoIC);

  *OUTBIT = 0;
  Delay(500);
  
  if(ReadCm(0x00,8,ReadBuf)==0) /*读卡状态*/
  { /*读IC卡状态正确*/
    if(CheckPsw(psw)==3)
    { /*密码校验成功*/
      for(i=0;i<16;i++) WriteBuf[i]=i+0x80;

      retw = WriteCm(0x20,16,WriteBuf);  /*写IC卡*/
      IC_WRS = 0; Delay(600); IC_WRS = 1;

      retr = ReadCm(0x20,16,ReadBuf);    /*读IC*/
      IC_RDS = 0; Delay(600); IC_RDS = 1;

      if(retw==0 && retr==0)         /*读写正确*/
      {
        for(i=0; i<16; i++) *PTR++ = ReadBuf[i]; /*将IC卡数据写入片外RAM*/
        while(1) DispLed(Led_ICGood);
      }
      else while(1) DispLed(Led_ICError);
    }
    else while(1) DispLed(Led_ICError);
  }
  else while(1) DispLed(Led_ICError);
}

⌨️ 快捷键说明

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