搜索
bottom↓
回复: 181

处女贴,看到这个版块的出现,迫不及待地把自己刚做好的RFID卡读卡解码程序同大家分享,带

  [复制链接]

出0入0汤圆

发表于 2011-4-25 11:58:11 | 显示全部楼层 |阅读模式
潜水有N天后,今天终于与大家分享一下我的东东。
看到这个版块的出现,相当鸡动,因为这几天刚好在搞RFID卡读卡解码的程序。
在坛里找了些资料,也看了此人家的程序。部分是用延时方式,用定时方式的好像说成功率不高。
由于延时方式占用CPU资源太高,所以我还是想自己写一个用定时器+外部中断引脚方式的程序,
当然,各位可以根据自己硬件的用定时器输入捕获方式,原理一样。
我用的是STM8三合1的板子做的,用PC3口作读卡头数据输入(中断方式),
用定时器2时间计数器,把解码得到的数据通过串口发送出去。
下面贴出我写的中断服务程序,可以直接使用。
环境是STVD V4.1.6,
编译器是COSMIC STM8 C Compiler 16K ,Version: 4.3.1
调用的库有:GPIO,TIM2

相关宏定义:

//RF数据引脚
#define DATA_PORT   GPIOC
#define DATA_PIN    GPIO_PIN_3

//定义每一位的宽度,t/4us
#define BIT_TIME        128//一位数据时间
#define HAFE_TIME       64//半位数据时间
#define ERROR_BAND      10//允许是时间误差
#define BIT_HAFE_TIME   192//1.5位数据时间

//端口C外部中断,捕捉RFID卡数据输出的所有电平跳变
@far @interrupt void IntSrvPortC(void)
{
    unsigned char ucTemp;
    unsigned char ucCurrBitTime;
    _Bool bData;
   
    static _Bool s_bLastData;
   
    //先读取定时器计数器,即与上次中断的时间间隔,这是当前位的位宽
    //定时器每个值为4us,单独开启一个定时器计数
    if(TIM2->CNTRH == 0)
    {
        ucCurrBitTime = TIM2->CNTRL;
    }
    else//如果定时时间超过255,则以255计算
    {
        ucCurrBitTime = 255;
    }
    TIM2_SetCounter(0);//复位计数器,从0开始重新计时
   
    //接收到数据,接收超时计数器清零
    g_ucNoDataCnt = 0;
   
    //开始接收
    if(s_ucBitCounter < 18)//同步头,一共9个1,所以有18个跳变
    {
        if(s_ucBitCounter == 0)
        {
            //先找上升沿,数据0
            if(RESET != GPIO_ReadInputPin(DATA_PORT,DATA_PIN))
            {
                //找到上升沿,进入下一步
                s_ucBitCounter = 1;
            }
        }
        else if(s_ucBitCounter == 1)
        {
            //再找下降沿,如果上次的上升沿与本下降沿时间间隔为1个数据周期,则为连续的"01"
            //高电平时间持续1个数据周期,必定是"01"
            if(RESET == GPIO_ReadInputPin(DATA_PORT,DATA_PIN)//本次为下降沿
            && ucCurrBitTime > BIT_TIME - ERROR_BAND)//一个周期以上的高电平
            {
                //找到"01",进入下一步
                s_ucBitCounter = 2;
            }
            else//不是"01",重新找"01"
            {
                s_ucBitCounter = 0;
            }
        }
        else
        {
            //已经找到"01"了,接下来要再找到连续的8个1
            //若两个电平跳变间隔1个数据周期,则必定出现0,重新找"01"
            if(ucCurrBitTime > BIT_TIME - ERROR_BAND)
            {
                if(RESET == GPIO_ReadInputPin(DATA_PORT,DATA_PIN))//下降沿
                {
                    //本次下降沿,重新找上升沿
                    s_ucBitCounter = 0;
                }
                else//本次上升沿,接着找下降沿
                {
                    s_ucBitCounter = 1;
                }
            }
            else
            {
                s_ucBitCounter++;
                bData = 1;//为下面接收到数据作准备
            }
        }
    }
    else//获取同步头成功
    {
        //根据本次电平跳变情况,与上次跳变间隔,及上次数据位,
        //可判断出本次跳变是空跳还是有效数据
        //本次是下降沿
        if(RESET == GPIO_ReadInputPin(DATA_PORT,DATA_PIN))
        {
            //与上次跳变间隔1个数据周期,说明高电平持续了1个数据周期,必然是1
            if(ucCurrBitTime > BIT_TIME - ERROR_BAND)
            {
                bData = 1;
            }
            //与上次跳变间隔半个周期,若上次数据为1,本次数据也为1
            //即连续的两个1
            else if(s_bLastData == 1)
            {
                bData = 1;
            }
            //间隔不足1个数据周期,且上次数据为0,则本次是空跳
            else
            {
                return;
            }
        }
        //本次上升沿
        else
        {
            //与上次跳变间隔1个数据周期,说明低电平持续了1个数据周期,必然是0
            if(ucCurrBitTime > BIT_TIME - ERROR_BAND)
            {
                bData = 0;
            }
            //与上次跳变间隔半个周期,若上次数据为0,本次数据也为0
            //即连续的两个0
            else if(s_bLastData == 0)
            {
                bData = 0;
            }
            //间隔不跳1个数据周期,且上次数据为1,则本次是空跳
            else
            {
                return;
            }
        }
        
        if(s_ucBitCounter >= 73)//同步头18个跳变,加上55个数据位
        {
            //接收到完成数据,重新开始接收数据
            s_ucBitCounter = 0;
            //把数据移出缓冲区,且清空缓冲区
            for(ucTemp=0;ucTemp<11;ucTemp++)
            {
                g_ucData[ucTemp] = g_ucDataBuff[ucTemp] & 0x1f;
            }
            g_bitResevData = TRUE;//接收完成,处理数据
        }
        else
        {
            //把数据放入缓冲区
            ucTemp = s_ucBitCounter - 18;//减去同步头的18个跳变
            ucTemp /= 5;//得到当前接收到的数据属于第几个字节
            g_ucDataBuff[ucTemp] <<= 1;//从高位开始接收
            g_ucDataBuff[ucTemp] += bData;
            s_ucBitCounter++;//继续接收下一位
        }
    }
   
    s_bLastData = bData;//更新历史数据
    return;
}

