数码之家

 找回密码
 立即注册
搜索
查看: 14225|回复: 34

[C51] 125KHZ门禁卡RFID卡读卡器模拟卡功能集合一体共用一个线圈

[复制链接]
发表于 2019-6-1 14:32:06 | 显示全部楼层 |阅读模式

爱科技、爱创意、爱折腾、爱极致,我们都是技术控

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

x
本帖最后由 xueyunmichen 于 2019-6-1 14:52 编辑

之前有人想要的 125KHZ ID卡 读卡 与 模拟卡一体合并的 现在奉上

验证 图片在二楼

用STC15W4K系列单片机的高级PWM 输出125khz载波信号;
01.jpg



以下代码
  1. #include <STC15.H>

  2. #define uchar unsigned char
  3. #define uint  unsigned int
  4.         
  5. #define FOSC 12000000L          //系统频率
  6. #define BAUD 115200             //串口波特率


  7. #define S1_S0 0x40              //P_SW1.6
  8. #define S1_S1 0x80              //P_SW1.7
  9.         
  10. sbit KEY1 = P3^4;

  11. void IntPWM(bit dat)
  12. {
  13.         P2M0=0X20;                //初始化PWM端口 P2^1 口
  14.         P2M1=0X00;        

  15.         P_SW2 |= 0x80;        
  16.         PWMCFG = 0x00;
  17.         PWMCKS = 0x00;                  //选择PWM的时钟为Fosc/1
  18.         PWMC = 95;                           //设置PWM周期        
  19.         PWM2T1 = 0;                                //设置PWM2第1次反转的PWM计数
  20.         PWM2T2 = 20;                        //设置PWM2第2次反转的PWM计数        
  21.         PWM3T1 = 48;                               //设置PWM3第1次反转的PWM计数
  22.         PWM3T2 = 68;                        //设置PWM3第2次反转的PWM计数        
  23.         if(dat)
  24.         {
  25.                         PWMCR = 0x00;                   //PWM通道2使能PWM信号输出
  26.         }
  27.         else
  28.         {
  29.                 PWMCR = 0x03;                   //PWM通道2使能PWM信号输出
  30.                 PWMCR |= 0x80;                  //使能PWM模块
  31.         }        
  32.         P_SW2 &= ~0x80;
  33. }






  34. void Timer0Init(bit dat)                //定时器工作于计时模式
  35. {
  36.         AUXR |= 0x80;                //定时器时钟1T模式
  37.         TMOD &= 0xF0;                //设置定时器模式        
  38.         if(dat)
  39.         {
  40.                 TL0 = 0x00;                //设置定时初值                256微秒@12.000MHz
  41.                 TH0 = 0xF4;                //设置定时初值
  42.                 TF0 = 0;                //清除TF0标志
  43.                 ET0 = 1;                //定时器中断
  44.                 TR0 = 1;                //定时器计时
  45.         }
  46.         else
  47.         {
  48.                 TL0 = 0x00;                //设置定时初值
  49.                 TH0 = 0x00;                //设置定时初值        
  50.                 TF0 = 0;                //清除TF0标志
  51.                 ET0 = 0;                //定时器中断
  52.                 TR0 = 0;                //定时器计时
  53.         }        
  54. }



  55. void Timer2Init(void)                //1毫秒@12.000MHz
  56. {
  57.         T2L = 0x20;                //设置定时初值
  58.         T2H = 0xD1;                //设置定时初值
  59.         AUXR |= 0x14;                //定时器2开始计时
  60.         IE2 |= 0X04;        
  61. }


  62. void Uart_Init()
  63. {
  64.         ACC = P_SW1;
  65.     ACC &= ~(S1_S0 | S1_S1);    //S1_S0=0 S1_S1=0
  66.     P_SW1 = ACC;                //(P3.0/RxD, P3.1/TxD)   
  67.     SCON = 0x50;                //8位可变波特率
  68.     AUXR = 0x40;                                //定时器1为1T模式
  69.     TMOD = 0x00;                                //定时器1为模式0(16位自动重载)
  70.     TL1 = (65536 - (FOSC/4/BAUD));           //设置波特率重装值
  71.     TH1 = (65536 - (FOSC/4/BAUD))>>8;
  72.     TR1 = 1;                                           //定时器1开始启动
  73.     ES = 1;                                                         //使能串口中断
  74. }


  75. uchar keyf=0;        //按键有效

  76. uchar  num_check=0;//低电平有效时间

  77. uchar anjian(void)
  78. {
  79.         unsigned char  num_key=0;//按键号  
  80.         static unsigned char  temp_code=0;//保存按键值  
  81.         static unsigned char  key_flag=0;//按键有效标识  
  82.         if(!KEY1)        //如按键按下
  83.         {
  84.                 keyf=1;        //按键按下 定时器2中断函数中 num_check 每1毫秒自加
  85.                
  86.                 temp_code = 1;        //记录按键号
  87.         
  88.                 if(num_check >= 50)        //当按键有效时间到达50毫秒
  89.                 {
  90.                         num_check = 50;        //保持计数时间
  91.                         key_flag = 1;        //按键有效        
  92.                 }
  93.                                 
  94.         }
  95.         else                                                //如松开按键
  96.         {
  97.                 keyf=0;                                        //按键松开停止计时
  98.                 num_check = 0;                        //计时时间清零
  99.                 if(key_flag == 1)                //如果按键有效
  100.                 {
  101.                         key_flag = 0;                //清除按键有效标识
  102.                         switch(temp_code)
  103.                         {
  104.                                 case 1: num_key=1;//记录按键号
  105.                                                  break;
  106.                         }
  107.                 }
  108.                 else num_key = 0;                //如果按键无效        清除按键号
  109.         }
  110.         return(num_key);                        //返回按键号
  111. }

  112. bit busy; //串口忙
  113. /*----------------------------
  114. 发送串口数据
  115. ----------------------------*/
  116. void SendData(uchar dat)
  117. {
  118.     while (busy);               //等待前面的数据发送完成
  119.     busy = 1;
  120.     SBUF = dat;                 //写数据到UART数据寄存器
  121. }



  122. bit jj;                        //开启串口打印标识
  123. uint time;                //记录时间
  124. bit tou=0;                //数据头
  125. bit FLAG=1;                //端口状态
  126. bit kt=1;                //空跳
  127. uchar k2=0;                //位 接收数
  128. uchar k=0,k1=0;        //数据头检测计数,数据缓存
  129. uchar i=0;                //字节 接收数

  130. uchar SCK=0;        //时钟周期
  131. bit dat1=0;                //数据发送标识

  132. uchar DD[8]={0};        //数据接收缓存数组
  133. uchar DD1[8]={0xFF, 0x99, 0x20, 0x00, 0xE5, 0xe0, 0x52, 0xe2}; //发送数据

  134. bit ka=0;                //1:模拟卡,0:读卡器


  135. void setka()        //卡号调制函数
  136. {
  137.         static uchar j1=0,k3,i1=0;        //发送字节计数 ,待发送数据缓存,发送位计数
  138.         if(i1==0)                //若发送位计数为零
  139.         k3 = DD1[j1];        //缓存下一个字节数据到发送缓存
  140.                         
  141.         if(SCK==0)                //如时钟在0*256us 开始准备数据 高位先发
  142.         {
  143.                         if(!(k3&0x80))          P33 = 0;        //如果待发送位 为“0” 需要上升沿 所以 数据发送口准备为 “0”
  144.                         if(  k3&0x80)    P33 = 1;        //如果待发送位 为“1” 需要下降沿 所以 数据发送口准备为 “1”               
  145.         }
  146.                
  147.         if(SCK==1)                //如果时钟到达第一个256us  开始发送 边沿
  148.         {
  149.                 if(!(k3&0x80))         {P33 = 1;dat1 = 1;}        //如果待发送位 为“0” 需要上升沿 所以 数据发送口发送上升沿 “1” 并记录数据已经发送
  150.                 if(  k3&0x80)   {P33 = 0;dat1 = 1;}        //如果待发送位 为“1” 需要下降沿 所以 数据发送口发送下降沿 “0” 并记录数据已经发送
  151.         }
  152.                
  153.         if(SCK >= 2)        //如果时钟到达512us
  154.         {
  155.                 SCK = 0;        //时钟清零
  156.                         
  157.                 if(dat1 == 1)        //如果数据已经发送
  158.                 {
  159.                         dat1 = 0;        //清除数据发送标识
  160.                         i1++;                //发送位 加1
  161.                         k3 = k3 << 1;        //数据缓存左移 发送下一位
  162.                                 
  163.                         if(i1==8)         //如果已经发完8个位
  164.                         {
  165.                                 i1=0;        //发送位计数清零
  166.                                 j1++;        //发送字节计数自加
  167.                                 if(j1 >= 8) j1 = 0;        //如果发送完8个字节(发完全部数据) 清零字节计数
  168.                         }                                
  169.                 }                        
  170.         }               
  171. }
  172. //P32        读卡数据输入(中断解码)
  173. //P33        模拟卡调制端口
  174. //P34        按键端口
  175. //P35        指示灯 高电平为读卡器模式 低电平为模拟卡模式
  176. //P37        125KHZ输出
  177. void main()
  178. {
  179.         uchar key=0;
  180.         uchar j;
  181.         P3M0=0XA8;
  182.         P3M1=0X00;                                        //初始化端口
  183.         Uart_Init();                                //串口初始化
  184.         if(!ka)                                                //如果为读卡器模式
  185.         {
  186.                 IntPWM(0);                                        //PWM初始化为125khz 占空比50%
  187.                 Timer0Init(0);                                //定时器0初始化为计时器
  188.                  EX0 = 1;                    //使能INT0中断
  189.         }
  190.         Timer2Init();                                //定时器1初始化
  191.         P33 = 0;                                        //调制端口置低
  192.         P32 = 1;                                        //
  193.     IT0 = 0;                    //设置INT0  上升沿和下降沿中断
  194.         EA=1;                                                //总中断开
  195.         while(1)
  196.         {               
  197.                 key = anjian();                        //检测按键
  198.                 if(key==1)                                //如果按键按下
  199.                 {
  200.                         key=0;                                //清除按键
  201.                         
  202.                         ka = ~ka;                        //改变模式
  203.                         P35 = ~P35;                        //改变指示灯状态
  204.                         if(ka)                                //如果模拟卡
  205.                         {
  206.                                 EX0 = 0;                                        //关闭外部中断
  207.                                 IntPWM(1);                                        //关闭PWM
  208.                                 P37=0;                                                //125KHZ端口置低
  209.                                 TR0 = 0;                                        //关闭计时        
  210.                                 TL0 = 0x00;                                        //计时器清零
  211.                                 TH0 = 0x00;        
  212.                                 Timer0Init(1);                                //定时器0初始化为定时器 256us        
  213.                                 SCK=0;                                                //发送时钟清零
  214.                         }
  215.                         if(!ka)                        //如果读卡器模式
  216.                         {
  217.                                 P33=0;                //模拟卡调制端口置低
  218.                                 tou=0;                //清除读卡模式一些状态
  219.                                 k=0;                //清除读卡模式一些状态
  220.                                 k1=0;                //清除读卡模式一些状态
  221.                                 k2=0;                //清除读卡模式一些状态
  222.                                 i=0;                //清除读卡模式一些状态
  223.                                 IntPWM(0);                                        //开启PWM
  224.                                 Timer0Init(0);                                //定时器0初始化为计时器
  225.                                 EX0 = 1;                                        //开启外部中断
  226.                         }
  227.                 }
  228.                 if(ka)setka();        //如果模拟卡 则运行模拟卡函数
  229.                 if(jj)                        //如果开启打印
  230.                 {                          
  231.                         jj=0;
  232.                         for(j=0;j<8;j++)
  233.                         {
  234.                                 SendData(DD[j]);//串口打印接收到的8字节数据
  235.                                 DD1[j]=DD[j];        //更新发送卡号数据
  236.                         }  
  237.                 }
  238.         }
  239. }


  240. uchar zdjs=0;        //无卡计时
  241. uchar rcc=0;        //读取校验计数
  242. void exint0() interrupt 0                      //INT0中断入口
  243. {
  244.         TR0 = 0;                                                //关闭计时        
  245.         FLAG=P32;                                                //记录信号状态(0:下降沿; 1:上升沿)
  246.         
  247.         time= ((TH0<<8) + TL0)/12;                //记录中断事件
  248.         TL0 = 0x00;                                                //计时器清零
  249.         TH0 = 0x00;                                                //计时器清零
  250.         TR0 = 1;        
  251.         if((time>200) && (time<520))        //过滤杂波信号 只处理中断时间为180-520微秒 的事件
  252.         {
  253.                 if(time>400)        kt=0;                //如果时间大于400微妙 则认为非空跳(有效边沿)
  254.                 if(time<256)                                //如果时间小于256微秒
  255.                 {
  256.                         if(kt==0) kt=1;                //如果上一次边沿 非空跳边沿 则记录为空跳        
  257.                         else kt=0;                                //否则 记录为非空跳        (有效边沿)
  258.                 }               
  259.                 if((!kt)  && (rcc<48))                                         //如果是有效边沿
  260.                 {
  261.                         if(!tou)                                //如果没有接收到数据头 则记录数据头 (9个下降沿)
  262.                         {
  263.                                 
  264.                                 if(FLAG) k++;                //如果为下降沿 开始记录
  265.                                 if(!FLAG)  k = 0;        //过程中 收到上升沿 记录清零
  266.                                 
  267.                                 if(k == 9) {k=0; tou =1;DD[i++]=0xff;}        //如果记录到9个下降沿 则已经取得数据头 头标识置位, 第一位数据记录为 0xff
  268.                         }
  269.                         if(tou)                                                        //如果已经获取数据头
  270.                         {
  271.                                 k1 <<= 1;                                        //数据左移一位 开始接收数据 高位在前 低位在后                                
  272.                                 if(FLAG) k1 |= 0x01;                //如果是下降沿 则为 “1” 如为上升沿 则记录为“0”        
  273.                                 k2++;                                                //记录次数标识
  274.                                 if(k2 == 8)                                        //如果记录到8次 则已经接收完一个字节
  275.                                 {
  276.                                         k2=0;                                        //记录次数清零
  277.                                        
  278.                                         if(DD[i] == k1) rcc++;
  279.                                         else rcc=0;
  280.                                         DD[i++] = k1;                        //将数据存入缓存 进行下一个字节的接收
  281.                                         k1=0;                                        //清零接收数据
  282.                                         if(i==8)                                //如果接收到八个字节 则接收完成                                
  283.                                         {
  284.                                                 i=0;                                //字节数清零
  285.                                                 tou=0;                                //清除数据头标识
  286.                                                 if((rcc>=16)&&(rcc<48)){jj=1;rcc=48;}                                //开启串口输出
  287.                                         }                                       
  288.                                 }                                
  289.                         }
  290.                 }
  291.         }
  292.         else                //清除读卡器接收状态
  293.         {
  294.                 tou=0;
  295.                 k=0;
  296.                 k1=0;
  297.                 k2=0;
  298.                 i=0;
  299.                 jj=0;
  300.         }
  301.         zdjs=0;        //清除无卡计时                                       
  302. }
  303. //定时器0中断函数
  304. void Timer0Interrupt(void) interrupt 1
  305. {
  306.         if(!ka)
  307.         {
  308.                 TR0 = 0;        //超时中断
  309.                 kt=0;                //记录为非空跳
  310.         }               
  311.         if(ka)SCK++;
  312. }
  313. //定时器2中断函数
  314. void Timer2Interrupt(void) interrupt 12
  315. {               
  316.         if(keyf)        //如果按键按下
  317.         num_check++;//按下时间计时
  318.         zdjs++;        //无卡计时
  319.         if(zdjs>=2)rcc=0;//如2毫秒内无中断 则判断移除卡片
  320. }
  321. /*----------------------------
  322. UART 中断服务程序
  323. -----------------------------*/
  324. void Uart() interrupt 4 using 1
  325. {
  326.     if (RI)        RI = 0;                 //清除RI位
  327.     if (TI)
  328.     {
  329.         TI = 0;                 //清除TI位
  330.         busy = 0;               //清忙标志
  331.     }
  332. }
