125KHZ RFID 曼彻斯特码在内核域解码

一. 曼彻斯特码理论分析:
曼彻斯特码编码的ID卡每次输出64bit 数据/8个字节,其载波编码为曼彻斯特码.
其时序图如下:
在这里插入图片描述
曼彻斯特码调制方式下,EM4100卡片每传送一位数据的时间是64个振荡周期。125KHZ载波时,卡片传送一bit数据理论频率为125KHz / 64 = 1.953125KHz。那么得到一个周期为:1 000 000us / 1.953125KHz = 512us。

也就是说:曼彻斯特码一个完整的数据跳变为一个周期(512us)。
但是特别需要注意的是:存在空跳则半个跳变为半个周期(256us)。

那么如何得到一个bit的数据呢?

如果捕获到一个电平变化,这个电平距离上次检测到电平变化时间为512us,则该位按以下读取:
	低电平-bit = 1,
	高电平-bit = 0;

如果捕获到一个电平变化,这个电平距离上次检测到电平变化时间256us,则此次不作判断,再次捕获到一个边沿时再判断如下:
	上次bit = 1 此次bit = 1,
	上次bit = 0,此次bit = 0.
此处有一个特别注意的地方,如果上次读取到256us,不管这次读取间隔是256us还是512us,都应该读取上一次的电平,并且重新检测跳包。

二.设备树配置:
配置设备树节点,用于内核驱动程序找到对应能检波的IO口。在anyka v300 平台如下:

编辑:anycloud_ak39ev330_common.dtsi
添加节点:在 gpiokeys: gpiokeys {
compatible = "anyka,ak39ev330-gpiokeys";
		status = "disable";
	};
 附近添加以下节点信息:
 rfid_control: rfid_control {
		compatible = "leo_rfid_control";
		status = "disable";
	};
	编辑:C500_SQ38_AK3918EV330_GC2063_MIPI_V1.0.0.dts:
	在"$gpio" 节点内部添加
	rfid_pins:rfid_pins{
	anyka,pins = <0>;
	anyka,function = <0>;
	anyka,pull = <0x00000001>;
    };

    然后退出$gpio节点,使能“rfid_control”节点,如下:
    
    &rfid_control{
    gpios = <&gpio 0 1>;
    pinctrl-names ="default";
    pinctrl-0 = <&rfid_pins>;
    status = "okay";
 };

好了,完成了设备树信息的编写,

第二部:接下来开始写驱动内核程序。
整个代码如下:

#include <linux/module.h>
#include <linux/poll.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>
#include <linux/gpio/consumer.h>
#include <linux/platform_device.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/slab.h>
#include <linux/fcntl.h>
#include <linux/timer.h>
#include <linux/workqueue.h>
#include <asm/current.h>
#include <linux/kthread.h>
#include <linux/delay.h>

#define diff_us(t1,t2) ((u64)t1.tv_sec - (u64)t2.tv_sec) * 1000000 + ((u64)t1.tv_usec - (u64)t2.tv_usec);

#define rfid_code_bit_value(data,index) ((data[(index)/8] >> (7 - (index)%8))&0x01)
/* 主设备号 */
static int major = 0;
/* 创建设备类的结构体 */
static struct class* rfid_class;
/* 记录设备树信息的结构体*/
static int rfid_gpio_index;

static struct task_struct *rfid_kthread;   

static char rfid_data_code[16] = {0};
static int rfid_data_count = 0;

static char rfid_code_number[4] = {0};
static char rfid_code_number_ready = 0;

static DEFINE_MUTEX(rfid_code_mutex);


static ssize_t rfid_read(struct file* file,char __user*buf,size_t size,loff_t* offset){
	
	int len  = 0;
	if(size < 4){
		return 0;
	}
	
	len = sizeof(rfid_code_number);
	//printk("read rfid value \n");	
	mutex_lock(&rfid_code_mutex);
	if(rfid_code_number_ready == 0){
		mutex_unlock(&rfid_code_mutex);
		return 0;
	}
	
	copy_to_user(buf, rfid_code_number , len); 
	rfid_code_number_ready = 0;
	mutex_unlock(&rfid_code_mutex);
	return len;
}
/* 创建设备方法 */
static struct file_operations rfid_control_fops = {
	.owner = THIS_MODULE,
	.read = rfid_read,
};

