STM32解码EM4100的曼彻斯特编码(库函数版本)

前言:

前些日子老师布置一个任务叫我们焊接一个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数据帧格式

EM4100数据帧模式

要点:

  • 数据总共有64bit。
  • 以连续的9个1开头。
  • 前4个bit为厂商位。
  • 采用偶校验的方法。(保证1的个数为偶数个)
  • 最后一列为行校验。
  • 最后一行为列检验。
  • 数据最后一位为0。

曼彻斯特编码:

两种格式刚好相反:

  • 第一种:(EM4100采用这种编码)
    1:高电平到低电平(下降)
    0:低电平到高电平(上升)
  • 第二种:
    1:低电平到高电平(上升)
    0:高电平到低电平(下降)

下图为一次完整的EM4100帧数据
图为完整的EM4100数据帧格式

STM32F103RBT6解码EM4100:

思路:

  1. 首先找到高电平时间或者低电平时间在512us附近。
  2. 找到后标记已经同步,并且此时为一次有效捕获中断。
  3. 下一次上升沿或者下降沿必须距离上一次有效捕获中断512us附近。
  4. 选用uint64_tRFID_DATA来存放每一次有效数据。
  5. 采集完一次有效捕获中断后检查RFID_DATA是否以连续的9个1开头并且最后一位为0。
  6. 如果满足条件则标记采集完成。否则继续采集。

采用的外设: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);
    }
 }
  • 13
    点赞
  • 50
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
EM4100卡是一种低频非接触式射频识别卡,常用于门禁系统、考勤系统等。下面是关于EM4100卡的相关问题的解答。 1. EM4100卡是什么? EM4100卡是一种低频射频识别卡,工作频率为125kHz,包装形式为芯片与线圈封装在一起的卡片。它采用125kHz的射频信号进行无线识别和通信,用于门禁、考勤、物品追踪等应用。 2. 如何读取EM4100卡的信息? 读取EM4100卡的信息需要使用与之兼容的读卡器设备。读卡器通过射频信号与卡片进行通信,读取卡片上存储的标识码或其他信息。读卡器一般通过USB、串口或者无线方式与计算机或其他设备连接,将读取到的信息传输给相应的应用程序进行处理。 3. EM4100卡的特点有哪些? EM4100卡具有价格低廉、传输距离较短、读取速度快等特点。它的通信协议简单,适用于一些对安全性要求不高的应用场景。 4. 如何编程控制EM4100卡? EM4100卡的编程操作一般需要通过特定的编程设备或者读卡器来进行。根据不同的需求,可以对卡片进行读取、写入、擦除等操作。编程操作需要遵循EM4100卡的通信协议规范进行。 5. EM4100卡的应用领域有哪些? EM4100卡广泛应用于门禁系统、考勤系统、图书馆管理、宾馆会议室管理、物品追踪等场景。它可用于识别用户身份、记录出入时间、管理物品位置等。由于其价格低廉,部署方便,被广泛应用于各种需要射频识别的场景。 以上是关于EM4100卡的一些相关问题的简要回答。希望对您有所帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值