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;
}
  • 3
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 51单片机是一种非常常用的单片机,它的核心是Intel公司制造的8051系列芯片。125kHz ID卡是一种低频射频卡,它采用125kHz的频率进行通信。而解曼彻斯特是将曼彻斯特进行解码的过程。 在51单片机中使用125kHz ID卡的C程序,主要分为两部分:读取ID卡信息和解码曼彻斯特。 在读取ID卡信息的过程中,首先需要使用51单片机的GPIO口连接到电磁感应模块,然后通过串行通信的方式进行数据交互。通过控制GPIO口的高低电平变化,实现与ID卡的通信。读取ID卡的信息之后,可以将其存储在单片机的内存中,或者通过串口输出。 解码曼彻斯特的过程比较复杂。曼彻斯特是一种基于波形来表示数字的编方式,通过观察波形的升降沿变化来判断传输的数据。解码曼彻斯特的过程需要对接收到的波形进行解码,根据波形的升降沿变化来确定数字的0和1。解码的结果可以根据应用的需求进行处理,例如将其转换为二进制数据进行处理或者输出。 总之,使用51单片机读取125kHz ID卡的C程序中,需要对串行通信进行控制以及解码曼彻斯特的过程。这些步骤需要对硬件和软件进行相应的配置和编程,并根据具体的需求进行调试和优化。 ### 回答2: 51单片机是一种高性能、低功耗的单片机芯片,广泛应用于嵌入式系统开发中。125kHz ID卡是一种低频射频识别卡,常用于门禁系统、停车场管理等场景。解曼彻斯特是将二进制数据编曼彻斯特信号的过程,用于数据传输中的同步和识别。 在51单片机上编写C程序实现125kHz ID卡的解曼彻斯特过程,需要以下步骤: 1. 配置IO口和中断:使用51单片机的IO口连接到读卡器,配置IO口为输入模式,并启用外部中断。 2. 初始化串口通信:通过串口与电脑进行数据传输,需要初始化串口的参数,如波特率、数据位数、停止位等。 3. 中断服务程序:设置中断服务程序,当IO口检测到信号变化时,触发中断,并执行相应的处理函数。 4. 读取曼彻斯特:在中断处理函数中,读取IO口信号的变化情况,并根据曼彻斯特原理解析出对应的二进制数据。 5. 数据处理和验证:根据ID卡的协议,解析出有效的二进制数据后,对数据进行处理和验证,如校验位校验、数据位截取等。 6. 串口通信:最后,将解析出来的数据通过串口进行传输,可以通过调用串口发送函数实现。 以上是简单的步骤,具体实现还需要根据实际需求和硬件环境进行调整。需要注意的是,51单片机编写C程序时需要熟悉相关的编程语言和51单片机的开发环境,同时了解曼彻斯特和ID卡的相关协议。 ### 回答3: 51单片机是一款常见的单片机系列,适用于各种嵌入式应用场景。而125khz ID卡是一种低频无线射频识别卡,常用于门禁、考勤等领。 解曼彻斯特是指将数据编的一种技术,它通过改变信号的波形来表示0和1两个状态。曼彻斯特中,每一位数据都分为两个时钟周期,根据波形的变化来表示0和1。 在51单片机中使用125khz ID卡进行读取的C程序可以通过以下步骤实现解曼彻斯特: 1. 设置串口通信参数,包括波特率、数据位、停止位等。 2. 确定曼彻斯特的时钟周期,通常为两个时钟周期表示一位数据。 3. 通过串口接收数据,并根据波形的变化判断0和1的状态。 4. 解析数据,获取ID卡的信息。 5. 进行相应的处理,比如验证ID卡的合法性,执行相应的操作等。 需要注意的是,曼彻斯特的解析是基于正确的波形变化来判断的,因此在实际应用中需要考虑噪声、干扰等因素对波形的影响,并采取相应的错误处理机制。 总的来说,通过编写C程序实现51单片机125khz ID卡的读取和解析曼彻斯特,可以实现对ID卡的识别和相应的操作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值