使用STC12C5A60S2控制PN532

/********************************************************************************
* STC12C5A60S2控制PN532进行寻卡操作
* STC12C5A60S2通过UART与PN532相连
* 通过中断实现接收UART数据,并通过定时判断PN532的响应是否超时
********************************************************************************/
#include "reg52.h"
#include <intrins.h>

#define ERR_NO        0
#define ERR_TIMEOUT   1
#define ERR_SENDDATA  2
#define ERR_RECVACK   3
#define ERR_RECVDATA  4

//-----------------------------UART1部分使用的全局变量---------------------------
xdata unsigned char gPn532Data[100];            //13.56M RF数据缓存
xdata unsigned char *gpPn532RxBuf, gPn532RxLen; //用于中断函数处理接收buf
xdata unsigned char gi;     //用于接收数据与接收ack之间进行区别
//-------------------------------------------------------------------------------

unsigned char gTimeMult;
unsigned char gTimeOutFlag;
unsigned char gUart1RecvFlag;

sbit p25 = P2^5;

void C51InitIo(void)
{  
 P2M0 |= 0x20;
 P2M1 |= 0x00;//配置P2.5为强上拉输出
}

//定时时间=num*25ms
void C51InitTimer(unsigned char num)
{
 //AUXR |= 0xC0;//bit7->T0x12:0->12T,1->1T;bit6->T1x12:0->12T,1->1T,默认情况下是传统8051速度
 TMOD |= 0x01;
 TH0 = 0x4C;
 TL0 = 0x00;//0x4C00=19456,(65536-19456)*12/22118400=0.025s=25ms
 gTimeMult = num;//25*40=1000ms=1s
 ET0 = 1;
 TR0 = 1;
}

void C51StopTimer()
{
 TR0 = 0;
}

/**************************************************
Function: init_uart();

Description:
  set uart working mode,
  使用独立波特率发生器作为波特率发生器
**************************************************/
void C51InitUart(void)
{
 AUXR |= 0x18; //BRTR=1,启动独立波特率发生器,S2SMOD=1,串口2波特率*2,S1BRS=1,串口1使用独立波特率发生器作为波特率发生器,S1BRS=0,串口1使用定时器1作为波特率发生器
     
 SCON |= 0x50; //UART1工作于模式1(8位uart,加上起始位与停止位共10位),可变速率f=((2^SMOD)/32)*BRT,ren==1->允许串行接收
 PCON |= 0x80; //smod=1,
 TMOD |= 0x20; //定时器工作与方式2,由TR1控制定时器的开启与关闭
 TH1   = 0xFF; //22.1184MHz:0xF4->9600, 0xFA->19200, 0xFD->38400, 0xFE->57600, 0xFF->115200
 TL1   = 0xFF;
 TR1   = 1;  //启动定时器1   
 ES    = 1;     //允许串口1中断

 S2CON |= 0x50; //UART2工作于模式1(8位uart,加上起始位与停止位共10位),可变速率f=((2^S2SMOD)/32)*BRT,ren==1->允许串行接收 
 BRT    = 0xF4; //BRTx12=0;0xFF->115200,0xF4->9600,0xA0->1200 
 IE2   |= 0x01; //允许串口2中断
}

//串口1发送一个字节函数
void C51Uart1SendByte(unsigned char num)
{
 ES = 0;  
 TI = 0;
 SBUF = num;
 while (0==TI);
 TI = 0;
 ES = 1;
}

//---------串口2发送与接收一个字节函数----------
void C51Uart2SendByte(unsigned char num)

 IE2   &= 0xFE; //允许串口2中断,需要增加关闭、打开中断语句,不然串口2工作不正常 
 S2CON = S2CON&0xFD;//清除发送中断标志
 S2BUF = num;
 while (0==(S2CON&0x02));//等于1说明发送完成
 S2CON = S2CON&0xFD;//清除发送中断标志
 IE2   |= 0x01; //允许串口2中断
}

//延时n*1us函数
void C51Delay1us(unsigned short n)
{
 while (--n)
 {
  _nop_();
  _nop_();
  _nop_();
  _nop_();
  _nop_();
 }
}
/*****************************************************************
* 函数名:  PN532SendData
* 函数功能:主控器向PN532发送数据
* 输入参数:
 pBuf:需要发送给PN532的帧数据 
 len: pBuf的长度
* 输出参数:
        返回是否成功标志
            成功:SUCCESS
            失败:相应的错误代码
********************************************************************/
unsigned char PN532SendData(unsigned char *pBuf, unsigned char len)
{
 unsigned char i;
 WDT_CONTR = 0x3F;
 for (i=0; i<len; i++)
 {
  C51Uart1SendByte(pBuf[i]);
 }     
    return ERR_NO;
}

