📄 yuanma.txt
字号:
源程序
sbit CTRL = P1^0;
sbit BP = P1^1;
// 密码宏定义
#define KEY_A 0xaa
#define KEY_B 0xbb
#define KEY_DEFAULT 0xff
// 返回值宏定义
#define OK 0 // 操作成功
#define ERR_N 'N' // 无卡
#define ERR_F 'F' // 操作失败
#define ERR_E 'E' // 格式错误
#define ERR_I 'I' // 非数值块
#define ERR_X 'X' // 操作后无法读出
#define ERR_U 'U' // 未知错误
uchar xdata hbuf[0x25]; // 缓冲区定义
uchar xdata block0buf[16];
uchar xdata block1buf[16];
bit flagok; // 读写块成功标志位
bit flagfirst; // 第一次选卡标志位
bit flagselok; // 选卡成功标志位
bit flaglogok; // 登录扇区成功标志位
uchar flagwr; // 写块成功标志位
uchar flagrd; // 读块成功标志位
uchar count;
// 定时器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); // 报警持续两秒
BP = 1;
}
}
else
TR0 = 1; // 启动T0 计数
}
// 串口发送命令函数
void sendcmd(uchar *str)
{
While (*str != 0)
{
TI = 0; // 清发送标志位
SBUF = *str; // 发送数据
str++;
while(!TI); // 等待发送完成
}
}
// 字符数组转换为十六进制字符串函数 十六进制字符串附接在给定字符串后面
// 参数 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; // 字符串结束
}
// 十六进制字符串转换为字节数组函数 参数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 波特率9600bps 允许接收
ES = 0; // 关闭串行中断
}
// H6125复位函数
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); // 第一张卡片序列号由十六进制字符串转换为字节数组
strcpy(hbug,”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 转换为十六进制字符串
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为扇区号 keytrpe为密码类型 keyvalue 为密码内容
// vkeyvalue 为null是 表示使用默认密码 keytpe为0X10~0X2f和0X30~ 0X4f
// 之间或者 0Xff时 程序忽略keyvalue的内容
uchar loginsect ( uchar sect,uchar keytype,uchar *keyvalue)
{
uchar tmp;
if(sect>16) // 扇区超过十六 报错
return EER_E;
strcpy(hbuf,"1");
Byte2Hex(§,1,hbuf); // 将sect转换为十六进制字符串
if(((keytype>0x10)&&(keytype<0x2f))||((keytype>0x30)&&(keytype<0x4f)))
Byte2Hex(&keytype,1,hbuf);
else if((keytype == KEY_A)||(keytype == KEY_B)) // 使用密码A或B登录
{
Byte2Hex(&keytype,1,hbuf);
If (keyvalue == NULL)
strcat(hbuf,"\r");
else
Byte2Hex(keyvalue,6,hbuf);
}
else if (keytype == KEY_DEFAULT) // 使用默认密码登录
strcat(hbuf,"\r");
else
return EER_U; // 未知错误
sendcmd(hbuf); // 发送命令
RI = 0;
while(!RI);
tmp = SBUF ;
if(tmp == 'l') // 登录成功
return 0;
else // 返回错误
return tmp;
}
// 读块函数 将块中内容读至缓冲区 缓冲区长度应为 16B
uchar readblock(uchar block,uchar *buf)
{
uchar i;
if(block>64) // 块号超过 64 报错
return EER_E;
strcpy(hbuf,"r");
Byte2Hex(&block,1,hbuf); // block转换为十六进制字符串
sendcmd(hbuf);
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); // 将块内容由十六进制字符串转换为字节数组
return 0;
}
// 写快函数 将缓冲区中内容写入到块 缓冲区长度16B
uchar writeblock(uchar block,uchar *buf)
{
uchar i;
if(block>64) // 块号超过64 报错
return EER_E;
strcpy(hbuf,"w");
Byte2Hex(&block,1,hbuf); // block 转换为十六进制字符串
Byte2Hex(buf,16,hbuf); // 将要写如块的内容转换为十六进制字符串
sendcmd(hbuf);
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~5共16个数写入扇区1的块0中 然后再从该扇区的块0中读出这个16个数 存入缓冲区 blockbuf
// 接着在将blockbuf中的内容写入该扇区的块1中 最后在从块1中读出16个数 存入缓冲区 block部分中
// 本设计的主要功能是验证H6125模块对飞接触式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共16B
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,blockbuf);
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 + -