stm32开发 -- RC522模块与AS608模块相关
一.RC522原理简介
RC522 是一种非接触式读写卡芯片,底层采用SPI模拟时序,可以应用于校园一卡通、水卡充值消费、公交卡充值消费设计、门禁卡等。如下图所示:
有两个部分,射频读写器和IC卡。射频读写器向IC卡发一组固定频率的电磁波,卡片内有一个LC串联谐振电路,其频率与读写器发射的频率相同,这样在电磁波激励下,LC谐振电路产生共振,从而使电容内有了电荷;在这个电荷的另一端,接有一个单向导通的电子泵,将电容内的电荷送到另一个电容内存储,当所积累的电荷达到2V时,此电容可作为电源为其它电路提供工作电压,将卡内数据发射出去或接受读写器的数据。
非接触性IC卡与读卡器之间通过无线电波来完成读写操作。二者之间的通讯频率为13.56MHZ。非接触性IC卡本身是无源卡,当读写器对卡进行读写操作时,读写器发出的信号由两部分叠加组成:一部分是电源信号,该信号由卡接收后,与本身的L/C产生一个瞬间能量来供给芯片工作。另一部分则是指令和数据信号,指挥芯片完成数据的读取、修改、储存等,并返回信号给读写器,完成一次读写操作。
流程如下图所示:
复位应答:M1射频卡的通讯协议和通讯波特率是定义好的,当有卡片进入读写器的操作范围时,读写器以特定的协议与它通讯,从而确定该卡是否为M1射频卡,即验证卡片的卡型。
防冲突机制:当有多张卡进入读写器操作范围时,防冲突机制会从其中选择一张进行操作,未选中的则处于空闲模式等待下一次选卡,该过程会返回被选卡的序列号。
选择卡片:选择被选中的卡的序列号,并同时返回卡的容量代码。
三次互相确认:选定要处理的卡片之后,读写器就确定要访问的扇区号,并对该扇区密码进行密码校验,在三次相互认证之后就可以通过加密流进行通讯。(在选择另一扇区时,则必须进行另一扇区密码校验。)
二.SPI通信
软件SPI通过控制MISO引脚和MOSI端口引脚的高低电平来控制数据的进出,下面读取和写入寄存器的函数都是靠这两个函数来接收和发送数据,如下图所示为spi通信模式3的时序图:
RC552采用模式3,上图为模式3的时序图,根据时序图写发送数据,共有8个时钟周期,所以循环8次, 按位查询需要发送的数据的高低电平,0将MOSI引输出低电平,1将MOSI输出高电平,然后调SCK时钟引脚,使时钟引脚输出低电平(默认状态高电平),延时一会,输出高电平。
/** 函数名:SPI_RC522_SendByte* 描述 :向RC522发送1 Byte 数据* 输入 :byte,要发送的数据* 返回 : RC522返回的数据* 调用 :内部调用*/
void SPI_RC522_SendByte( u8 byte )
{u8 counter;for ( counter = 0; counter < 8; counter++ ){if ( byte & 0x80 )RC522_MOSI_1();elseRC522_MOSI_0();RC522_DELAY();RC522_SCK_0();RC522_DELAY();RC522_SCK_1();RC522_DELAY();byte <<= 1;}
}/** 函数名:SPI_RC522_ReadByte* 描述 :从RC522发送1 Byte 数据* 输入 :无* 返回 : RC522返回的数据* 调用 :内部调用*/
u8 SPI_RC522_ReadByte( void )
{u8 counter;u8 SPI_Data;for ( counter = 0; counter < 8; counter++ ){SPI_Data <<= 1;RC522_SCK_0();RC522_DELAY();if ( RC522_MISO_GET() == 1 )SPI_Data |= 0x01;RC522_DELAY();RC522_SCK_1();RC522_DELAY();}return(SPI_Data);
}
三.获取卡号实验
使用RC522设计门禁系统,卡片内部有块地址,它用于存放厂商代码,已经固化,不可更改。这样一个东西,叫做UID,这是一个存储在ic中的不可更改的数据,他是一个4字节16进制数,所以我们将他作为我们的判断依据。
RC522引脚说明:
引脚名称 | 功能 |
3.3v | 电源正 |
RST | 复位引脚,高电平有效 |
GND | 地,电源负 |
IRQ | 中断引脚,悬空不使用 |
MISO | SPI协议数据线 |
MOSI | SPI协议数据线 |
SCK | SPI时钟线 |
SDA | SPI片选端口 |
示例代码如下所示:
void RC522_Init( void )
{SPI1_Init();RC522_Reset_Disable();RC522_CS_Disable();PcdReset();M500PcdConfigISOType( 'A' ); /* 设置工作方式 */
}void SPI1_Init( void )
{GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOF,ENABLE); //使能端口F时钟GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP; //输出模式GPIO_InitStructure.GPIO_Pin=GPIO_Pin_1|GPIO_Pin_0|GPIO_Pin_2|GPIO_Pin_4;//管脚设置GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;//速度为50MGPIO_Init(GPIOF,&GPIO_InitStructure); //初始化结构体 GPIO_SetBits(GPIOF,GPIO_Pin_1|GPIO_Pin_0|GPIO_Pin_2|GPIO_Pin_4); //拉高GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //上拉输入 GPIO_Init(GPIOF, &GPIO_InitStructure);
}/** 函数名:SPI_RC522_SendByte* 描述 :向RC522发送1 Byte 数据* 输入 :byte,要发送的数据* 返回 : RC522返回的数据* 调用 :内部调用*/
void SPI_RC522_SendByte( u8 byte )
{u8 counter;for ( counter = 0; counter < 8; counter++ ){if ( byte & 0x80 )RC522_MOSI_1();elseRC522_MOSI_0();RC522_DELAY();RC522_SCK_0();RC522_DELAY();RC522_SCK_1();RC522_DELAY();byte <<= 1;}
}/** 函数名:SPI_RC522_ReadByte* 描述 :从RC522发送1 Byte 数据* 输入 :无* 返回 : RC522返回的数据* 调用 :内部调用*/
u8 SPI_RC522_ReadByte( void )
{u8 counter;u8 SPI_Data;for ( counter = 0; counter < 8; counter++ ){SPI_Data <<= 1;RC522_SCK_0();RC522_DELAY();if ( RC522_MISO_GET() == 1 )SPI_Data |= 0x01;RC522_DELAY();RC522_SCK_1();RC522_DELAY();}return(SPI_Data);
}/** 函数名:ReadRawRC* 描述 :读RC522寄存器* 输入 :ucAddress,寄存器地址* 返回 : 寄存器的当前值* 调用 :内部调用*/
u8 ReadRawRC( u8 ucAddress )
{u8 ucAddr, ucReturn;ucAddr = ( (ucAddress << 1) & 0x7E) | 0x80;RC522_CS_Enable();SPI_RC522_SendByte( ucAddr );ucReturn = SPI_RC522_ReadByte();RC522_CS_Disable();return(ucReturn);
}/** 函数名:WriteRawRC* 描述 :写RC522寄存器* 输入 :ucAddress,寄存器地址* ucValue,写入寄存器的值* 返回 : 无* 调用 :内部调用*/
void WriteRawRC( u8 ucAddress, u8 ucValue )
{u8 ucAddr;ucAddr = (ucAddress << 1) & 0x7E;RC522_CS_Enable();SPI_RC522_SendByte( ucAddr );SPI_RC522_SendByte( ucValue );RC522_CS_Disable();
}/** 函数名:SetBitMask* 描述 :对RC522寄存器置位* 输入 :ucReg,寄存器地址* ucMask,置位值* 返回 : 无* 调用 :内部调用*/
void SetBitMask( u8 ucReg, u8 ucMask )
{u8 ucTemp;ucTemp = ReadRawRC( ucReg );WriteRawRC( ucReg, ucTemp | ucMask ); /* set bit mask */
}/** 函数名:ClearBitMask* 描述 :对RC522寄存器清位* 输入 :ucReg,寄存器地址* ucMask,清位值* 返回 : 无* 调用 :内部调用*/
void ClearBitMask( u8 ucReg, u8 ucMask )
{u8 ucTemp;ucTemp = ReadRawRC( ucReg );WriteRawRC( ucReg, ucTemp & (~ucMask) ); /* clear bit mask */
}/** 函数名:PcdAntennaOn* 描述 :开启天线* 输入 :无* 返回 : 无* 调用 :内部调用*/
void PcdAntennaOn( void )
{u8 uc;uc = ReadRawRC( TxControlReg );if ( !(uc & 0x03) )SetBitMask( TxControlReg, 0x03 );
}/** 函数名:PcdAntennaOff* 描述 :开启天线* 输入 :无* 返回 : 无* 调用 :内部调用*/
void PcdAntennaOff( void )
{ClearBitMask( TxControlReg, 0x03 );
}/** 函数名:PcdRese* 描述 :复位RC522* 输入 :无* 返回 : 无* 调用 :外部调用*/
void PcdReset( void )
{RC522_Reset_Disable();delay_us( 1 );RC522_Reset_Enable();delay_us( 1 );RC522_Reset_Disable();delay_us( 1 );WriteRawRC( CommandReg, 0x0f );while ( ReadRawRC( CommandReg ) & 0x10 );delay_us( 1 );WriteRawRC( ModeReg, 0x3D ); /* 定义发送和接收常用模式 和Mifare卡通讯,CRC初始值0x6363 */WriteRawRC( TReloadRegL, 30 ); /* 16位定时器低位 */WriteRawRC( TReloadRegH, 0 ); /* 16位定时器高位 */WriteRawRC( TModeReg, 0x8D ); /* 定义内部定时器的设置 */WriteRawRC( TPrescalerReg, 0x3E ); /* 设置定时器分频系数 */WriteRawRC( TxAutoReg, 0x40 ); /* 调制发送信号为100%ASK */
}/** 函数名:M500PcdConfigISOType* 描述 :设置RC522的工作方式* 输入 :ucType,工作方式* 返回 : 无* 调用 :外部调用*/
void M500PcdConfigISOType( u8 ucType )
{if ( ucType == 'A' ) /* ISO14443_A */{ClearBitMask( Status2Reg, 0x08 );WriteRawRC( ModeReg, 0x3D ); /* 3F */WriteRawRC( RxSelReg, 0x86 ); /* 84 */WriteRawRC( RFCfgReg, 0x7F ); /* 4F */WriteRawRC( TReloadRegL, 30 ); /* tmoLength);// TReloadVal = 'h6a =tmoLength(dec) */WriteRawRC( TReloadRegH, 0 );WriteRawRC( TModeReg, 0x8D );WriteRawRC( TPrescalerReg, 0x3E );delay_us( 2 );PcdAntennaOn(); /* 开天线 */}
}/** 函数名:PcdComMF522* 描述 :通过RC522和ISO14443卡通讯* 输入 :ucCommand,RC522命令字* pInData,通过RC522发送到卡片的数据* ucInLenByte,发送数据的字节长度* pOutData,接收到的卡片返回数据* pOutLenBit,返回数据的位长度* 返回 : 状态值* = MI_OK,成功* 调用 :内部调用*/
char PcdComMF522( u8 ucCommand, u8 * pInData, u8 ucInLenByte, u8 * pOutData, u32 * pOutLenBit )
{char cStatus = MI_ERR;u8 ucIrqEn = 0x00;u8 ucWaitFor = 0x00;u8 ucLastBits;u8 ucN;u32 ul;switch ( ucCommand ){case PCD_AUTHENT: /* Mifare认证 */ucIrqEn = 0x12; /* 允许错误中断请求ErrIEn 允许空闲中断IdleIEn */ucWaitFor = 0x10; /* 认证寻卡等待时候 查询空闲中断标志位 */break;case PCD_TRANSCEIVE: /* 接收发送 发送接收 */ucIrqEn = 0x77; /* 允许TxIEn RxIEn IdleIEn LoAlertIEn ErrIEn TimerIEn */ucWaitFor = 0x30; /* 寻卡等待时候 查询接收中断标志位与 空闲中断标志位 */break;default:break;}WriteRawRC( ComIEnReg, ucIrqEn | 0x80 ); /* IRqInv置位管脚IRQ与Status1Reg的IRq位的值相反 */ClearBitMask( ComIrqReg, 0x80 ); /* Set1该位清零时,CommIRqReg的屏蔽位清零 */WriteRawRC( CommandReg, PCD_IDLE ); /* 写空闲命令 */SetBitMask( FIFOLevelReg, 0x80 ); /* 置位FlushBuffer清除内部FIFO的读和写指针以及ErrReg的BufferOvfl标志位被清除 */for ( ul = 0; ul < ucInLenByte; ul++ )WriteRawRC( FIFODataReg, pInData [ul] ); /* 写数据进FIFOdata */WriteRawRC( CommandReg, ucCommand ); /* 写命令 */if ( ucCommand == PCD_TRANSCEIVE )SetBitMask( BitFramingReg, 0x80 ); /* StartSend置位启动数据发送 该位与收发命令使用时才有效 */ul = 1000; /* 根据时钟频率调整,操作M1卡最大等待时间25ms */do /* 认证 与寻卡等待时间 */{ucN = ReadRawRC( ComIrqReg ); /* 查询事件中断 */ul--;}while ( (ul != 0) && (!(ucN & 0x01) ) && (!(ucN & ucWaitFor) ) ); /* 退出条件i=0,定时器中断,与写空闲命令 */ClearBitMask( BitFramingReg, 0x80 ); /* 清理允许StartSend位 */if ( ul != 0 ){if ( !( (ReadRawRC( ErrorReg ) & 0x1B) ) ) /* 读错误标志寄存器BufferOfI CollErr ParityErr ProtocolErr */{cStatus = MI_OK;if ( ucN & ucIrqEn & 0x01 ) /* 是否发生定时器中断 */cStatus = MI_NOTAGERR;if ( ucCommand == PCD_TRANSCEIVE ){ucN = ReadRawRC( FIFOLevelReg ); /* 读FIFO中保存的字节数 */ucLastBits = ReadRawRC( ControlReg ) & 0x07; /* 最后接收到得字节的有效位数 */if ( ucLastBits )*pOutLenBit = (ucN - 1) * 8 + ucLastBits; /* N个字节数减去1(最后一个字节)+最后一位的位数 读取到的数据总位数 */else*pOutLenBit = ucN * 8; /* 最后接收到的字节整个字节有效 */if ( ucN == 0 )ucN = 1;if ( ucN > MAXRLEN )ucN = MAXRLEN;for ( ul = 0; ul < ucN; ul++ )pOutData [ul] = ReadRawRC( FIFODataReg );}}elsecStatus = MI_ERR;
/* printf(ErrorReg); */}SetBitMask( ControlReg, 0x80 ); /* stop timer now */WriteRawRC( CommandReg, PCD_IDLE );return(cStatus);
}/** 函数名:PcdRequest* 描述 :寻卡* 输入 :ucReq_code,寻卡方式* = 0x52,寻感应区内所有符合14443A标准的卡* = 0x26,寻未进入休眠状态的卡* pTagType,卡片类型代码* = 0x4400,Mifare_UltraLight* = 0x0400,Mifare_One(S50)* = 0x0200,Mifare_One(S70)* = 0x0800,Mifare_Pro(X))* = 0x4403,Mifare_DESFire* 返回 : 状态值* = MI_OK,成功* 调用 :外部调用*/
char PcdRequest( u8 ucReq_code, u8 * pTagType )
{char cStatus;u8 ucComMF522Buf [MAXRLEN];u32 ulLen;ClearBitMask( Status2Reg, 0x08 ); /* 清理指示MIFARECyptol单元接通以及所有卡的数据通信被加密的情况 */WriteRawRC( BitFramingReg, 0x07 ); /* 发送的最后一个字节的 七位 */SetBitMask( TxControlReg, 0x03 ); /* TX1,TX2管脚的输出信号传递经发送调制的13.56的能量载波信号 */ucComMF522Buf [0] = ucReq_code; /* 存入 卡片命令字 */cStatus = PcdComMF522( PCD_TRANSCEIVE, ucComMF522Buf, 1, ucComMF522Buf, &ulLen ); /* 寻卡 */if ( (cStatus == MI_OK) && (ulLen == 0x10) ) /* 寻卡成功返回卡类型 */{*pTagType = ucComMF522Buf [0];*(pTagType + 1) = ucComMF522Buf [1];}elsecStatus = MI_ERR;return(cStatus);
}/** 函数名:PcdAnticoll* 描述 :防冲撞* 输入 :pSnr,卡片序列号,4字节* 返回 : 状态值* = MI_OK,成功* 调用 :外部调用*/
char PcdAnticoll( u8 * pSnr )
{char cStatus;u8 uc, ucSnr_check = 0;u8 ucComMF522Buf [MAXRLEN];u32 ulLen;ClearBitMask( Status2Reg, 0x08 ); /* 清MFCryptol On位 只有成功执行MFAuthent命令后,该位才能置位 */WriteRawRC( BitFramingReg, 0x00 ); /* 清理寄存器 停止收发 */ClearBitMask( CollReg, 0x80 ); /* 清ValuesAfterColl所有接收的位在冲突后被清除 */ucComMF522Buf [0] = 0x93; /* 卡片防冲突命令 */ucComMF522Buf [1] = 0x20;cStatus = PcdComMF522( PCD_TRANSCEIVE, ucComMF522Buf, 2, ucComMF522Buf, &ulLen ); /* 与卡片通信 */if ( cStatus == MI_OK ) /* 通信成功 */{for ( uc = 0; uc < 4; uc++ ){*(pSnr + uc) = ucComMF522Buf [uc]; /* 读出UID */ucSnr_check ^= ucComMF522Buf [uc];}if ( ucSnr_check != ucComMF522Buf [uc] )cStatus = MI_ERR;}SetBitMask( CollReg, 0x80 );return(cStatus);
}/** 函数名:CalulateCRC* 描述 :用RC522计算CRC16* 输入 :pIndata,计算CRC16的数组* ucLen,计算CRC16的数组字节长度* pOutData,存放计算结果存放的首地址* 返回 : 无* 调用 :内部调用*/
void CalulateCRC( u8 * pIndata, u8 ucLen, u8 * pOutData )
{u8 uc, ucN;ClearBitMask( DivIrqReg, 0x04 );WriteRawRC( CommandReg, PCD_IDLE );SetBitMask( FIFOLevelReg, 0x80 );for ( uc = 0; uc < ucLen; uc++ )WriteRawRC( FIFODataReg, *(pIndata + uc) );WriteRawRC( CommandReg, PCD_CALCCRC );uc = 0xFF;do{ucN = ReadRawRC( DivIrqReg );uc--;}while ( (uc != 0) && !(ucN & 0x04) );pOutData [0] = ReadRawRC( CRCResultRegL );pOutData [1] = ReadRawRC( CRCResultRegM );
}/** 函数名:PcdSelect* 描述 :选定卡片* 输入 :pSnr,卡片序列号,4字节* 返回 : 状态值* = MI_OK,成功* 调用 :外部调用*/
char PcdSelect( u8 * pSnr )
{char ucN;u8 uc;u8 ucComMF522Buf [MAXRLEN];u32 ulLen;ucComMF522Buf [0] = PICC_ANTICOLL1;ucComMF522Buf [1] = 0x70;ucComMF522Buf [6] = 0;for ( uc = 0; uc < 4; uc++ ){ucComMF522Buf [uc + 2] = *(pSnr + uc);ucComMF522Buf [6] ^= *(pSnr + uc);}CalulateCRC( ucComMF522Buf, 8, &ucComMF522Buf [8] );ClearBitMask( Status2Reg, 0x08 );ucN = PcdComMF522( PCD_TRANSCEIVE, ucComMF522Buf, 9, ucComMF522Buf, &ulLen );if ( (ucN == MI_OK) && (ulLen == 0x18) )ucN = MI_OK;elseucN = MI_ERR;return(ucN);
}/** 函数名:PcdAuthState* 描述 :验证卡片密码* 输入 :ucAuth_mode,密码验证模式* = 0x60,验证A密钥* = 0x61,验证B密钥* u8 ucAddr,块地址* pKey,密码* pSnr,卡片序列号,4字节* 返回 : 状态值* = MI_OK,成功* 调用 :外部调用*/
char PcdAuthState( u8 ucAuth_mode, u8 ucAddr, u8 * pKey, u8 * pSnr )
{char cStatus;u8 uc, ucComMF522Buf [MAXRLEN];u32 ulLen;ucComMF522Buf [0] = ucAuth_mode;ucComMF522Buf [1] = ucAddr;for ( uc = 0; uc < 6; uc++ )ucComMF522Buf [uc + 2] = *(pKey + uc);for ( uc = 0; uc < 6; uc++ )ucComMF522Buf [uc + 8] = *(pSnr + uc);cStatus = PcdComMF522( PCD_AUTHENT, ucComMF522Buf, 12, ucComMF522Buf, &ulLen );if ( (cStatus != MI_OK) || (!(ReadRawRC( Status2Reg ) & 0x08) ) ){
/** if(cStatus != MI_OK)* printf("666") ;* else* printf("888");*/cStatus = MI_ERR;}return(cStatus);
}/** 函数名:PcdWrite* 描述 :写M1卡一块数据* 输入 :u8 ucAddr,块地址* pData,写入的数据,16字节* 返回 : 状态值* = MI_OK,成功* 调用 :外部调用*/
char PcdWrite( u8 ucAddr, u8 * pData )
{char cStatus;u8 uc, ucComMF522Buf [MAXRLEN];u32 ulLen;ucComMF522Buf [0] = PICC_WRITE;ucComMF522Buf [1] = ucAddr;CalulateCRC( ucComMF522Buf, 2, &ucComMF522Buf [2] );cStatus = PcdComMF522( PCD_TRANSCEIVE, ucComMF522Buf, 4, ucComMF522Buf, &ulLen );if ( (cStatus != MI_OK) || (ulLen != 4) || ( (ucComMF522Buf [0] & 0x0F) != 0x0A) )cStatus = MI_ERR;if ( cStatus == MI_OK ){memcpy( ucComMF522Buf, pData, 16 );for ( uc = 0; uc < 16; uc++ )ucComMF522Buf [uc] = *(pData + uc);CalulateCRC( ucComMF522Buf, 16, &ucComMF522Buf [16] );cStatus = PcdComMF522( PCD_TRANSCEIVE, ucComMF522Buf, 18, ucComMF522Buf, &ulLen );if ( (cStatus != MI_OK) || (ulLen != 4) || ( (ucComMF522Buf [0] & 0x0F) != 0x0A) )cStatus = MI_ERR;}return(cStatus);
}/** 函数名:PcdRead* 描述 :读取M1卡一块数据* 输入 :u8 ucAddr,块地址* pData,读出的数据,16字节* 返回 : 状态值* = MI_OK,成功* 调用 :外部调用*/
char PcdRead( u8 ucAddr, u8 * pData )
{char cStatus;u8 uc, ucComMF522Buf [MAXRLEN];u32 ulLen;ucComMF522Buf [0] = PICC_READ;ucComMF522Buf [1] = ucAddr;CalulateCRC( ucComMF522Buf, 2, &ucComMF522Buf [2] );cStatus = PcdComMF522( PCD_TRANSCEIVE, ucComMF522Buf, 4, ucComMF522Buf, &ulLen );if ( (cStatus == MI_OK) && (ulLen == 0x90) ){for ( uc = 0; uc < 16; uc++ )*(pData + uc) = ucComMF522Buf [uc];}elsecStatus = MI_ERR;return(cStatus);
}/** 函数名:PcdHalt* 描述 :命令卡片进入休眠状态* 输入 :无* 返回 : 状态值* = MI_OK,成功* 调用 :外部调用*/
char PcdHalt( void )
{u8 ucComMF522Buf [MAXRLEN];u32 ulLen;ucComMF522Buf [0] = PICC_HALT;ucComMF522Buf [1] = 0;CalulateCRC( ucComMF522Buf, 2, &ucComMF522Buf [2] );PcdComMF522( PCD_TRANSCEIVE, ucComMF522Buf, 4, ucComMF522Buf, &ulLen );return(MI_OK);
}void IC_CMT( u8 * UID, u8 * KEY, u8 RW, u8 * Dat )
{u8 ucArray_ID [4] = { 0 }; /* 先后存放IC卡的类型和UID(IC卡序列号) */PcdRequest( 0x52, ucArray_ID ); /* 寻卡 */PcdAnticoll( ucArray_ID ); /* 防冲撞 */PcdSelect( UID ); /*选定卡 */PcdAuthState( 0x60, 0x10, KEY, UID ); /* 校验 */if ( RW ) /* 读写选择,1是读,0是写 */PcdRead( 0x10, Dat );elsePcdWrite( 0x10, Dat );PcdHalt();
}void ShowID(unsigned char *p) //显示卡的卡号,以十六进制显示
{u8 num[9];u8 i;for(i=0; i<4; i++){num[i*2]=p[i]/16;num[i*2]>9?(num[i*2]+='7'):(num[i*2]+='0');num[i*2+1]=p[i]%16;num[i*2+1]>9?(num[i*2+1]+='7'):(num[i*2+1]+='0');}num[8]=0;printf("ID>>>%s\r\n", num);
}u8 GET_CARD(void)
{while(1){status = PcdRequest( PICC_REQALL, CT ); /* 寻卡 */if ( status != MI_OK ) /* 寻卡成功 */{continue;}status = PcdAnticoll( ID ); /* 防冲撞 */status = PcdSelect( ID ); /*选定卡片 */if ( status != MI_OK ) /*选定卡片成功 */{ if(ID[0]==CardNumber[ 0 ]&&ID[ 1 ]==CardNumber[ 1 ]&&ID[ 2 ]==CardNumber[ 2 ]&&ID[ 3 ]==CardNumber[ 3 ]){return 1;}elsereturn 0;}}}
四.AS608指纹识别模块
AS608 指纹识别模块是一款高性能的光学指纹识别模块。芯片内置DSP 运算单元,集成了指纹识别算法,能高效快速采集图像并识别指纹特征。模块配备了串口、USB 通讯接口,只需通过简单的串口、USB 按照通讯协议便可控制模块,本模块可应用于各种考勤机、保险箱柜、指纹门禁系统、指纹锁等场合。
1.AS608模块接线说明:
2.AS608引脚说明:
名称 | 说明 |
Vi | 模块电源正输入端 |
Tx | 串行数据输出。TTL逻辑电平 |
Rx | 串行数据输入。TTL逻辑电平 |
GND | 信号地,内部与电源地连接 |
WAK | 感应信号输出,默认高电平有效 |
Vt | 触摸感应电源输入端,3v端 |
U+ | USB D+ |
U- | USB D- |
3.AS608模块通信协议:
串口通讯参数:57600波特率,8位数据,1位停止位,无校验。
MCU与模块通讯发送与接收模块指令和数据按照模块指令格式打包,MCU对接收到的数据包数据解析也按照模块指令格式。模块指令格式分为三种:命令包格式、数据包格式、结束包格式。一般指令包是由MCU发送到模块上,模块接收到指令包后,返回对应的数据包。
包长度=包长度至校验和(指令、参数或数据)的总字节数,包含校验和,但不包含包长度本身的字节数。校验和是从包标识至校验和之间所有字节之和。模块芯片地址在没有生成之前为缺省的 0xFFFFFFFF,一旦MCU通过指令配置了新的芯片地址,则所有的数据包都必须按照生成的地址收发,模块将拒绝地址错误的数据包,一般我们都是以默认0xFFFFFFFF为地址,不需要配置地址。
命令包格式 :
常用命令集及功能描述 :
自动验证指纹 PS_Identify
功能说明:自动采集指纹,在指纹库中搜索目标模板并返回搜索结果。如果目标模板同当前采集的指纹比对得分大于最高阀值,并且目标模板为不完整特征则以采集的特征更新目标模板的空白区域。
指令代码:11H
指令包格式:
应答包格式:
确认码=00H 表示搜索到;确认码=01H 表示收包有错;确认码=09H 表示没搜索到;此时页码与得分为 0;sum 指校验和。
五.AS608模块相关函数
//串口发送字节函数
static void AS608_SendData(uint8_t data)
{USART_SendData(USARTx,data);while(USART_GetFlagStatus(USARTx,USART_FLAG_TXE) == RESET);
}//发送命令包头格式函数
static void AS608_PackHead(void)
{ /*包头*/AS608_SendData(0xEF);AS608_SendData(0x01); /*指纹模块地址*/AS608_SendData(AS608_Addr>>24);AS608_SendData(AS608_Addr>>16); AS608_SendData(AS608_Addr>>8);AS608_SendData(AS608_Addr);
}//发送包标识
static void SendFlag(uint8_t flag)
{AS608_SendData(flag);
}//发送包长度
static void SendLength(uint16_t length)
{AS608_SendData(length>>8);AS608_SendData(length);
}//发送指令码
static void Sendcmd(uint8_t cmd)
{AS608_SendData(cmd);
}//发送校验和
static void SendCheck(uint16_t check)
{AS608_SendData(check>>8);AS608_SendData(check);
}void PS_Identify(void)
{uint16_t temp;AS608_PackHead();SendFlag(0x01);SendLength(0x03);Sendcmd(0x11); temp = 0x01+0x03+0x11;SendCheck(temp);delay_ms(500);
}