static int rfid_code_leave_wait(int* level,int min,int middle,int max,struct timeval* pre_tv){
	
	u64 us = 0;
  	struct timeval tv;
  	
  	int cur_level = gpio_get_value(rfid_gpio_index) ;
	while(gpio_get_value(rfid_gpio_index) == cur_level){
	
		do_gettimeofday(&tv);
		us = diff_us(tv,(*pre_tv));
		
		if(us > max){
			return -1;
		}
	}
	do_gettimeofday(&tv);
	us = diff_us(tv,(*pre_tv));
	*level = cur_level?0:1;
	if(us < min){
		return -1;
	}
	else if((us > min)&&(us < middle)){
		return 0;
	}
	return 1;
}

static char rfid_code_jump_flg = 0;

static int rfid_code_read_proc(void){

	int i = 0;
	int reslut = 0;
	int level = 0;
	struct timeval tv;
	unsigned char value = 0;

	memset(rfid_data_code,0,sizeof(rfid_data_code));
	rfid_data_count = 0;
	rfid_code_jump_flg = 0;
	do_gettimeofday(&tv);
	while(1){
	
		reslut = rfid_code_leave_wait(&level,125,375,625,&tv);
		do_gettimeofday(&tv);
		if((reslut == 0)&&(rfid_code_jump_flg == 0)){

			rfid_code_jump_flg = 1;
		}
		else if((reslut == 1)||((reslut == 0)&&(rfid_code_jump_flg == 1))){
		
			if(rfid_code_jump_flg == 1){
			
				value = ((rfid_data_code[(rfid_data_count - 1) / 8] >> (7 - (rfid_data_count - 1) % 8)) & 0x01) ? 1 : 0;
			}
			else{
				value = level?0:1;
			}
			
			rfid_code_jump_flg = 0;
			rfid_data_code[rfid_data_count / 8] |= (value << (7 - rfid_data_count % 8));
			rfid_data_count++;
			if(rfid_data_count >= 128){
			
				return 1;
			}
		}
		else if(reslut < 0){
			
			return -1;
		}
	}
	return 0;
}

static int rfid_code_data_check(void){

	int index = 0,i = 0,j = 0,n = 0;
	int value = 0;
	for(index = 0; index < 64 ; index++){
		
		value = 0;
		for(i = 0 ; i < 9 ; i++){
		
			value <<= 1;
			value |= rfid_code_bit_value(rfid_data_code,index + i);
			//printk("%d",rfid_code_bit_value(rfid_data_code,index + i));
		}
		
		if(value == 0x1FF){
			index += 9;
			break;
		}
	}
	
	if(index == 64){
	
		printk("check rfid data failed (%s,%d)\n",__func__,__LINE__);
		return -1;
	}
	
	for(i = index; i < (index + 45) ; i+=5){
		
		value = 0;
		for( j = 0 ;j < 4 ; j++){
		
			value += rfid_code_bit_value(rfid_data_code,i + j);
		}
		if((value %2) != rfid_code_bit_value(rfid_data_code,i + j)){
		
			printk("check rfid data failed (%s,%d)\n",__func__,__LINE__);
			return -1;
		}
	}
	
	for( i = index; i < (index + 4) ; i++){
	
		value = 0;
		for( j = 0 ; j < 50 ; j+= 5){
		
			value += rfid_code_bit_value(rfid_data_code,i + j);
		}
		
		if((value %2) != rfid_code_bit_value(rfid_data_code,i + j)){
			
			printk("check rfid data failed (%s,%d)\n",__func__,__LINE__);
			return -1;
		}
	}
	
	if(rfid_code_bit_value(rfid_data_code,index + 54) != 0){
	
		printk("stop failed \n");
		return -1;
	}
	n = 0;
	mutex_lock(&rfid_code_mutex);
	rfid_code_number_ready = 0;
	mutex_unlock(&rfid_code_mutex);
	memset(rfid_code_number,0,sizeof(rfid_code_number));
	for(i = index + 10 ; i < (index + 50) ; i+=10){
		
		value = 0;
		for( j = 0 ; j < 9; j++){
		
			if(j == 4){
			
				continue;
			}
			value <<= 1;
			value |= rfid_code_bit_value(rfid_data_code,i+j);
			
		}
		rfid_code_number[n++] = value;
		//printk("%02x ",value);
	}
	//printk("\n");
	
	mutex_lock(&rfid_code_mutex);
	rfid_code_number_ready = 1;
	mutex_unlock(&rfid_code_mutex);
	return 1;
}

