嵌入式开发记录-day53 门禁系统介绍

1、门禁系统的动作分析

  1、门正常关闭状态:门禁正常关闭状态下,有一个电源指示灯显示电源正常,门正常上锁指示;

  2、门开启状态:人持卡在感应区刷卡,此时门打开,指示灯指示门打开;

  3、在门打开的时候,记录下打开门的时间,并将时间保存在文件中;

2、需要的硬件组件:

  1、正常的4412开发板;

  2、RFID读卡模块,RFID标签(卡),天线板;

3、门禁状态指示灯表示含义:

  1、LED1亮,表示门禁上电正常

  2、LED2闪,表示门禁正常并处于开启状态;

  3、LED2亮,表示门禁处于正常的关闭状态;

  4、开门,关门:使用高低电平表示

4、关于源码分析

  1、由于此次包含较多的头文件和源文键,因此使用Makefile来完成自动化编译,其中脚本文件如下

// 开始编译,生成中间文件object file
arm-none-linux-gnueabi-gcc -c spidev.c -o spidev.o
arm-none-linux-gnueabi-gcc -c main.c -o main.o
arm-none-linux-gnueabi-gcc -c leds.c -o leds.o
arm-none-linux-gnueabi-gcc -c buzzer.c -o buzzer.o
arm-none-linux-gnueabi-gcc -c relay.c -o relay.o
arm-none-linux-gnueabi-gcc -c rtc_record.c -o rtc_record.o
arm-none-linux-gnueabi-gcc -c card_record.c -o card_record.o

// 开始连接,将目标文件,转换成可执行问件
arm-none-linux-gnueabi-gcc -o rc522 spidev.o main.o leds.o buzzer.o relay.o rtc_record.o card_record.o

  2、在主函数中main.c

#include "main.h"

extern int rc522_init(void);
extern void PcdAntennaOn();
extern void HandleConfigMenu(unsigned char inputvalue);

extern void led_control(char *led_dev,int lednum,int cmd);
extern void buzzer_control(char *buzzer_dev , int state);
extern void relay_control(char *relay_dev,int state);

extern void rtc_record(char *rtc_dev,char *file_record);
extern void card_record(char *file_record);

extern unsigned char UID[5];
extern int g_SPI_Fd;
//No card reader led all ON
//Find card state LED1 ON,LED2 OFF
//Open the door led all OFF

int main(void)
{
        // 打开设备节点
    g_SPI_Fd = open(DEVICE_RC522, O_RDWR);
    if (g_SPI_Fd < 0){
        perror(DEVICE_RC522);
        return -1;
    }
        // 判断RC522初始化是否成功
    if(rc522_init()==0xff){
        printf("No Card Reader\n");
        
        led_control(DEVICE_LEDS,LEDON,LEDONE);
        led_control(DEVICE_LEDS,LEDON,LEDTWO);
        
        return -1;
    }else{// 模块上电成功,打开和关闭对应的LED指示灯
        led_control(DEVICE_LEDS,LEDON,LEDONE);
        led_control(DEVICE_LEDS,LEDOFF,LEDTWO);
    }
    // 天线打开
    PcdAntennaOn();
    HandleConfigMenu('A');
    close(g_SPI_Fd);
    //if find card ,record date and cardnumber
    if(UID[0]!='\0'){ // 检测到有刷卡
                // 打开蜂鸣器
        buzzer_control(DEVICE_BUZZER,BUZZERON);
        
        relay_control(DEVICE_RELAY,RELAYON);
        // 控制LED指示
        led_control(DEVICE_LEDS,LEDOFF,LEDONE);
        led_control(DEVICE_LEDS,LEDOFF,LEDTWO);
        // 使用rtc时钟记录当前的数据
        rtc_record(DEVICE_RTC,FILE_RECORD);
        card_record(FILE_RECORD);
    }
    else{
        printf("No Card\n");
        return -1;
    }
    buzzer_control(DEVICE_BUZZER,BUZZEROFF);
    
    sleep(1);
    relay_control(DEVICE_RELAY,RELAYOFF);
    
    led_control(DEVICE_LEDS,LEDON,LEDONE);
    led_control(DEVICE_LEDS,LEDOFF,LEDTWO);
    
    return 0;
}
View Code

  3、RC522模块的初始化以及SPI总线读写数据实现

/*
 * SPI testing utility (using spidev driver)
 *
 * Copyright (c) 2007  MontaVista Software, Inc.
 * Copyright (c) 2007  Anton Vorontsov <avorontsov@ru.mvista.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License.
 *
 * Cross-compile with cross-gcc -I/path/to/cross-kernel/include
 */

#include <stdint.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/types.h>

#include "spidev.h"
#include "rc522.h"

#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))

static uint8_t mode;
static uint8_t bits = 8;
static uint32_t speed = 400 * 1000;//500000;
static uint16_t delay;

