门禁系统项目驱动程序

发布者:Xinmei最新更新时间:2015-07-06 来源: 51hei关键字:门禁系统  驱动程序  51单片机 手机看文章 扫描二维码
随时随地手机看文章
/*****************************************************************************

   门禁系统项目驱动程序

 (1)晶振 11.0592MHZ
 (2)芯片 DS1302,AT24C64,HEF4053BP
 (3)ZIMO21.EXE纵向、字节倒序取字模
(4)完整代码下载(包含头文件):http://www.51hei.com/f/12154f.rar
*****************************************************************************/
#include "reg51.h"
#include "intrins.h"
#include "7041_Door.h"   //字模

#define LCD_DATA P1 //液晶屏数据输入
#define EEAddr EAddr.All //AT24C64片内地址
#define EAddrH EAddr.array[0]
#define EAddrL EAddr.array[1]

#define uchar unsigned char
#define uint unsigned int

union Add{      //定义EEPROM地址
        uint All;
        uchar array[2];
}EAddr;

uchar Sto = 1,Del = 0;
uint DelCount;  //定时器中断中用于延时的变量DelCount
uchar Function = 0; //按键功能变量Function
uchar SCount = 0; //串行中断中用于计数卡号信息的循环变量
bit TimeDisFlag = 0,KEndFlag = 0,StoreFlag = 0,DeleteFlag = 0,SwitchFlag = 0,WXFlag = 0,NSK12Flag = 0; //控制时间显示标志位TimeDisFlag,14位卡号接收完的标志KEndFlag
uchar CardNo[14] = {0},GetTime[7],RD24C64[32] = 0,CardMax = 0,CardNum = 0;//存储读到的卡号CardNo[14],存储从1302读到的时间GetTime[7],存入卡的个数CardMax

/*---------------------------------定义P口-----------------------------------*/

sbit LCD_RS = P2^7;  //LCD12864
sbit LCD_RW = P2^6;
sbit LCD_E = P2^5;
sbit LCD_CS1 = P2^4;
sbit LCD_CS2 = P2^3;
sbit Busy = P1^7;
sbit Motor2 = P3^7;
sbit Motor1 = P3^6;
sbit SDA_24C64 = P3^5; //AT24C64
sbit SCL_24C64 = P3^4;
sbit CLK_1302 = P2^2; //DS1302
sbit IO_1302 = P2^1;
sbit RST_1302 = P2^0;
sbit RS_485 = P3^2; //485R/S,其为1时允许发送,为0时允许接收
sbit CON_4053 = P3^3; //通信控制,其为1时读卡,为0时485通信
sbit KEY1 = P0^0; //定义按键
sbit KEY2 = P0^1;
sbit KEY3 = P0^2;
sbit KEY4 = P0^3;

/***************************液晶屏驱动程序*********************************/

void LCD_BusyCheck(bit BCS){ //检测忙子程序
 LCD_DATA = 0xff; //LCD_RS = 0,LCD_RW = 1,LCD_E = 高电平。
 LCD_RS = 0;
 LCD_RW = 1;
 if(BCS){  //检测片1忙状态
  LCD_CS1 = 1;
  LCD_E = 1;
  while(Busy);
  LCD_E = 0;
  LCD_CS1 = 0;
 }
 else{   //检测片2忙状态
  LCD_CS2 = 1;
  LCD_E = 1;
  while(Busy);
  LCD_E = 0;
  LCD_CS2 = 0;
 }
}
void LCD_Write_Code(uchar WCode,bit CS){//写指令子程序
 LCD_BusyCheck(CS);  //调用忙检测子程序:写前检测
 LCD_DATA = WCode;
 LCD_RS = 0; //LCD_RS = 0,LCD_RW = 0,LCD_E = 高脉冲。
 LCD_RW = 0;
 if(CS){   //检测片1忙状态
  LCD_CS1 = 1;
  LCD_E = 1;
  _nop_();
  LCD_E = 0;
  LCD_CS1 = 0;
 }
 else{   //检测片2忙状态
  LCD_CS2 = 1;
  LCD_E = 1;
  _nop_();
  LCD_E = 0;
  LCD_CS2 = 0;
 }
}
void LCD_Write_Data(uchar WData,uchar CS){ //写数据子程序
 LCD_BusyCheck(CS);  //调用忙检测子程序:写前忙状态检测
 LCD_DATA = WData;
 LCD_RS = 1; //LCD_RS = 1,LCD_RW = 0,LCD_E = 高脉冲。
 LCD_RW = 0;
 if(CS){   //检测片1忙状态
  LCD_CS1 = 1;
  LCD_E = 1;
  _nop_();
  LCD_E = 0;
  LCD_CS1 = 0;
 }
 else{   //检测片2忙状态
  LCD_CS2 = 1;
  LCD_E = 1;
  _nop_();
  LCD_E = 0;
  LCD_CS2 = 0;
 }
}
void LCD_Write(uchar xpos,uchar ypos,uchar WData){//写屏子(地址转换)程序
 uchar WCS;
 if(xpos < 64) WCS = 1; //判断将要操作片1或片2:WCS = 1操作LCD_CS1
 else  WCS = 0;  //WCS = 2 操作LCD_CS2
 ypos &= 0x07;   //页地址转换
 ypos |= 0xb8;
 LCD_Write_Code(ypos,WCS); //写入页地址到对应片
 xpos &= 0x3f;   //列地址转换
 xpos |= 0x40;
 LCD_Write_Code(xpos,WCS); //写入列地址到对应片
 LCD_Write_Data(WData,WCS); //写入数据到对应片
}
void LCD_Data_DisWord(uchar xpos,uchar ypos,uchar array[]){//汉字显示子程序:12*16
 uchar Cnt = 0,x = 0,y = 0;
 for(y = ypos;y < ypos + 2;y ++){
  for(x = xpos;x < xpos + 12;x ++,Cnt ++)
   LCD_Write(x,y,array[Cnt]); //调用写屏子程序:在对应的地址上写入要显示的内容
 }
}
void LCD_Data_DisNum(uchar xpos,uchar ypos,uchar array[]){//数字及符号显示子程序:6*16
 uchar Cnt = 0,x = 0,y = 0;
 for(y = ypos;y < ypos + 2;y ++){
  for(x = xpos;x < xpos + 6;x ++,Cnt ++)
   LCD_Write(x,y,array[Cnt]); //调用写屏子程序:在对应的地址上写入要显示的内容
 }
}
void LCD_All_Clear(void){//清屏子程序:全屏清0
 uchar x,y;
 for(y = 0;y < 8;y ++)
  for(x = 0;x < 128;x ++)
   LCD_Write(x,y,0x00); //调用写屏子程序:全屏写0
}
void LCD_Page_Clear(uchar yPage){//清屏子程序:清除以所给页坐标为起始的两页的内容
 uchar x,y;
 for(y = yPage;y < yPage + 2;y ++)
  for(x = 0;x < 128;x ++)
   LCD_Write(x,y,0x00); //调用写屏子程序:以所给页坐标为起始的两页写0
}
void LCD_Reset(void){//液晶屏初始化设置
 LCD_E = 0;
 LCD_Write_Code(0x3f,1);  //开片1显示
 LCD_Write_Code(0x3f,0);  //开片2显示
 LCD_Write_Code(0xc0,1);  //设片1起始行显示
 LCD_Write_Code(0xc0,0);  //设片2起始行显示
}

