51单片机的FM1702射卡程序历程许昌美景电子产品有限公司
#include
#include
#include
#define uchar unsigned char
#define uint unsigned int
uchar Fbuff[16]; //发送FIFO缓存
uchar Jbuff[16]; //接收FIFO缓存
uchar UID[7]; //卡型及卡号
uchar Data[4]; //按键值存储区
uchar code seg[16]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0x88,0x83,0xC6, 0xA1,0x86,0x8E}; //数码管段选对应0~f
uchar count=0 ; //按键回传的值
uchar shuaka,chongzhi,keyflag=0;
sbit k2=P3^5; //充值‘加值键(实现加1或者加10)
sbit k3=P3^2; //刷卡’减值键(实现减1或者减10)
sbit k4=P3^3; //确认键
sbit nWR=P2^4; //74hc373片选
/*****************1702函数声明**************************/
uchar spi(uchar m);
void fifo_clear();
void resig_write(uchar reg,uchar da);
uchar resig_read(uchar reg);
uchar fifo_read(uchar count,uchar *s);
void fifo_write(uchar count,uchar *s);
uchar inti_1702();
void card_halt();
uchar request();
uchar card_anticoll();
uchar card_select();
uchar card_authtication(uchar m) ;
uchar card_read(uchar m);
uchar card_write(uchar m);
uchar loadkey();
void delay(uchar m);
/********************按键显示函数声明***************/
void display();
void keyscan() ;
void data1deal() ;
void data2deal(uchar m);
void lcdclear();
/***********************子函数解释******************/
/*********************************************************/
//解释:这是spi总线的读写时序,所有的寄存器操作基于此时序,非常重要
//
//
//输入:要写入的16进制参数
//
//
//输出:内部传回的16进制参数
//
/********************************************************/
uchar spi(uchar m)
{
uchar i,temp=0;
for(i=0;i<8;i++)
{
sck=0;
if(m&0x80)
mosi=1;
else
mosi=0;
m<<=1;
sck=1;
temp<<=1;
if(miso)
temp|=0x01;
}
sck=0;
mosi=0;
return temp;
}
/*********************************************************/
//解释:写寄存器函数
//
//
//输入:寄存器地址以及要写入的参数
//
//
//输出:
//
//注意!!在所有的资料中都没有给出寄存器寻址时的格式,下边的有,看仔细了,如果连寄存器都找不到,后边的就不用看了
/********************************************************/
void resig_write(uchar reg,uchar da)
{
sck=0;
reg<<=1;
cs=0;
reg=reg&0x7e;
spi(reg);
spi(da);
cs=1;
}
/*********************************************************/
//解释:读寄存器函数
//
//
//输入:寄存器地址
//
//
//输出:该寄存器目前的值
//
//注意!!读写寄存器时指令不一样,仔细看。
/********************************************************/ uchar resig_read(uchar reg)
{
uchar temp;
sck=0;
_nop_();
_nop_();
cs=0;
reg<<=1;
reg|=0x80;
spi(reg);
temp=spi(0x00);
cs=1;
return temp;
}
/*********************************************************/ //解释:FIFO缓冲器的读函数
//
//
//输入:读取的字节个数,返回的值存放首地址
//
//
//输出:读成功的话会返回真值,否则返回0
//
//
/********************************************************/ uchar fifo_read(uchar count,uchar *s)
uchar i,temp;
temp=resig_read(FIFOLength);
if(temp手册的启动步骤来,参考所给pdf
/********************************************************/
uchar inti_1702()
{
uchar temp,i;
FM1702rst=1;
mosi=1;
sck=1;
delay(20);
FM1702rst=0;
delay(20);
while(resig_read(Command));
resig_write(0x00,0x80);
temp=resig_read(Command);
while(temp);
resig_write(0x00,0x00); //切换到线性寻址(此命令非常重要,否则无法启动发送)
resig_write(TimerClock,0x0b); //address 2AH /* 定时器周期设置寄存器*/
resig_write(TimerControl,0x02); //address 2BH /* 定时器控制寄存器*/
resig_write(TimerReload,0x42); //address 2CH /* 定时
器初值寄存器*/
resig_write(InterruptEn,0x7f); //address 06H /* 中断使能/禁止寄存器*/
resig_write(InterruptRq,0x7f); //address 07H /* 中断请求标识寄存器*/
resig_write(MFOUTSelect,0x02); //address 26H /* mf OUT 选择配置寄存器*/
resig_write(TxControl,0x5b); //address 11H /* 发送控制寄存器*/
resig_write(RxControl2,0x01);
resig_write(RxWait,0x07);
for(i=0;i<16;i++)
{
Fbuff[i]=0;
Jbuff[i]=0;
}
lcdclear() ;
if(temp==0x00)
return 1;
else
return 0;
}
/*********************************************************/
//解释:延时函数,单次延时为5ms
//
//
//输入:要延时的次数
//
//
//输出:
//
//
/********************************************************/
void delay(uchar m) //单次定时为10ms
{
TMOD=0x01;
while(m--)
{
TH0=0xfe;
TL0=0x33 ;
TR0=1;
while(!TF0);
TF0=0;
TR0=0;
}
}
/*********************************************************/ //解释:卡的回应函数,判断是否有卡在读写器跟前
//
//
//输入:
//
//
//输出:如果有卡在的话返回真值,否则返回0
//
//
/********************************************************/ uchar request()
{
uchar temp;
resig_write(CRCResultLSB,0x63);
resig_write(CWConductance,0x3f);
resig_write(BitFraming,0x07);
resig_write(ChannelRedundancy,0x03);
temp=resig_read(Control);
temp=temp&0x7f;
resig_write(Control,temp);
resig_read(FIFOLength);
temp=resig_read(Control);
temp=temp|0x01;
resig_write(Control,temp);
Fbuff[0]=0x52;
fifo_write(1,Fbuff);
resig_write(Command,0x1e);
delay(1);
temp=resig_read(FIFOLength);
if(temp==0x02)
return 1;
else
return 0;
}
/*********************************************************/
//解释:防冲突函数(我所做的此函数没有手册的那种功能,只是实现了单卡交易功能)
//
//
//输入:
//
//
//输出:防冲突成功的话返回真值,否则返回0
//
//实现功能:如果有多张卡在读卡器区域,只选中一张,并读取验证这张卡的ID,然后存储
/********************************************************/
uchar card_anticoll() //防冲突函数
{
uchar temp,i;
resig_write(DecoderControl,0x28);
resig_write(Control,0x08);
resig_write(ChannelRedundancy,0x03);
temp=resig_read(Control);
temp=temp|0x01;
resig_write(Control,temp);
Fbuff[0]=0x93;
Fbuff[1]=0x20;
fifo_write(2,Fbuff);
resig_write(Command,0x1e);
delay(2);
temp=resig_read(FIFOLength);
if(temp==0x05)
{
temp=0;
fifo_read(5,UID);
delay(1);
for(i=0;i<5;i++)
{
temp=temp^UID[i];
}
if(temp==0)
return 1;
else
return 0;
}
else
return 0;
}
/*********************************************************/ //解释:选卡函数
//
//
//输入:
//
//
//输出:选卡成功的话返回真值,否则返回0
//
//实现功能:将要交易的卡号发给卡,如果回应正确则选卡成功
/********************************************************/ uchar card_select()
{
uchar i,temp;
resig_write(ChannelRedundancy,0x0f);
resig_write(Control,0x08);
temp=resig_read(Control);
temp=temp|0x01;
resig_write(Control,temp);
Fbuff[0]=0x93;
Fbuff[1]=0x70;
for(i=0;i<5;i++)
{
Fbuff[i+2]=UID[i];
}
fifo_write(7,Fbuff);
resig_write(Command,0x1e);
delay(2);
temp=resig_read(FIFOLength);
if(temp==0x01)
return 1 ;
else
return 0 ;
}
/*********************************************************/ //解释:三重认证函数
//
//
//输入:要操作的块号
//
//
//输出:如果三重认证的话返回真值,否则返回0
//
//实现功能:这是卡片与读卡器之间的默认通信
,次程序执行成功后才可以与卡进行交易
/********************************************************/
uchar card_authtication(uchar m)
{
uchar i,temp;
temp=resig_read(Control);
temp=temp|0x01;
resig_write(Control,temp);
Fbuff[0]=0x60;
Fbuff[1]=m;
for(i=0;i<4;i++)
{
Fbuff[i+2]=UID[i];
}
fifo_write(6,Fbuff);
resig_write(InterruptEn,0xa5);
resig_write(Command,0x0c);
delay(2);
temp=resig_read(SecondaryStatus);
temp=temp&0x07;
if(temp==0)
{
temp=resig_read(Control);
temp=temp|0x01;
resig_write(Control,temp);
resig_write(InterruptEn,0xa4);
resig_write(Command,0x14);
delay(2);
temp=temp=resig_read(Control);
temp&=0x08;
if(temp==0x08)
return 1;
else
return 0;
}
return 0;
}
/*********************************************************/ //解释:读卡函数
//
//
//输入:要读的考号
//
//
//输出:读卡成功的话返回真值,否则返回0
//
//实现功能:读取指定卡号的
,并传送给FIFO
/********************************************************/ uchar card_read(uchar m)
{
uchar temp;
temp=resig_read(Control);
temp=temp|0x01;
resig_write(Control,temp);
resig_write(ChannelRedundancy,0x0f);
temp=resig_read(Control);
temp=temp|0x01;
resig_write(Control,temp);
Fbuff[0]=0x30;
Fbuff[1]=m;
fifo_write(2,Fbuff);
resig_write(Command,0x1e);
delay(0x04);
temp=resig_read(FIFOLength);
if(temp==16)
{
fifo_read(16,Jbuff);
return 1;
}
else
return 0;
}
/*********************************************************/ //解释:写卡函数
//
//
//输入:要写入的卡号
//
//
//输出:写卡成功的话返回真值,否则返回0
//
//实现功能:将发送缓冲区的数据写入指定的块号
/********************************************************/ uchar card_write(uchar m)
{
uchar temp;
temp=resig_read(Control);
temp=temp|0x01;
resig_write(Control,temp);
Fbuff[0]=0xA0;
Fbuff[1]=m;
fifo_write(2,Fbuff);
resig_write(Command,0x1e);
delay(2);
temp=resig_read(FIFOLength);
if(temp==1)
{
temp=resig_read(Control);
temp=temp|0x01;
resig_write(Control,temp);
Fbuff[0]=Jbuff[0];
fifo_write(16,Fbuff);
resig_write(Command,0x1e);
delay(10);
temp=resig_read(FIFOLength);
if(temp==1)
return 1;
else
return 0;
}
else
return 0;
}
/*********************************************************/
//解释:加载密匙函数
//
//
//输入:
//
//
//输出:成功的话返回真值,否则返回0
//
//实现功能:建立与卡通信协议的第一步,将密匙发送给卡,验证密匙是否成功,成功的话执行三重认证
/********************************************************/
uchar loadkey()
{
uchar temp;
temp=resig_read(Control);
temp=temp|0x01;
resig_write(Control,temp);
fifo_write(12,changekey);
resig_write(Command,0x19);
delay(3);
temp=resig_read(ErrorFlag);
if(temp==0)
return 1;
else
return 0;
}
/*********************************************************/
//解释:设置卡的暂停态函数
//
//
//输入:
//
//
//输出:执行成功的话返回真值,否则返回0
//
//实现功能:将卡设置为终止交易态,若要再次交易必须从头重新开始认证/********************************************************/
void card_halt()
{
uchar temp;
resig_write(InterruptEn,0x7f);
resig_write(InterruptRq,0x7f);
resig_write(Command,0x00);
temp=resig_read(Control);
temp=temp|0x01;
resig_write(Control,temp);
Fbuff[0]=0x50;
Fbuff[1]=0x00;
fifo_write(2,Fbuff);
resig_write(InterruptEn,0xbd);
resig_write(Command,0x1e);
delay(2);
}
/****************按键显示子函数解释********************/
/*********************************************************/ //解释:卡的高两位序列号函数
//
//
//输入:
//
//
//输出:
//
//实现功能:将卡的高两位序列号处理为16进制后存放在相应显示区/********************************************************/ void data1deal() //序列号处理
{
uchar temp,i;
for(i=0;i<4;i++)
Data[i]=0;
temp=UID[3];
Data[1]=temp/16;
Data[0]=temp%16;
temp=UID[2];
Data[3]=temp/16;
Data[2]=temp%16;
}
/*********************************************************/ //解释:显示数据处理函数
//
//
//输入:
//
//
//输出:
//
//实现功能:将要现实的数据处理为10进制后存放在相应显示区
/********************************************************/
void data2deal(uchar m) //显示数据及按键处理
{
uchar i,temp;
for(i=0;i<4;i++)
Data[i]=0;
temp=m;
Data[0]=temp%10;
Data[1]=temp%100/10;
Data[2]=temp/100;
}
/*********************************************************/
//解释:按键扫描函数
//
//
//输入:
//
//
//输出:输出相应的交易种类以及交易数额(会在说明里做详细说明) //
//
/********************************************************/ void keyscan()
{
if(k2==0||k3==0)
{
if(k2==0)
{
delay(100);
if(k2==0)
delay(250);
if(keyflag==1)
{
if(k2==1)
{
if(count==255)
count=0 ;
else
count++;
}
if(k2==0)
{
while(!k2)
display();
if(count>=246)
count=count+11;
else
count=count+10;
}
}
else
{
chongzhi=1;
shuaka=0;
}
}
if(k3==0)
{
delay(100);
if(k3==0)
delay(250);
if(keyflag==1)
{
if(k3==1)
{
if(count==0)
count=255;
else
count--;
}
if(k3==0)
{
while(!k3)
display();
if(count<=9)
count=245+count;
else
count=count-10;
}
}
else
{
shuaka=1;
chongzhi=0;
}
}
}
if(k4==0)
{
delay(180);
if(k4==0)
keyflag=keyflag+1;
}
}
/*********************************************************/ //解释:显示函数
//
//
//输入:
//
//
//输出:
//
//
/********************************************************/ void display()
{
unsigned char time=0;
nWR=0;
P2=0x0f;
WR=0;
P0=seg[Data[3]];
WR=1;
P2=0X0e;
time=5000;
while(time--);
nWR=0;
P2=0x0f;
WR=0;
P0=seg[Data[2]];
WR=1;
P2=0X0d;
time=5000;
while(time--);
nWR=0;
P2=0x0f;
WR=0;
P0=seg[Data[1]];
WR=1;
P2=0X0b;
time=5000;
while(time--);
nWR=0;
P2=0x0f;
WR=0;
P0=seg[Data[0]];
WR=1;
P2=0X07;
time=5000;
while(time--);
}
/*********************************************************/ //解释:lcd清屏函数
//
//
//输入:
//
//
//输出:
//
/********************************************************/ void lcdclear()
{
nWR=0;
P2=0x0f;
WR=0;
P0=0xff;
WR=1;
P2=0X0e;
nWR=0;
P2=0x0f;
WR=0;
P0=0xff;
WR=1;
P2=0X0d;
nWR=0;
P2=0x0f;
WR=0;
P0=0xff;
WR=1;
P2=0X0b;
nWR=0;
P2=0x0f;
WR=0;
P0=0xff;
WR=1;
P2=0X07;
}
/*****************************主函数****************************/ void main()
{
uchar temp,p,i,j;
temp=inti_1702();
while(1)
{
switch(temp)
{
case 0: p=inti_1702();if(p) temp++;else temp=0;break;
case 1: p=request(); if(p) {temp++;led5=~led5;}else temp=1;break;
case 2: p=card_anticoll(); if(p){ temp++;led6=~led6;}else temp=1;break;
case 3: p=card_select(); if(p) temp++; else temp=1;break;
case 4: p=loadkey();if(p){temp++;led7=~led7;} else temp=1;break;
case 5: p=card_authtication(PICC_BLOCK);if(p){ temp++;led8=~led8;}else
temp=1;break;
case 6: p=card_read(PICC_BLOCK);
if(p)
{
temp++;
data1deal();
for(i=0;i<2;i++)
for(j=0;j<150;j++)
display();
data2deal(Jbuff[0]);
i=10;
j=200;
while(i--)
{
while(j--)
{ display();
keyscan();
if(shuaka||chongzhi)
{ data2deal(count);
display();
if(keyflag==0x02)
{
if(shuaka)
Jbuff[0]=Jbuff[0]-count ;
if(chongzhi)
Jbuff[0]=Jbuff[0]+count;
keyflag=0;
shuaka=0;
chongzhi=0;
count=0;
j=0;
i=0;
}
else
j=100;
}
}
}
}
else
temp=0;break;
case 7: p=card_write(PICC_BLOCK);if(p){temp++;led9=~led9;} else temp=0;break;
case 8: p=card_read(PICC_BLOCK);
if(p)
{
temp++;
data1deal();
for(i=0;i<2;i++)
for(j=0;j<150;j++)
display();
data2deal(Jbuff[0]);
i=5;
j=200;
while(i--)
{
while(j--)
display();
}
lcdclear() ;
}
else
temp=0; break;
case 9: card_halt();temp=0;break;
default: break;
}
}
}