/***************************************************
* 函数名:  PN532RecvData
* 函数功能:主控器从PN532接收数据
* 输入参数:
        无 
* 输出参数:
        pBuf:
            接收帧缓存 
        返回是否成功标志
            成功:SUCCESS
            失败:相应的错误代码
***************************************************/
unsigned char PN532RecvData(unsigned char *pBuf)

 gTimeOutFlag = 0;
 gUart1RecvFlag = 0;

 C51InitTimer(4);

 gpPn532RxBuf = pBuf;        //Start of RX buffer
    gPn532RxLen = 6;            // Load RX byte counter
 gi = 0;
 while (!(gTimeOutFlag||gUart1RecvFlag));//只要有一个为1则退出循环

 C51StopTimer();
 if (1==gUart1RecvFlag)
 {
     return ERR_NO;
 }
 else
 {
  return ERR_TIMEOUT;
 }
}

/****************************************
* 函数名:  PN532SendAck
* 函数功能:主控器向PN532发送ACK帧
* 输入参数:
 无
* 输出参数:
        返回是否成功标志
            成功:SUCCESS
            失败:相应的错误代码
*****************************************/
unsigned char PN532SendAck()

 unsigned char pAckBuf[6] = {0x00,0x00,0xFF,0x00,0xFF,0x00};
 unsigned char i;
 
 for (i=0; i<6; i++)
 {
  C51Uart1SendByte(pAckBuf[i]);
 }  
    return ERR_NO;
}

/***********************************************
* 函数名:  PN532RecvAck
* 函数功能:主控器从PN532接收ACK帧
* 输入参数:
 无 
* 输出参数:
        pBuf:
            接收ACK帧缓存
        返回是否成功标志
            成功:SUCCESS
            失败:相应的错误代码
*************************************************/
unsigned char PN532RecvAck(unsigned char *pBuf)

 gTimeOutFlag = 0;
 gUart1RecvFlag = 0;

 C51InitTimer(1);

 gpPn532RxBuf = pBuf;        //Start of RX buffer
    gPn532RxLen = 6;            // Load RX byte counter
 gi = 0;
 while (!(gTimeOutFlag||gUart1RecvFlag));//只要有一个为1则退出循环

 C51StopTimer();

 if (1==gUart1RecvFlag)
 {
     return ERR_NO;
 }
 else
 {
  return ERR_TIMEOUT;
 }
}

/*********************************************************************************************************
* 函数名:  SAMConfiguration
* 函数功能:设置PN532的内部参数
* 输入参数:
 mode:
      0x01:normal mode
      0x02:virtual mode
      0x03:wired mode
      0x04:dual mode
 timeout:
      0x00:不使用timeout
      0x01-0xFF:超时值
 irq:
      0x00:不使用P70_IRQ
      0x01:使用P70_IRQ
* 输出参数:
 成功:ERR_NO
        失败:ERR_RECVACK,ERR_RECVDATA
* 输入输出参数:
        pRfBuf:输入,用于存放输入参数的缓存,从外部传入,用于解决在函数内部定义过大的数组问题
                输出,存放从PN532接收的结果
**********************************************************************************************************/
unsigned char SAMConfiguration(unsigned char *pRfBuf, unsigned char mode, unsigned char timeout, unsigned char irq)
{
    unsigned char temp;
    unsigned char s;
    pRfBuf[0] = 0x00; //前导码
    pRfBuf[1] = 0x00; //包开始标志2个字节
    pRfBuf[2] = 0xFF;
    pRfBuf[3] = 3 + 1 + 1;//len + 1字节的PD0 + 1字节的TFI
    pRfBuf[4] = 0x100-pRfBuf[3];
    pRfBuf[5] = 0xD4; //方向标示
    temp = pRfBuf[5];
    pRfBuf[6] = 0x14; //命令码
    temp += pRfBuf[6];
    pRfBuf[7] = mode; 
    temp += pRfBuf[7];
    pRfBuf[8] = timeout;
    temp += pRfBuf[8];
    pRfBuf[9] = irq;
    temp += pRfBuf[9];
   
    pRfBuf[10] = 0x100 - temp; //DCS
    pRfBuf[11] = 0x00;
   
    //底层发送函数
    s = PN532SendData(pRfBuf,12);
    if (s!=ERR_NO)
    {
        return ERR_SENDDATA;
    }
    s = PN532RecvAck(pRfBuf);
    if (s!=ERR_NO)
    {
        return ERR_RECVACK;
    }
    s = PN532RecvData(pRfBuf);
    if (s!=ERR_NO)
    {
        return ERR_RECVDATA;
    }
   
    return ERR_NO;
}

