一、前言

本编文章记录使用stm32驱动fm1702nl的一些硬件经验,首次使用FM1702这款芯片,这款芯片分为SL和NL两种型号,SL封装是24脚的,NL封装是32脚的,SL只支持SPI通讯,NL支持IO和SPI通讯,本文虽然我使用了NL,但是仍然使用的是SPI通讯,与SL无区别。

目录

  • 一、前言
  • 二、环境
  • 三、正文
    • 硬件部分
    • 软件部分
      • 下位机软件
      • 上位机软件
    • 卡片介绍
    • 结构部分
  • 四、结语

二、环境

stm32 spi驱动
参考链接

三、正文

硬件部分

这里首先总结一下硬件接线图,手册中引脚
图1

图2

注意图1,A0不是MOSI,AO是单片机端的MOSI,这里AO是MISO,与单片机MOSI输出连接。DO是MOSI,与单片机MISO连接,图2的网络标号是单片机端的标号。
因为这里我就搞错了,这个官方手册也不是很严谨,所以有50%的概率出错,这里我为大家纠正一下。放上引脚图

这里还有一个难点就是天线的设计,天线设计不好就会导致信号不好或者无法使用,这里天线我也没详细研究,参照成品电路设计直接使用,不同IC天线设计参照网上更详细天线线圈设计资料。

软件部分

下位机软件

软件核心程序:
使用硬件SPI,首先main函数如下

int main(void)
{    u32 len;   u8 usbstatus=0;    u8 led_count;u8 status = 0;u8 i=0;u8 bload=0;unsigned char readbuf[16];unsigned char writbuf[16];//  u32 saveaddrgroup,address;//设备的编码地址
//  u8 datatemp[4]={0};//spiflash存储的地址,从内部flash读取//初始化系统delay_init();            //延时函数初始化    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);    //设置NVIC中断分组2:2位抢占优先级,2位响应优先级 JTAG_Set(JTAG_SWD_DISABLE);     //=====关闭JTAG接口JTAG_Set(SWD_ENABLE);           //=====打开SWD接口 可以利用主板的SWD接口调试//初始化外设uart1_init(115200);      //串口初始化为115200 LED_Init();              //初始化与LED连接的硬件接口TIM3_Int_Init(49,7199);//10Khz的计数频率,计数到50为5ms  //    //读取stm内部flash存储的spiflash存储到的地址
//  STMFLASH_Read(0X08070000,(u16*)datatemp,4);//设置FLASH 保存地址(必须为偶数,且其值要大于本代码所占用FLASH的大小+0X08000000),总共512k即0x80000,存储位置0x70000=458752,大于代码占用Code+RO-data+RW-data即可
//  saveaddrgroup=((datatemp[0]<<24)&0xFF000000)+((datatemp[1]<<16)&0x00FF0000)+((datatemp[2]<<8)&0x0000FF00)+(datatemp[3]&0x000000FF);
//  //读取stm内部flash存储的设备地址
//  STMFLASH_Read(0X08070400,(u16*)datatemp,4);
//  address=((datatemp[0]<<24)&0xFF000000)+((datatemp[1]<<16)&0x00FF0000)+((datatemp[2]<<8)&0x0000FF00)+(datatemp[3]&0x000000FF);Init_FM1702(0);delay_ms(500);USB_Port_Set(0);    //USB先断开delay_ms(200);USB_Port_Set(1);  //USB再次连接Set_USBClock();   USB_Interrupts_Config();    USB_Init();  while(1){/**************************USB虚拟串口部分*************************///检测usb热插拔状态if(usbstatus!=bDeviceState){//USB连接状态发生了改变.usbstatus=bDeviceState;//记录新的状态if(usbstatus==CONFIGURED)printf("USB连接成功\r\n");//提示USB连接成功else printf("USB连接断开\r\n");//提示USB断开}//终端接收usb虚拟串口数据if(USB_USART_RX_STA&0x8000){ len=USB_USART_RX_STA&0x3FFF;//得到此次接收到的数据长度//printf("接收消息长度为:%d,内容为%X\r\n",len,USB_USART_RX_BUF[0]);//提示USB接收数据长度USB_USART_RX_STA=0;if(USB_USART_RX_BUF[0]==0x01&&len==1){//选取卡片status = Request1702(RF_CMD_REQUEST_ALL);//寻天线范围内所有的卡if(status == FM1702_OK){status = AntiColl();//冲突检测if(status != FM1702_OK){continue;usb_printf("卡片冲突!\r\n");//打印选卡状态}LEDG=1;LEDB=0;delay_ms(200);LEDB=1;status=Select_Card(); //选卡,这里不选卡,也可以直接进行读写if(status == FM1702_OK)usb_printf("选卡成功!\r\n");//打印选卡状态elseusb_printf("选卡失败!\r\n");//打印选卡状态usb_printf("识别卡号:%02X%02X%02X%02X\r\n",UID[0],UID[1],UID[2],UID[3]);//打印卡号                     }else{usb_printf("未识别到卡片\r\n");//打印选卡状态LEDG=1;LEDR=0;delay_ms(200);LEDR=1;}}else if(USB_USART_RX_BUF[0]==0x02&&len==3){//读取某一扇区和块数据bload=USB_USART_RX_BUF[1];//块0-63//                    for(i=0;i<16;i++)
//                          RevBuffer[i]=0xBB;for(i=0;i<6;i++)KeyAB_Buffer[i]=0xBB;if(HL_Read(readbuf,bload,RF_CMD_AUTH_LB)==0)//RF_CMD_AUTH_LA、RF_CMD_AUTH_LBusb_printf("扇区:%d,块:%d  %d  读取成功!块数据内容:%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\r\n",bload/4,bload%4,bload,readbuf[0],readbuf[1],readbuf[2],readbuf[3],readbuf[4],readbuf[5],readbuf[6],readbuf[7],readbuf[8],readbuf[9],readbuf[10],readbuf[11],readbuf[12],readbuf[13],readbuf[14],readbuf[15]);//提示USB接收数据长度elseusb_printf("扇区:%d,块:%d  %d  读取失败!\r\n",bload/4,bload%4,bload);}else if(USB_USART_RX_BUF[0]==0x03&&len==2){bload=USB_USART_RX_BUF[1];//块0-63for(i=0;i<16;i++)writbuf[i]=0xaa;if(HL_Write(writbuf,bload,RF_CMD_AUTH_LA)==0)//RF_CMD_AUTH_LA、RF_CMD_AUTH_LBusb_printf("写入成功!扇区:%d,块:%d  %d\r\n",bload/4,bload%4,bload);elseusb_printf("写入失败!扇区:%d,块:%d  %d\r\n",bload/4,bload%4,bload);}else if(USB_USART_RX_BUF[0]==0x04&&len==2){}memset(USB_USART_RX_BUF,0,len);//缓存清零          }if(usbstatus==CONFIGURED){//判断USB已经连接//定时5*200ms进入一次if(led_flag>199){//5ms×200=1000msled_flag=0;LEDB=LEDR=1;LEDG=!LEDG;//绿灯闪烁}}else{//USB未连接//定时500ms进入一次if(led_flag>99){//5ms×100=500msled_flag=0;led_count++;if(led_count>7)led_count=0;led_run(led_count);//彩灯闪烁}}/**************************USB虚拟串口部分end*************************/}
}

使用到了USB虚拟串口通讯,程序文件目录如下

程序中基本只有1702驱动程序, 没有乱七八槽的程序
spi部分