int g_SPI_Fd = 0;
unsigned char UID[5], Temp[4];

void pabort(const char *s)
{
    perror(s);
    abort();
}
// read和write都是基于SPI协议实现的
int WriteRawRC(int addr, int data)
{
    int ret;
    int fd = g_SPI_Fd;
    unsigned char  TxBuf[2];

    //bit7:MSB=0,bit6~1:addr,bit0:RFU=0
    TxBuf[0] = ((unsigned char)addr << 1)&0x7E;
    //TxBuf[0] &= 0x7E;

    TxBuf[1] = (unsigned char)data;
    
    ret = write(fd, TxBuf, 2);
    if (ret < 0)
        printf("spi:SPI Write error\n");

    usleep(10);

    return ret;
}

unsigned char ReadRawRC(int addr)
{
    int ret;
    int fd = g_SPI_Fd;
    unsigned char  ReData;
    unsigned char  Address;
    
    Address  = (unsigned char)addr << 1;
    Address |= (1 << 7);
    Address &= ~(1 << 0);
    
    ret = write(fd, &Address, 1);
    if (ret < 0)
        printf("spi:SPI Write error\n");

    usleep(100);

    ret = read(fd, &ReData, 1);
    if (ret < 0)
        printf("spi:SPI Read error\n");

    return ReData;
}

void SetBitMask(unsigned char reg,unsigned char mask)  
{
      char tmp = 0x0;
    
      tmp = ReadRawRC(reg) | mask;
    
      WriteRawRC(reg,tmp | mask);
}

//******************************************************************/
//功    能:清RC522寄存器位
//参数说明:reg[IN]:寄存器地址
//          mask[IN]:清位值
//******************************************************************/
void ClearBitMask(unsigned char reg, unsigned char mask)  
{
    char tmp = 0x0;
    
    tmp = ReadRawRC(reg)&(~mask);
    
    WriteRawRC(reg, tmp);  // clear bit mask
}
// 模块的初始化
// RC522模块使用的SPI协议
int rc522_init()
{
    int ret;
    char version = 0;

    //reset
    WriteRawRC(CommandReg, PCD_RESETPHASE);
    usleep(10);
    WriteRawRC(ModeReg, 0x3D);
    WriteRawRC(TReloadRegL, 30);
    WriteRawRC(TReloadRegH, 0);
    WriteRawRC(TModeReg, 0x8D);
    WriteRawRC(TPrescalerReg, 0x3E);

    version = ReadRawRC(VersionReg);
    printf("Chip Version: 0x%x\n", version);
    usleep(50000);

    return version;
}

void PcdAntennaOn()
{
    unsigned char i;
  
    WriteRawRC(TxASKReg, 0x40);
      usleep(20);
  
    i = ReadRawRC(TxControlReg);
      if(!(i&0x03))
        SetBitMask(TxControlReg, 0x03);
      
    i = ReadRawRC(TxASKReg);
}

static void print_usage(const char *prog)
{
    printf("Usage: %s [-DsbdlHOLC3]\n", prog);
    puts("  -D --device   device to use (default /dev/spidev1.1)\n"
         "  -s --speed    max speed (Hz)\n"
         "  -d --delay    delay (usec)\n"
         "  -b --bpw      bits per word \n"
         "  -l --loop     loopback\n"
         "  -H --cpha     clock phase\n"
         "  -O --cpol     clock polarity\n"
         "  -L --lsb      least significant bit first\n"
         "  -C --cs-high  chip select active high\n"
         "  -3 --3wire    SI/SO signals shared\n");
    exit(1);
}

/*void parse_opts(int argc, char *argv[])
{
    while (1) {
        static const struct option lopts[] = {
            { "device",  1, 0, 'D' },
            { "speed",   1, 0, 's' },
            { "delay",   1, 0, 'd' },
            { "bpw",     1, 0, 'b' },
            { "loop",    0, 0, 'l' },
            { "cpha",    0, 0, 'H' },
            { "cpol",    0, 0, 'O' },
            { "lsb",     0, 0, 'L' },
            { "cs-high", 0, 0, 'C' },
            { "3wire",   0, 0, '3' },
            { "no-cs",   0, 0, 'N' },
            { "ready",   0, 0, 'R' },
            { NULL, 0, 0, 0 },
        };
        int c;

        c = getopt_long(argc, argv, "D:s:d:b:lHOLC3NR", lopts, NULL);

        if (c == -1)
            break;

        switch (c) {
        case 'D':
            device = optarg;
            break;
        case 's':
            speed = atoi(optarg);
            break;
        case 'd':
            delay = atoi(optarg);
            break;
        case 'b':
            bits = atoi(optarg);
            break;
        case 'l':
            mode |= SPI_LOOP;
            break;
        case 'H':
            mode |= SPI_CPHA;
            break;
        case 'O':
            mode |= SPI_CPOL;
            break;
        case 'L':
            mode |= SPI_LSB_FIRST;
            break;
        case 'C':
            mode |= SPI_CS_HIGH;
            break;
        case '3':
            mode |= SPI_3WIRE;
            break;
        case 'N':
            mode |= SPI_NO_CS;
            break;
        case 'R':
            mode |= SPI_READY;
            break;
        default:
            print_usage(argv[0]);
            break;
        }
    }
}*/

//******************************************************************/
//功    能:通过RC522和ISO14443卡通讯
//参数说明:Command[IN]:RC522命令字
//          pInData[IN]:通过RC522发送到卡片的数据
//          InLenByte[IN]:发送数据的字节长度
//          pOutData[OUT]:接收到的卡片返回数据
//          *pOutLenBit[OUT]:返回数据的位长度
//******************************************************************/
char PcdComMF522(unsigned char Command, unsigned char *pInData, 
                                 unsigned char InLenByte, unsigned char *pOutData, 
                                 unsigned int  *pOutLenBit)
{
    char status = MI_ERR;
    unsigned char irqEn  = 0x00;
    unsigned char waitFor = 0x00;
    unsigned char lastBits;
    unsigned char n;
    unsigned int  i;
    
    switch (Command)
    {
        case PCD_AUTHENT:
              irqEn   = 0x12;
              waitFor = 0x10;
              break;
        case PCD_TRANSCEIVE:
              irqEn   = 0x77;
              waitFor = 0x30;
              break;
        default:
              break;
    }
    
    WriteRawRC(ComIEnReg, irqEn|0x80);
    ClearBitMask(ComIrqReg, 0x80);
    WriteRawRC(CommandReg, PCD_IDLE);
    SetBitMask(FIFOLevelReg, 0x80); // 清空FIFO 
    for(i=0; i<InLenByte; i++)
        WriteRawRC(FIFODataReg, pInData[i]); // 数据写入FIFO 
        
    WriteRawRC(CommandReg, Command); // 命令写入命令寄存器

    if(Command == PCD_TRANSCEIVE)
        SetBitMask(BitFramingReg,0x80); // 开始发送     

    i = 6000; //根据时钟频率调整,操作M1卡最大等待时间25ms
      do 
    {
        n = ReadRawRC(ComIrqReg);
        i--;
    }
    while((i!=0)&&!(n&0x01)&&!(n&waitFor));
    
    ClearBitMask(BitFramingReg, 0x80);

    if(i!=0)
    {
        if(!(ReadRawRC(ErrorReg) & 0x1B))
        {
            status = MI_OK;
            if (n&irqEn&0x01)
                status = MI_NOTAGERR;
            if(Command == PCD_TRANSCEIVE)
            {
                n = ReadRawRC(FIFOLevelReg);
                
                lastBits = ReadRawRC(ControlReg) & 0x07;
                if(lastBits)
                    *pOutLenBit = (n-1)*8 + lastBits;
                else
                    *pOutLenBit = n*8;

                if(n == 0)
                    n = 1;
                if(n>MAXRLEN)
                    n = MAXRLEN;

                for (i=0; i<n; i++)
                    pOutData[i] = ReadRawRC(FIFODataReg); 
            }
        }
        else
        {
            status = MI_ERR;
        }
    }

    SetBitMask(ControlReg, 0x80);// stop timer now
    WriteRawRC(CommandReg, PCD_IDLE); 

    return status;
}

char PcdRequest(unsigned char req_code, unsigned char *pTagType)
{
    char status;  
    unsigned int  unLen;
    unsigned char ucComMF522Buf[MAXRLEN]; 

    ClearBitMask(Status2Reg, 0x08);
    WriteRawRC(BitFramingReg, 0x07);
    SetBitMask(TxControlReg, 0x03);
 
      ucComMF522Buf[0] = req_code;

      status = PcdComMF522(PCD_TRANSCEIVE, ucComMF522Buf,
                                       1, ucComMF522Buf, &unLen);

      if ((status == MI_OK) && (unLen == 0x10))
      {    
            *pTagType     = ucComMF522Buf[0];
            *(pTagType+1) = ucComMF522Buf[1];
      }
      else
    {
        status = MI_ERR;
      }

      return status;
}