/******************************DS1302时钟程序*******************************/

void DS1302_WriteByte(uchar WData){    //写入一个字节
 uchar Cnt;
    for(Cnt=0;Cnt<8;Cnt++){
         WData >>= 1; //写入数据时先写低位再写高位(D0---D7)
         CLK_1302 = 0;
         IO_1302 = CY;
  CLK_1302 = 1;  //上升沿将数据写入1302
    }
}
uchar DS1302_ReadByte(){       //读出一个字节
    uchar Cnt,RData = 0;
        for(Cnt = 0;Cnt < 8;Cnt ++){
  RData >>= 1; //读数据时先读低位再读高位(D0---D7)
                CLK_1302 = 1;
         CLK_1302 = 0;  //下降沿将数据读出来
         if(IO_1302)
   RData |= 0x80;
  else RData &= 0x7f;
 }
 return RData;
}
void DS1302_WriteData(uchar Waddr,uchar Wdata){  //向某地址中写入一个字节的数据
 RST_1302 = 0;
 CLK_1302 = 0;
 RST_1302 = 1;
 DS1302_WriteByte(Waddr);//写入地址
 DS1302_WriteByte(Wdata);//写入数据
 CLK_1302 = 0;
 RST_1302 = 0;
}
uchar DS1302_ReadData(uchar RAddr){   //读取1302某地址中一个字节的数据
     uchar Rdata;
 RST_1302 = 0;
 CLK_1302 = 0;
 RST_1302 = 1;
 DS1302_WriteByte(RAddr); //写入读取数据的地址
 Rdata = DS1302_ReadByte(); //读取数据
 RST_1302 = 0;
 IO_1302 = 1;
 return(Rdata);
}
void DS1302_SetTime(){      //设置1302时间
      uchar Cnt,Add = 0x80;//秒 寄存器的写地址0x80
        // 秒   分   时   日   月 星期 年
 uchar STime[7] = {0x00,0x19,0x14,0x18,0x07,5,0x08};

      DS1302_WriteData(0x8e,0x00); //禁止写保护(可写入数据)
      for(Cnt = 0;Cnt < 7;Cnt ++,Add += 2)//循环写入秒,分,时,日,月,星期,年
       DS1302_WriteData(Add,STime[Cnt]);
     DS1302_WriteData(0x8e,0x80); //写保护(不能写入数据)
}
void DS1302_GetTime(){    //读取1302中当前时间
 uchar Cnt,Addr = 0x81;//秒 寄存器的读地址0x81
   for(Cnt = 0;Cnt < 7;Cnt ++,Addr += 2)//循环读取秒,分,时,日,月,星期,年
    GetTime[Cnt] = DS1302_ReadData(Addr);
}

/**************************液晶屏显示程序******************************/

void LCD_DisTime(){  //显示从1302读取的时间
 DS1302_GetTime();
 LCD_Data_DisNum(32,0,num[GetTime[6] >> 4]); //年(由1302循环读出显示)
 LCD_Data_DisNum(38,0,num[GetTime[6] & 0x0f]);
        LCD_Data_DisNum(50,0,num[GetTime[4] >> 4]); //月
 LCD_Data_DisNum(56,0,num[GetTime[4] & 0x0f]);
 LCD_Data_DisNum(68,0,num[GetTime[3] >> 4]); //日
        LCD_Data_DisNum(74,0,num[GetTime[3] & 0x0f]);
 LCD_Data_DisNum(122,0,num[GetTime[5]]); //星期
 LCD_Data_DisNum(32,2,num[GetTime[2] >> 4]); //时
 LCD_Data_DisNum(38,2,num[GetTime[2] & 0x0f]);
        LCD_Data_DisNum(50,2,num[GetTime[1] >> 4]); //分
 LCD_Data_DisNum(56,2,num[GetTime[1] & 0x0f]);
 LCD_Data_DisNum(68,2,num[GetTime[0] >> 4]); //秒
        LCD_Data_DisNum(74,2,num[GetTime[0] & 0x0f]);
}
void LCD_DisCell(){//显示固定不变的内容(日期,时间等汉字及符号的显示)(图1~4)
 LCD_Data_DisWord(2,0,ri);
 LCD_Data_DisWord(14,0,qi);
        LCD_Data_DisNum(26,0,maohao);
        LCD_Data_DisNum(44,0,heng);
        LCD_Data_DisNum(62,0,heng);
        LCD_Data_DisWord(92,0,xing);
 LCD_Data_DisWord(104,0,qi);
 LCD_Data_DisNum(116,0,maohao);
        LCD_Data_DisWord(2,2,shi);
 LCD_Data_DisWord(14,2,jian);
        LCD_Data_DisNum(26,2,maohao);
        LCD_Data_DisNum(44,2,heng);
        LCD_Data_DisNum(62,2,heng);
}
void LCD_Display1(){  //无操作状态时显示内容
 LCD_DisCell();
        LCD_Data_DisWord(34,4,wu); //无操作状态
 LCD_Data_DisWord(46,4,cao);
 LCD_Data_DisWord(58,4,zuo);
 LCD_Data_DisWord(70,4,zhuang);
 LCD_Data_DisWord(82,4,tai);
}
void LCD_Display2(){ //刷卡后显示此卡有效或无效
        LCD_Data_DisWord(2,4,ka); //显示刷卡后的卡号
 LCD_Data_DisWord(14,4,hao);
 LCD_Data_DisNum(26,4,maohao);
}
void LCD_Display3(){ //显示电机状态:打开或关闭
 //LCD_DisCell();  //显示固定不变的内容
        LCD_Data_DisWord(2,4,dian); //电机状态
 LCD_Data_DisWord(14,4,ji);
 LCD_Data_DisWord(26,4,zhuang);
 LCD_Data_DisWord(38,4,tai);
 LCD_Data_DisNum(50,4,maohao);
}
void LCD_Display4(){  //显示数据上传过程:上传成功或失败
        LCD_Data_DisWord(2,4,shu); //数据上传
 LCD_Data_DisWord(14,4,ju);
 LCD_Data_DisWord(26,4,shang);
 LCD_Data_DisWord(38,4,chuan);
 LCD_Data_DisNum(50,4,maohao);

 LCD_Data_DisWord(56,4,kuang1);
 LCD_Data_DisWord(68,4,kuang1);
 LCD_Data_DisWord(80,4,kuang1);
 LCD_Data_DisWord(92,4,kuang1);
 LCD_Data_DisWord(104,4,kuang1);
 LCD_Data_DisWord(116,4,kuang1);

  LCD_Data_DisWord(35,6,cheng);
  LCD_Data_DisWord(47,6,gong);

  LCD_Data_DisWord(75,6,shibai);
  LCD_Data_DisWord(87,6,bai);
}
void LCD_Display5(){  //显示存卡过程:存入或取消存储
        LCD_Data_DisWord(2,0,cun); //存卡
 LCD_Data_DisWord(14,0,ka);
 LCD_Data_DisWord(2,2,ka); //卡号
 LCD_Data_DisWord(14,2,hao);
 LCD_Data_DisNum(26,2,maohao);
}
void LCD_Display6(){  //显示卡号删除过程:确认删除或取消删除
        LCD_Data_DisWord(2,0,liu); //浏览卡号
 LCD_Data_DisWord(14,0,lan);
 LCD_Data_DisWord(26,0,ka);
 LCD_Data_DisWord(38,0,hao);
 LCD_Data_DisWord(2,2,ka); //卡号显示
 LCD_Data_DisWord(14,2,hao);
 LCD_Data_DisNum(26,2,maohao);
 LCD_Data_DisWord(35,4,shan);
 LCD_Data_DisWord(47,4,chu);
 LCD_Data_DisWord(75,4,qu);
 LCD_Data_DisWord(87,4,quxiao);
}

/******************************AT24C64存储程序*******************************/

void I2C_Start(void){ //I2C总线启动
 SCL_24C64 = 1;
 _nop_();
 SDA_24C64 = 1;
 _nop_();
 SDA_24C64 = 0;
}
void I2C_Stop(void){ //I2C总线通信结束
 SCL_24C64 = 0;
 SDA_24C64 = 0;
 _nop_();
 SCL_24C64 = 1;
 SDA_24C64 = 1;
}
void I2C_ACK_Send(bit ack){//发送返回帧
 SDA_24C64 = ack;
 SCL_24C64 = 1;
 _nop_();
 SCL_24C64 = 0;
 SDA_24C64 = 1; //释放总线
}
bit I2C_ACK_Receive(){//接收返回帧
 bit ACKR;
 SDA_24C64 = 1; //释放总线
 SCL_24C64 = 1;
 _nop_();
 ACKR = SDA_24C64;
        SCL_24C64 = 0;
 return ACKR;
}
void I2C_SendByte(uchar WData){ //写入一个字节的数据
 uchar Count;
 SCL_24C64 = 0;
 for(Count = 0;Count < 8;Count ++){
  WData <<= 1;
  SDA_24C64 = CY;
  SCL_24C64 = 1; //下降沿写入数据
  _nop_();
  SCL_24C64 = 0;
 }
}
uchar I2C_ReceiveByte(){ //读出一个字节的数据
 uchar Count,RData;
 SCL_24C64 = 0;
 for(Count = 0;Count < 8;Count ++){
  RData <<= 1;
  SCL_24C64 = 1; //高电平读出数据
  _nop_();
  if(SDA_24C64)
   RData |= 0x01;
  else RData &= 0xfe;
  SCL_24C64 = 0;
 }
 return RData;
}
void I2C_Write_AT24C64(uchar WAddrH,uchar WAddrL,uchar *Point,uchar WNum){//向WAddrH,WAddrL为首地址的页中写入WNum个字节
 bit ACK;uchar Cnt;
  I2C_Start(); //启动通信
  do{
   I2C_SendByte(0xa0); //AT24C64的写地址
          ACK = I2C_ACK_Receive();
 }while(ACK);
  do{
   I2C_SendByte(WAddrH); //写字节高地址
          ACK = I2C_ACK_Receive();
      }while(ACK);
 do{
  I2C_SendByte(WAddrL); //写字节低地址
      ACK = I2C_ACK_Receive();
 }while(ACK);
 for(Cnt = 0;Cnt < WNum;Cnt ++,Point ++){ //循环写入WNum个字节
  do{
  I2C_SendByte(*Point);  //写的内容
         ACK = I2C_ACK_Receive();
  }while(ACK);
 }
 I2C_Stop();    //通信结束
}
uchar I2C_Read_AT24C64(uchar WAddrH,uchar WAddrL,uchar RNum){ //从WAddrH,WAddrL为首地址的页中读取RNum个字节
 uchar Cnt; //一页最多32个字节
 bit ACK;
  I2C_Start(); //启动通信
  do{
   I2C_SendByte(0xa0);//AT24C64的写地址
             ACK = I2C_ACK_Receive();
        }while(ACK);
 do{
  I2C_SendByte(WAddrH); //写入地址的高5位
      ACK = I2C_ACK_Receive();
 }while(ACK);
 do{
  I2C_SendByte(WAddrL); //写入地址的低8位
      ACK = I2C_ACK_Receive();
 }while(ACK);
 I2C_Start(); //再次启动通信
 do{
  I2C_SendByte(0xa1); //AT24C64的读地址
      ACK = I2C_ACK_Receive();
 }while(ACK);
 for(Cnt = 0;Cnt < RNum;Cnt ++){ //循环读取RNum个字节
  RD24C64[Cnt] = I2C_ReceiveByte();
  if(Cnt != RNum - 1)
   I2C_ACK_Send(0);
 }
 I2C_ACK_Send(1); //读取最后一个字节的数据后的返回帧
 I2C_Stop(); //通信结束
}
void AT24C64Init(){ //24C64初始化
 //I2C_Write_AT24C64(0x00,0x1f,&CardMax,1); //将存储卡的最大数目初始化为0
 //I2C_Write_AT24C64(0x00,0x1e,&CardNum,1); //将存储卡的数目初始化为0
 I2C_Read_AT24C64(0x00,0x1f,1); //读取0x00,0x1f地址中的内容,其为存储卡过程中曾存卡的最多个数
 CardMax = RD24C64[0]; //将读取的数据存入卡数目最大值变量CardMax中
 I2C_Read_AT24C64(0x00,0x1e,1); //读取0x00,0x1e地址中的内容,其为存储卡的数目
 CardNum = RD24C64[0]; //将读取的数据存入卡数目变量CardNum中
 EEAddr = 0x0000; //将24C64的地址初始化到首地址
}[page]

/******************************按键控制程序*********************************/

