1.介绍
FM17XX 系列通用非接触读卡机芯片是复旦微电子股份有限公司设计的,基于 ISO14443 标准的系
列通用非接触卡读卡机芯片,采用 0.6 微米 CMOS EEPROM 工艺。
FM17XX 系列读卡机芯片可分别支持 13.56MHz 频率下的 typeA、typeB、15693 三种非接触通信协
议;支持 MIFARE 和上海标准的加密算法;可兼容飞利浦公司的 RC500、RC530、RC531 及 RC632
等读卡机芯片;芯片内部高度集成了模拟调制解调电路,所以只需最少量的外围电路即可工作;支
持 6 种微处理器接口;其数字电路具有 TTL、CMOS 两种电压工作模式;该芯片适用于各类计费系
统读卡器的应用。
尤其是 FM17XXL 系列芯片,其三路电源的最低工作电压均可达 2.9V,这一特性优于其他公司的同
类产品。
FM17XX型号众多,实际上只是接口、加密算法、协议支的不一样,大部分都是兼容的。
下面是FM17xx的选型表
我使用的是FM1722NL这一款,上面的表里没有,实际上和FM1702NL、FM1724/5兼容,只是FM1722NL相对FM1702NL支持的协议多一点,基本代码(读写ISO 14443A卡)通用。
2.硬件电路(硬件SPI)
FM1722的引脚图如上图所示,特别注意NRD、NWR、A1这三个脚,必须按照上图的要求连接高电平或者低电平,否则可能会导致FM1722无法使用SPI接口通信。
虽然FM1722NL支持3.3V~5V供电,实际使用发现3.3V供电时,天线发射功率很小,
卡片需要紧贴着天线才能读到卡,有时甚至无法读卡,所以建议(主要针对IO口为3.3V单片机)
1.模拟+天线使用 5V供电
2.数字使用3.3V供电
FM1722的SPI时序采用标准SPI时序,主要注意以下几点
- 注意下CPOL和CPHA的设置
- NSS在发送时必须拉低,发送完必须拉高。
- 8位数据位,MSB在前
- FM1722必须配置为从机
3.软件调试
软件部分主要是SPI通信,这里采用STM32的硬件SPI(SPI2:PB13、PB14、PB15),需要注意的是前面提到的SPI的CPOL、CPHA和NSS的配置。
主机端SPI配置如下:
void SPI1_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
SPI_InitTypeDef SPI_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE );//PORTB 时钟使能
RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE );//SPI2 时钟使能
// 初始化SPI接口引脚 //PB13/14/15 复用推挽输出
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化 GPIOB
// 初始化片选、复位引脚 PB12:片选 PB9:复位
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_12;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化 PB9/12
// 初始化SPI参数
GPIO_SetBits(GPIOB,GPIO_Pin_9);//FM17XX NSS拉高 开始复位
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //双线双向全双工
SPI_InitStructure.SPI_Mode = SPI_Mode_Master; //主 SPI
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; // SPI 发送接收 8 位帧结构
SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;//CLK空闲为电平
SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;//上升沿数据被采样
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; //NSS 信号由软件控制
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256; //预分频 256
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //数据传输从 MSB 位开始
SPI_InitStructure.SPI_CRCPolynomial = 7; //CRC 值计算的多项式
SPI_Init(SPI2, &SPI_InitStructure); //根据指定的参数初始化外设 SPIx 寄存器
SPI_Cmd(SPI2, ENABLE); //使能 SPI2 外设
SPI1_ReadWriteByte(0xff);
}
u8 SPI1_ReadWriteByte(u8 TxData)
{
u8 retry=0;
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET) //等待发送区空
{
retry++;
if(retry>200)
return 0;
}
SPI2->DR = TxData;
retry=0;
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET) //等待接收完一个 byte
{
retry++;
if(retry>200)
return 0;
}
return (SPI2->DR); //返回通过 SPIx 最近接收的数据
}
FM1722主要是初始化函数、读写寄存器函数。
/****************************************************************/
/*名称: WriteReg */
/*功能: 写FM1702寄存器 */
/*输入: Address - 寄存器地址; value - 写入的值 */
/*输出: N/A */
/****************************************************************/
void SPIWrite(unsigned char Address, unsigned char Data)
{
Address = ((Address<<1)&0x7E);
FM1702_CS_L;
SPI1_ReadWriteByte(Address);
SPI1_ReadWriteByte(Data);
FM1702_CS_H;
}
/****************************************************************/
/*名称: ReadReg */
/*功能: 读FM1702寄存器 */
/*输入: Address-寄存器地址 */
/*输出: 读出的值 */
/****************************************************************/
unsigned char SPIRead(unsigned char Address)
{
unsigned char Temp;
Address=(Address<<1)|0x80;
FM1702_CS_L;
SPI1_ReadWriteByte(Address);
Temp=SPI1_ReadWriteByte(0x0);
FM1702_CS_H;
return Temp;
}
其中FM1702_CS_L就是拉低NSS脚
/****************************************************************/
/*名称: Init_FM1702 */
/*功能: 该函数实现对FM1702初始化操作*/
/*输入: mode:工作模式, 0:TYPEA模式*/
/* 1:TYPEB模式*/
/* 2:上海模式*/
/*输出: N/A */
/****************************************************************/
void Init_FM1702(uchar mode)
{
uchar temp;
uint i;
SPI1_Init();//初始化SPI接口
GPIO_SetBits(GPIOB,GPIO_Pin_9);
delay_ms(10);
GPIO_ResetBits(GPIOB,GPIO_Pin_9);
delay_ms(10); //RST引脚下降沿 FM17xx复位
while(SPIRead(Command) != 0) // 等待Command = 0,FM1702复位成功
{
temp=SPIRead(Command);
printf("复位中...%d\r\n",temp);
if(temp==FM1702_OK)break;
delay_ms(500);
}
SPIWrite(Page_Sel,0x80); //往Page寄存器写80hex初始化SPI接口
for(i = 0; i < 0x1fff; i++) /* 延时 */
{
if(SPIRead(Command) == 0x00)
{
SPIWrite(Page_Sel,0x00);
}
}
if(mode ==2)
{
SPIWrite(TypeSH,0x01);
}
else
{
SPIWrite(TypeSH,0x00);
}
}
这些代码实际上都是根据官方代码修改的。
4.调试
首先调试SPI通信,确保主机和FM1722通信正常,方法如下:
需要找一个FM1722可读可写的寄存器,主机向该寄存器中写入一个数,然后再读出来,如果写入的值与读出来的一样,那么SPI通信基本上没有问题,可以多找几个寄存器试试。
然后就是尝试读卡号,基本流程是Request->AntiColl->Select_Card ,AntiColl成功后就能读到卡号了。
STM32F103调试通过例程:FM1702NL/FM1722硬件SPI读写程序_fm1702-硬件开发文档类资源-CSDN下载