#include "spi.h"
void SPI2_Init(void)
{GPIO_InitTypeDef GPIO_InitStructure;SPI_InitTypeDef  SPI_InitStructure;RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE );//PORTB时钟使能 RCC_APB1PeriphClockCmd(  RCC_APB1Periph_SPI2,  ENABLE );//SPI2时钟使能   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //PB13/14/15复用推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIOBGPIO_SetBits(GPIOB,GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15);  //PB13/14/15上拉SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;  //设置SPI单向或者双向的数据模式:SPI设置为双线双向全双工SPI_InitStructure.SPI_Mode = SPI_Mode_Master;       //设置SPI工作模式:设置为主SPISPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;       //设置SPI的数据大小:SPI发送接收8位帧结构SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;        //串行同步时钟的空闲状态为低电平SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;  //串行同步时钟的第二个跳变沿(上升或下降)数据被采样SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;     //NSS信号由硬件(NSS管脚)还是软件(使用SSI位)管理:内部NSS信号有SSI位控制SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;     //定义波特率预分频的值:波特率预分频值为256SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //指定数据传输从MSB位还是LSB位开始:数据传输从MSB位开始SPI_InitStructure.SPI_CRCPolynomial = 7;  //CRC值计算的多项式SPI_Init(SPI2, &SPI_InitStructure);  //根据SPI_InitStruct中指定的参数初始化外设SPIx寄存器SPI_Cmd(SPI2, ENABLE); //使能SPI外设SPI2_ReadWriteByte(0xff);//启动传输         }
//SPI 速度设置函数
//SpeedSet:
//SPI_BaudRatePrescaler_2   2分频
//SPI_BaudRatePrescaler_8   8分频
//SPI_BaudRatePrescaler_16  16分频
//SPI_BaudRatePrescaler_256 256分频
void SPI2_SetSpeed(u8 SPI_BaudRatePrescaler)
{assert_param(IS_SPI_BAUDRATE_PRESCALER(SPI_BaudRatePrescaler));SPI2->CR1&=0XFFC7;SPI2->CR1|=SPI_BaudRatePrescaler; //设置SPI2速度 SPI_Cmd(SPI2,ENABLE);
}
//SPIx 读写一个字节
//TxData:要写入的字节
//返回值:读取到的字节
u8 SPI2_ReadWriteByte(u8 TxData)
{       u8 retry=0;                    while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET) //检查指定的SPI标志位设置与否:发送缓存空标志位{retry++;if(retry>200)return 0;}              SPI_I2S_SendData(SPI2, TxData); //通过外设SPIx发送一个数据retry=0;while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET) //检查指定的SPI标志位设置与否:接受缓存非空标志位{retry++;if(retry>200)return 0;}                               return SPI_I2S_ReceiveData(SPI2); //返回通过SPIx最近接收的数据
}

FM1702部分核心代码

unsigned char    F_FIFO_Buff[16];
unsigned char   J_FIFO_Buff[16];
unsigned char   RevBuffer[16];
unsigned char   FIFO_Buff[16];
/* FM1702命令发送接收缓冲区 */
unsigned char   UID[5];                 /* 序列号 */
unsigned char  Secnr;
unsigned char  tagtype[2];unsigned char   KeyAB_Buffer[6];//A或B密钥void FM1702NL_Init(void)
{ GPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);//使能PORTA,PORTC时钟GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11|GPIO_Pin_12;               //reset  nssGPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;       //推挽输出GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;        //IO口速度为50MHzGPIO_Init(GPIOB, &GPIO_InitStructure);                     //根据设定参数初始化GPIOA.5GPIO_SetBits(GPIOB,GPIO_Pin_12);                      //FM17XX NSS拉高 开始复位SPI2_Init();//spi2初始化}
/****************************************************************/
/*名称: Init_FM1702 */
/*功能: 该函数实现对FM1702初始化操作*/
/*输入: mode:工作模式,  0:TYPEA模式*//* 1:TYPEA模式*//* 2:上海模式*/
/*输出: N/A */
/****************************************************************/
void Init_FM1702(uchar mode)
{uchar temp;uint    i;FM1702NL_Init();//初始化SPI接口    //复位芯片delay_ms(100);FM1702NL_RST_H;delay_ms(200);FM1702NL_RST_L;delay_ms(100); //RST引脚下降沿 FM17xx复位    while(FM1702NL_Read(Command) != 0)        // 等待Command = 0,FM1702复位成功 {     temp=FM1702NL_Read(Command);           usb_printf("复位中...%d\r\n",temp);      if(temp==FM1702_OK)break;delay_ms(500);LEDR=!LEDR;//红灯闪烁}
FM1702NL_Write(Page_Sel,0x80);    //往Page寄存器写80hex初始化SPI接口for(i = 0; i < 0x1fff; i++){ /* 延时 */if(FM1702NL_Read(Command) == 0x00){FM1702NL_Write(Page_Sel,0x00);}}          if(mode ==2){FM1702NL_Write(TypeSH,0x01);//上海标准}else{FM1702NL_Write(TypeSH,0x00);//MIFARE标准}
}
/****************************************************************/
/*名称: FM1702NL_Write                                          */
/*功能: 写FM1702NL寄存器                                        */
/*输入: Address - 寄存器地址; value - 写入的值                   */
/*输出: N/A                                                     */
/****************************************************************/
void FM1702NL_Write(unsigned char Address, unsigned char Data)
{Address = ((Address<<1)&0x7E);FM1702NL_NSS_L;SPI2_ReadWriteByte(Address);SPI2_ReadWriteByte(Data);FM1702NL_NSS_H;
}
/****************************************************************/
/*名称:  FM1702NL_Read                                          */
/*功能: 读FM1702NL寄存器                                        */
/*输入: Address-寄存器地址                                      */
/*输出: 读出的值                                                */
/****************************************************************/
unsigned char FM1702NL_Read(unsigned char Address)
{unsigned char Temp;Address=(Address<<1)|0x80;   FM1702NL_NSS_L;SPI2_ReadWriteByte(Address);Temp=SPI2_ReadWriteByte(0x0); FM1702NL_NSS_H;return Temp;

头文件

#ifndef __FM1702NL_H
#define __FM1702NL_H
#include "sys.h"
#define FM1702NL_RST_H     {GPIOB->BSRR = GPIO_Pin_11;}
#define FM1702NL_RST_L     {GPIOB->BRR = GPIO_Pin_11;}
#define FM1702NL_NSS_H     {GPIOB->BSRR = GPIO_Pin_12;}
#define FM1702NL_NSS_L     {GPIOB->BRR = GPIO_Pin_12;}
/* FM1702命令发送接收缓冲区 */
extern unsigned char    UID[5];                 /* 序列号 */
extern unsigned char   KeyAB_Buffer[6];//A或B密钥
#define uchar   unsigned char
#define uint    unsigned int
#define FM1702_TRUE   1
#define FM1702_FALSE  0
//#define ERROR     1
#define OK      0
/* FM1702命令码 */
#define Transceive  0x1E            /* 发送接收命令 */
#define Transmit    0x1a            /* 发送命令 */
#define ReadE2      0x03            /* 读FM1702 EEPROM命令 */
#define WriteE2     0x01            /* 写FM1702 EEPROM命令 */
#define Authent1    0x0c            /* 验证命令认证过程第1步 */
#define Authent2    0x14            /* 验证命令认证过程第2步 */
#define LoadKeyE2   0x0b            /* 将密钥从EEPROM复制到KEY缓存 */
#define LoadKey     0x19            /* 将密钥从FIFO缓存复制到KEY缓存 */
#define RF_TimeOut  0xff            /* 发送命令延时时间 */
#define Req     0x01
#define Sel     0x02
/* 卡片类型定义定义 */
#define TYPEA_MODE  0           /* TypeA模式 */
//#define SHANGHAI_MODE 2           /* 上海模式 */
#define TM0_HIGH    0xf0            /* 定时器0高位,4MS定时 */
#define TM0_LOW     0x60            /* 定时器0低位 */
#define TIMEOUT     100         /* 超时计数器4MS×100=0.4秒 */
/* 射频卡通信命令码定义 */
#define RF_CMD_REQUEST_STD  0x26
#define RF_CMD_REQUEST_ALL  0x52
#define RF_CMD_ANTICOL      0x93
#define RF_CMD_SELECT       0x93
#define RF_CMD_AUTH_LA      0x60
#define RF_CMD_AUTH_LB      0x61
#define RF_CMD_READ     0x30
#define RF_CMD_WRITE        0xa0
#define RF_CMD_INC          0xc1
#define RF_CMD_DEC          0xc0
#define RF_CMD_RESTORE      0xc2
#define RF_CMD_TRANSFER     0xb0
#define RF_CMD_HALT         0x50
/* 函数错误代码定义 ERR CODE  */
#define FM1702_OK       0       /* 正确 */
#define FM1702_NOTAGERR     1       /* 无卡 */
#define FM1702_CRCERR       2       /* 卡片CRC校验错误 */
#define FM1702_EMPTY        3       /* 数值溢出错误 */
#define FM1702_AUTHERR      4       /* 验证不成功 */
#define FM1702_PARITYERR    5       /* 卡片奇偶校验错误 */
#define FM1702_CODEERR      6       /* 通讯错误(BCC校验错) */
#define FM1702_SERNRERR     8       /* 卡片序列号错误(anti-collision 错误) */
#define FM1702_SELECTERR    9       /* 卡片数据长度字节错误(SELECT错误) */
#define FM1702_NOTAUTHERR   10      /* 卡片没有通过验证 */
#define FM1702_BITCOUNTERR  11      /* 从卡片接收到的位数错误 */
#define FM1702_BYTECOUNTERR 12      /* 从卡片接收到的字节数错误仅读函数有效 */
#define FM1702_RESTERR      13      /* 调用restore函数出错 */
#define FM1702_TRANSERR     14      /* 调用transfer函数出错 */
#define FM1702_WRITEERR     15      /* 调用write函数出错 */
#define FM1702_INCRERR      16      /* 调用increment函数出错 */
#define FM1702_DECRERR      17      /* 调用decrement函数出错 */
#define FM1702_READERR      18      /* 调用read函数出错 */
#define FM1702_LOADKEYERR   19      /* 调用LOADKEY函数出错 */
#define FM1702_FRAMINGERR   20      /* FM1702帧错误 */
#define FM1702_REQERR       21      /* 调用req函数出错 */
#define FM1702_SELERR       22      /* 调用sel函数出错 */
#define FM1702_ANTICOLLERR  23      /* 调用anticoll函数出错 */
#define FM1702_INTIVALERR   24      /* 调用初始化函数出错 */
#define FM1702_READVALERR   25      /* 调用高级读块值函数出错 */
#define FM1702_DESELECTERR  26
#define FM1702_CMD_ERR      42      /* 命令错误 */
/* FM1702寄存器定义 */
#define Page_Sel        0x00    /* 页写寄存器 */
#define Command         0x01    /* 命令寄存器 */
#define FM_FIFO         0x02    /* 64字节FIFO缓冲的输入输出寄存器 */
#define PrimaryStatus       0x03    /* 发射器接收器及FIFO的状态寄存器1 */
#define FIFO_Length     0x04    /* 当前FIFO内字节数寄存器 */
#define SecondaryStatus     0x05    /* 各种状态寄存器2 */
#define InterruptEn     0x06    /* 中断使能/禁止寄存器 */
#define Int_Req         0x07    /* 中断请求标识寄存器 */
#define Control         0x09    /* 控制寄存器 */
#define ErrorFlag       0x0A    /* 错误状态寄存器 */
#define CollPos         0x0B    /* 冲突检测寄存器 */
#define TimerValue      0x0c    /* 定时器当前值 */
#define Bit_Frame       0x0F    /* 位帧调整寄存器 */
#define TxControl       0x11    /* 发送控制寄存器 */
#define CWConductance       0x12    /* 选择发射脚TX1和TX2发射天线的阻抗 */
#define ModConductance      0x13    /* 定义输出驱动阻抗 */
#define CoderControl        0x14    /* 定义编码模式和时钟频率 */
#define DecoderControl      0x1a    /* 解码控制寄存器 */
#define RxControl1      0x19    /*接收增益控制*/
#define RxControl2      0x1e    /* 解码控制及选择接收源 */
#define RxWait          0x21    /* 选择发射和接收之间的时间间隔 */
#define ChannelRedundancy   0x22    /* RF通道检验模式设置寄存器 */
#define CRCPresetLSB        0x23
#define CRCPresetMSB        0x24
#define MFOUTSelect     0x26    /* mf OUT 选择配置寄存器 */
#define TimerClock      0x2a    /* 定时器周期设置寄存器 */
#define TimerControl        0x2b    /* 定时器控制寄存器 */
#define TimerReload     0x2c    /* 定时器初值寄存器 */
#define TypeSH          0x31    /* 上海标准选择寄存器 */
#define TestDigiSelect      0x3d    /* 测试管脚配置寄存器 */
/* Status Values */
#define ALL 0x01
#define KEYB    0x04
#define KEYA    0x00
#define _AB 0x40
#define CRC_A   1
#define CRC_B   2
#define CRC_OK  0
#define CRC_ERR 1
#define BCC_OK  0
#define BCC_ERR 1
/* 卡类型定义 */
//#define MIFARE_8K 0           /* MIFARE系列8KB卡片 */
#define MIFARE_TOKEN    1           /* MIFARE系列1KB TOKEN卡片 */
//#define SHANGHAI_8K   2           /* 上海标准系列8KB卡片 */
#define SHANGHAI_TOKEN  3           /* 上海标准系列1KB TOKEN卡片 */
#define mifare1         1
#define mifarepro       2
#define mifarelight     3
#define unknowncard     4
void FM1702NL_Init(void);//IO初始化
void Init_FM1702(uchar mode);/*功能: 该函数实现对FM1702初始化操作*/
void FM1702NL_Write(unsigned char Address, unsigned char Data);/*功能: 写FM1702NL寄存器*/
unsigned char FM1702NL_Read(unsigned char Address);/*功能: 读FM1702NL寄存器*/
uchar Clear_FIFO(void);/*功能: 该函数实现清空FM1702中FIFO的数据*/
void Write_FIFO(uchar count, uchar  *buff);/*功能: 该函数实现向FM1702的FIFO中写入x bytes数据*/
uchar Read_FIFO(uchar  *buff);/*功能: 该函数实现从FM1702的FIFO中读出x bytes数据*/
uchar Judge_Req(uchar  *buff);/*功能: 该函数实现对卡片复位应答信号的判断*/
uchar Check_UID(void);/*功能: 该函数实现对收到的卡片的序列号的判断*/
void Save_UID(uchar row, uchar col, uchar length);/*功能: 该函数实现保存卡片收到的序列号*/
void Set_BitFraming(uchar row, uchar col);/*功能: 该函数设置待发送数据的字节数*/
uchar Command_Send(uchar count, uchar  *buff, uchar Comm_Set);/*功能: 该函数实现向FM1702发送命令集的功能*/
uchar Read_E2(uchar lsb, uchar msb, uchar count, uchar  *buff);/*功能: 该函数实现从FM1702的EE中读出数据*/
uchar Write_E2(uchar lsb, uchar msb, uchar count, uchar  *buff);/*功能: 该函数实现向FM1702的EE中写入数据*/
uchar MIF_Halt(void);/*功能: 该函数实现暂停MIFARE卡*/
char M500HostCodeKey( uchar *uncoded, uchar *coded);/*转换密钥格式*/
uchar Load_keyE2_CPY(uchar Secnr, uchar Mode);/*功能: 该函数实现把E2中密码存入FM1702的keyRevBuffer中*/
uchar Load_keyE2(uchar Secnr, uchar Mode);/*功能: 该函数实现把E2中密码存入FM1702的keyRevBuffer中*/
uchar Request1702(uchar mode);/*功能: 该函数实现对放入FM1702操作范围之内的卡片的Request操作*/
uchar AntiColl(void);/*功能: 该函数实现对放入FM1702操作范围之内的卡片的防冲突检测*/
uchar Select_Card(void);/*功能: 该函数实现对放入FM1702操作范围之内的某张卡片进行选择*/
uchar Authentication(uchar  *UID, uchar SecNR, uchar mode);/*功能: 该函数实现密码认证的过程*/
uchar MIF_READ(uchar  *buff, uchar Block_Adr);/*功能: 该函数实现读MIFARE卡块的数值*/
uchar MIF_Write(uchar  *buff, uchar Block_Adr);/*功能: 该函数实现写MIFARE卡块的数值*/
uchar HL_Active(uchar Block_Adr, uchar Mode);/*功能: 该函数实现高级MIFARE卡激活命令*/
uchar HL_Read(uchar /*idata*/ *buff, uchar Block_Adr, uchar Mode);/*功能: 该函数实现高级读命令*/
uchar HL_Write(uchar /*idata*/ *buff, uchar Block_Adr, uchar Mode);/*功能: 该函数实现高级写命令*/
uchar MIF_Initival(uchar /*idata*/ *buff, uchar Block_Adr);/*功能: 该函数实现MIFARE卡初始化值操作*/
uchar MIF_Increment(uchar  *buff, uchar Block_Adr);/*功能: 该函数实现MIFARE卡自动增值操作*/
uchar MIF_Decrement(uchar  *buff, uchar Block_Adr);/*功能: 该函数实现MIFARE卡自动减值操作*/
uchar MIF_Restore(uchar Block_Adr);/*功能: 该函数实现MIFARE卡自动恢复,备份操作*/
uchar MIF_Transfer(uchar Block_Adr);/*功能: 该函数实现MIFARE卡电子钱包保存操作*/
#endif

程序源码,有意想不到的二重惊喜哦,第二重绝对值

上位机软件

。。。由于项目原因,按照下位机软件自定义协议后对应通讯匹配,暂不开源

卡片介绍

这里在简单记录一下S50卡扇区和后续程序二次开发重要注意事项:
简介
M1卡就是非接触式IC卡中应用最广泛的卡。M1卡就是Mifare非接触式感应卡,M1卡数据保存期为10年,可改写10万次,读无限次。无电源,自带天线,工作频率为13.56MHZ.M1卡内含加密控制逻辑和通讯逻辑电路。M1卡主要有两种,一种是S50和一种是S70。主要应用:门禁、考勤、会议签到、身份识别、物流、工业自动化、各种会员卡、如售饭、地铁、公交代币卡、俱乐部等电子消费、电子门票、动物识别、目标跟踪、洗衣管理、各种一卡通等等
卡片内容
M1 卡分为 16 个扇区,每个扇区由 4 块(块 0、块 1、块 2、块 3)组成,(我们也将 16 个扇区的 64 个块按绝对地址编号为 0~63,存贮结构如下图所示。而每个扇区的块3为控制块,包括密码keyA,存取控制,密码keyB。存取控制的作用是控制对应扇区记录的读写权限与keyA和keyB的关系。由于每个扇区都有独立的key和存取控制,因此M1卡可以做到一卡多用互不干扰。
每一张M1卡的0扇区0块都称作绝对地址块,这一串是在卡片出厂时厂商赋予的,代表着这张卡独立的身份识别信息。绝对地址块的内容已被固化,无法更改。

M1卡控制位

以下为控制位的结构,前6位为密钥A,中间4位存取控制,后6位密钥B。
例如 A1A2A3A4A5 FF078069 B1B2B3B4B5

          密码A           控制位         密码B字节0-5          字节6-9      字节10-15

4位控制位中前3位是真实的控制位,第4位是备用控制位,一般用不上,因此我们可以只分析前3位。
控制字这里不详细介绍,因为一般我们不涉及修改控制字,因为改不好会把卡片扇区改废,我手里的卡片就是将扇区块3全部数据改为0xAA,然后肯本没有这种控制字,密钥也无法解读数据,也无法覆写数据,扇区就废了,所以这里要说明的是在上面我的程序上二次开发,在涉及到修改扇区块3数据时,要避开控制字部分,上述链接程序支持密钥识别功能,输入A或B密钥,然后选择识别方式,验证成功即可读取和修改任意扇区数据(扇区0的块0除外)
卡片使用总结:
1)0扇区的1-2块,1-15扇区的0-3块随便用
2)密钥扇区非必要情况不要更改,密码默认全为FF,虽然A密钥读取为00,是隐藏字符,实际默认为FF,修改后A密钥读取也是00,实际为修改的密钥
3)控制字非必要不要更改,容易照成扇区损坏,当然调试程序成熟后可以使用
4)下载上述程序,免去基础专研,直接二次开发,要把软件核心掌握在自己手中

结构部分

简单设计一款结构,当天晚上就安排打印,妥妥的
顶视图

前视图

后视图

汉堡包结构

睡一觉取件

定制亚克力顶盖在路上

四、结语

技术发展和创新的路上有很多坎坷,在每一个困难面前抱有认真面对、努力专研、沟通交流的态度,一切的路皆是平坦无阻的,只要有一颗坚持的本心,剩下的交给时间!

STM32 + FM1702NL读卡器使用记录相关推荐

  1. STM32模拟读卡器,对于工控机方案谨防踩坑

    前段时间,帮朋友设计了个小玩意.需求比较简单,就是用STM32模拟读卡器,通过TF卡读写一些文件,然后再有一些别的功能就可以了. 当时我觉得,这个不难啊,之前做过类似的东西.如果你看过我之前写的关于S ...

  2. STM32之QSPI调试记录

    STM32之QSPI调试记录 先声明一下,STM32的QSPI外设同样支持单线模式(兼容普通spi),只是相比普通的spi少了一些特性(比如只支持模式0和3.不能LSB发送等),但是用来操作flash ...

  3. STM32相关手册使用记录

    目录 一.概述 二.手册获取 2.1 芯片手册 2.2 库手册和官方DEMO 三.手册内容 3.1 数据手册 3.1.1 查看外设挂载哪条总线 3.2 参考手册 3.2.1 查看芯片flash页大小, ...

  4. STM32的SysTick定时器记录一篇

    CSDN博客主页 ID : Eterlove 一笔一画,记录我的学习生活!站在巨人的肩上Standing on Shoulders of Giants! 该文章为原创,转载请注明出处和作者! 前言 我 ...

  5. FT6206在STM32上的调试记录

    最近因为项目需要,需要在STM32平台上(裸机)驱动电容触摸屏,触摸屏控制IC为FT6206,触摸屏供应商只提供了Linux的驱动代码,看得一头雾水,只好自己写. 网上搜索相关资料,好不容易才搜索到一 ...

  6. STM32与GSM800A调试记录

    最近在做一个项目,调试单片机与GSM(我这里用的是GSM800A)通信时遇到问题. 实现功能:单片机控制GSM模块发送短信(很基础的功能).用的的是AT指令,还有就是GSM模块启动工作流程. 当我们要 ...

  7. STM32开发指南阅读记录

    一.STM32的开发方式:标准库,HAL库,寄存器开发 1.寄存器开发:通过直接操作寄存器进行开发,但是由于STM32的寄存器数量众多,逐个查询比较繁琐. 2.标准库:ST公司为每一款芯片都编写了一份 ...

  8. STM32硬件CRC32问题记录

    前言:STM32硬件本身没有问题,只是其中的校验值计算方式跟平常的不太一样 硬件平台 我使用的是STM32F103ZET6单片机,用cubeMX新建的工程(使能crc即可加载\STM32F1xx_HA ...

  9. 火牛版STM32学习板摸索记录

    N久之前买了2块火牛STM32学习板,一直就没怎么动,印象中买来那会就做了做了个简单的测试就放下了.前两天突然想起来再弄竟然不好使了!郁闷至极,难道真的老年痴呆了!上网搜索也没找什么有用的资料,评价也 ...

最新文章

  1. 算法入门经典-第七章 例题7-2-2 可重集的排列
  2. 如何用matlab测a相相电流,电流平均值谐波检测方法MATLAB仿真
  3. JavaMail 发送邮件
  4. ASP.NET MVC5+EF6+EasyUI 后台管理系统(19)-权限管理系统-用户登录
  5. spring boot整合mybatis+通用mapper+pagehelper分页插件
  6. Integer注意_享元设计模式
  7. Pile 0009: Vim命令梳理
  8. 腾讯视频网页下载_腾讯视频怎么下载视频
  9. Multi-thread--C++11中std::mutex的使用
  10. OC 获取view相对位置_【全职业P4阶段世界BUFFS和药剂】BUFFS获取方法药剂自己查询出处...
  11. 特斯拉Model Y Performance高性能版车型价格上调一万元
  12. mysql的to datetime_mysql-笔记-datetime
  13. 移动网络设备睁开均盘绕Linux睁开
  14. Android pm命令(持续更新中...)
  15. 关于M1芯片版Mac安装Photoshop后储存psd时出现程序错误提示的解决方法
  16. 海康监控摄像头能做视频直播那些事!
  17. 19.4.17 javaScript基础 培训第三天
  18. 分号的html文本,html分号
  19. 一个宽带猫能不能连接两个路由器?
  20. spring技巧之bean加载顺序控制

热门文章

  1. 局域网会议直播方案适用于局域网内部的直播
  2. 海量点云数据快速读取方法
  3. Python —— Faker 生成模拟数据
  4. 二.了解zigbee协议栈中几个常用语句
  5. 3.设计模式--适配器模式(adapter模式)
  6. Openstack之路(二)认证服务Keystone
  7. 使用‘net.sf.ehcache.CacheManager‘进行Shiro配置时报错
  8. 真无线耳机哪个牌子好?蓝牙耳机十大品牌排行榜!
  9. VM 安装 Photon OS
  10. Object-C---Swift之(七)嵌套函数与闭包