void KeyScan(){  //按键扫描
 if(!KEY1){
  DelCount = 0;
  while(DelCount < 2);
  if(!KEY1){
   while(!KEY1);
   Function = 1;
  }
 }
 if(!KEY2){
  DelCount = 0;
  while(DelCount < 2);
  if(!KEY2){
   while(!KEY2);
   Function = 2;
  }
 }
 if(!KEY3){
  DelCount = 0;
  while(DelCount < 2);
  if(!KEY3){
   while(!KEY3);
   Function = 3;
  }
 }
 if(!KEY4){
  DelCount = 0;
  while(DelCount < 2);
  if(!KEY4){
   while(!KEY4);
   Function = 4;
  }
 }
}
void KeyFunc(){  //按键功能分配
 uchar Cnt = 0;
 bit CFlag = 0; //待存入的卡与EEPROM中的卡号比较标志位
 switch(Function){ //具体按键功能分配程序
  case 1: if(!SwitchFlag){//切换标志位,用于存卡及浏览卡号时上翻
    TimeDisFlag = 1;//存储卡号期间主函数运行时不再显示时间
    KEndFlag = 0; //确认在进入存卡系统后刷卡有效,否则无效
    WXFlag = 1; //按下KEY1后,接着按key2无效
    StoreFlag = 1; //存储标志位,0为无效,1为存储
    LCD_All_Clear(); //清全屏
    LCD_Display5(); //显示存卡界面
    while(!KEndFlag);//等待刷卡后读取卡信息结束
                         KEndFlag = 0; //确认在进入存卡系统后刷卡有效,否则无效
           for(Cnt = 1;Cnt < 11;Cnt ++){ //显示读取的卡号
            if(CardNo[Cnt] >= 0x40)
             LCD_Data_DisNum(32 + Cnt * 6,2,num[CardNo[Cnt]-0x40+10]);
            else LCD_Data_DisNum(32 + Cnt * 6,2,num[CardNo[Cnt]-0x30]);
           }
    LCD_Data_DisWord(35,4,cun); //显示汉字“存入”“取消”
    LCD_Data_DisWord(47,4,ru);
    LCD_Data_DisWord(75,4,qu);
    LCD_Data_DisWord(87,4,quxiao);
   }
   if(SwitchFlag){ //浏览卡号时上翻功能
    if(!NSK12Flag){
     while(1){
      if(EEAddr == 0x0000)
       EEAddr = 0x0000 + (CardMax - 1) * 0x20;
      else EEAddr -= 0x20; //24C64存储时一页存储一张卡号
      I2C_Read_AT24C64(EAddrH,EAddrL,12); //读取24C64中存储的卡号
             if(RD24C64[0] == 1){ //从24C64EEAddr地址中读取的卡号有效
              for(Cnt = 2;Cnt < 12;Cnt ++){ //显示读取的卡号
               if(RD24C64[Cnt] >= 0x40)
                LCD_Data_DisNum(32 + (Cnt - 1) * 6,2,num[RD24C64[Cnt]-0x40+10]);
               else LCD_Data_DisNum(32 + (Cnt - 1) * 6,2,num[RD24C64[Cnt]-0x30]);
              }
              break; //显示一个有效的卡号后退出
             }
     }
    }
   }
   break;
  case 2: if(!WXFlag){
    if(SwitchFlag){ //浏览卡号时下翻功能
     if(!NSK12Flag){
      while(1){
       EEAddr += 0x20; //往下翻页
       if(EEAddr == 0x0000 + CardMax * 0x20)
        EEAddr = 0x0000;
       I2C_Read_AT24C64(EAddrH,EAddrL,12);
              if(RD24C64[0] == 1){ //读取的卡号有效
               for(Cnt = 2;Cnt < 12;Cnt ++){ //显示读取的卡号
                if(RD24C64[Cnt] >= 0x40)
                 LCD_Data_DisNum(32 + (Cnt - 1) * 6,2,num[RD24C64[Cnt]-0x40+10]);
                else LCD_Data_DisNum(32 + (Cnt - 1) * 6,2,num[RD24C64[Cnt]-0x30]);
               }
               break;
              }
      }
     }
    }
    if(!SwitchFlag){ //删除卡号
     TimeDisFlag = 1;//删除卡号期间主函数运行时不再显示时间
     DeleteFlag = 1; //删除标志位,0为无效,1为存储
     SwitchFlag = 1;
     LCD_All_Clear(); //清全屏
     I2C_Read_AT24C64(0x00,0x1e,1);
            CardNum = RD24C64[0];
            if(CardNum == 0)NSK12Flag = 1;
     for(EEAddr = 0x0000;EEAddr < 0x0000 + CardMax * 0x20;EEAddr += 0x20){//读出卡号和存储器中的卡号进行比较
             I2C_Read_AT24C64(EAddrH,EAddrL,12);
             if(RD24C64[0] == 1){
              for(Cnt = 2;Cnt < 12;Cnt ++){ //显示读取的卡号
               if(RD24C64[Cnt] >= 0x40)
                LCD_Data_DisNum(32 + (Cnt - 1) * 6,2,num[RD24C64[Cnt]-0x40+10]);
               else LCD_Data_DisNum(32 + (Cnt - 1) * 6,2,num[RD24C64[Cnt]-0x30]);
              }
              break;
             }
            }
     LCD_Display6(); //显示存卡界面
    }
   }
   break;
  case 3: if(StoreFlag){ //存储卡号
    Cnt = 0;
    for(EEAddr = 0x0000;EEAddr < 0x0000 + CardMax * 0x20;EEAddr += 0x20){//读出卡号和存储器中的卡号进行比较
            I2C_Read_AT24C64(EAddrH,EAddrL,12);
            if(RD24C64[0] == 1){
             for(Cnt = 0;Cnt < 11;Cnt ++){ //11位卡号进行比较
              if(CardNo[Cnt] != RD24C64[Cnt + 1]) //比较过程中有不相等的就读下一内存
               break;
             }
            }
            if(Cnt == 11){ //一组数据比较过程中全部相等时,此卡已存在
             CFlag = 1;
             LCD_Page_Clear(4);//清除4,5页的显示内容
             LCD_Data_DisWord(34,4,ci); //显示“此卡已存在”
      LCD_Data_DisWord(46,4,ka);
      LCD_Data_DisWord(58,4,yi);
      LCD_Data_DisWord(70,4,cun);
      LCD_Data_DisWord(82,4,zai);
      break;
            }
           }
           if(!CFlag){
            I2C_Read_AT24C64(0x00,0x1e,1);
            CardNum = RD24C64[0];
            I2C_Read_AT24C64(0x00,0x1f,1);
            CardMax = RD24C64[0];
            if(CardNum == CardMax){ //往后边空间存储
             EEAddr = 0x0000 + CardMax * 0x20;
      I2C_Write_AT24C64(EAddrH,EAddrL,&Sto,1);//存入标志位,表示此页已存入卡号
      DelCount = 0; //延时10ms
      while(DelCount < 2);
      I2C_Write_AT24C64(EAddrH,EAddrL + 1,CardNo,11); //存入11位卡号
      DelCount = 0; //延时10ms
      while(DelCount < 2);
      CardMax ++;
      CardNum ++;
      I2C_Write_AT24C64(0x00,0x1f,&CardMax,1);
      DelCount = 0; //延时10ms
      while(DelCount < 2);
      I2C_Write_AT24C64(0x00,0x1e,&CardNum,1);
            }
            else if(CardMax > CardNum){ //在CardMax范围内找空间存储
             for(EEAddr = 0x0000;EEAddr < 0x0000 + CardMax * 0x20;EEAddr += 0x20){//读出卡号和存储器中的卡号进行比较
              I2C_Read_AT24C64(EAddrH,EAddrL,12);
              if(RD24C64[0] == 0){
               I2C_Write_AT24C64(EAddrH,EAddrL,&Sto,1);//存入标志位,表示此页已存入卡号
        DelCount = 0; //延时10ms
        while(DelCount < 2);
        I2C_Write_AT24C64(EAddrH,EAddrL + 1,CardNo,11); //存入11位卡号
               CardNum ++;
               DelCount = 0; //延时10ms
        while(DelCount < 2);
        I2C_Write_AT24C64(0x00,0x1e,&CardNum,1);
                                                                break;
              }
             }
            }
     LCD_Page_Clear(4);//清除4,5页的显示内容
     LCD_Data_DisWord(34,4,cun); //显示“存入成功”
     LCD_Data_DisWord(46,4,ru);
     LCD_Data_DisWord(58,4,cheng);
     LCD_Data_DisWord(70,4,gong);
           }
           DelCount = 0; //延时2s
           StoreFlag = 0;
           TimeDisFlag = 0;//返回后继续显示时间,时间显示标志为清零
    while(DelCount < 400);
    LCD_All_Clear(); //清全屏
   }
   if(DeleteFlag){ //删除
    I2C_Read_AT24C64(0x00,0x1e,1);
           CardNum = RD24C64[0];
           if(CardNum != 0){
     I2C_Write_AT24C64(EAddrH,EAddrL,&Del,1);
     DelCount = 0; //延时10ms
     while(DelCount < 2);
     CardNum --; //删除一张卡后卡的数量减1
     I2C_Write_AT24C64(0x00,0x1e,&CardNum,1);//存入标志位,表示此页已存入卡号
     LCD_Page_Clear(4);//清除4,5页的显示内容
     LCD_Data_DisWord(34,4,shan); //显示“删除成功”
     LCD_Data_DisWord(46,4,chu);
     LCD_Data_DisWord(58,4,cheng);
     LCD_Data_DisWord(70,4,gong);
     DelCount = 0; //延时2s
     while(DelCount < 400);
    }
    DeleteFlag = 0;
    SwitchFlag = 0;
    TimeDisFlag = 0;//返回后继续显示时间,时间显示标志为清零
    LCD_All_Clear(); //清全屏
   }
   NSK12Flag = 0;
   WXFlag = 0;
   break;
  case 4: if(StoreFlag || DeleteFlag){
    TimeDisFlag = 0;//推出存储或删除,显示时间
    StoreFlag = 0;
    WXFlag = 0;
    DeleteFlag = 0;
    NSK12Flag = 0;
    SwitchFlag = 0;
    LCD_All_Clear(); //清全屏
   }
   break;
  default:break;
 }
 Function = 0;
}
void TimeInit(void){ //定时器,串口初始化(定时器1作为波特率发生器[9600BPS],定时器0作为程序中的延时)
 TMOD = 0x21; //定时器0,工作方式1,定时器1,工作方式2
 TH0 = 0xec; //定时器赋初值:5ms
 TL0 = 0x78;
 TR0 = 1; //启动定时器0
 ET0 = 1; //开定时器0中断
 TH1 = 0xfd; //波特率发生器:9600BPS
 TL1 = 0xfd;
 TR1 = 1;
 SCON = 0x50; //串行工作方式1,允许接收
 PCON = 0x00; //SMOD = 0
 ES = 1;  //开串行通信中断
 EA = 1;  //开中断总开关
}