static int k_rfid_task(void*data){

	int pre_level = gpio_get_value(rfid_gpio_index);
	int cur_level = pre_level;
	char det_start_flag = 0;
	
	printk("leo:kernel rfid card task success! \n");
	while(1){
	
		if(kthread_should_stop()){
			break;
		}
		
		if(det_start_flag == 0){
			cur_level = gpio_get_value(rfid_gpio_index);
			if(cur_level == 0){
				det_start_flag = 1;
				pre_level = cur_level;
			}
			else
			{
				msleep(100);
			}
		}
		else{
		
			if(rfid_code_read_proc() == 1){
				
				//printk("check data \n");
				rfid_code_data_check();	
			}
			gpio_set_value(rfid_gpio_index,1);
			pre_level = gpio_get_value(rfid_gpio_index);
			det_start_flag = 0;
			msleep(10);
		}
	}
	return 0;
}

static int rfid_probe(struct platform_device*pdev){

	int irq;
	struct device_node *np = pdev->dev.of_node;
	printk("leo:rfid probe success \n");
	rfid_gpio_index = of_get_named_gpio(np, "gpios", 0);
	if(rfid_gpio_index < 0){
	
		printk("rfid gpio setting failed\n");
	}
	else{
		printk("rfid setting gpio%d\n",rfid_gpio_index);
	}
	device_create(rfid_class,NULL,MKDEV(major,0),NULL,"rfid_control");
	
	gpio_direction_output(rfid_gpio_index,1);
	msleep(100);
	gpio_direction_input(rfid_gpio_index);
	
	mutex_init(&rfid_code_mutex);
	
	rfid_kthread = kthread_create(k_rfid_task,NULL,"rfid_kthread");
	if(IS_ERR(rfid_kthread)){
		printk("create rfid_kthread faield\n");
		return 0;
	}
	wake_up_process(rfid_kthread);
	return 0;	
}

static int rfid_remove(struct platform_device*pdev)
{
	int irq;
	printk("leo:rfid driver remove\n");
	kthread_stop(rfid_kthread);
	
	device_destroy(rfid_class,MKDEV(major,0));
	return 0;
}

static const struct of_device_id rfid_board_control[]={
	{.compatible = "leo_rfid_control"},
	{}
};

static struct platform_driver rfid_platform_drv = {
	
	.probe = rfid_probe,
	.remove = rfid_remove,
	.driver = {
		.name = "rfid_control",
		.of_match_table = rfid_board_control,
	},
};

static int __init rfid_drv_init(void){

	printk("leo:rfid drv init start\n");
	
	//注册主字符设备号
	major = register_chrdev(0,"rfid_control",&rfid_control_fops);
	
	//创建设备类
	rfid_class = class_create(THIS_MODULE,"rfid_class");
	if(IS_ERR(rfid_class)){
		printk("rfid class create failed\n");
		unregister_chrdev(major,"rfid_control");
		return PTR_ERR(rfid_class);
	}
	
	return platform_driver_register(&rfid_platform_drv);
}



static void __exit rfid_drv_exit(void){

	platform_driver_unregister(&rfid_platform_drv);
	class_destroy(rfid_class);
	unregister_chrdev(major,"rfid_control");
}

/*
* ko创建
*/
module_init(rfid_drv_init);
module_exit(rfid_drv_exit);

MODULE_LICENSE("GPL");

生成rfid.ko之后,上次insom rfid.ko,完成内核模块的安装。
第三步:应用层的编写:
整体代码如下:

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>

#define RFID_DEVICE_PATH "/dev/rfid_control"

int main(int argc,char** argv){

	if(access(RFID_DEVICE_PATH,F_OK) != 0){
		
		printf("%s not exit\n",RFID_DEVICE_PATH);
		return 0;
		
		
	}
	
	int fd = open(RFID_DEVICE_PATH,O_RDONLY);
	if(fd < 0 ){
	
		printf("open %s failed \n",RFID_DEVICE_PATH);
		return 0;
	}
	
	unsigned char data[4] = {0};
	while(1){
	
		if(read(fd,data,sizeof(data)) == 4){
		
			printf("%02x%02x%02x%02x\n",data[0],data[1],data[2],data[3]);
		}
		usleep(1000*10);
	}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值