出0入0汤圆

 楼主| 发表于 2012-9-17 23:12:12 | 显示全部楼层
86793 发表于 2012-9-17 17:31
你好,请问一下EM4095在收发状态时,没有进行读卡时(即ID卡没有靠近时)的电流也有100来mA吗? ...

这个我还真的不太清楚,没用过这个。

出0入0汤圆

 楼主| 发表于 2012-12-5 21:54:40 | 显示全部楼层
本帖最后由 gentlerain 于 2012-12-5 21:56 编辑
czg94215 发表于 2012-11-9 10:19
请教一下楼主, 收到的数据怎么解码 换算得到卡号呢?


各位抱歉了,这么久都没有回复大家的问题.
我这个程序是125K非接触ID卡的解码程序,其中卡体中主要有台湾4001卡和瑞士H4001卡,EM4100。它们都采用125kHz的典型工作频率,有64位激光可编程ROM,调制方式为曼彻斯特码(Manchester)调制,位数据传送周期为512μs,其64位数据结构如下图所示。

连续9位“1”作为头数据,是读取数据时的同步标识;D00~D93位是用户定义数据位;P0~P9是行奇校验位,PC0~PC3是列奇校验位,最后位“0”是结束标志。非接触ID卡的这种数据结构非常有利于判断读出数据的正确性。
至于读到的数据如何转换成卡号,是这样的.
以上图为说明,除了9个同步头和其它的校验,你将收到5个字节的数据.即该芯片的十位 16 进制唯一序列号代码是 84C2A6E195。该卡的序列号代码在卡面印制卡号时,又以这串序列号代码为依据,采用掐头留尾、分段相加、高低倒置等多种转换方式,将其转换为人们易于理解的十进制代码。例如:将上述16进制序列号的低6位印刷为8位10进制代码,即取‘A6E195’转换为‘10936665’;又如:将上述 16 进制序列号取其低 6 位,并将其分为前两位+后4位的微根格式:‘A6’+‘E195’再分别转换为两段 5 位的 10 进制数,段间以小数点或豆号隔开,即印刷卡号为:‘00166,57749’。




本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

 楼主| 发表于 2012-12-5 22:04:25 | 显示全部楼层
下面上传我根据一块读卡头重画的读卡原理图,可用于读取125K的非接触式ID卡.
下图中,PWM输入125KHz的方波,345uH的电感就是感应线圈,可以自己用漆包线绕制.当有卡进入读卡区域时,在LM358的7脚即可接收到数据.

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

 楼主| 发表于 2012-12-5 22:08:01 | 显示全部楼层
正面上传一份清晰的PDF文档,内容同上面的原理图.


本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

 楼主| 发表于 2013-4-17 15:41:49 | 显示全部楼层
下面再详细说说卡号的表示方法。
由于各个厂家的读卡器译码格式不尽相同,在读卡输出时,读出的二进制或十六进制(Hex)结果应该是唯一的,但是又可以通过以下几种主要换算办法,输出不同结果的十进制卡号(Dec),因此,请您一定在购买卡片或卡片喷号时,注意卡号格式的一致性:

1、格式0:10位十六进制的ASCII字符串,即10 Hex格式。
如:某样卡读出十六进制卡号为:“01026f6c3a”。

2、格式1:将格式0中的后8位,转换为10位十进制卡号,即8H---10D。
即将“ 026f6c3a”转换为:“0040856634”。

此格式喷码喷码较为常见。

3、格式2:将格式0中的后6位,转换为8位十进制卡号,即6H---8D。
即将“ 6f6c3a”转换为:“07302202”。

