嵌入式开发记录-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; }
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(); }
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); }
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); }
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); }
8、门禁系统软件实现框架


浙公网安备 33010602011771号