?? rficrdwr.c
字號:
/*****************************************/
/* Copyright (c) 2005, 通信工程學院 */
/* All rights reserved. */
/* 作 者:戴 佳 */
/*****************************************/
#include "RFICRdWr.h"
/* 延時t毫秒函數 */
void delay(uint t)
{
uint i;
while(t--)
{
/* 對于11.0592M時鐘,約延時1ms */
for (i=0;i<125;i++)
{}
}
}
/* 定時器0中斷服務子程序 */
void timer0() interrupt 1 using 1
{
TR0 = 0; // 停止計數
TH0 = -5000/256; // 重設計數初值
TL0 = -5000%256;
count++;
if (count>300) // 第一次檢測到卡1.5s后
{
count = 0;
if(!flagok) // 如果檢測到1.5s后讀寫標志還是失敗,則蜂鳴器報警
{
BP = 0;
delay(2000); // 報警持續2s
BP = 1;
}
}
else
TR0 = 1; // 啟動T0計數
}
/* 串口發送命令函數 */
void sendcmd(uchar *str)
{
while(*str != 0)
{
TI = 0; // 清發送標志位
SBUF = *str; // 發送數據
str++;
while(!TI); // 等待發送完成
}
}
/* 字符數組轉換為16進制字符串函數,16進制字符串附接在給定字符串后,
參數byte為數組地址,len為數組長度,str為轉換后字符串 */
void Byte2Hex(uchar *byte,uchar len,uchar *str)
{
uchar i, j;
uchar tmp;
j = strlen(str);
for(i=0; i<len; i++)
{
tmp = ((*byte)>>4)&0x0f; // 字節高位
if(tmp < 0x0a)
*(str+j) = tmp+0x30;
else
*(str+j) = tmp-0x0a+'a';
str++;
tmp = (*byte)&0x0f; // 字節低位
if(tmp < 0x0a)
*(str+j) = tmp+0x30;
else
*(str+j) = tmp-0x0a+'a';
str++;
}
*(str+j) = 0; // 字符串結束
}
/* 16進制字符串轉換為字節數組函數,參數str為要轉換的字符串,byte為
轉換后數組地址,若str長度不為偶數,則轉換后最后一個字節高位補0*/
void Hex2Byte(uchar *str, uchar *byte)
{
uchar tmp;
while(*str != 0)
{
tmp = ((*str)<<4)&0xf0; // 字節高位
str++;
if(*str == 0) // 若str長度為奇數,則轉換后最后一個字節高位補0
{
*byte = (tmp>>4)&0x0f;
return;
}
tmp += (*str)&0x0f; // 字節低位
*byte = tmp;
byte++;
}
}
/* 串口初始化 */
void serial_init()
{
/* 9600,n,8,1,外部晶振11.0592MHz,查詢方式 */
TMOD = 0x20; // T1使用工作方式2
TH1 = 250; // 設置T1初值
TL1 = 250;
TR1 = 1; // T1開始計數
PCON = 0x80; // SMOD = 1
SCON = 0x50; // 工作方式1,波特率9600bit/s,允許接收
ES = 0; // 關閉串行中斷
}
/* H6152復位函數 */
void H6152Rst()
{
strcpy(hbuf,"x");
sendcmd(hbuf); // 發送命令"x"
delay(300); // 延時300ms確保H6152復位完畢
}
/* 卡片檢測函數,檢測到有卡在讀寫器有效區域內返回 */
void cardcheck()
{
strcpy(hbuf,"c");
sendcmd(hbuf); // 發送命令"c",命令進入“連續讀”模式
delay(10); // 延時10ms
/* 一旦發現串口接收到數據就立即返回,
表示檢測到讀寫器有效區域內有卡片 */
RI = 0;
while(!RI);
delay(10); // 延時10ms,消抖
RI = 0;
while(!RI);
/* 確認工作區內有卡片,返回 */
}
/* 停止卡片檢測函數,即取消“連續讀"模式 */
void endcheck()
{
strcpy(hbuf," ");
sendcmd(hbuf); // 發送" "取消”連續讀“模式
delay(10); // 延時10ms
}
/* 自動選卡函數,讀取所有卡片,隨機選中并
返回其序列號,主要用于第一次選卡 */
uchar autoselect(uchar *buf)
{
uchar i;
strcpy(hbuf,"m\r");
sendcmd(hbuf); // 發送"m<CR>"
for(i=0;i<8;i++) // 接收第一張卡的序列號
{
RI = 0;
while(!RI);
*(hbuf+i) = SBUF;
/* 如果接收到錯誤信息則返回錯誤代碼 */
if((*(hbuf+i)>0x39)&&(*(hbuf+i)<'a'))
return *(hbuf+i);
}
*(hbuf+i) = 0;
Hex2Byte(hbuf,buf); // 第一張卡片序列號由16進制字符串轉換為字節數組
strcpy(hbuf,"m");
Byte2Hex(buf,4,hbuf);
delay(10);
sendcmd(hbuf); // 發送"m<SN>",選中第一張卡片
for(i=0;i<8;i++) // 接收選中卡片的序列號
{
RI = 0;
while(!RI);
*(hbuf+i) = SBUF;
/* 如果接收到錯誤信息則返回錯誤代碼 */
if((*(hbuf+i)>0x39)&&(*(hbuf+i)<'a'))
return *(hbuf+i);
}
return 0; // 成功
}
/* 指定選卡函數,根據制定序列號選卡 */
uchar snselect(uchar *sn)
{
uchar i;
strcpy(hbuf,"m");
Byte2Hex(sn,4,hbuf); // 將序列號sn轉換為16進制字符串
delay(10);
sendcmd(hbuf); // 發送"m<SN>",選中第一張卡片
for(i=0;i<8;i++) // 接收選中卡片的序列號
{
RI = 0;
while(!RI);
*(hbuf+i) = SBUF;
/* 如果接收到錯誤信息則返回錯誤代碼 */
if((*(hbuf+i)>0x39)&&(*(hbuf+i)<'a'))
return *(hbuf+i);
}
return 0; // 成功
}
/* 登錄扇區函數,參數sect為扇區號,keytype為密碼類型,keyvalue為密碼內容。
keyvalue為NULL時,表示使用默認密碼;keytype為0x10~0x2f和0x30~0x4f
之間或者0xff時,程序忽略keyvalue的內容。 */
uchar loginsect(uchar sect,uchar keytype,uchar *keyvalue)
{
uchar tmp;
if(sect>16) // 扇區號超過16報錯
return ERR_E;
strcpy(hbuf,"l");
Byte2Hex(§,1,hbuf); // 將sect轉換為16進制字符串
if(((keytype>0x10)&&(keytype<0x2f))||((keytype>0x30)&&(keytype<0x4f)))
Byte2Hex(&keytype,1,hbuf); // "l<sect><reg>
else if((keytype==KEY_A)||(keytype==KEY_B)) // 使用密碼A或B登錄
{
Byte2Hex(&keytype,1,hbuf);
if (keyvalue==NULL)
strcat(hbuf,"\r"); // "l<sect>aa<CR>或"l<sect>bb<CR>"
else
Byte2Hex(keyvalue,6,hbuf); // "l<sect>aa<value>或"l<sect>bb<value>"
}
else if(keytype==KEY_DEFAULT) // 使用默認密碼登錄
strcat(hbuf,"\r"); // "l<sect><CR>
else
return ERR_U; // 未知錯誤
sendcmd(hbuf); // 發送命令
RI = 0;
while(!RI);
tmp = SBUF;
if(tmp=='L') // 登錄成功
return 0;
else
return tmp; // 返回錯誤
}
/* 讀塊函數,將塊中內容讀至緩沖區,緩沖區長度應為16字節 */
uchar readblock(uchar block,uchar *buf)
{
uchar i;
if (block>64) // 塊號超過64報錯
return ERR_E;
strcpy(hbuf,"r");
Byte2Hex(&block,1,hbuf); // block轉換為16進制字符串
sendcmd(hbuf); // "r<block>"
for (i=0;i<32;i++) // 接收塊數據
{
RI = 0;
while(!RI);
*(hbuf+i) = SBUF;
/* 如果接收到錯誤信息則返回錯誤代碼 */
if((*(hbuf+i)>0x39)&&(*(hbuf+i)<'a'))
return *(hbuf+i);
}
*(hbuf+32) = 0;
Hex2Byte(hbuf,buf); // 將塊內容由16進制字符串轉換為字節數組
return 0; // 成功
}
/* 寫塊函數,將緩沖區中內容寫入塊,緩沖區長度16字節 */
uchar writeblock(uchar block,uchar *buf)
{
uchar i;
if (block>64) // 塊號超過64報錯
return ERR_E;
strcpy(hbuf,"w");
Byte2Hex(&block,1,hbuf); // block轉換為16進制字符串
Byte2Hex(buf,16,hbuf); // 將要寫入塊的內容轉換為16進制字符串
sendcmd(hbuf); // "w<block><data>"
for (i=0;i<32;i++) // 接收返回數據,為寫入的內容
{
RI = 0;
while(!RI);
*(hbuf+i) = SBUF;
/* 如果接收到錯誤信息則返回錯誤代碼 */
if((*(hbuf+i)>0x39)&&(*(hbuf+i)<'a'))
return *(hbuf+i);
}
return 0; // 成功
}
/* 主程序,選取一張卡,將0~15共16個數寫入扇區1的塊0中,然后再從該扇區的
塊0中讀出這16個數,存入緩沖區block0buf,接著再將block0buf中的內容寫入
該扇區的塊1中,最后再從塊1中讀出16個數,存入緩沖區block1buf中。本程序
的主要功能是驗證H6152模塊對非接觸式IC卡的讀寫 */
void main()
{
char sn[4];
uchar sectno,blockno; // 扇區號、塊號
uchar blockbuf[16]; // 要寫入塊的內容緩沖區
uchar i;
sectno = 1; // 扇區1
blockno = 0; // 塊0
flagok = 0;
flagfirst = 1;
flagselok = 0;
flaglogok = 0;
count = 0;
for (i=0;i<16;i++) // 寫入0~15共16字節
blockbuf[i]=i;
CTRL = 0; // H6152正常工作
BP = 1; // 蜂鳴器不發聲
EA = 1;
TMOD = 0x01; // 模式1,T0為16位定時/計數器
TH0 = -5000/256; // 設置計數初值
TL0 = -5000%256;
ET0 = 1; // 打開T0中斷
serial_init(); // 串口初始化
H6152Rst(); // H6152復位
while(!flagok)
{
cardcheck(); // 卡片檢測
endcheck(); // 停止檢測
if (flagfirst) // 如果是第一次選卡
{
flagfirst = 0;
if (autoselect(sn)==0) // 第一張卡片選擇成功,并保存序列號sn
{
flagselok = 1;
TR0 = 1; // T0開始計時
}
}
else
{
if(snselect(sn)==0) // 指定序列號sn的卡片選擇成功
flagselok = 1;
}
if (flagselok)
{
if(loginsect(sectno,KEY_DEFAULT,NULL)=='L') // 登錄成功
flaglogok = 1;
else
{
flagselok = 0; // 登錄不成工,重新去選卡
flaglogok = 0;
}
if (flaglogok)
{
flagwr = writeblock(blockno,blockbuf);
if(flagwr!=0)
flagselok = 0; // 寫塊錯誤,重新去選卡
else
{
flagrd = readblock(blockno,block0buf);
if (flagrd!=0)
flagselok = 0; // 讀塊錯誤,重新去選卡
else
{
flagwr = writeblock(blockno+1,block0buf);
if (flagwr!=0)
flagselok = 0; // 寫塊錯誤,重新去選卡
else
{
flagrd = readblock(blockno+1,block1buf);
if (flagrd!=0)
flagselok = 0; // 讀塊錯誤,重新去選卡
else
flagok = 1; // 讀寫成功
}
}
}
}
}
}
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -