本帖最后由 cnkids 于 2012-8-8 14:46 编辑
8月9日更新:我对不起人民,一觉起来,我又更新了程序。先贴个实物图吧。。
这次只改了读卡识别的,加了个液晶显示,就不用电脑的串口监视器了,设置好,通电就能用:- #include <LiquidCrystal.h>
- #include <EEPROM.h>
- #define EEPROM_write(address, p) {int i = 0; byte *pp = (byte*)&(p);for(; i < sizeof(p); i++) EEPROM.write(address+i, pp[i]);}
- #define EEPROM_read(address, p) {int i = 0; byte *pp = (byte*)&(p);for(; i < sizeof(p); i++) pp[i]=EEPROM.read(address+i);}
- LiquidCrystal lcd(12, 11, 10, 9, 8, 7, 6);
- int backLight = 13;
- const int ENPin = 2; // the number of the EN pin
- int ENState = 1; //default EN state was HIGH
- void setup()
- {
- Serial.begin(9600);
- pinMode(ENPin, INPUT);
- pinMode(backLight, OUTPUT);
- digitalWrite(backLight, HIGH);
- lcd.begin(16,2);
- lcd.clear();
- }
- void loop()
- {
- unsigned long ID = 0; //define a string variable
- unsigned long IDR = 0;
- for(ENState = digitalRead(ENPin) ; ENState == LOW && Serial.available() > 0; ) // read the state of the EN value,check if the EN is LOW,the output the data.
- {
- ID = ID * 10 + int(Serial.read()-'0'); //read the number from IDcard
- delay(2);
- }
- if(ID != 0) //if comdata gets the IDcard number,show it
- {
- lcd.setCursor(0,0);
- lcd.print("ID: ");
- lcd.print(ID);
- for(int addr = 0; addr <= 1020; addr = addr + 10)
- {
- EEPROM_read(addr, IDR);
- if(ID == IDR)
- {
- lcd.setCursor(0,1);
- lcd.print("Welcome! "); break;
- }
- }
- if(ID != IDR)
- {
- lcd.setCursor(0,1);
- lcd.print("who you are? ");
- }
- ID = 0; //clean the comdata
- }
- }
复制代码
————————————————————————无视我吧,写程序的分割线——————————————————
8月8日更新:我错了,不应该半夜不睡觉,爬起来码程序,最后优化修改过的程序,估计短时间内不会再改了,要改也要配合其他模块一起。读卡识别这部分的程序改成了for循环依次进入地址读取卡号进行匹配,正确则跳出循环,或是循环结束仍不匹配;EEPROM卡号存储改成了读卡时将卡号自行写入EEPROM,就不用人工一个一个变量的定义写入了。具体的往下看吧,欢迎拍砖~
读卡识别部分代码:- #include <EEPROM.h>
- #define EEPROM_write(address, p) {int i = 0; byte *pp = (byte*)&(p);for(; i < sizeof(p); i++) EEPROM.write(address+i, pp[i]);}
- #define EEPROM_read(address, p) {int i = 0; byte *pp = (byte*)&(p);for(; i < sizeof(p); i++) pp[i]=EEPROM.read(address+i);}
- const int ENPin = 2; // 定义使能端的管脚
- int ENState = 1; //初始化使能端为高电平
- void setup()
- {
- Serial.begin(9600);
- pinMode(ENPin, INPUT);
- }
- void loop()
- {
- unsigned long ID = 0; //定义一个变量用于存储读入的ID卡号
- unsigned long IDR = 0; //定义一个变量用于存储从EEPROM读出的ID卡号
- for(ENState = digitalRead(ENPin) ; ENState == LOW && Serial.available() > 0; ) // 读取使能端的电平,判断是否为低电平,是且串口有输入,则进入循环
- {
- ID = ID * 10 + int(Serial.read()-'0'); //读出卡号
- delay(2);
- }
- if(ID != 0) //如果变量ID不为0
- {
- Serial.println(ID); //输出读入的卡号,实际应用中考虑到安全性可不输出
- for(int addr = 0; addr <= 1020; addr = addr + 10) //定义一个变量表示为EEPROM的地址位,UNO的EEPROM有1024B,所以这里设定地址位在小于等于1020时进入循环
- {
- EEPROM_read(addr, IDR); //读出EEPROM中存放的ID卡号
- if(ID == IDR) //判断串口读入的ID卡号与EEPROM中的卡号是否匹配
- {
- Serial.println("Welcome!"); break; //匹配则输出WELCOME,并跳出循环
- } //若不匹配,则地址位加10,进行下一卡号匹配,直到与EEPROM内存储的所有卡号对比完,均不匹配,则跳出循环
- }
- if(ID != IDR) Serial.println("Sorry,you are not allowed!"); //均不匹配,则输出SORRY
- ID = 0; //变量ID清0
- }
- }
复制代码
效果如下:
EEPROM写入卡号程序: - #include <EEPROM.h>
- #define EEPROM_write(address, p) {int i = 0; byte *pp = (byte*)&(p);for(; i < sizeof(p); i++) EEPROM.write(address+i, pp[i]);}
- #define EEPROM_read(address, p) {int i = 0; byte *pp = (byte*)&(p);for(; i < sizeof(p); i++) pp[i]=EEPROM.read(address+i);}
- const int ENPin = 2; // the number of the EN pin
- int ENState = 1; //default EN state was HIGH
- int addr = 0;
- void setup()
- {
- Serial.begin(9600);
- }
- void loop()
- {
- unsigned long ID = 0;
- for(ENState = digitalRead(ENPin); ENState == LOW && Serial.available() > 0; )
- {
- ID = ID * 10 + int(Serial.read()-'0'); //read the number from IDcard
- delay(2);
- }
- if(ID != 0)
- {
- Serial.println(ID);
- EEPROM_write(addr, ID); //写入从串口读出的ID卡号
- unsigned long IDR = 0; //定义一个变量IDR用于存储从EEPROM中读出的卡号
- EEPROM_read(addr, IDR); //读出刚刚写入的卡号
- Serial.println(IDR);
- Serial.println(addr); //显示地址位
- addr = addr + 10; //由于卡号位10数,所以地址位每次加10,进行下一个卡号的写入
- ID = 0;
- }
- }
复制代码
效果如下:
——————————————————————默默写程序的分割线——————————————————————————
8月7日:小更新一下。这次是将卡号存在EEPROM中,通过读取,然后再进行对比。目前正在思考利用什么算法能个加快卡号匹配的速度。- #include <EEPROM.h>
- #define EEPROM_write(address, p) {int i = 0; byte *pp = (byte*)&(p);for(; i < sizeof(p); i++) EEPROM.write(address+i, pp[i]);}
- #define EEPROM_read(address, p) {int i = 0; byte *pp = (byte*)&(p);for(; i < sizeof(p); i++) pp[i]=EEPROM.read(address+i);}
- const int ENPin = 2; // 定义使能管脚
- int ENState = 1; //初始化使能状态为高电平
- unsigned long ID; //定义一个数字量用于存储卡号
- unsigned long IDR; //定义一个数字量用于存储从EEPROM中读出的卡号
- unsigned long IDR1;
- void setup()
- {
- Serial.begin(9600);
- pinMode(ENPin, INPUT);
- EEPROM_read(0, IDR); //读出从地址0存储的卡号
- Serial.print("ID card1: ");
- Serial.println(IDR);
- EEPROM_read(10, IDR1); //读出从地址10存储的卡号
- Serial.print("ID card2: ");
- Serial.println(IDR1);
- }
- void loop()
- {
- for(ENState = digitalRead(ENPin) ; ENState == LOW && Serial.available() > 0; ) //判断使能端是否为低电平,是且串口有输入,则读入卡号
- {
- ID = ID * 10 + int(Serial.read()-'0'); //读出卡号
- delay(2); //加个小延时,让串口有充裕的时间读出数据
- }
- if(ID != 0) //如果ID内存的值不为0,则输出该卡号
- {
- Serial.println(ID);
- if(ID == IDR) Serial.println("welcome"); //判断是否与EEPROM中的卡号相匹配
- else if(ID == IDR1) Serial.println("welcome");
- else Serial.println("sorry,you are not allowed.");
- ID = 0; //清0
- }
- }
复制代码
结果如下:
还用了单独的EEPROM读写程序先存储一遍卡号,通过读写的结果,因为存的是数字量,一个数就占一位了,卡号10个数,所以第二个卡号的地址从10开始写入: - #include <EEPROM.h>
- #define EEPROM_write(address, p) {int i = 0; byte *pp = (byte*)&(p);for(; i < sizeof(p); i++) EEPROM.write(address+i, pp[i]);}
- #define EEPROM_read(address, p) {int i = 0; byte *pp = (byte*)&(p);for(; i < sizeof(p); i++) pp[i]=EEPROM.read(address+i);}
- unsigned long ID = 4294916953;
- unsigned long ID1 = 4294917240;
- unsigned long IDR = 0;
- unsigned long IDR1 = 0;
- void setup()
- {
- Serial.begin(9600);
- EEPROM_write(0, ID);
- EEPROM_write(10, ID1);
- EEPROM_read(0, IDR);
- Serial.println(IDR);
- EEPROM_read(10, IDR1);
- Serial.println(IDR1);
- }
- void loop()
- {
-
- }
复制代码
结果如下:
———————————————————低调写程序的分割线——————————————————————
首先感谢thomas,本程序是在他原有程序的基础上进行修改的,来个传送门:http://www.geek-workshop.com/thread-905-1-1.html
thomas的程序有个小BUG,在测试的时候发现卡号并没有依次存入递增的数组下标地址中,而是重复的存入下标为0的首地址中,导致了调试的时候,不能够进行很好的有效卡号设置和匹配。奋斗了两天,把数组接收改成了字符串变量接收,调用的时候,可以以数组的形式依次调用。
comdata += char(Serial.read()) 这里最后直接输出 Serial.println(comdata) 时,输出的是ASCII码的形式,所以改成了逐个地址输出,转成了16进制。有兴趣的一起研究改进哈~
下面放代码:- const int ENPin = 2; //使能端口
- int ENState = 1; // 初始化为高电平
- String comdata = ""; //定义一个字符串变量
- char ID[4] = {0x00,0x17,0x3E,0x41}; //设置一个有效卡的卡号
-
- void setup()
- {
- Serial.begin(9600);
- pinMode(ENPin, INPUT);
- }
- void loop()
- {
- // 读取使能端的电平,如果使能端为低电平,则读出卡号
- for(ENState = digitalRead(ENPin) ; ENState == LOW && Serial.available() > 0; )
- {
- comdata += char(Serial.read()); //读出ID卡号
- delay(2); //加一个短延时,给单片机足够的时间读取卡号
- }
- if(comdata.length() > 0) //如果comdata接收到卡号,则读出卡号
- {
- Serial.print(comdata[0],HEX);
- Serial.print(comdata[1],HEX);
- Serial.print(comdata[2],HEX);
- Serial.println(comdata[3],HEX);
- if(comdata[0] == ID[0] && comdata[1] == ID[1] && comdata[2] == ID[2] && comdata[3] == ID[3])
- { //判断读入的ID卡是否与预先设置的有效卡号匹配,匹配则输入welcome
- Serial.println("welcome");
- }
- else Serial.println("sorry,you are not allowed.");
- comdata = ""; //清除comdata内的值
- }
- }
复制代码 输出的效果:
|