复制代码

125读卡模拟卡一体.rar (26.63 KB, 下载次数: 77)

打赏

参与人数 2家元 +12 收起 理由
devcang + 7 優秀文章 謝謝分享
keye + 5 優秀文章

查看全部打赏

 楼主| 发表于 2019-6-1 14:45:18 来自手机浏览器 | 显示全部楼层
为何手机不能编辑帖子 另占用一楼算了

两个钥匙片 测试
IMG_20190601_141120.jpg

这是一个认真的读卡器
IMG_20190601_141131.jpg

这个是读卡 模拟一体
读卡器状态 指示灯亮
IMG_20190601_141237.jpg

这个是模拟卡状态 指示灯灭
IMG_20190601_141248.jpg

读卡器读它一下
IMG_20190601_141356.jpg

收到默认卡号
IMG_20190601_141408.jpg

此时将合体机 切换读卡器模式读一张
IMG_20190601_141450.jpg

收到卡号
IMG_20190601_141454.jpg

在读
IMG_20190601_141505.jpg

收到卡号两个
IMG_20190601_141511_1.jpg

此时切换到模拟卡模式  此时将模拟最后一次读到的卡号
IMG_20190601_141539.jpg

读卡器收到卡号
IMG_20190601_141548.jpg

好的 完

打赏