//******************************************************************/
//功    能:防冲撞                                                  /
//参数说明: pSnr[OUT]:卡片序列号,4字节                             /
//返    回: 成功返回MI_OK                                           /
//******************************************************************/
char PcdAnticoll(unsigned char *pSnr)
{
    char status;
    unsigned char i, snr_check = 0;
    unsigned int  unLen;
    unsigned char ucComMF522Buf[MAXRLEN]; 
    
    ClearBitMask(Status2Reg, 0x08);
    WriteRawRC(BitFramingReg, 0x00);
    ClearBitMask(CollReg, 0x80);
 
    ucComMF522Buf[0] = PICC_ANTICOLL1;
    ucComMF522Buf[1] = 0x20;

        status = PcdComMF522(PCD_TRANSCEIVE, ucComMF522Buf,
                                2, ucComMF522Buf, &unLen);

        if(status == MI_OK)
    {
        for (i=0; i<4; i++)
        {   
            *(pSnr+i)  = ucComMF522Buf[i];
            snr_check ^= ucComMF522Buf[i];
        }
        if (snr_check != ucComMF522Buf[i])
        {
            status = MI_ERR;
        }
    }
    
    SetBitMask(CollReg,0x80);
    
    return status;
}

void Find_Card(void)
{
    if(PcdRequest(0x52, Temp) == MI_OK)
    {
          if(Temp[0]==0x04 && Temp[1]==0x00)  
                  printf("MFOne-S50\n");
            else if(Temp[0]==0x02 && Temp[1] == 0x00)
                  printf("MFOne-S70\n");
            else if(Temp[0]==0x44 && Temp[1]==0x00)
                  printf("MF-UltraLight\n");
            else if(Temp[0]==0x08 && Temp[1]==0x00)
                  printf("MF-Pro\n");
            else if(Temp[0]==0x44 && Temp[1]==0x03)
                  printf("MF Desire\n");
            else
                  printf("Unknown\n");
            
            printf("SUCCESS!\n");
    }
    else
    {
        printf("No card!\n");
    }
}

void Auto_Reader(void)
{
    int i = 0;
    unsigned long num = 0;
    
  //    while(1)
    //{
        if(PcdRequest(0x52,Temp) == MI_OK)
        {
            if(Temp[0]==0x04 && Temp[1]==0x00)  
                printf("MFOne-S50\n");
            else if(Temp[0]==0x02 && Temp[1]==0x00)
                printf("MFOne-S70\n");
            else if(Temp[0]==0x44 && Temp[1]==0x00)
                printf("MF-UltraLight\n");
            else if(Temp[0]==0x08 && Temp[1]==0x00)
                printf("MF-Pro\n");
            else if(Temp[0]==0x44 && Temp[1]==0x03)
                printf("MF Desire\n");
            else
                printf("Unknown\n");
            
            if(PcdAnticoll(UID) == MI_OK)
            { 
                printf("Card Id is(%d):", num++);
#if 1
                for(i=0; i<4; i++)
                    printf("%x", UID[i]);
#else            
                tochar(UID[0]);
                tochar(UID[1]);
                tochar(UID[2]);
                tochar(UID[3]);
#endif
                printf("\n");
                
                PcdRequest(0x52,Temp);//clear
            }
            else
            {
                printf("no serial num read\n");
            }
        }
        else
        {
            printf("No Card!\n");
        }

        usleep(300000);
//    } 
}

void HandleConfigMenu(unsigned char inputvalue)
{
#if 0
    switch(toupper(inputvalue)) 
    {
    case 'A':
              Auto_Reader();
              break;
    case 'F':
              Find_Card();
              break;
    default:
             DisplayConfigMenu();
    }
#endif

    //Find_Card();

    Auto_Reader();
}
View Code

  4、控制LED状态指示

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

void led_control(char *led_dev,int cmd,int lednum)
{
    int fd;
    
    fd = open(led_dev, O_RDWR);
    if(lednum>1 || cmd>1){
        printf("led arg is err\n");        
    }

    ioctl(fd,cmd,lednum);
    
    close(fd);
}
View Code

  5、蜂鸣器模块

void buzzer_control(char *buzzer_dev , int state)
{
    int fd;
    
    fd = open(buzzer_dev, O_RDWR);
    if(fd<0)
        printf("open %s failed\n",buzzer_dev); 
    ioctl(fd,state,0);

    close(fd);
}
View Code

  6、延时模块

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

void relay_control(char *relay_dev,int state)
{
    int fd;
    
    fd = open(relay_dev, O_RDWR);
    ioctl(fd,state,0);
    close(fd);
}

  7、记录卡动作的时间信息

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

extern unsigned char UID[5];

void card_record(char *file_record)
{
    FILE *time_stream;
    int i;
    
    fprintf(stderr,"card_record:%x%x%x%x\n",
        UID[0],UID[1],UID[2],UID[3]);
    
    time_stream = fopen(file_record,"a+");
    fprintf(time_stream,":%x%x%x%x\n",
            UID[0],UID[1],UID[2],UID[3]);        
    fclose(time_stream);
}
View Code

   8、门禁系统软件实现框架

 

posted @ 2020-10-26 23:15  笑不出花的旦旦  阅读(634)  评论(0)    收藏  举报