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