参与人数 1家元 +18 收起 理由
cushion + 18 優秀文章

查看全部打赏

回复 支持 反对

使用道具 举报

发表于 2019-6-1 21:46:23 来自手机浏览器 | 显示全部楼层
mark,能不能改个stc15f2k的?
回复 支持 反对

使用道具 举报

发表于 2019-6-1 21:54:26 | 显示全部楼层

不错,技术牛人!
回复 支持 反对

使用道具 举报

 楼主| 发表于 2019-6-1 22:57:55 来自手机浏览器 | 显示全部楼层
zzj80 发表于 2019-6-1 21:46
mark,能不能改个stc15f2k的?

这个只需改变pwm的设置就可以的 我看看15F2K 的能否输出125Khz
回复 支持 反对

使用道具 举报

 楼主| 发表于 2019-6-1 22:59:05 来自手机浏览器 | 显示全部楼层
devcang 发表于 2019-6-1 21:54
不错,技术牛人!

(((*°▽°*)八(*°▽°*)))♪
回复 支持 反对

使用道具 举报

发表于 2019-6-2 02:23:16 来自手机浏览器 | 显示全部楼层
xueyunmichen 发表于 2019-6-1 22:57
这个只需改变pwm的设置就可以的 我看看15F2K 的能否输出125Khz

