标题:
在家无聊自己给家里做个门禁
[打印本页]
作者:
heicc
时间:
2015-1-5 14:08
标题:
在家无聊自己给家里做个门禁
由于上个月丢了家钥匙,今天无聊中没啥事儿,就想自己动手设计个自己用的门禁来玩,至少钥匙丢了也不愁了,还可以一卡通。由于基本上目前没硬件来设计,那就先用软件来模拟一下吧,到时感觉不错再买元器件。
今天估计也做不了什么,就大概分析下机器的一些东东吧。
首先考虑使用的卡的类型,是使用id卡还是ic卡还是二代身份证呢?身份证嘛怕丢,不能老是随身带。id卡和ic卡都行,不过ic卡的读头要贵很多又不方便自做,所以最后决定用id卡吧,就算自己做也没什么,大不了买个芯片读曼彻斯特*码也应该容易,况且读卡器,卡片也便宜嘛。
id读卡器到时买最便宜的就行了,不用多想什么了,只要记得到时搞清楚到手的参数就行,不要拿个维根32的当成维根26的来用,就可能走很多弯路了。
主控芯片就用89s52吧,二个外部中断,二个定时中断,32个I/O应该够用了。
存储器的话只存开门卡号和密码等数据,不用太大,就用24c02够了,几十个用户容量够家里用了。
其他的配件都是小件散件,用到时再考虑吧。
用电脑做上位机进行联网远程开门,加卡删卡等操作,电脑软件以后做好下位机后再写了,唉,英语不行,VB,DP等流行软件都不能用,看来只能用易语言了。
现在到晚上了,今天白天已经画好了proteus图,大概说一一分布:1,电源12v输入12v/5v输出。2,主控P3口控制继电器蜂鸣器LED输出和曼码,IIC,中断(读卡器输入)输入和串口通讯。P2,P1口留做读卡器输入(用查询法来读数据)和信号输出。P0口做键盘输入了。主控就暂时就样分布到时需要时再改吧。
今天就先做到就里,任务才刚刚开始,单片机程序估计要几天才能写好吧。
作者:
heicc
时间:
2015-1-5 14:08
今天开始写下位机也就是89s52的程序。一个早上才搞定键盘扫描程序,程序基本上正确,只是明明加了松开检测了,怎么有时在按下时会发送呢。实在是检查不出哪儿的问题,也许是模拟软件的问题吧。
现在突然想到怎么先写键盘程序呢,应该写重要的先才对啊,不然到最后重要的部分没写成那不是浪费很多精力?但是没有实际硬件做起来费劲,串口通讯不知怎么用软件模拟,也就是因为这样早上的键盘程序都是靠软件调试和蜂鸣器来提示来叛断是否正确,所以做起来很慢。如果有终端来显示那就方便多了。不想买液晶显示,虽然1602液晶应该没多少钱但是怕以后用不到还是用电脑来做显示吧,接上串口来通讯就行。但问题是现在要有芯片,数据线,基本外围元件和洞洞板等等才行。家里街上和工业城市不一样,东西应该不好买,到市区里去看看吧,不行再淘宝了,马上去了……
贴上我的键盘程序:
/*////////////////////////////////////
函数原型: uchar key(void)
函数说明:键盘扫描
版本:V1.0.0
程序员:LIY12586
////////////////////////////////////*/
uchar key(void)
{
uchar temp,number;
P0=0x0f;
if(P0!=0x0f)
{
P0=0xfe;
if(P0!=0xfe)
{
temp=P0;
switch (temp)
{ //11110000
case 0xee: //01111110
number=4;
break;
case 0xde:
number=3;
break;
case 0xbe:
number=2;
break;
case 0x7e:
number=1;
break;
}
while(P0!=0xfe);
sound(1);
return number;
}
P0=0xfd;
if(P0!=0xfd)
{
temp=P0;
switch (temp)
{
case 0xed:
number=8;
break;
case 0xdd:
number=7;
break;
case 0xbd:
number=6;
break;
case 0x7d:
number=5;
break;
}
while(P0!=0xfd);
sound(1);
return number;
}
P0=0xfb;
//temp=P0;
//temp=temp|0xf0;
if(P0!=0xfb)
{
temp=P0;
switch (temp)
{
case 0xeb:
number=12;
break;
case 0xdb:
number=11;
break;
case 0xbb:
number=10;
break;
case 0x7b:
number=9;
break;
}
while(P0!=0xfb);
sound(1);
return number;
}
P0=0xf7;
//temp=P0;
//temp=temp|0xf0;
if(P0!=0xf7)
{
temp=P0;
switch (temp)
{
case 0xe7:
number=16;
break;
case 0xd7:
number=15;
break;
case 0xb7:
number=14;
break;
case 0x77:
number=13;
break;
}
while(P0!=0xf7);
sound(1);
return number;
}
}return 0;
}
作者:
heicc
时间:
2015-1-5 14:09
终于完成了韦根26查询法的程序了,IIC和串口通询昨天改好,因为现在没做到联网部分,所以没做联网方面的通讯协议和程序。
串口通讯程序
void Init(void)
{
TMOD|=0x21;//定时器1为方式2,定时器0方式1
TL1=0xfd; //初始值设置波特率为9600 //
TH1=0xfd;
ET0=1;
TR1=1; //开定时器1
REN=1; //允许接收数据//
SM0=0;
SM1=1;
EA=1; //开所有中断
ES=1;
}
void SEND(unsigned char *a)
{
uchar b;
for(b=0;b<8;b++)
{
SBUF=*a;
while(TI==0);
TI=0;
a=a+1;
}
}
IIC总线24cxx读写通用程序
#include<config.h>
//#include<delay.h>
#ifndef MCU_MODEL
#define MCU_MODEL 51 //<----在此设定mcu类型, 51代表51系列; avr代表avr系列
#endif
//-----------------------51类MCU-------------------------------------------
#if MCU_MODEL==51
// #include<reg51.h> //在此设定51类MCU的头文件
// #include<intrins.h> //_nop_()函数需要
// #include"xd.h"
// #include"xdprj.h"
//---------定义I2总线端口, 可根据实际使用改变-----------
sbit SCL=P2^0; //I2总线时钟线
sbit SDA=P2^1; //I2总线数据线
#define SCL_L SCL=0
#define SCL_H SCL=1
#define SDA_L SDA=0
#define SDA_H SDA=1
#define SDA_TO_IN //为配合avr共用次程序而空定义的宏
#define SDA_TO_OUT //为配合avr共用次程序而空定义的宏
#define SDA_IF_L SDA==0 //如果sda为低
#define SDA_IF_H SDA==1 //如果sda为高
//------------------------------------------------------
#define DELAY_us _nop_(); _nop_(); _nop_(); _nop_(); _nop_() //延时用,如果要加长延时,可增加或减少 _nop_();
//------------------------avr类MCU-----------------------------------------
#elif MCU_MODEL==avr
#include<iom16v.h> //在此设定avr类MCU的头文件
#include<macros.h>
// #include"xd.h"
// #include"xdprj.h"
//-----定义I2总线端口, 可根据实际使用改变----
#define SCL_L PORTC&=~BIT(0) //I2总线时钟线
#define SCL_H PORTC|=BIT(0)
#define SDA_L PORTC&=~BIT(1) //I2总线数据线
#define SDA_H PORTC|=BIT(1)
#define SDA_TO_IN DDRC&=~BIT(1); _NOP() //设数据线位输入
#define SDA_TO_OUT DDRC|=BIT(1); _NOP() //设数据线位输出
#define SDA_IF_L (PINC&BIT(1))==0 //如果sda为低
#define SDA_IF_H (PINC&BIT(1))==BIT(1) //如果sda为高
//-------------------------------------------
#define DELAY_us tus(7) //avr单片机在晶振为8MHz时,延时5us, 可根据实际情况改变
#endif
//---------------------------------------------------------------------------
//------在此设定芯片型号------
#define e2prom 2 // <---在此设定芯片型号, 1代表24C01; 16代表24C16; 512代表24C512
#if e2prom==1
#define PAGE_SIZE 8 //芯片页写缓冲器大小,单位:字节/
#define SIZE 0x007f // 芯片内含有多少个8位的字节/
#elif e2prom==2
#define PAGE_SIZE 8
#define SIZE 0x00ff
#elif e2prom==4
#define PAGE_SIZE 16
#define SIZE 0x01ff
#elif e2prom==8
#define PAGE_SIZE 16
#define SIZE 0x03ff
#elif e2prom==16
#define PAGE_SIZE 16
#define SIZE 0x07ff
#elif e2prom==32
#define PAGE_SIZE 32
#define SIZE 0x0fff
#elif e2prom==64
#define PAGE_SIZE 32
#define SIZE 0x1fff
#elif e2prom==128
#define PAGE_SIZE 64
#define SIZE 0x3fff
#elif e2prom==256
#define PAGE_SIZE 64
#define SIZE 0x7fff
#elif e2prom==512
#define PAGE_SIZE 128
#define SIZE 0xffff
#endif
//--------------------------
//--------在此设定芯片地址-------
#define W_ADD_COM 0xa0 //写字节命令及器件地址(根据地址实际情况改变), 1010 A2 A1 A0 0
#define R_ADD_COM 0xa1 //读命令字节及器件地址(根据地址实际情况改变), 1010 A2 A1 A0 1
//-------------------------------
//-----在此改变预置错误号-----
//#define I2C_ERR ERR_10 //写字节命令及器件地址错, 在此也就是读写器件错!!
//---------------------------
//-------------------------------以下为其它I2总线器件可调用的函数--------------------------
//起始信号
void i2cstart(void)
{
//SCL_L;
//DELAY_us;
SDA_H; //发送起始条件的数据信号*/
DELAY_us;
SCL_H;
DELAY_us; //起始条件建立时间大于4.7us,延时*/
SDA_L; //发送起始信号*/
DELAY_us; //起始条件锁定时间大于4μs*
SCL_L; //钳住I2C总线,准备发送或接收数据/
DELAY_us;
}
//停止信号 /
void i2cstop(void)
{
//SCL_L;
//DELAY_us;
SDA_L; //发送结束条件的数据信号*
DELAY_us;
SCL_H;
DELAY_us; // 结束条件建立时间大于4μs
SDA_H; // 发送I2C总线结束信号*
DELAY_us;
}
//等待从器件应答/
void i2cask()
{
uchar i;
SCL_H;
DELAY_us;
while((SDA==1)&&(i<250))i++;
SCL_L;
DELAY_us;
}
/*/MCU应答信号/
void i2cack()
{
SDA_L;
DELAY_us;
SCL_H;
DELAY_us;
SCL_L;
DELAY_us;
} */
//i2c读要调用的函数
//从器件读出一个字节
uchar i2crd(void)
{ uchar i,temp;
//i2c读要调用的函数
//从器件读出一个字节
uchar i2crd(void)
{ uchar i,temp;
SCL_L; DELAY_us; // 准备接收数据位*时钟低电平周期大于4.7μs
SDA_H; DELAY_us; //置数据线接上内部上拉(数据输入方式),此为必须/
for(i=0;i<8;i++)
{
SCL_H; // 置时钟线为高使数据线上数据有效/
DELAY_us;
temp<<=1;
SDA_TO_IN; //如果是avr单片机,就设SDA引脚位输入状态
if(SDA_IF_H)
temp=temp+1; //读数据位,接收的数据位放入temp中;
SCL_L;
DELAY_us;
SDA_TO_OUT; //如果是avr单片机,就设SDA引脚位输出状态
}
// SCL_L;
// DELAY_us; //主器件应答脉冲
// SDA_L; DELAY_us;
// SCL_H; DELAY_us;
return(temp);
}//把一个字节数据输入器件,并以收到应答信号为止/
//写入成功返回1,失败返回0
uchar i2cwt(uchar a)
{ uchar i;
for(i=0;i<8;i++) //要写入的数据长度为8位*
{
SCL_L;
DELAY_us;
if((a<<i)&0x80) // 判断发送位(按位与,只要最高位为1则真)
SDA_H;
else
SDA_L;
DELAY_us;
SCL_H; //置时钟线为高,通知被控器开始接收数据位*
DELAY_us; //保证时钟高电平周期大于4μs*
}
SCL_L;
DELAY_us;
SDA_H; // 8位发送完后释放数据线,准备接收应答位*
DELAY_us;
SCL_H;
DELAY_us;
SDA_TO_IN; //如果是avr单片机,就设SDA引脚位输入状态/
if(SDA_IF_L) //测试有无应答/
{ SDA_TO_OUT;
return(1); //有应答返回1
}
else
{ SDA_TO_OUT;
return(0); //无应答
}
}
void wt24c(uchar address,uchar date)
{
i2cstart();
i2cwt(0xa0);
i2cask();
i2cwt(address);
i2cask();
i2cwt(date);
i2cask();
i2cstop();
}
uchar rd24c(uchar address)
{
uchar temp;
i2cstart();
i2cwt(0xa0);
i2cask();
i2cwt(address);
i2cask();
i2cstart();
i2cwt(0xa1);
i2cask();
temp=i2crd();
return temp;
i2cstop();
}
查询法读韦根26程序
idata unsigned char WGDATA[26]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};//接收韦根数据26位
idata unsigned char WG[8]={0xaa,0xbb,0,0,0,0,0xcc,0xdd};//存韦根ID卡卡号的HID和PID码,其中HID码为8位即一字节,PID码16位两字节
uchar a,x,j,LL,II,YY;
void ys100us(uint u)
{ uint y;
uchar x;
for(y=u;y>0;y--)
{
for(x=20;x>0;x--)
_nop_();
}
}
void DATA(void)
{
if(DATA0!=DATA1)
{
if(DATA0==0)
{
WGDATA[Cnt]=0;
if(Cnt==25)
a=1;
Cnt++;
ys100us(15);
}
if(DATA1==0)
{
WGDATA[Cnt]=1;
if(Cnt==25)
a=1;
Cnt++;
ys100us(15);
}
}
}
bit re(void)
{
if(Read_Card())
{
WG[3]=WGDATA[1];
WG[4]=WGDATA[2];
WG[5]=WGDATA[3];
return 1;
// SEND(&WG[0]);
}
DATA();
if(a==1)
{
EA=0; //关中断以免外部中断的干扰
a=0;
Cnt=0;
// rd24c(ptr,0,10);
// WG[0]=*ptr;
for(x=1;x<9;x++)
LL=(LL<<1)|WGDATA[x];
for(x=9;x<17;x++)
II=(II<<1)|WGDATA[x];
for(x=17;x<25;x++)
YY=(YY<<1)|WGDATA[x];
//WG[0]=rd24c(0);
//ysms(100);
WG[3]=LL;
WG[4]=II;
WG[5]=YY;
EA=1;
// SEND(&WG[0]);
return 1;
}
return 0;
}
作者:
heicc
时间:
2015-1-5 14:10
写好的部分程序
累啊!脑力劳动比体力劳动要累多了!写得并调式好几个程序花了我不少精力,打字都嫌累了,贴上几个程序:
/*////////////////////////////////////
函数原型:
函数说明:串口接收中断
版本:V1.0.0
程序员:LIY12586
////////////////////////////////////*/
void ser() interrupt 4
{
RI=0;
z=SBUF;
ai=1;
}
/*////////////////////////////////////
函数原型:void sound(uchar a)
函数说明:蜂鸣器发声,a为需要发出多少次DIDI音
版本:V1.0.0
程序员:LIY12586
////////////////////////////////////*/
void sound(uchar a)
{
uchar x,y;
for(;a>0;a--)
{
for(x=255;x>0;x--)
{
beep=0;
for(y=150;y>0;y--)
beep=1;
beep=0;
}
ysms(500);
}
}
void ysms(unsigned int x)
{
unsigned int a;
unsigned int b;
for(a=x;a>0;a--)
{
for(b=50;b>0;b--);
}
}
/*////////////////////////////////////
函数原型:void inscard(void)
函数说明:存入卡号到EEPROM
版本:V1.0.0
程序员:LIY12586
////////////////////////////////////*/
void inscard(void)
{
while(1)
{
if(re())
{
if(iscard()==0)//如果没有这卡号/
{
uchar a,b;
b=ckdz(); //查找空置/
for(a=3;a<6;a++)
{
wt24c(b,WG[a]);
ys100us(1000);
b++;
}
// wt24c(0,b);
ys100us(1000);
sound(1);
break;
}
sound(2);
break;
}
if(key()==12)
{
sound(1);
break;
}
}
}
/*////////////////////////////////////
函数原型:void delcard(void)
函数说明:从EEPROM中删除卡号
版本:V1.0.0
程序员:LIY12586
////////////////////////////////////*/
void delcard(void)
{
while(1)
{
if(re())
{
if(iscard()!=0) //如果有这张卡号/
{
uchar a,b;
b=iscard(); //查找空置/
for(a=0;a<3;a++)
{
wt24c(b,0xff);
ys100us(1000);
b=b+1;
}
// wt24c(0,b);
ys100us(1000);
sound(1);
break;
}
sound(2);
break;
}
if(key()==12)
{
sound(2);
break;
}
}
}
/*////////////////////////////////////
函数原型:uchar iscard(void)
函数说明:查找是否有此卡
版本:V1.0.0
程序员:LIY12586
////////////////////////////////////*/
uchar iscard(void)
{
uchar a,b;
for(a=8;a<128;a++)
{
if(rd24c(a)==WG[3])
{
a++;
if(rd24c(a)==WG[4])
{
a++;
if(rd24c(a)==WG[5])
{
b=a-2;
return b;
}
}
}
if(a==127)return 0;
}
}
/*////////////////////////////////////
函数原型:uchar ckdz(void)
函数说明:查找EEPROM的空白位置地址
版本:V1.0.0
程序员:LIY12586
////////////////////////////////////*/
uchar ckdz(void)//查空地址/
{
uchar a,b,c;
for(a=2;a<126;a++)
{
c=a;
c++;
if(rd24c(a)==0xff)
{
a++;
if(rd24c(a)==0xff)
{
a++;
if(rd24c(a)==0xff)
{
b=a-2;
return b;
}
}
}
if(c==126)return 0xff;
}
}
/*////////////////////////////////////
函数原型:void readcard(void)
函数说明:读卡正确
版本:V1.0.0
程序员:LIY12586
////////////////////////////////////*/
void readcard(void)
{
if(re())
{
if(iscard()!=0)
{
SEND(&WG[0]);
open();
}sound(2);
}
}
/*////////////////////////////////////
函数原型:void open(void)
函数说明:打开
版本:V1.0.0
程序员:LIY12586
////////////////////////////////////*/
void open(void)
{
//out=0;
SEND(&WG[0]);
sound(1);
ysms(10000);
//out=1;
}
作者:
heicc
时间:
2015-1-5 14:10
完成按键操作
昨天晚上终于完成了按键操作,由于太晚没上传,大部分功能已经完成,一个简单(功能相对于专业门禁来说简单,制作对我来说相当复杂,但也是体现我的单片机和电子技术水平又有提高)的门禁可以使用了,目前的功能有:读卡开门,密码开门,加卡,删卡,更改密码,系统初始化。后期要加上:远程控制开门,加卡,删卡,监控等。下面是程序:
/*////////////////////////////////////
函数原型:void psw(void)
函数说明:密码写入EEPROM中
版本:V1.0.0
程序员:LIY12586
////////////////////////////////////*/
void psw(void)
{
uchar a=0,b=2,c,d,x=0;
timer=0;
while(1)
{
c=key();
if(c==12)
{
sound(1);
break;
}
if(ex==1)
{
sound(1);
ex=0;
break;
}
if(c!=0)
{
if(a<6)
{
keybuff[a]=c;
a++;
if(a==6)sound(2);
}
else if(a>6,a<13)
{
if(c!=keybuff[x])
{
sound(20);
x=0;
a=0;
break;
}
a++;
x++;
if(a==12)
{
a=0;
x=0;
b=2;
for(d=0;d<6;d++)
{
wt24c(b,keybuff[d]);
ys100us(1000);
b++;
}
SEND(&keybuff[0]);
break;
}
}
}
}
}
/*////////////////////////////////////
函数原型:bit keyscan(void)
函数说明:键盘操作扫描
版本:V1.0.0
程序员:LIY12586
////////////////////////////////////*/
bit keyscan(void)
{
uchar a=1,c,d;
scan=key();
if(scan!=0)
{
if(scan!=11)
{
d=scan;
timer=0;
keybuff[0]=scan;
scan=0;
while(1)
{
if(d==12)
{
sound(1);
break;
}
c=key();
if(c==12)
{
sound(1);
break;
}
else if(ex==1)
{
sound(1);
ex=0;
break;
}
else if(c!=0)
{
keybuff[a]=c;
a++;
if(a==6)
{
a=0;
SEND(&keybuff[0]);
return 1;
break;
}
}
}
}
}
return 0;
}
/*////////////////////////////////////
函数原型:void password(void)
函数说明:确认密码
版本:V1.0.0
程序员:LIY12586
////////////////////////////////////*/
bit password(void)
{
uchar a,b;
if(keyscan())
{
b=2;
for(a=0;a<6;a++)
{
if(keybuff[a]!=rd24c(b))
{
break;
}
b++;
if(b==8)return 1;
}
if(b!=8)
{
sound(5);
// LED=0;
return 0;
}
}
}
/*////////////////////////////////////
函数原型:void systeminit(void)
函数说明:系统初始化
版本:V1.0.0
程序员:LIY12586
////////////////////////////////////*/
void systeminit(void)
{
uchar a;
wt24c(0,0x02);
ys100us(1000);
wt24c(1,0xab);
ys100us(1000);
wt24c(2,0x01);
ys100us(1000);
wt24c(3,0x02);
ys100us(1000);
wt24c(4,0x03);
ys100us(1000);
wt24c(5,0x04);
ys100us(1000);
wt24c(6,0x05);
ys100us(1000);
wt24c(7,0x06);
ys100us(1000);
for(a=8;a<128;a++)
{
if(rd24c(a)!=0xff)
{
//ysms(100)
wt24c(a,0xff);
ys100us(1000);
}
}
sound(5);
}
复制代码
作者:
尘世精灵
时间:
2015-1-20 22:42
xuexixia ding
作者:
huzi
时间:
2015-5-14 21:45
楼主你好!!!做毕业设计,,,需要这样的,,,系统,,,求分享,,,proteus图等,,,谢谢。
1138279190@QQ.com
作者:
yzl
时间:
2015-6-10 06:34
单片机是怎样看门把关的能教教别人吗
作者:
清唱96
时间:
2015-9-26 14:04
楼主你好 求分享proteus图 硬软件设计 万分感谢 谢谢,谢谢
364640663@qq.com
作者:
great058
时间:
2017-5-29 22:27
你好!能不能把门禁的代码给我参考一下?
作者:
great058
时间:
2017-5-29 22:28
你好!能不能把门禁的代码给我参考一下?
liuwei058@163.com
作者:
harly2200
时间:
2017-12-17 23:58
做个记號,以后学习使用 谢谢楼主
作者:
tieq1952
时间:
2017-12-19 15:05
等待分享楼主的成果
作者:
zdmjjp
时间:
2018-10-6 20:00
想学习一下,请多帮助,谢谢!
作者:
凤的情绪
时间:
2018-11-30 22:59
好强呀,有实物图吗楼主?
作者:
cancan1993
时间:
2020-1-12 23:54
大师就是牛x
作者:
赤子之心
时间:
2020-4-5 22:11
楼主你好 求分享软、硬件设计 万分感谢 谢谢,谢谢
739004020@qq.com
欢迎光临 (http://www.51hei.com/bbs/)
Powered by Discuz! X3.1