本电路是由STC89C52 单片机为控制核心,射频卡信息由MFRC522模块读出,通过MCU在LCD12864上显示,通过按键完成密码验证和修改密码的功能。整个门禁系统框图如图3-1所示。
3.1 STC89C52主控模块
3.1.1 STC89C52简介
STC89C52是宏晶科技发行的一款兼容标准MCS-51指令系统,工业80C51产品指令和引脚完全兼容的51单片机。传统的8051系列单片机只有128-256个字节RAM可使用,对于工程量较大的程序设计时往往会不够用。而STC89C52RC系列单片机扩展了256个字节RAM,拓展的容量,在应用中渐渐取代传统单片机被广泛应用。STC89C52还拥有8K字节在线可编程的Flash存储器、支持在线SPI编程、32个双向数据I/O口线、两个16位定时器/计数器和全双工UART串行通道[12]。
3.1.2 STC89C52主要特性
1)与MCS-51 兼容
2)寿命:1000次擦/写
3)据保留时间:10年
4)全静态工作:0Hz-24Hz
5)512M内部RAM
6)32双向数据I/O线
7)两个16位定时器/计数器
8)5个中断源
9)可编程串行通道
10)芯片内自带振荡器和时钟电路[13]
3.1.3 STC89C52管脚说明
图3-2 STC89C52管脚图
VCC:电源电压。
GND:接地。
P0口:P0口为一个8位双向I/O口,内部不提供上拉电阻。连接电路时需外接上拉电阻。P0口缓冲器能接受输出8TTL门电流。当P0口的管脚第一次写入“1”时,被定义为高阻输入。P0能够作为外部程序数据存储器,暂时存储外部输入数据而不需反复输入。
P1口:P1口是一个内部提供上拉电阻的8位双向I/O口,P1口缓冲器能接收输出4TTL门电流。由于内部上拉的缘故,P1口管脚写入“1”后,其管脚电平被上拉电阻拉高,此时管脚用作输入。P1口被上拉电阻下拉为低电平时,此时管脚作为将输出电流端口用。
P2口:P2口为一个内部上拉电阻的8位双向I/O口,P2口缓冲器可接收输出4个TTL门电流。由于内部上拉的缘故,当P2口被写“1”时,其管脚电平被上拉电阻拉高,且作为输入。P2口被上拉电阻下拉为低电平时,此时管脚作为将输出电流端口用。在FLASH编程和
校验时,P2口用来接收高八位地址和控制信号。
P3口:P3 口是一个具有内部上拉电阻的8 位双向I/O 口,P3口缓冲器可接收输出4个TTL门电流。对P3口管脚写入“1”时,其管脚电平被上拉电阻拉高,此时可以作为输入口使用。P3口也作为STC89C52的第二功能使用[14]。具体功能如表3-1所示:
表3-1 P3口功能表
端口引脚 第二功能
P3.0 RXD(串行输入口)
P3.1 TXD(串行输出口)
P3.2 INT0(外部中断0)
P3.3 INT1(外部中断1)
P3.4 T0(记时器0)
P3.5 T1(记时器1)
P3.6 WR(外部数据存储器写选通)
P3.7 RD(外部数据存储器读选通)
RST:复位输入,高电平有效。当需对器件进行复位时,要保持RST脚两个机器周期的高电平时间。
ALE/PROG: ALE是地址锁存允许信号端,低电平有效。在FLASH编程期间,此引脚用于输入编程脉冲。PORG为编程脉冲的输入端。当ALE/PROG接上低电平的时候,单片机对外部存储器进行数据读取时,用来锁住地址线的低位地址。
/PSEN:外部程序存储器的选通信号。在由外部程序存储器取指期间,每个机器周期两次/PSEN有效。但在访问外部数据存储器时,这两次有效的/PSEN信号将不出现。
/EA/VPP:当/EA保持低电平时,在此期间数据输入都存入外部程序存储器,不管内部程序存储器是否有空间存储数据。
XTAL1:反向振荡放大器的输入及外部时钟工作电路的输入。
XTAL2:反向振荡放大器的输出及外部时钟工作电路的输出。
3.2.4 LCD12864基本特性
(1)显示分辨率:128×64点
(2)内置128个16×8点阵字符
(3)内部含有繁体、简体中文字库,包括含8192个汉字
(4)低电源电压(VDD:+3.0-+5.5V)
(5)2MHZ时钟频率
(6)显示方式:STN、正显、半透
(7)工作温度: 0℃-+55℃ ,存储温度: -20℃- +60℃
(8)通讯方式:串行、并行
(9)内置转换电路,无需转换电压或外加负压 [17]
#include
#include
#include "main.h"
#define uchar unsigned char
#define uint unsigned int
/*LCD12864 端口定义*/
#define LCD_data P0 //数据口
sbit LCD_RS = P3^5; //寄存器选择输入
sbit LCD_RW = P3^6; //液晶读/写控制
sbit LCD_EN = P3^4; //液晶使能控制
sbit LCD_PSB = P3^7; //串/并方式控制,部分液晶不需要
uchar code dis0[]=" IC卡门禁系统 ";
uchar code dis1[]="1.IC卡输入 ";
uchar code dis2[]="2.密码输入:8位 ";
uchar code dis3[]="3.IC卡登记 ";
uchar code dis4[]="4.密码设置:8位 ";
uchar code dis5[]="成功 ";
uchar code dis6[]="失败 ";
void delay(int ms) //延时xms
{
while(ms--)
{
uchar i;
for(i=0;i<250;i++)
{
_nop_();
_nop_();
_nop_();
_nop_();
}
}
}
void delayNOP() //延时4us
{ _nop_(); _nop_(); _nop_(); _nop_();}
/*******************************************************************/
/* */
/*因为引脚的定义DB0..DB7是从P1.7...P1.0排列的 */
/*所以顺序需要调换一下 */
/* */
/*******************************************************************/
INT8U swapbit(INT8U udata)
{
INT8U ii,tmp=0;
for(ii=0;ii<8;ii++)
{
tmp<<=1;
if(udata&0x01)
{
tmp|=0x01;
}
udata>>=1;
}
return tmp;
}
/*******************************************************************/
/* */
/*检查LCD忙状态 */
/*lcd_busy为1时,忙,等待。lcd-busy为0时,闲,可写指令与数据。 */
/* */
/*******************************************************************/
bit lcd_busy()
{
bit result;
LCD_RS = 0;
LCD_RW = 1;
LCD_EN = 1;
delayNOP();
result = (bit)(LCD_data&0x80);
LCD_EN = 0;
return(result);
}
/*******************************************************************/
/* */
/*写指令数据到LCD */
/*RS=L,RW=L,E=高脉冲,D0-D7=指令码。 */
/* */
/*******************************************************************/
void write_cmd(unsigned char WCLCM,BuysC)
{
unsigned int K=20000;
while(lcd_busy() && K--); //预防没插LCD时候停在这
LCD_RS = 0;
LCD_RW = 0;
LCD_EN = 0;
_nop_();
_nop_();
LCD_data = swapbit(WCLCM);
delayNOP();
LCD_EN = 1;
delayNOP();
LCD_EN = 0;
}
/*******************************************************************/
/* */
/*写显示数据到LCD */
/*RS=H,RW=L,E=高脉冲,D0-D7=数据。 */
/* */
/*******************************************************************/
void lcd_wdat(unsigned char WDLCM)
{
unsigned int K=20000;
while(lcd_busy() && K--); //预防没插LCD时候停在这
LCD_RS = 1;
LCD_RW = 0;
LCD_EN = 0;
LCD_data= swapbit(WDLCM);
delayNOP();
LCD_EN = 1;
delayNOP();
LCD_EN = 0;
}
/*******************************************************************/
/* */
/* LCD初始化设定 */
/* */
/*******************************************************************/
void lcd_init()
{
LCD_PSB = 1; //并口方式 ,部分液晶不需要
write_cmd(0x36); //扩充指令操作
delay(5);
write_cmd(0x30); //基本指令操
delay(5);
write_cmd(0x0C); //显示开,关光标
delay(5);
write_cmd(0x01); //清除LCD的显示内容
delay(5);
}
/*********************************************************/
/* */
/* 设定显示位置 */
/* */
/*********************************************************/
void lcd_pos(uchar X,uchar Y)
{
uchar pos;
if (X==0)
{X=0x80;}
else if (X==1)
{X=0x90;}
else if (X==2)
{X=0x88;}
else if (X==3)
{X=0x98;}
pos = X+Y ;
write_cmd(pos); //显示地址
}
/*********************************************************/
/* */
/* 显示主程序 */
/* */
/*********************************************************/
void display_all()
{
uchar i;
lcd_pos(0,0); //第一行显示数字0~9
i = 0;
while(dis0[i] != '\0')
{
lcd_wdat(dis0[i]); //显示字母
i++;
}
lcd_pos(1,0); //第二行显示字母
i = 0;
while(dis1[i] != '\0')
{
lcd_wdat(dis1[i]); //显示字母
i++;
}
lcd_pos(2,0); //第三行显示文字
i = 0;
while(dis2[i] != '\0')
{
lcd_wdat(dis2[i]);
i++;
}
lcd_pos(3,0); //第四行显示广工无线电社
i = 0;
while(dis3[i] != '\0')
{
lcd_wdat(dis3[i]);
i++;
}
}
/*********************************************************/
/* */
/* 特定字符显示主程序 */
/*
C:
0=" IC卡点台灯 ";
1="1.读卡中.... ";
2="2.登记.... ";
3="成功 ";
4="失败 ";
/*********************************************************/
void display(uchar a,uchar b,uchar c)
{
uchar i;
lcd_pos(a,b); //第一行显示数字0~9
i = 0;
switch(c)
{
case 0:
while(dis0[i] != '\0')
{
lcd_wdat(dis0[i]); //显示字母
i++;
}
break;
case 1:
while(dis1[i] != '\0')
{
lcd_wdat(dis1[i]); //显示字母
i++;
}
break;
case 2:
while(dis2[i] != '\0')
{
lcd_wdat(dis2[i]); //显示字母
i++;
}
break;
case 3:
while(dis3[i] != '\0')
{
lcd_wdat(dis3[i]); //显示字母
i++;
}
break;
case 4:
while(dis4[i] != '\0')
{
lcd_wdat(dis4[i]); //显示字母
i++;
}
break;
case 5:
while(dis5[i] != '\0')
{
lcd_wdat(dis5[i]); //显示字母
i++;
}
break;
case 6:
while(dis6[i] != '\0')
{
lcd_wdat(dis6[i]); //显示字母
i++;
}
break;
default :break;
}
}
附:http://www.jh-tec.cn/archives/7319