我测试过用高速脉冲模式输出125KHZ,用频率计验证过。比PWM模式简单方便
回复 支持 反对

使用道具 举报

 楼主| 发表于 2019-6-2 07:55:43 来自手机浏览器 | 显示全部楼层
zzj80 发表于 2019-6-2 02:23
我测试过用高速脉冲模式输出125KHZ,用频率计验证过。比PWM模式简单方便

高速脉冲模式需要用到中断 当为默认优先模式  解码中断会扰乱高速中断 导致频率不准 偏移很大 并且不停变化
如设置高速脉冲中断为最高优先 它又会影响解码中断! 要用15f2k 看来需要使用查询方式解码
回复 支持 1 反对 0

使用道具 举报

发表于 2019-6-2 12:05:33 来自手机浏览器 | 显示全部楼层
xueyunmichen 发表于 2019-6-2 07:55
高速脉冲模式需要用到中断 当为默认优先模式  解码中断会扰乱高速中断 导致频率不准 偏移很大 并且不停变 ...

我觉得解码用查询方式好,因为要放卡才需要解码,平时都是待机时间比较多吧
回复 支持 反对

使用道具 举报

发表于 2019-6-2 12:08:16 来自手机浏览器 | 显示全部楼层
xueyunmichen 发表于 2019-6-2 07:55
高速脉冲模式需要用到中断 当为默认优先模式  解码中断会扰乱高速中断 导致频率不准 偏移很大 并且不停变 ...

