?? 7816.c
字號:
//**********************************************************************************
// Copyright (c), 1994 - 2007
// 文件名:7816.c
// 創(chuàng)建人:
// 日期: 2007.4.28
// 描述: IEC 7816協(xié)議在電能表CPU卡片和SAM上的應(yīng)用
// 接口數(shù)據(jù):
// bSamCardFlag: 位變量,1--卡片命令 0--ESAM命令
// bRESPAUTOFlag: 位變量,1--自動取響應(yīng) 0--不自動取響應(yīng)
// 接口函數(shù):
// 停活卡片或ESAM
// void Deactivation(void);
// 返回:無
// 參數(shù):無
// 復(fù)位應(yīng)答
// unsigned char resetICC(unsigned char *len, unsigned char *resp);
// 返回:0為成功,其它為不成功。
// 參數(shù):len為返回?cái)?shù)據(jù)長度指針,resp為返回?cái)?shù)據(jù)指針
// 發(fā)送命令并接收返回的數(shù)據(jù)
// unsigned char command(unsigned char len, unsigned char *comm, unsigned char *lenr, unsigned char *resp);
// 返回:0為成功,其它為不成功。
// 參數(shù):len為命令數(shù)據(jù)長度,comm為為命令數(shù)據(jù)指針
// lenr為返回?cái)?shù)據(jù)長度指針,resp為返回?cái)?shù)據(jù)指針
// 修改人:
// 日期:070525
// 描述:command中的兩處bug;復(fù)位時(shí)控制時(shí)鐘
// 單片機(jī)型號:PIC18F65J10
// 時(shí)鐘: Fosc = 4Mz(外部時(shí)鐘)
// 指令周期: 0.25us(4Mz)
// 版本: V1.0
//**********************************************************************************
// 硬件接口操作函數(shù)
unsigned char GetIO(void); // 讀I/O狀態(tài)
void SetVCC(unsigned char s); // 置VCC狀態(tài)
void Activation(void); // 激活
// 基本函數(shù)
void delayETU(unsigned char i); // 延時(shí),i為 1/10 ETU
void delay3us(void); // 延時(shí)3us
unsigned char sendAByte(unsigned char c); // 發(fā)送一個(gè)8位數(shù)據(jù),返回0為成功,其它為不成功
unsigned char receiveAByte(unsigned char *c); // 接收一個(gè)8位數(shù)據(jù),返回0為成功,其它為不成功
// 接口函數(shù)
void Deactivation(void); // 停活
unsigned char resetICC(unsigned char *len, unsigned char *resp);
// 復(fù)位應(yīng)答,返回0為成功,其它為不成功。resp為返回?cái)?shù)據(jù),len為返回?cái)?shù)據(jù)長度
unsigned char command(unsigned char len, unsigned char *comm, unsigned char *lenr, unsigned char *resp);
// 發(fā)送命令并接收返回的數(shù)據(jù)
// 程序體
// 以下注釋部分為測試程序
/*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);
}*/
//*********************************************************************************
// 函數(shù)名: unsigned char GetIO(void)
// 返回: 卡片或ESAM的IO狀態(tài)
// 描述: 根據(jù) bSamCardFlag 值返回IO狀態(tài)
//*********************************************************************************
unsigned char GetIO(void)
{
if (bSamCardFlag) // 1--卡片命令 0--ESAM命令
return ICCData;
else return EsamData;
}
//*********************************************************************************
// 函數(shù)名: void SetVCC(unsigned char s)
// 輸入: s 為VCC管腳狀態(tài)
// 描述: 根據(jù) bSamCardFlag 設(shè)置卡片或ESAM的VCC端狀態(tài)
//*********************************************************************************
void SetVCC(unsigned char s) // 置VCC狀態(tài)
{
// if (bSamCardFlag)
// ICCVCC = s;
// else EsamVCC = s;
}
//*********************************************************************************
// 函數(shù)名: void Activation(void)
// 描述: 激活卡片或ESAM
//*********************************************************************************
void Activation(void)
{
SetRST_OUT;
SetCLKControl_OUT;
SetCLKControl_L;
SetRST_L; // RST置為狀態(tài)L
SetVCC(VCC_ACTIVE); // VCC被加電
SetIO_IN; // IO置為接收模式
// SetIO_Z;
}
//*********************************************************************************
// 函數(shù)名: void Deactivation(void)
// 描述: 停活卡片或ESAM
//*********************************************************************************
void Deactivation(void)
{
SetRST_L; // RST置為L
SetCLKControl_L; // CLK置為L
SetIO_A; // IO置為A
SetVCC(VCC_INACTIVE); // VCC停活
}
//*********************************************************************************
// 函數(shù)名: void delay3us(void)
// 描述: 延時(shí) 3us
//*********************************************************************************
void delay3us(void)
{
Nop();
Nop();
Nop();
Nop();
Nop();
Nop();
Nop();
}
//*********************************************************************************
// 函數(shù)名: void delayETU(unsigned char i)
// 輸入: i 為 1/10個(gè)ETU
// 描述: 延時(shí)i/10個(gè)ETU
// 注釋: delayETU(10)可以延時(shí)一個(gè)標(biāo)準(zhǔn)ETU,為94us,delayETU(1)比0.1個(gè)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();
}
}
//*********************************************************************************
// 函數(shù)名: unsigned char sendAByte(unsigned char c)
// 輸入: c 為要發(fā)送的8位數(shù)據(jù)
// 返回: 0為正確,1為不正確
// 描述: 向卡或ESAM發(fā)送一個(gè)8位字節(jié)
//*********************************************************************************
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++) // 發(fā)送8個(gè)數(shù)據(jù)位
{
if (c & check)
{
SetIO_Z;
even = !even;
}
else
{
SetIO_A;
delay3us();
}
Nop();
Nop();
Nop();
Nop();
check <<= 1;
delayETU(9);
}
if (even) // 偶校驗(yàn)位
{
SetIO_Z;
}
else SetIO_A;
delayETU(10);
SetIO_Z;
delayETU(10); // 第11個(gè)ETU
SetIO_IN;
check = GetIO();
delayETU(10); // 第12個(gè)ETU
EnableInt;
if (check != STATE_A) // 發(fā)送正確
return 0;
delayETU(10);
}
return 1; // 出錯(cuò)返回
}
//*********************************************************************************
// 函數(shù)名: unsigned char receiveAByte(unsigned char c)
// 輸入: c 為要接收的8位數(shù)據(jù)
// 返回: 0為正確,1為不正確
// 描述: 從卡或ESAM接收一個(gè)8位字節(jié)
// 注釋: 接收成功后等待1個(gè)ETU返回,從檢測到啟始位到成功返回時(shí)長大于11個(gè)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) // 超時(shí)
return 1;
*/
///*
//循環(huán)查詢起始位
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; // 偶校驗(yàn)數(shù)
delayETU(12); // 延時(shí)1.5ETU開始采樣
// delayETU(14); // 延時(shí)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) // 偶校驗(yàn)正確
{
// delayETU(24);
delayETU(15); // 校驗(yàn)正確,延時(shí)1.5個(gè)ETU,此時(shí)已進(jìn)行超過11個(gè)ETU
EnableInt;
*c = rcv;
return 0;
}
else
{
delayETU(9); // 第10.5ETU
delay3us();
SetIO_OUT;
SetIO_A;
delayETU(15); // 拉低1.5ETU,要求重發(fā)
SetIO_Z;
SetIO_IN;
EnableInt;
}
}
return 1; // 出錯(cuò)返回
}
//*********************************************************************************
// 函數(shù)名: unsigned char resetICC(unsigned char *len, unsigned char *resp)
// 輸入: len為返回?cái)?shù)據(jù)長度的指針
// resp為返回?cái)?shù)據(jù)的指針
// 輸出: *len為返回?cái)?shù)據(jù)長度,范圍0--0xff
// *resp為返回?cái)?shù)據(jù)
// 返回: 0為正確
// 1為不正確
// 描述: 復(fù)位卡或ESAM
//*********************************************************************************
unsigned char resetICC(unsigned char *len, unsigned char *resp)
{
unsigned char rcv, Y, K, T, i, check;
unsigned char *p;
Activation(); // 激活I(lǐng)CC
delayETU(40); // 延時(shí)372*4個(gè)時(shí)鐘周期,比標(biāo)準(zhǔn)寬
SetRST_H; // RST為狀態(tài)H
delayETU(5); // 延時(shí)0.5ETU=372/2個(gè)時(shí)鐘周期后開始采是否有應(yīng)答,比標(biāo)準(zhǔn)寬
if (!receiveAByte(&rcv) && (rcv == 0x3b)) // 收TS,最大等待9600ETU,即9600*372個(gè)時(shí)鐘周期,比標(biāo)準(zhǔn)寬
{
p = resp;
*p++ = rcv;
*len = 1;
check = rcv ^ 0x0;
}
else
{
// Deactivation; // 停活I(lǐng)CC
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;
}
//*********************************************************************************
// 函數(shù)名: unsigned char command(unsigned char len, unsigned char *comm, unsigned char *lenr, unsigned char *resp)
// 輸入: len為命令長度
// comm為命令數(shù)據(jù)指針
// lenr為返回?cái)?shù)據(jù)長度指針
// resp為返回?cái)?shù)據(jù)指針
// 輸出: *lenr為返回?cái)?shù)據(jù)長度,范圍0--255
// *resp為返回?cái)?shù)據(jù)
// 返回: 0為正確
// 1為不正確
// 描述: 向卡或ESAM發(fā)送命令并接收返回信息
//*********************************************************************************
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;
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -