3. EBF-SL2823模块¶
3.1. EBF-SL2823 简介¶
EBF-SL2823 是野火设计的一款高度集成的非接触式(13.56MHz)读写器模块。 它采用了捷联微芯公司的 SL2823 非接触式读写器芯片,该芯片利用了调制和解调的通信原理, 支持各种 13.56MHz 频段的非接触式的通信协议,包括 ISO/IEC 14443 Type A/B、ISO15693 和 Felica 通信协议。 SL2823 同时还支持 LPCD 低功耗检测的功能,在 500ms 的寻卡周期条件下,只需要消耗 6uA 左右功耗即可完成 LPCD 微波检测卡片功能,具有稳定可靠且功耗超低的特点。
3.2. 产品特性参数¶
EBF-SL2823 模块产品特性
特性 |
说明 |
---|---|
读写器功能 |
支持 ISO/IEC 14443 A/B、ISO 15693 和 Felica |
通信方式 |
I2C、SPI通信 |
读写器通讯距离(读卡距离) |
2~5 cm(因卡片内部线圈大小等实际情况而异) |
工作电压 |
3.3V |
LPCD模式静态功耗(不含开场检测) |
实测: 6.4uA (无电源LED灯) 实测:643uA(有电源LED灯) |
3.3. EBF-SL2823 模块的引脚说明¶
引脚编号 |
SPI引脚名称 |
I2C引脚名称 |
SPI引脚说明 |
I2C引脚说明 |
---|---|---|---|---|
1 |
3V3 |
3V3 |
电源正 |
电源正 |
2 |
RST |
RST |
复位 |
复位 |
3 |
IRQ |
IRQ |
中断信号 |
中断信号 |
4 |
GND |
GND |
地线 |
地线 |
5 |
MISO |
SCL |
主进从出数据引脚 |
时钟引脚 |
6 |
MOSI |
ADDR2 |
主出从进数据引脚 |
I2C地址选择引脚2(默认接地) |
7 |
SCK |
ADDR1 |
时钟引脚 |
I2C地址选择引脚1(默认接地) |
8 |
CS或者NSS |
SDA |
片选引脚 |
数据引脚 |
提示
SL2823模块与各开发板的具体接线方法请查看 SL2823 模块配套资料里面的 “野火SL2823与各开发板接线说明与使用注意事项” 表格,同时也可参考 “野火SL2823与各开发板连接图”。
3.4. EBF-SL2823 模块工作原理¶
EBF-SL2823 模块的结构如下图所示。
模块简要说明:
①:主控CPU,也就是我们的开发板等。
②:SL2823芯片
③:天线部分(线圈),SL2823芯片通过天线线圈发送射频信号,发送能量给卡片/标签并与其进行通信
模块工作原理:
卡片/标签其实是由线圈和IC集成电路组成的。而读写器(PCD)则主要由主控CPU、PCD读写器芯片(比如SL2823)和线圈组成。 所以我们可以把我们的STM32开发板和 SL2823 模块作为一个PCD来使用,对卡片/标签进行读写数据,实现信息交换。
其基本工作原理为:当卡片/标签进入到读写器的感应区域后,卡片/标签通过内部线圈接受读写器发出的射频信号, 并凭借线圈感应电流所获得的能量发送出存储在内部芯片中的信息,读写器读取到信息并解码后,送至处理单元进行数据处理。
感兴趣的用户可根据以下关键词自行网上搜索相关资料。
RFID——射频识别技术(Radio Frequency Identification)
NFC——近场通讯(Near Field Communication)
MIFARE
3.5. 实验现象¶
注意
由于 SL2823 模块在硬件上 默认 选用的是 I2C 接口模式,而相应的配套例程默认使用的是 软件 I2C 来与模块进行通信。 此外还可以选用 SPI 接口模式,注意 UART 接口并不可用,所以请忽略它。
SL2823 模块的两个 I2C 地址选择引脚 ADDR_1 和 ADDR_2(以丝印标注的为准)默认接到 GND,使得默认I2C地址为: 0x28 (写地址), I2C 读地址为 0x28 的最低位置 1。如果用户需要更改模块的 I2C 地址的话,调整I2C地址选择引脚1和2 接到3V3即可(要注意:这两个引脚外部如果焊接了下拉 0Ω 电阻的话需要拆掉,否则接到3V3会造成短路), 同时也要修改例程里面的 I2C 设备地址宏定义 “SL2x23_DEV_ADDRESS” (位于文件 “sl2x23_iic.h” 中)。
如果用户需要将模块切换到 SPI 接口模式,需要根据模块原理图 换焊电阻,并且通过例程里的 宏定义切换 为 SPI 接口模式。 首先打开并查看原理图,换焊电阻的具体方法为:将SL2823芯片 I2C 引脚到高电平的上拉电阻 R7 换到 EA 引脚的上拉电阻 R5 位置, 也就是使得原本的 EA=0, I2C=1 的硬件配置变为 EA=1, I2C=0 (SL2823芯片的“EA”、“I2C”这两个引脚在芯片内部都自带下拉电阻, 只要没有 0Ω 的上拉电阻,“I2C”这个引脚就会被下拉为低电平)。另外还需要注意,原本用于设定模块I2C地址的两个 I2C 地址选择引脚 ADDR_1 和 ADDR_2(以丝印标注的为准),这两个引脚上面默认焊接的 0Ω 下拉电阻( R8 和 R9 )必须拆掉,否则影响SPI通信。
SL2823模块接口在硬件上切换到 SPI 模式之后,需要根据 “野火SL2823与各开发板接线说明与使用注意事项” 表格中的说明重新接线。 并且,在软件上还需要修改例程里面的模块通信方式宏定义:注释掉宏 SL2X23_IIC_Mode, 取消注释宏 SL2X23_SPI_Mode (这两个宏位于文件 “sl2x23_if.h” 中。请忽略宏SL2X23_UART_Mode,因为模块不支持UART通信方式)。
例程使用,操作步骤:
根据 SL2823 模块配套资料里面的 “野火SL2823与各开发板接线说明与使用注意事项” 表格, 将 SL2823 模块的 I2C 接口引脚连接到开发板,编译并下载程序到开发板中,打开串口助手, 并复位开发板让程序重新运行,可观察到串口助手的接收窗口显示接收到 “iic test pass!” 的字样, 表示开发板与模块的 I2C 通信成功。如果使用的是 SPI 模式,则是 “spi test pass!” 的字样。
接着输出 “System Init OK.” 的提示信息之后表示开发板和模块初始化配置完成,接下来将会通过 SL2823 模块检测读卡。
用户可以把卡片放到 SL2823 模块的读卡区域,就可以观察到如下所示的普通查询模式的实验现象了。
SL2823 查询模式实验现象
若用户想要让SL2823模块工作在 LPCD 模式,可以通过宏定义 _ENABLE_LPCD_ (位于文件 “lpcd.h” 中)切换到LPCD模式。 操作步骤与普通查询模式的是一样的。
实际上,LPCD 低功耗模式就是一种“周期性低功耗检测 + 检测到卡片后产生中断并进入普通查询模式”的流程。 以下是 LPCD 模式下观察到的实验现象。
SL2823 LPCD模式实验现象
3.6. 例程介绍¶
例程默认使用的是软件I2C,即用IO引脚直接模拟I2C协议进行通信,软件I2C在《I2C基础知识》章节已经介绍,不再赘述,这里主要分析代码框架。
由于篇幅问题,这里只贴出部分代码,完整代码请参考模块例程。
在编写EBF-SL2823模块驱动时,需要考虑到更改硬件环境的情况,因此我们把EBF-SL2823模块引脚相关的宏 定义到 “sl2x23_if.h”、“sl2x23_spi.h”和“sl2x23_iic.h” 这三个文件中,在更改或移植的时候一般只用改宏定义就可以了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | /* 切换通信方式 I2C/SPI/UART */
#define SL2X23_IIC_Mode
//#define SL2X23_SPI_Mode
//#define SL2X23_UART_Mode
// 复位,即SL2x23模块的RST引脚,接STM32的普通IO即可
#define SL2x23_GPIO_RST_CLK_FUN RCC_APB2PeriphClockCmd
#define SL2x23_GPIO_RST_CLK RCC_APB2Periph_GPIOB
#define SL2x23_GPIO_RST_PORT GPIOB
#define SL2x23_GPIO_RST_PIN GPIO_Pin_8
#define SL2x23_GPIO_RST_Mode GPIO_Mode_Out_PP
// IRQ中断,即SL2x23模块的IRQ引脚,使用外部中断
#define SL2x23_GPIO_IRQ_CLK_FUN RCC_APB2PeriphClockCmd
#define SL2x23_GPIO_IRQ_CLK RCC_APB2Periph_GPIOB
#define SL2x23_GPIO_IRQ_PORT GPIOB
#define SL2x23_GPIO_IRQ_PIN GPIO_Pin_9
#define SL2x23_GPIO_IRQ_Mode GPIO_Mode_IPU /* IRQ脚上拉输入模式 */
// IRQ中断线
#define SL2x23_IRQ_EXTI_CLK_FUN RCC_APB2PeriphClockCmd
#define SL2x23_IRQ_EXTI_CLK RCC_APB2Periph_AFIO
#define SL2x23_IRQ_EXTI_IRQ EXTI9_5_IRQn
#define SL2x23_IRQ_EXTI_LINE EXTI_Line9
#define SL2x23_IRQ_EXTI_PORTSOURCE GPIO_PortSourceGPIOB
#define SL2x23_IRQ_EXTI_PINSOURCE GPIO_PinSource9
#define SL2x23_IRQPin_IRQHandler EXTI9_5_IRQHandler
// RST复位
#define SL2x23_Reset_Enable() GPIO_ResetBits( SL2x23_GPIO_RST_PORT, SL2x23_GPIO_RST_PIN )
#define SL2x23_Reset_Disable() GPIO_SetBits ( SL2x23_GPIO_RST_PORT, SL2x23_GPIO_RST_PIN )
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | /* 硬件/软件I2C 切换 */
//#define HARDWARE_I2C //软硬件I2C两种都可以使用
/* SL2x23 设备地址 */
#define SL2x23_DEV_ADDRESS 0x28
/* SL2x23 I2C超时 */
#define SL2x23_FLAG_TIMEOUT ((uint32_t)0x1000)
#define SL2x23_LONG_TIMEOUT ((uint32_t)(10 * SL2x23_FLAG_TIMEOUT))
/* 等待标志位 */
#define WAIT_FOR_FLAG(flag, value, timeout) SL2x23_Timeout = timeout;\
while(I2C_GetFlagStatus(SL2x23_I2C, flag) != value) {\
if((SL2x23_Timeout--) == 0) return SL2x23_TIMEOUT_UserCallback(); \
}
/* 读序列,清零ADDR标志位 */
#define CLEAR_ADDR_BIT I2C_ReadRegister(SL2x23_I2C, I2C_Register_SR1);\
I2C_ReadRegister(SL2x23_I2C, I2C_Register_SR2);
/**
* @brief I2C Interface pins
*/
#define SL2x23_I2C I2C2
#define SL2x23_I2C_CLK RCC_APB1Periph_I2C2
#define SL2x23_I2C_SCL_PIN GPIO_Pin_10 /* PB.10 */
#define SL2x23_I2C_SCL_GPIO_PORT GPIOB /* GPIOB */
#define SL2x23_I2C_SCL_GPIO_CLK RCC_APB2Periph_GPIOB
#define SL2x23_I2C_SCL_SOURCE GPIO_PinSource10
#define SL2x23_I2C_SDA_PIN GPIO_Pin_11 /* PB.11 */
#define SL2x23_I2C_SDA_GPIO_PORT GPIOB /* GPIOB */
#define SL2x23_I2C_SDA_GPIO_CLK RCC_APB2Periph_GPIOB
#define SL2x23_I2C_SDA_SOURCE GPIO_PinSource11
/* 软件模拟 I2C */
#define SL2x23_I2C_SCL_1() SL2x23_I2C_SCL_GPIO_PORT->BSRR = SL2x23_I2C_SCL_PIN /* SCL = 1 */
#define SL2x23_I2C_SCL_0() SL2x23_I2C_SCL_GPIO_PORT->BRR = SL2x23_I2C_SCL_PIN /* SCL = 0 */
#define SL2x23_I2C_SDA_1() SL2x23_I2C_SDA_GPIO_PORT->BSRR = SL2x23_I2C_SDA_PIN /* SDA = 1 */
#define SL2x23_I2C_SDA_0() SL2x23_I2C_SDA_GPIO_PORT->BRR = SL2x23_I2C_SDA_PIN /* SDA = 0 */
#define SL2x23_I2C_SDA_READ() ((SL2x23_I2C_SDA_GPIO_PORT->IDR & SL2x23_I2C_SDA_PIN) != 0) /* 读SDA口线状态 */
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | /* 硬件/软件SPI 切换 */
//#define HARDWARE_SPI //软硬件SPI两种都可以使用
//SL2x23 硬件SPI
#define SL2x23_SPI SPI2
#define SL2x23_SPI_CLK RCC_APB1Periph_SPI2
/*********************************** SL2x23 硬件SPI引脚定义 *********************************************/
//SL2x23模块
// 片选,即SL2x23模块的SDA引脚(NSS片选引脚)
#define SL2x23_GPIO_CS_CLK_FUN RCC_APB2PeriphClockCmd
#define SL2x23_GPIO_CS_CLK RCC_APB2Periph_GPIOA
#define SL2x23_GPIO_CS_PORT GPIOA
#define SL2x23_GPIO_CS_PIN GPIO_Pin_4
#define SL2x23_GPIO_CS_Mode GPIO_Mode_Out_PP
// 时钟,即SL2x23模块的SCK引脚,接STM32的SPI的SCK引脚
#define SL2x23_GPIO_SCK_CLK_FUN RCC_APB2PeriphClockCmd
#define SL2x23_GPIO_SCK_CLK RCC_APB2Periph_GPIOB
#define SL2x23_GPIO_SCK_PORT GPIOB
#define SL2x23_GPIO_SCK_PIN GPIO_Pin_13
#define SL2x23_GPIO_SCK_Mode GPIO_Mode_Out_PP
// 数据输出,即SL2x23模块的MISO引脚,接STM32的SPI的MISO引脚
#define SL2x23_GPIO_MISO_CLK_FUN RCC_APB2PeriphClockCmd
#define SL2x23_GPIO_MISO_CLK RCC_APB2Periph_GPIOB
#define SL2x23_GPIO_MISO_PORT GPIOB
#define SL2x23_GPIO_MISO_PIN GPIO_Pin_14
#define SL2x23_GPIO_MISO_Mode GPIO_Mode_IN_FLOATING
// 数据输入,即SL2x23模块的MOSI引脚,接STM32的SPI的MOSI引脚
#define SL2x23_GPIO_MOSI_CLK_FUN RCC_APB2PeriphClockCmd
#define SL2x23_GPIO_MOSI_CLK RCC_APB2Periph_GPIOB
#define SL2x23_GPIO_MOSI_PORT GPIOB
#define SL2x23_GPIO_MOSI_PIN GPIO_Pin_15
#define SL2x23_GPIO_MOSI_Mode GPIO_Mode_Out_PP
/*********************************** SL2x23 软件SPI宏定义*********************************************/
#define SL2x23_CS_Enable() GPIO_ResetBits ( SL2x23_GPIO_CS_PORT, SL2x23_GPIO_CS_PIN )
#define SL2x23_CS_Disable() GPIO_SetBits ( SL2x23_GPIO_CS_PORT, SL2x23_GPIO_CS_PIN )
#define SL2x23_SPI_CS_LOW SL2x23_CS_Enable()
#define SL2x23_SPI_CS_HIGH SL2x23_CS_Disable()
#define SL2x23_SCK_0() GPIO_ResetBits( SL2x23_GPIO_SCK_PORT, SL2x23_GPIO_SCK_PIN )
#define SL2x23_SCK_1() GPIO_SetBits ( SL2x23_GPIO_SCK_PORT, SL2x23_GPIO_SCK_PIN )
#define SL2x23_MOSI_0() GPIO_ResetBits( SL2x23_GPIO_MOSI_PORT, SL2x23_GPIO_MOSI_PIN )
#define SL2x23_MOSI_1() GPIO_SetBits ( SL2x23_GPIO_MOSI_PORT, SL2x23_GPIO_MOSI_PIN )
#define SL2x23_MISO_GET() GPIO_ReadInputDataBit ( SL2x23_GPIO_MISO_PORT, SL2x23_GPIO_MISO_PIN )
|
这里使用 SL2x23_Init 初始化 SPI 和 I2C 接口和 RST、IRQ 引脚的配置。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | void SL2x23_Init(void)
{
/* RST IRQ */
SL2x23_RST_IRQ_Config(); /* RST IRQ引脚配置 */
SL2x23_IRQ_EXTI_Config(); /* IRQ引脚中断配置 */
#if defined SL2X23_IIC_Mode
SL2x23_I2C_Init();
#elif defined SL2X23_SPI_Mode
SL2x23_SPI_Config();
#elif defined SL2X23_UART_Mode
#error "串口通信暂未实现!"
#else
#error "请先定义通信方式!"
#endif
SL2x23_Reset_Disable(); /* NRSTPD 复位引脚高电平 */
Delay_us(1000); /* SL2823 上电/NRSTPD 管脚拉高后,软件需要等待 800us 才能对寄存器进行读写 */
}
|
在主函数中初始化 SysTick 和调试串口,对于使用ST HAL库的例程,还会初始化内核DWT定时器,方便后面使用延时函数和串口调试。
接着初始化 SL2823 的功能配置,如果使用普通查询模式时(在头文件”lpcd.h”里注释掉宏定义 “_ENABLE_LPCD_” ),会调用 SL2x23_Para_Init 和 Rfid_Init 函数; 而使用 LPCD 查询模式时(在头文件”lpcd.h”里取消注释宏定义 “_ENABLE_LPCD_” ),则会调用 SL2x23_Para_Init_LPCD 和 Rfid_Init_LPCD 函数。 之后串口助手会打印 “System Init OK.” 的调试信息。
接着主循环里面会根据宏定义条件调用 lpcd_demo、nfc_demo 和 nfc_demo_user 中的其中一个函数,这些函数都是用来展示读卡功能的小demo。 三者的区别是:
lpcd_demo: 可以检测到TypeA和TypeB卡。在 LPCD 查询模式下使用(LPCD 模式需要使用到中断)
nfc_demo: 可以检测到TypeA和TypeB卡。在普通查询模式下使用(使用或者不使用中断都可以,用查询状态寄存器的方式,这需要在头文件 “sl2x23.h” 里定义宏 #define NOT_IRQ)
nfc_demo_user: 可以检测到TypeA卡。跟 nfc_demo 函数的区别主要在于读卡的效果不同,nfc_demo 函数实现的是不断的重复读卡测试,而 nfc_demo_user 函数可以实现放一次刷一次的用户刷卡效果,在读到一次卡后会令卡进入休眠状态,只有把卡拿开在重新放入读卡区域才能再次读到卡。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | int main(void)
{
/* MCU 初始化 */
SysTick_Init();
USART_Config();
/* SL2823 接口初始化 */
SL2x23_Init();
Communication_Test(); //测试通信
/* SL2823 RFID功能初始化 */
#ifdef _ENABLE_LPCD_
SL2x23_Para_Init_LPCD();
Rfid_Init_LPCD();
#else
SL2x23_Para_Init();
Rfid_Init();
#endif
pcd_default_info();
/* Debug(不调试应全部注释掉这部分代码) */
//test_setagc_getadc();
//print_all_reg();
/* End Debug */
printf("System Init OK.\r\n\r\n");
while(1)
{
#ifdef _ENABLE_LPCD_
lpcd_demo(); /* LPCD中断+查询 */
#else
#if 1
nfc_demo(); /* 仅查询模式 */
#else //先把上面的 #if 1 改成 #if 0
nfc_demo_user(); //模拟用户刷卡:刷一次仅识别一次
#endif
#endif
}
}
|
提示
关于 SL2823 的 LPCD 模式 :LPCD 是一种由SL2823硬件上实现的低功耗读卡器的功能,它提供比普通的定时间隔查询模式更低的功耗。 LPCD 的工作原理其实也很简单,当配置好芯片的 LPCD 工作模式之后,就可以通过 lpcd_entry 函数调用进入软掉电模式以降低功耗, 芯片会自动以低功耗模式对读卡区域的磁场变化进行周期性地检测,检测的周期为500ms(检测周期可以通过宏 LPCD_DETECT_PERIOD 设置)。 当检测到磁场的变化幅度超过一定值时(磁场变化检测灵敏度可以通过宏 LPCD_DETECT_SENS 设置),则芯片会通过IRQ引脚触发中断, 通知主控MCU来进一步处理用户刷卡的行为(在我们的例程里是直接调用普通查询模式的函数来读写卡片)。 当然这在某些条件下也会存在误判的情况出现,一般没有外在环境干扰时误判的概率很低。
另外,使用 LPCD 模式的注意事项请参考模块配套资料里面的 “野火SL2823与各开发板接线说明与使用注意事项” 表格。
以上,野火的例程中主要是实现了 ISO/IEC 14443 A/B,因此只能识别 TypeA 和 TypeB 的IC卡。 实际上 SL2823 模块还可以支持 ISO 15693(对应TypeV)和 Felica(对应TypeF)的标准, 可在例程里面可以通过函数 pcd_config 将SL2823配置为符合 ISO 15693 和 Felica 标准的工作模式, 但是如果想要读写符合 ISO 15693 和 Felica 标准的IC卡或标签,还需要自己根据这两个标准协议以及厂家的卡或标签文档来实现具体的操作细节。 这方面建议用户参考捷联微芯官方的最新版本 SDK:SL2823_SDK_A_B_F_V_V1.11, 该SDK中包含有读写 TypeA、TypeB、TypeV、TypeF 类型IC卡的 demo 示例,可以识别到全协议类型IC卡。
ISO/IEC 14443 A/B、ISO 15693 和 Felica 这三个是不同的协议标准,由于具体的实现细节相对来说比较复杂, 这里不做深入分析,对此感兴趣的读者可以将它们的技术规范文档找来自行研究。
提示
关于 NFC : NFC 是由 RFID 和无线互联通讯发展而来的技术,NFC 也是工作在 13.56 MHz,跟我们的 SL2823 模块一样。 实际上,NFC 最底层的协议规范就是 ISO/IEC 14443 A/B、ISO 15693 和 Felica 等,因此可以把 SL2823 读写器芯片当做NFC芯片, 但是 SL2823 并不属于NFC控制器芯片,它也仅能支持 NFC 工作模式当中的 读写器模式 。 与 NFC 相关的概念除了NFC控制器,还有NFC标签、NFC标签类型、NFC标签数据存储交换格式、NFC论坛协议和NFC协议栈等等, 感兴趣的读者可网上查阅相关资料。