/****************************************************************************************
* 函数名:  InListPassiveTarget
* 函数功能:PN532检测卡
* 输入参数:
 maxTag:
            PN532最大初始化卡的个数,PN532一次只能同时处理2张卡        
 brty:
            0x00 : 106 kbps type A (ISO/IEC14443 Type A),
            0x01 : 212 kbps (FeliCa polling),
            0x02 : 424 kbps (FeliCa polling),
            0x03 : 106 kbps type B (ISO/IEC14443-3B),
            0x04 : 106 kbps Innovision Jewel tag.
        pData:
* 输出参数:
 成功:ERR_NO
        失败:ERR_RECVACK,ERR_RECVDATA
* 输入输出参数:
        pRfBuf:输入,用于存放输入参数的缓存,从外部传入,用于解决在函数内部定义过大的数组问题
                输出,存放从PN532接收的结果
*****************************************************************************************/
unsigned char InListPassiveTarget(unsigned char *pRfBuf, unsigned char maxTag, unsigned char brty,
                                  unsigned char *pData, unsigned char len)
{
    unsigned char i,temp;
    unsigned char s;
    pRfBuf[0] = 0x00; //前导码
    pRfBuf[1] = 0x00; //包开始标志2个字节
    pRfBuf[2] = 0xFF;
    pRfBuf[3] = len + 1 + 1 + 1 + 1;//len + 1字节的maxTag + 1字节的brty + 1字节的PD0 + 1字节的TFI
    pRfBuf[4] = 0x100-pRfBuf[3];
    pRfBuf[5] = 0xD4; //方向标示
    temp = pRfBuf[5];
    pRfBuf[6] = 0x4A; //命令码
    temp += pRfBuf[6];
    pRfBuf[7] = maxTag; 
    temp += pRfBuf[7];
    pRfBuf[8] = brty; 
    temp += pRfBuf[8];
   
    for (i=0; i<len; i++)
    {
        pRfBuf[9+i] = pData[i];
        temp  += pData[i];
    }
   
    pRfBuf[9+i] = 0x100 - temp; //DCS
    pRfBuf[9+i+1] = 0x00; 
   
    //底层发送函数   
    s = PN532SendData(pRfBuf,9+i+1+1);
    if (s!=ERR_NO)
    {
        return ERR_SENDDATA;
    }
    s = PN532RecvAck(pRfBuf);
    if (s!=ERR_NO)
    {
        return ERR_RECVACK;
    }
    s = PN532RecvData(pRfBuf);
    if (s!=ERR_NO)
    {
        return ERR_RECVDATA;
    }
   
    return ERR_NO;
}
       
void main()

 unsigned char i,s; 

 C51InitIo();
 C51InitUart();
    
 WDT_CONTR = 0x3F;//使能看门狗、清看门狗标志、空闲模式计数、分频系数(scale:bit2-bit0),溢出时间=(12*scale*32768)/Fosc
   
 EA = 1;   //cpu中断总允许
 
 p25 = 0;
 C51Delay1us(60000);
 C51Delay1us(60000);
 C51Delay1us(60000);
 C51Delay1us(60000);
 C51Delay1us(60000);
 p25 = 1;

 gTimeOutFlag = 0;
 gUart1RecvFlag = 0;

//--------------唤醒PN532----------------
 C51Uart1SendByte(0x55);
 C51Uart1SendByte(0x55);
 C51Uart1SendByte(0x00);
 C51Uart1SendByte(0x00);
 C51Uart1SendByte(0x00);
 SAMConfiguration(gPn532Data,1,0,1);
 for (i=0; i<gPn532Data[3]+7; i++)
 {
  C51Uart2SendByte(gPn532Data[i]);
 }
//---------------------------------------

 while(1)
 {
  WDT_CONTR = 0x3F;
  
  s = InListPassiveTarget(gPn532Data,1,0,0,0);

  if (ERR_NO==s)
  {
   for (i=0; i<gPn532Data[3]+7; i++)
   {
    C51Uart2SendByte(gPn532Data[i]);
   }
   p25 = 0;
   C51Delay1us(60000);
   C51Delay1us(60000);
   C51Delay1us(60000);
   C51Delay1us(60000);
   C51Delay1us(60000);
   p25 = 1;
  }
 }
}

//串口中断服务程序
void Uart1IsrHandler(void) interrupt 4

 if (RI)
 {
  RI = 0;  
  gPn532RxLen--;
  if (gPn532RxLen)
  {
   *gpPn532RxBuf = SBUF;
   
   gi++;
   if (gi==4)
   {
    if (0x00==*gpPn532RxBuf)//由于ACK帧与普通帧有一定的区别,所以要区别对待
    {
     gPn532RxLen = *gpPn532RxBuf + 2;  //接收ACK
    }
    else
    {
     gPn532RxLen = *gpPn532RxBuf + 3;  //包长度 + 1字节的包长度校验 + 1字节的数据校验 + 1字节的后导码
    }
   }
   
   gpPn532RxBuf++;
  }
  else
  {
   *gpPn532RxBuf = SBUF;
   gUart1RecvFlag = 1;
  }  
 }
 if (TI)
 {          
  TI = 0; 
 }
}

void Timer0IsrHandler(void) interrupt 1
{
 TH0 = 0x4C;
 TL0 = 0x00;
 if (--gTimeMult)
  return;
 gTimeOutFlag = 1;
}

 

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值