/***************************主程序******************************/

main(){
 uchar Cnt;
 bit ComFlag = 0;
 CON_4053 = 1;//允许读卡
 Motor1 = 1; //电机正转停止
 Motor2 = 1; //电机反转停止
 TimeInit();  //定时器,串口初始化
 LCD_Reset();  //液晶屏初始化设置
 LCD_All_Clear(); //清全屏
 DS1302_SetTime(); //1302设置初始时间
 AT24C64Init(); //24C64初始化
 while(1){
  if(!TimeDisFlag){
   LCD_Display1();
          LCD_DisTime();
  }
         KeyScan(); //按键扫描
         KeyFunc(); //按键功能分配
         if(KEndFlag){  //卡号接收完毕
          //KEndFlag = 0;
          LCD_Page_Clear(4);//清除4,5页的显示内容
          LCD_Display2();
          for(Cnt = 1;Cnt < 11;Cnt ++){ //显示读取的卡号
           if(CardNo[Cnt] >= 0x40)
            LCD_Data_DisNum(32 + Cnt * 6,4,num[CardNo[Cnt]-0x40+10]);
           else LCD_Data_DisNum(32 + Cnt * 6,4,num[CardNo[Cnt]-0x30]);
          }
                        Cnt = 0;//显示卡号后Cnt已经是11,故先清零,以便下边比较卡号时使用Cnt == 11
          for(EEAddr = 0x0000;EEAddr < 0x0000 + CardMax * 0x20;EEAddr += 0x20){//读出卡号和存储器中的卡号进行比较
           I2C_Read_AT24C64(EAddrH,EAddrL,12);
           if(RD24C64[0] == 1){
            for(Cnt = 0;Cnt < 11;Cnt ++){ //11位卡号进行比较
            if(CardNo[Cnt] != RD24C64[Cnt + 1]) //比较过程中有不相等的就读下一内存
             break;
            }
           }
           if(Cnt == 11){ //一组数据比较过程中全部相等时,显示有效并推出比较
            ComFlag = 1;//比较后的卡号相同
            LCD_Data_DisWord(70,6,you); //显示“有效”
     LCD_Data_DisWord(82,6,xiao);
     DelCount = 0; //延时100ms
     while(DelCount < 20);
     LCD_Page_Clear(4);//清除4,5页的显示内容
     LCD_Page_Clear(6);//清除6,7页的显示内容
     break;
           }
          }
          LCD_DisTime(); //若比较卡号时耗时较长,及时读取时间显示
          if(!ComFlag){ //比较无此卡号时显示“无效”
    LCD_Data_DisWord(100,6,wu);
    LCD_Data_DisWord(112,6,xiao);
    DelCount = 0;
           while(1){
            LCD_DisTime(); //读取时间显示
            if(DelCount > 400){
             LCD_Page_Clear(4);//清除4,5页的显示内容
             LCD_Page_Clear(6);//清除6,7页的显示内容
             break;
            }
           }
          }
          if(ComFlag){
           LCD_Display3();
    LCD_Data_DisWord(60,4,da);
    LCD_Data_DisWord(72,4,kai);
    Motor1 = 0; //电机正转
    DelCount = 0;
    while(1){ //电机正转中
     LCD_DisTime(); //时间显示
     if(DelCount > 600)
      break;
    }
    Motor1 = 1; //电机正转停止
    LCD_Data_DisWord(60,4,guan);
    LCD_Data_DisWord(72,4,bi);
    DelCount = 0;
    while(1){ //等待人过去
     LCD_DisTime(); //时间显示
     if(DelCount > 600)
      break;
    }
    Motor2 = 0; //电机反转
    LCD_Data_DisWord(60,4,da);
    LCD_Data_DisWord(72,4,kai);
    DelCount = 0;
    while(1){ //电机反转中
     LCD_DisTime(); //时间显示
     if(DelCount > 600)
      break;
    }
    Motor2 = 1; //电机反转停止
    DelCount = 0;
    LCD_Data_DisWord(60,4,guan);
    LCD_Data_DisWord(72,4,bi);
    while(1){ //门关上上后延时2s
     LCD_DisTime(); //时间显示
     if(DelCount > 400)
      break;
    }
    LCD_Page_Clear(4);
    LCD_Page_Clear(6);
          }
          ComFlag = 0;
          KEndFlag = 0;
         }
 }
}
void Serial() interrupt 4{ //串行中断入口地址
 if(RI){
  CardNo[SCount] = SBUF;
  RI = 0;
  SCount ++;
  if(SCount == 14){
   KEndFlag = 1;
   SCount = 0;
  }
 }
}
void Time0() interrupt 1{ //定时器0入口地址
 TH0 = 0xec; // 5ms
 TL0 = 0x78;
 DelCount ++;
}

