IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> STM32解码EM4100的曼彻斯特编码(库函数版本) -> 正文阅读

[嵌入式]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码的空格
		}
	}
}
  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2021-07-26 12:14:17  更:2021-07-26 12:15:42 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年4日历 -2024/4/20 10:07:47-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码