概述
前言:
前些日子老师布置一个任务叫我们焊接一个RFID读卡器,其中刚好我们手上也有一个STM32F103RBT6开发板,老师于是布置任务叫我们用STM32完成对EM4100进行读卡操作
EM4100简介:
中 文 名:EM4100卡
存储容量:64bit
工作频率:125KHZ
读写距离:2-15cm
产品名称:EM4100/EM4102卡
芯片类型:μEM瑞士微电 EM4100/EM4102
擦写寿命:读不限,只读
外形尺寸:ISO标准卡/厚卡
封装材料:PVC、ABS
典型应用:身份识别、考勤系统、门禁系统、财物标识等
详细资料:
进口瑞士微电子EM4100/4102无线射频芯片,采用先进的芯片封装工艺,可作为非接触卡片应用的优良解决方案。同时提供优惠的印刷服务和适合应用环境的异形卡。可广泛用于身份识别,考勤系统,门禁系统,财物标识,过程控制,企业一卡通系统,停车,物流,动物识别,身份识别,识别货品,工业自动化,会议签到,电子标签,超市,仓库管理,人员管理,安防系统,医疗机构等。
EM4100卡命名的原因是该卡的核心芯片是由EM Microelectronic(瑞士微电)公司生产。
该段信息来源 https://blog.csdn.net/yichu5074/article/details/82621415
EM4100数据帧格式
要点:
- 数据总共有64bit。
- 以连续的9个1开头。
- 前4个bit为厂商位。
- 采用偶校验的方法。(保证1的个数为偶数个)
- 最后一列为行校验。
- 最后一行为列检验。
- 数据最后一位为0。
曼彻斯特编码:
两种格式刚好相反:
- 第一种:(EM4100采用这种编码)
1:高电平到低电平(下降)
0:低电平到高电平(上升) - 第二种:
1:低电平到高电平(上升)
0:高电平到低电平(下降)
下图为一次完整的EM4100帧数据
STM32F103RBT6解码EM4100:
思路:
- 首先找到高电平时间或者低电平时间在
512us
附近。- 找到后标记已经同步,并且此时为一次有效捕获中断。
- 下一次上升沿或者下降沿必须距离上一次有效捕获中断512us附近。
- 选用
uint64_t
的RFID_DATA
来存放每一次有效数据。- 采集完一次有效捕获中断后检查
RFID_DATA
是否以连续的9个1开头并且最后一位为0。- 如果满足条件则标记采集完成。否则继续采集。
采用的外设:TIM2 TIM3
- TIM2:捕获中断以及125khz载波生成。
- TIM3:计时器(32us更新中断一次,每次
RFID_CNT
增加1
)
行校验以及列检验思路:
方案①:
每一行(除了连续的9个1以及最后一行)加起来%2
为0。前四列加起来%2
为0。(不推荐)
方案②:
采用异或逻辑^
:每一行(除了连续的9个1以及最后一行)异或为0。前四列异或为0。
代码片段:
RFID_init(void)
void RFID_init(void){
TIM_TimeBaseInitTypeDef TIM2_struct;
TIM_OCInitTypeDef TIM2_oc;
GPIO_InitTypeDef GPIO1_InitStruct;
GPIO_InitTypeDef GPIO2_InitStruct;
TIM_ICInitTypeDef TIM2_ICInitStruct;
NVIC_InitTypeDef NVIC_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
TIMER_init(3,71,31);//定时器3初始化
GPIO1_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;
GPIO1_InitStruct.GPIO_Pin=RFID_PIN_IN;
GPIO1_InitStruct.GPIO_Speed=GPIO_Speed_10MHz;
GPIO2_InitStruct.GPIO_Mode=GPIO_Mode_IN_FLOATING;
GPIO2_InitStruct.GPIO_Pin=RFID_PIN_OUT;
GPIO2_InitStruct.GPIO_Speed=GPIO_Speed_10MHz;
GPIO_Init(RFID_IN, &GPIO1_InitStruct);
GPIO_Init(RFID_OUT, &GPIO2_InitStruct);
TIM2_struct.TIM_ClockDivision=TIM_CKD_DIV1;
TIM2_struct.TIM_Prescaler=71;
TIM2_struct.TIM_CounterMode=TIM_CounterMode_Up;
TIM2_struct.TIM_Period=7;
TIM_ARRPreloadConfig(TIM2, ENABLE);
TIM_TimeBaseInit(TIM2, &TIM2_struct);
TIM2_oc.TIM_OCMode=TIM_OCMode_PWM1;
TIM2_oc.TIM_OCPolarity=TIM_OCPolarity_High;
TIM2_oc.TIM_OutputState=TIM_OutputState_Enable;
TIM2_oc.TIM_Pulse=4;
TIM_OC1Init(TIM2,&TIM2_oc);
TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Enable);
NVIC_InitStruct.NVIC_IRQChannel=TIM2_IRQn;
NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=2;
NVIC_InitStruct.NVIC_IRQChannelSubPriority=0;
NVIC_Init(&NVIC_InitStruct);
TIM2_ICInitStruct.TIM_Channel=TIM_Channel_2;
TIM2_ICInitStruct.TIM_ICFilter=0xf;//这个很重要!!
TIM2_ICInitStruct.TIM_ICPolarity=TIM_ICPolarity_Falling;
TIM2_ICInitStruct.TIM_ICPrescaler=TIM_ICPSC_DIV1;
TIM2_ICInitStruct.TIM_ICSelection=TIM_ICSelection_DirectTI;
TIM_ICInit(TIM2, &TIM2_ICInitStruct);
TIM_ITConfig(TIM2, TIM_IT_CC2, ENABLE);
TIM_Cmd(TIM2, ENABLE);
}
void TIM2_IRQHandler(void)
uint64_t RFID_DATA=0;
u8 RFID_CNT=0;//溢出次数
u8 RFID_STA=0;//RFID状态
u16 TIME_CNT=0;
const u16 Sample=384;//(256+512)/2
const u8 Sample_Per=32;//定时器3溢出一次 32us
/*
RFID_STA 没有用到后4位
bit7是否同步 bit6是否捕捉上升沿 bit5是否捕捉下降沿 bit4解析成功
*/
void TIM2_IRQHandler(void){
if(TIM_GetITStatus(TIM2,TIM_IT_CC2)!=RESET){
if((RFID_STA&0X80)==0){//没有建立同步
if(GPIO_ReadInputDataBit(RFID_OUT, RFID_PIN_OUT)==Bit_SET){//代表上升沿
TIM_OC2PolarityConfig(TIM2, TIM_ICPolarity_Falling);//设置下降沿捕获
if(RFID_STA&0X20){//之前已经捕捉到一个下降沿
if((RFID_CNT>(Sample/Sample_Per))&&(RFID_CNT<2*(Sample/Sample_Per))){RFID_STA|=0X80;}//标记同步
else{RFID_STA|=0X40;if((RFID_CNT>2*(Sample/Sample_Per))||(RFID_CNT<(Sample/Sample_Per)/2)){RFID_STA=0;RFID_CNT=0;}}//标记捕捉到上升沿
RFID_STA&=0XDF;//取消之前捕捉的下降沿
RFID_CNT=0;//清空溢出次数
}else{
RFID_STA|=0X40;//标记捕捉到上升沿
RFID_CNT=0;//清空溢出次数
}
}else{//代表下降沿
TIM_OC2PolarityConfig(TIM2, TIM_ICPolarity_Rising);//设置上升沿捕获
if(RFID_STA&0X40){//之前已经捕捉到一个上升沿
if((RFID_CNT>(Sample/Sample_Per))&&(RFID_CNT<2*(Sample/Sample_Per))){RFID_STA|=0X80;}//标记同步
else{RFID_STA|=0X20;if((RFID_CNT>2*(Sample/Sample_Per))||(RFID_CNT<(Sample/Sample_Per)/2)){RFID_STA=0;RFID_CNT=0;}}//标记捕捉到下降沿
RFID_STA&=0XBF;//取消之前捕捉的上升沿
RFID_CNT=0;//清空溢出次数
}else{
RFID_STA|=0X20;//标记捕捉到下降沿
RFID_CNT=0;//清空溢出次数
}
}
}else{//已经建立同步
if((RFID_STA&0X10)==0){//没有捕捉完成
if(GPIO_ReadInputDataBit(RFID_OUT, RFID_PIN_OUT)==Bit_SET){//代表上升沿
TIM_OC2PolarityConfig(TIM2, TIM_ICPolarity_Falling);//设置下降沿捕获
if((RFID_CNT>2*(Sample/Sample_Per))||(RFID_CNT<(Sample/Sample_Per)/2)){RFID_STA=0;RFID_CNT=0;}
if((RFID_CNT>(Sample/Sample_Per))&&(RFID_CNT<2*(Sample/Sample_Per))){RFID_DATA=RFID_DATA<<1;RFID_CNT=0;}//上升沿代表0
}else{//代表下降沿
TIM_OC2PolarityConfig(TIM2, TIM_ICPolarity_Rising);//设置上升沿捕获
if((RFID_CNT>2*(Sample/Sample_Per))||(RFID_CNT<(Sample/Sample_Per)/2)){RFID_STA=0;RFID_CNT=0;}
if((RFID_CNT>(Sample/Sample_Per))&&(RFID_CNT<2*(Sample/Sample_Per))){RFID_DATA=RFID_DATA<<1;RFID_DATA|=0x01;RFID_CNT=0;}//下降沿代表1
}
if(((RFID_DATA&0XFF80000000000001)==0XFF80000000000000)){RFID_STA|=0X10;}//RFID_DATA以9个连续的1开头,以0结尾标记捕捉完成
}else{//捕捉完成后还有数据就每次反转一次捕获状态,易于下次重新开始捕获
if(GPIO_ReadInputDataBit(RFID_OUT, RFID_PIN_OUT)==Bit_SET){//代表上升沿
TIM_OC2PolarityConfig(TIM2, TIM_ICPolarity_Falling);//设置下降沿捕获
RFID_CNT=0;
}else{//代表下降沿
TIM_OC2PolarityConfig(TIM2, TIM_ICPolarity_Rising);//设置上升沿捕获
RFID_CNT=0;
}
}
}
}//捕获中断
TIM_ClearITPendingBit(TIM2, TIM_IT_CC2);
}
void TIM3_IRQHandler(void)
void TIM3_IRQHandler(void){
if(TIM_GetITStatus(TIM3,TIM_IT_Update)!=RESET){
if(RFID_CNT==0XFF){RFID_CNT=0;}//溢出次数满了
if(TIME_CNT==0XFFFF){TIME_CNT=0;}//溢出次数满了
RFID_CNT+=1;
TIME_CNT+=1;//时间计时单位
}//更新中断
TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
}
数据切片
采用
unsigned char
类型的数组ID[11]
,通过移位操作进行获取:
u8 i=0;
u8 ID[11]={0};//包括最后一行的数据
u8 RFID_ID[10]={0};//换算成ASCII码的RFID_ID值
if(RFID_STA&0X10){
for(i=0;i<11;i++)
{
ID[i]=((RFID_DATA>>(50-5*i))&0x1f);
}
}
行校验以及列检验
u8 RFID_check(void){
u8 i=0,j=0;
u8 sum=0;
for(i=0;i<10;i++){
for(j=0;j<5;j++){
sum^=(ID[i]>>(4-j))&0x01;//行校验
}
if(sum!=0)return 0;//行校验失败
}
for(i=0;i<11;i++){
sum^=ID[i];//列校验
}
if(sum>>1!=0)return 0;//列检验失败
return 1;//校验成功
}
附加功能:(把每一位换算成ASCII码值)
void RFID_process(void)
{
u8 i;
for(i=0;i<10;i++){
switch(ID[i]>>1){
case 0:case 1:case 2:case 3:case 4:case 5:case 6:case 7:case 8: case 9:RFID_ID[i]=(ID[i]>>1)+48;break;//换算成ASCII码的1 2 3 4 5 6 7 8 9
case 10:case 11:case 12:case 13:case 14:case 15:RFID_ID[i]=(ID[i]>>1)-10+65;break;//换算成ASCII码的A B C D E F
default:RFID_ID[i]=32;//转换成ASCII码的空格
}
}
}
下面附上51单片机C语言发送EM4100曼彻斯特信号代码:
#include <regx51.h>
sbit TAG_OUT=P2^0;
typedef unsigned char uint8_t;
void DELAY256(void)
{
unsigned char a,b;
for(b=23;b>0;b--)
for(a=4;a>0;a--);
}
uint8_t EVEN_Generate(uint8_t d)
{
uint8_t ans=0;
uint8_t i=0;
for(i=0;i<4;i++){
ans^=d>>i&0X01;
}
d=d<<1|ans;
return d;
}
void TAG_BIT_1(void)
{
TAG_OUT=1;
DELAY256();
TAG_OUT=0;
DELAY256();
}
void TAG_BIT_0(void)
{
TAG_OUT=0;
DELAY256();
TAG_OUT=1;
DELAY256();
}
void TAG_Send_Bit(uint8_t b)
{
if(b){
TAG_BIT_1();
}else{
TAG_BIT_0();
}
}
void TAG_Send_5_Bits(uint8_t d)//高位先发
{
uint8_t i=0;
for(i=0;i<5;i++){
TAG_Send_Bit(d>>(4-i)&0X01);
}
}
void TAG_Send_4_Bits(uint8_t d)//高位先发
{
uint8_t i=0;
for(i=0;i<4;i++){
TAG_Send_Bit(d>>(3-i)&0X01);
}
}
void TAG_Send_Begin(void)
{
uint8_t i=0;
for(i=0;i<9;i++){
TAG_Send_Bit(1);
}
}
void TAG_Send_End(void)
{
TAG_Send_Bit(0);
}
void TAG_Send_ID(uint8_t id[])
{
uint8_t i=0;
TAG_Send_Begin();
for(i=0;i<10;i++){
TAG_Send_5_Bits(id[i]);
}
TAG_Send_4_Bits(id[i]);
TAG_Send_End();
}
void ID_Process(uint8_t id[])
{
uint8_t i=0;
id[10]=0;
for(i=0;i<10;i++){
id[10]=id[10]^id[i];
}
for(i=0;i<10;i++){
id[i]=EVEN_Generate(id[i]);
}
}
void main(void)
{
uint8_t LGA[11]={5,7,2,0,1,9,2,7,2,1};
ID_Process(LGA);
while(1){
TAG_Send_ID(LGA);
}
}
最后
以上就是忧心唇膏为你收集整理的STM32解码EM4100的曼彻斯特编码(库函数版本)前言:EM4100简介:EM4100数据帧格式曼彻斯特编码:STM32F103RBT6解码EM4100:行校验以及列检验思路:代码片段:的全部内容,希望文章能够帮你解决STM32解码EM4100的曼彻斯特编码(库函数版本)前言:EM4100简介:EM4100数据帧格式曼彻斯特编码:STM32F103RBT6解码EM4100:行校验以及列检验思路:代码片段:所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复