关键字:门禁系统  驱动程序  51单片机 引用地址:门禁系统项目驱动程序

上一篇:谈谈自学C51单片机的一些见解仅作参考
下一篇:基于单片机的便携数字存储示波器

推荐阅读最新更新时间:2024-03-16 14:24

51单片机简易加法计算器
#include reg52.h typedef unsigned char uchar; typedef unsigned int uint; typedef unsigned long ulong; sbit ADDR0 = P1^0; sbit ADDR1 = P1^1; sbit ADDR2 = P1^2; sbit ADDR3 = P1^3; sbit ENLED = P1^4; sbit KEY_IN_0 = P2^4; sbit KEY_IN_1 = P2^5; sbit KEY_IN_2 = P2^6; sbit KEY_IN_3 = P2^7;
[单片机]
基于51单片机实现模拟IIC总线时序
最近用到测量光线的模块BH1750FVI时需要用到IIC总线操作, 于是就又费功夫学习了下, 基本上算是了解了, 所以呢, 就用51的IO口, 模拟出了总线时序, 并能正确操纵需要用IIC总线访问地一系列模块. 本来想写篇文章简单介绍下我对IIC总线的理解的, 但, 发现没工夫, 所以, 放在以后有时候再来弄吧. 今天我还是只给出一个范例程序, 它能在我的51单片机机系统上工作得很好. iic.h 列出了所有IIC总线的操作函数. 下面给出源代码: //iic.h - 实现相关的头文件 //女孩不哭 2013-01-18 #ifndef __IIC_H__ #define __IIC_H__ void iic_start(
[单片机]
MCS-51单片机内部数据存储器特点及如何设置
MCS-51单片机内部数据存储器是怎样设置的? 答:MCS-51单片机内部有128个字节的数据存储器,内部RAM编址为00H~7FH。 MCS-51对其内部的RAM存储器有很丰富的操作指令,方便了程序设计。 单片机内部数据存储器的特点是什么? 答:工作寄存器和数据存储器是统一编址的,这是单片机内部存储器的主要特点。
[单片机]
从零开始51单片机教程 —— 27 矩阵式键盘接口技术及程序设计
矩阵式键盘接口技术及程序设计 在单片机系统中键盘中按钮数量较多时,为了减少I/O口的占用,常常将按钮排列成矩阵形式,如图1所示。在矩阵式键盘中,每条水平线和垂直线在交叉处不直接连通,而是通过一个按钮加以连接。这样,一个端口(如P1口)就能组成4*4=16个按钮,比之直接将端口线用于键盘多出了一倍,而且线数越多,区别越明显,比如再多加一条线就能组成20键的键盘,而直接用端口线则只能多出一键(9键)。由此可见,在需要的键数比较多时,采用矩阵法来做键盘是合理的。 单片机矩阵式键盘接口技术及编程接口图 矩阵式结构的键盘显然比直接法要复杂一些,识别也要复杂一些,上图中,列线通过电阻接正电源,并将行线所接的单片机的I/O口作
[单片机]
从零开始<font color='red'>51单片机</font>教程 —— 27 矩阵式键盘接口技术及程序设计
51单片机矩阵键盘与左右流水灯控制C程序
本程序所用的原理图下载: 点这里 ,单片机芯片使用的stc89c52;找到本程序所使用的相应部分即可.这是一整个单片机开发板的电路图其他的忽略. hex文件及其工程文件下载:http://www.51hei.com/f/jzzyou.rar 以下是测试ok的源代码: /* *功能:使用矩阵按键使得按键按下时数码管上显示各自对应的数字的平方数; * 且使用定时器0中断使得彩色流水灯先以20毫秒的速度左移流动4秒后, * 然后使得彩色流水灯以20毫秒的速度右移流动; *日期:2013-05-02-16:46 *作者:徐冉 *特别说明:本程序代码已经通过调试,仅供学习使用; * */ /***********AT89C52-RC 单
[单片机]
51单片机实验(一)定时/计数器及其中断
我们这学期开了单片机的课,不知道为什么我们要用汇编语言写程序,感觉汇编程序真的挺难写的,所以把实验记录下来把。 如果没有学过汇编的小伙伴建议先去熟悉一下简单的汇编指令,之前简单的实验我就不记录了,我们从定时计数器实验开始吧。 首先来回顾一下和中断,定时有关的知识 51单片机中断级别 中断源 中断允许寄存器IE EA---全局中允许位。 EA=1,打开全局中断控制,在此条件下,由各个中断控制位确定相应中断的打开或关闭。 EA=0,关闭全部中断。 -------,无效位。 ET2---定时器/计数器2中断允许位。 EA总中断开关,置1为开; ET2=1,打开T2中断。 EX0为外部中断0(INT0)开关,…… ET
[单片机]
<font color='red'>51单片机</font>实验(一)定时/计数器及其中断
基于Linux系统的指纹识别门禁系统
  指纹作为人体的身体特征,具有唯一性、稳定性和不易盗用等特点。随着指纹识别理论逐渐成熟、指纹采集工具这一难题得到解决,指纹识别已经成为目前最广泛应用的生物识别之一,逐渐取代了传统的认证识别方式,广泛应用于金融、公安、证券、门禁系统等领域。指纹识别技术的研究已经成为当前建筑智能化研究的热点。但是对于在Linux 系统下的由FPI 指纹识别模块、Raspberry Pi 主控模块、AVR 模块组成的,采用无线通讯方式定时向用户发送邮件来监控门锁状态的指纹识别系统的研究至今未见诸报端。本文在不改变现有门锁结构的前提下,通过设计编程,开发了一套基于指纹识别的门禁系统,定时检测门锁状态并向用户发送报警邮件,大大增强了门锁的安全性。   1
[电源管理]
基于Linux系统的指纹识别<font color='red'>门禁系统</font>
使用51单片机实现抢答器的设计资料和代码说明
在知识比赛中, 特别是做抢答题目的时候, 在抢答过程中,为了知道哪一组或哪一位选手先答题,必须要设计一个系统来完成这个任务。如果在抢答中,靠视觉是很难判断出哪组先答题。利用单片机系统来设计抢答器,使以上问题得以解决,即使两组的抢答时间相差几微秒,也可分辨出哪组优先答题。本文主要介绍了单片机抢答器设计及工作原理,以及它的实际用途。 ! 系统工作原理本系统采用8051单片机作为核心。控制系统的四个模块分别为:存储模块、显示模块、语音模块、抢答开关模块。该抢答器系统通过开关电路四个按键输入抢答信号;利用语音芯片ISD1420 完成语音的录放功能; 利用存储程序; 利用一个数码管来完成显示功能。工作时,用按键通过开关电路输入各路的抢答信号
[单片机]
使用<font color='red'>51单片机</font>实现抢答器的设计资料和代码说明
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved