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

📄 7816.c

📁 cpu卡驱动程序,带ESAM模块认证,已经调试通过的
💻 C
📖 第 1 页 / 共 2 页
字号:
//**********************************************************************************
// Copyright (c), 1994 - 2007
// 文件名:7816.c
// 创建人:
// 日期:  2007.4.28
// 描述:  IEC 7816协议在电能表CPU卡片和SAM上的应用
// 接口数据:
//   bSamCardFlag:  位变量,1--卡片命令         0--ESAM命令
//   bRESPAUTOFlag: 位变量,1--自动取响应       0--不自动取响应
// 接口函数:
//   停活卡片或ESAM
//   void Deactivation(void);
//     返回:无
//     参数:无
//   复位应答				    
//   unsigned char resetICC(unsigned char *len, unsigned char *resp);
//     返回:0为成功,其它为不成功。
//     参数:len为返回数据长度指针,resp为返回数据指针
//   发送命令并接收返回的数据
//   unsigned char command(unsigned char len, unsigned char *comm, unsigned char *lenr, unsigned char *resp);	
//     返回:0为成功,其它为不成功。
//     参数:len为命令数据长度,comm为为命令数据指针
//           lenr为返回数据长度指针,resp为返回数据指针
// 修改人:
// 日期:070525
// 描述:command中的两处bug;复位时控制时钟
// 单片机型号:PIC18F65J10
// 时钟:       Fosc = 4Mz(外部时钟)
// 指令周期:   0.25us(4Mz)
// 版本:       V1.0
//**********************************************************************************

// 硬件接口操作函数

unsigned char GetIO(void);						// 读I/O状态
void SetVCC(unsigned char s);					// 置VCC状态
void Activation(void);							// 激活

// 基本函数

void delayETU(unsigned char i);					// 延时,i为 1/10 ETU
void delay3us(void);                            // 延时3us
unsigned char sendAByte(unsigned char c);		// 发送一个8位数据,返回0为成功,其它为不成功
unsigned char receiveAByte(unsigned char *c);	// 接收一个8位数据,返回0为成功,其它为不成功

// 接口函数

void Deactivation(void);						// 停活
unsigned char resetICC(unsigned char *len, unsigned char *resp);	           
  // 复位应答,返回0为成功,其它为不成功。resp为返回数据,len为返回数据长度
unsigned char command(unsigned char len, unsigned char *comm, unsigned char *lenr, unsigned char *resp);	
  // 发送命令并接收返回的数据





// 程序体

// 以下注释部分为测试程序

/*unsigned char Buflen;
unsigned char Buff[0x50];

void main()
{
  unsigned char ReturnFlag;
  unsigned char c;
  
  SetIO_IN;
  OSCCON = 0x60;
  OSCTUNEbits.PLLEN = 1;
  Nop();
  Nop();
  Nop();
  Nop();
  SetRST_OUT;
  SetEsamCommFlag();
  PORTHbits.RH3 = 0;

//  for (;;)
//  {
//    PORTHbits.RH3 = 1;
//    delayETU(10);
//    PORTHbits.RH3 = 0;
//  }
  do
  {
    ReturnFlag = resetICC(&Buflen, Buff);
    Nop();
  }
  while(ReturnFlag);
  Nop();
  do
  {
//    Buff[0] = 0x00;
//    Buff[1] = 0x84;
//    Buff[2] = 0x00;
//    Buff[3] = 0x00;
//    Buff[4] = 0x08;
    Buff[0] = 0x00;
    Buff[1] = 0xD6;
    Buff[2] = 0x83;
    Buff[3] = 0x00;
    Buff[4] = 0x02;
    Buff[5] = 0x00;
    Buff[6] = 0x01;
    ReturnFlag = command(7,Buff,&Buflen,Buff);
    Buff[0] = 0x00;
    Buff[1] = 0xB0;
    Buff[2] = 0x83;
    Buff[3] = 0x00;
    Buff[4] = 0x02;
    ReturnFlag = command(5,Buff,&Buflen,Buff);
    Nop();
  }
  while(ReturnFlag);
  
  while(1);
}*/

//*********************************************************************************
// 函数名:  unsigned char GetIO(void)
// 返回:   卡片或ESAM的IO状态
// 描述:   根据 bSamCardFlag 值返回IO状态
//*********************************************************************************

unsigned char GetIO(void)
{
  if (bSamCardFlag)								// 1--卡片命令  0--ESAM命令
    return ICCData;
  else return EsamData;
}

//*********************************************************************************
// 函数名: void SetVCC(unsigned char s)
// 输入:   s 为VCC管脚状态
// 描述:   根据 bSamCardFlag 设置卡片或ESAM的VCC端状态
//*********************************************************************************
void SetVCC(unsigned char s)					// 置VCC状态
{
//  if (bSamCardFlag)
//    ICCVCC = s;
//  else EsamVCC = s;
}

//*********************************************************************************
// 函数名: void Activation(void)
// 描述:   激活卡片或ESAM
//*********************************************************************************
void Activation(void)
{
  SetRST_OUT;						
  SetCLKControl_OUT;
  SetCLKControl_L;
  SetRST_L;     								// RST置为状态L
  SetVCC(VCC_ACTIVE);							// VCC被加电
  SetIO_IN;     								// IO置为接收模式
  
//  SetIO_Z;								
}

//*********************************************************************************
// 函数名: void Deactivation(void)
// 描述:   停活卡片或ESAM
//*********************************************************************************
void Deactivation(void)
{
  SetRST_L;								// RST置为L
  SetCLKControl_L;						// CLK置为L
  SetIO_A;      						// IO置为A
  SetVCC(VCC_INACTIVE);					// VCC停活
}

//*********************************************************************************
// 函数名: void delay3us(void)
// 描述:   延时 3us
//*********************************************************************************
void delay3us(void)
{
  Nop();
  Nop();
  Nop();
  Nop();
  Nop();
  Nop();
  Nop();
}

//*********************************************************************************
// 函数名: void delayETU(unsigned char i)
// 输入:   i 为 1/10个ETU
// 描述:   延时i/10个ETU
// 注释:   delayETU(10)可以延时一个标准ETU,为94us,delayETU(1)比0.1个ETU稍大
//*********************************************************************************
void delayETU(unsigned char i)
{
  unsigned char j;

  for (j = 1; j > 0; j--)
    Nop();
  Nop();
  Nop();
  Nop();
  i--;
  for (; i > 0; i--)
  {
    for (j = 2; j > 0; j--)
    {
      Nop();
      Nop();
    }
    Nop();
    Nop();
    Nop();
    Nop();
    Nop();
    Nop();
  }
}

//*********************************************************************************
// 函数名: unsigned char sendAByte(unsigned char c)
// 输入:   c 为要发送的8位数据
// 返回:   0为正确,1为不正确
// 描述:   向卡或ESAM发送一个8位字节
//*********************************************************************************
unsigned char sendAByte(unsigned char c)
{
  unsigned char i, check, even, times;
  
  for (times = 0; times < 5; times++)
  {
    even = 0;
    check = 1;
    SetIO_OUT;
    DisableInt;
    SetIO_A;					    // 启始位
    delayETU(9);
    delay3us();
    delay3us();
    Nop();
    Nop();
    Nop();
    Nop();
    for (i = 0; i < 8; i++)			// 发送8个数据位
    {
      if (c & check)
      {
        SetIO_Z;
        even = !even;
     }
      else 
      {
        SetIO_A;
        delay3us();
      }
      Nop();
      Nop();
      Nop();
      Nop();
      check <<= 1;
      delayETU(9);
    }
    if (even)                       // 偶校验位
    {
      SetIO_Z;
    }
    else SetIO_A;
    delayETU(10);
    SetIO_Z;
    delayETU(10);					// 第11个ETU
    SetIO_IN;
    check = GetIO();
    delayETU(10);					// 第12个ETU
    EnableInt;
    if (check != STATE_A)			// 发送正确
      return 0;
    delayETU(10);
  }
  return 1;							// 出错返回
}

//*********************************************************************************
// 函数名: unsigned char receiveAByte(unsigned char c)
// 输入:   c 为要接收的8位数据
// 返回:   0为正确,1为不正确
// 描述:   从卡或ESAM接收一个8位字节
// 注释:   接收成功后等待1个ETU返回,从检测到启始位到成功返回时长大于11个ETU
//*********************************************************************************
unsigned char receiveAByte(unsigned char *c)
{
  unsigned long int wait;
  unsigned char flag, i, j, rcv, even, times;

  for (times = 0; times < 5; times++)
  {
    flag = 0;
/*
    for (wait = 85000; wait > 0; wait--)		// 最大等待9600ETU
      if (GetIO() == STATE_A)						// 收到启始位
      {
        flag = 1;
        break;
      }
    if (!flag)									// 超时
      return 1;
*/
///*
//循环查询起始位    	
	for(i = 0; --i>0; )		
	{
		EnableInt;
        ClrWdt();
	    DisableInt;
    	for( j = 0; --j>0; )	
        {
    	    if (GetIO() == STATE_A)						// 收到启始位
    	        goto getchar;
        }
    }
    EnableInt;
    return 1;	        
getchar:
//*/    
    DisableInt;
    even = 0;									// 偶校验数
    delayETU(12);								// 延时1.5ETU开始采样
//    delayETU(14);								// 延时1.5ETU开始采样
//    delay3us();
//    delay3us();
    for (i = 0; i < 8; i++)
    {
      rcv >>= 1;
      if (GetIO() == STATE_Z)
      {
        rcv |= 0x80;
        even = !even;
      }
      else
      {
        rcv &= 0x7f;
        delay3us();
      }
      delayETU(9);
      delay3us();
      Nop();
      Nop();
      Nop();
      Nop();
    }
    if (GetIO() == even)							// 偶校验正确
    {
//      delayETU(24);
      delayETU(15);                             // 校验正确,延时1.5个ETU,此时已进行超过11个ETU
      EnableInt;
      *c = rcv;
      return 0;
    }
    else
    {
      delayETU(9);								// 第10.5ETU
      delay3us();
      SetIO_OUT;
      SetIO_A;
      delayETU(15);								// 拉低1.5ETU,要求重发
      SetIO_Z;
      SetIO_IN;
      EnableInt;
    }
  }
  return 1;										// 出错返回
}