4、格式3:将格式0中的倒数第5、第6位,转换为3位十进制卡号,再将后4位,转换为5位十进制卡号,中间用“,”分开,即“2H + 4H”。
即将2H“ 6f”转换为:“111”,4H “6c3a”转为“27706”。 最终将2段号连在一起输出为“111,27706”。

此格式为标准的韦根26(V26)格式,只使用最后6位编码,也有许多卡采用此格式喷码。

5、格式4:将格式0中后8位的前4位,转换为5位十进制卡号,再将后4位,转换为5位十进制卡号,中间用“,”分开,即“4Hex + 4Hec”。
照此推算结果为:00623,27706 (4H+4H)。

出0入0汤圆

 楼主| 发表于 2013-5-28 12:15:12 | 显示全部楼层
本帖最后由 gentlerain 于 2013-5-28 12:16 编辑
380523337 发表于 2013-5-28 10:36
你好,能不能把定时器2设置贴出?还有可以用定时器1吗?


用任意的定时器都可以,只要定时器的Counter每个值等于4us即可.
不需要开任何中断.前提是不会溢出,因为此程序没有溢出处理.
而且还能与其它定时器共用.
至于定时器的设置,就不用我教你了吧

出0入0汤圆

 楼主| 发表于 2013-6-7 21:05:51 | 显示全部楼层
本帖最后由 gentlerain 于 2013-6-7 21:24 编辑
zyw19987 发表于 2013-6-7 20:35
缺点:定时器4US的中断太频繁,还需要外部中断,没有行列校验。

解决:定时器定时打点采样的方式。 ...


我从来没有说过4us的定时器要开中断啊,只是用来采时间的.只要外部中断进入去读取定时器的计数值就可以了.
校验的工作不放在外部中断里.成功收到数据后志一个标志,在外部处理数据.

出0入0汤圆

 楼主| 发表于 2013-6-8 12:20:07 | 显示全部楼层
zyw19987 发表于 2013-6-8 05:00
只需定时器,和一个普通IO。并非所有单片机都有边缘触发中断的IO,定时器可能溢出。刁难一下楼主,能否做 ...

长短按当然是可以的,跟按键的长短按没什么两样。

出0入0汤圆

 楼主| 发表于 2013-6-9 13:13:00 | 显示全部楼层
jaskle 发表于 2013-6-9 10:01
lZ,这个能读多远的卡?

十来厘米应该没有问题,没仔细测过。

出0入0汤圆

 楼主| 发表于 2013-8-11 16:17:51 | 显示全部楼层
dainqi10 发表于 2013-8-11 00:11
要是有解码程序就好了 哈哈


老兄,这不是解码程序是什么?

出0入0汤圆

 楼主| 发表于 2013-8-31 00:18:52 | 显示全部楼层
dainqi10 发表于 2013-8-30 22:28
我的程序能读出卡,但是不能奇偶校验。还有  距离太短楼主能不能给点建议?是谐振电容不对 还是电压不对   ...

这个电路读卡距离一般10cm左右,跟程序没太大关系。

出0入0汤圆

 楼主| 发表于 2013-10-30 20:40:36 | 显示全部楼层
huangyiting1990 发表于 2013-10-30 09:38
距离能做到多元?

我相信大家对这个距离要求不会太远

出0入0汤圆

 楼主| 发表于 2014-12-2 11:58:48 | 显示全部楼层
wt19891114 发表于 2014-12-1 22:52
楼主还在吗? 请问一下:原理图中的R319是62欧 还是620欧 。 同理,R312 是10欧还是100欧 。  期待您的回复 ...

分别是620欧和100欧.

出0入0汤圆

 楼主| 发表于 2019-4-22 10:49:39 | 显示全部楼层
taojie 发表于 2019-4-21 12:25
距离再加大点就完美了

距离跟电路和天线有关系,我之前做到88mm的天线读28mm的卡,可做到20cm左右

出0入0汤圆

 楼主| 发表于 2019-6-18 17:26:30 | 显示全部楼层
yueming 发表于 2019-6-18 16:30
本人小白一枚,最近在学习125KHZ的 RFID 解码,应用的和楼主是一样的用定时器来计数,因为没有输入捕获通道 ...

有问题直接在这里说吧

出0入0汤圆

 楼主| 发表于 2019-6-19 15:02:36 | 显示全部楼层
yueming 发表于 2019-6-19 14:47
定时器还是不成功,换了几种方式了,大佬们 救命啊

这样很难帮你的,你先把定时器调好吧。
你要对读卡的数据波形有深刻的理解才能知道程序应该怎么写

出0入0汤圆

 楼主| 发表于 2019-6-25 08:44:50 | 显示全部楼层
yueming 发表于 2019-6-24 19:30
楼主,遇见了一个问题,不加行校验和列校验,就能读出数据来,但是只要靠近线圈就会读出数据,不贴着就会读 ...

读卡受距离影响,太近反而读不到的话,要检查你的电路,这跟软件没关系。
至于校验,你还是要认真研读数据格式,看是不是校验过程搞错了
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-4-29 23:41

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表