但是解码程序我一窍不通,只是我觉得查询方式更加合适
回复 支持 反对

使用道具 举报

发表于 2019-6-2 14:46:41 | 显示全部楼层
很厉害啊,支持下
回复 支持 反对

使用道具 举报

发表于 2019-6-4 15:31:55 | 显示全部楼层
这个叫ID卡还是IC卡?
回复 支持 反对

使用道具 举报

 楼主| 发表于 2019-6-4 19:30:42 来自手机浏览器 | 显示全部楼层
feitian227 发表于 2019-6-4 15:31
这个叫ID卡还是IC卡?

低频的125Khz  ID卡
回复 支持 反对

使用道具 举报

发表于 2019-8-23 10:02:38 | 显示全部楼层
STC15W 用定时器对时钟分频输出更方便 就占用一个定时器
也可以把 中断 开了还可以顺带解码
回复 支持 反对

使用道具 举报

发表于 2019-8-23 12:56:00 | 显示全部楼层
要是能写卡就完美了。小区门禁卡好像是125k的,带卡好麻烦,想复制卡贴到手机后面。
回复 支持 反对

使用道具 举报

发表于 2019-8-23 14:54:01 | 显示全部楼层
stc8A可行?可能推挽输出,这样就不用lm358了啊。
回复 支持 反对

使用道具 举报

发表于 2019-10-9 16:45:40 | 显示全部楼层
xueyunmichen 发表于 2019-6-1 14:45
为何手机不能编辑帖子 另占用一楼算了

两个钥匙片 测试

你好,有没有读过125K 的HID卡呢
回复 支持 反对

使用道具 举报

发表于 2019-10-9 16:47:14 | 显示全部楼层
大家有没有读过125K的HID卡呢?
回复 支持 反对

使用道具 举报

发表于 2020-3-23 23:14:27 | 显示全部楼层
大牛真厉害
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

APP|手机版|小黑屋|关于我们|联系我们|法律条款|技术知识分享平台

闽公网安备35020502000485号

闽ICP备2021002735号-2

GMT+8, 2024-4-27 03:40 , Processed in 0.109200 second(s), 12 queries , Redis On.

Powered by Discuz!

© 2006-2023 smzj.net

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