//*********************************************************************************
// 函数名: unsigned char resetICC(unsigned char *len, unsigned char *resp)
// 输入:   len为返回数据长度的指针
//          resp为返回数据的指针
// 输出:   *len为返回数据长度,范围0--0xff
//          *resp为返回数据
// 返回:   0为正确
//          1为不正确
// 描述:   复位卡或ESAM
//*********************************************************************************
unsigned char resetICC(unsigned char *len, unsigned char *resp)
{
  unsigned char rcv, Y, K, T, i, check;
  unsigned char *p;

  Activation();									// 激活ICC
  delayETU(40);									// 延时372*4个时钟周期,比标准宽
  SetRST_H;     								// RST为状态H
  delayETU(5);									// 延时0.5ETU=372/2个时钟周期后开始采是否有应答,比标准宽
  if (!receiveAByte(&rcv) && (rcv == 0x3b))		// 收TS,最大等待9600ETU,即9600*372个时钟周期,比标准宽
  {
    p = resp;
    *p++ = rcv;
    *len = 1;
    check = rcv ^ 0x0;
  }
  else
  {
//    Deactivation;								// 停活ICC
    return 1;
  }
  if (!receiveAByte(&rcv))						// T0
  {
    *p++ = rcv;
    *len = 2;
    check ^= rcv;
    Y = rcv & 0xf0;
    K = rcv & 0xf;
    T = 0;										// Default
  }
  else
  {
//    Deactivation;
    return 1;
  }
  while (Y)
  {
    for (i = 0x10; i != 0x80; i <<= 1)			// TAi, TBi, TCi
    {
      if (Y & i)
      {
        if (receiveAByte(&rcv))
        {
//          Deactivation;
          return 1;
        }
        *p++ = rcv;
        (*len)++;
        check ^= rcv;
      }
    }
    if (Y & 0x80)								// TDi
    {
      if (receiveAByte(&rcv))
      {
//        Deactivation;
        return 1;
      }
      *p++ = rcv;
      (*len)++;
      check ^= rcv;
      Y = rcv & 0xf0;
      T = rcv & 0xf;
    }
    else Y = 0;
  }
  for (i = 0; i < K; i++)								// T1 .. TK
  { 
    if (receiveAByte(&rcv))
    {
//      Deactivation;
      return 1;
    }
    *p++ = rcv;
    (*len)++;
    check ^= rcv;
  }
  if (T == 1)
  {
    if (!receiveAByte(&rcv) && (check == rcv))			// TCK
    {
      *p++ = rcv;
      (*len)++;
    }
    else
    {
//      Deactivation;
      return 1;
    }
  }
  return 0;
}

//*********************************************************************************
// 函数名: unsigned char command(unsigned char len, unsigned char *comm, unsigned char *lenr, unsigned char *resp)
// 输入:   len为命令长度
//          comm为命令数据指针
//          lenr为返回数据长度指针
//          resp为返回数据指针
// 输出:   *lenr为返回数据长度,范围0--255
//          *resp为返回数据
// 返回:   0为正确
//          1为不正确
// 描述:   向卡或ESAM发送命令并接收返回信息
//*********************************************************************************
unsigned char command(unsigned char len, unsigned char *comm, unsigned char *lenr, unsigned char *resp)
{
  unsigned char INS, buflen, rcv, Lc, Le, i, Buf[5];
  unsigned char *p;
  
  if (len < 5)
    return 1;
  buflen = len;
  for (i = 0; i < 5; i++)
    Buf[i] = *(comm + i);
  *lenr = 0;
command_begin:
  INS = Buf[1];
  if (buflen > 5)
  {
    Lc = Buf[4];
    if (len > 5 + Lc)
      Le = Buf[5 + Lc];
    else Le = 0;
  }
  else
  {
    Le = Buf[4];
    Lc = 0;
  }
  p = resp;

⌨️ 快捷键说明

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