51单片机项目 门禁系统



/**
 * 项目名:门禁系统
 * 文件名:main.h
 */

#ifndef _MAIN_H
#define _MAIN_H

sbit RELAY_PIN = P0^4;
sbit BUZZER_PIN = P0^6;

void sys_init();
void samplingDS1302();
void samplingUlt();
void initDispMode1();
void initDispMode2();
void initDispMode3();
void refreshTimeDisplay();

#endif


/**
 * 项目名:门禁系统
 * 
 * 7:00-22:00工作在模式0(自动门状态)
 * 22:00-7:00工作在模式1(密码门状态)
 * 难点:继电器在接通5s后断开
 *         蜂鸣器报警3s
 * 文件名:main.c
 */

#include <stc15f2k60s2.h>
#include <string.h>
#include "stdint.h"
#include "timer.h"
#include "digitalTube.h"
#include "matrixKey.h"
#include "DS1302.h"
#include "EEPROM.h"
#include "ultrasonic.h"
#include "electromagneticDev.h"
#include "main.h"

volatile bit flag50ms = 0, flag200ms = 0, flag500ms = 0;    //任务标志

bit workingMode = 1;    //工作模式,初始化时间为06:59:00
uint8_t dispMode = 0;    //在密码门状态下的显示模式{0, 1, 2, 3}

uint8_t code initPassword[7] = "654321";    //初始密码
uint8_t password[7];    //当前密码

bit isOpen = 0;    //继电器是否打开
volatile bit enBuzzer = 0;

sTime_t time;

static uint8_t wrongTimes = 0, passwdTmpIndex = 0;    //!!!here

void main() {
    uint8_t cnt500ms = 0;

    sys_init();

    while (1) {
        if (flag50ms) {
            flag50ms = 0;
            
            keyDriver();
        }

        if (flag200ms) {
            flag200ms = 0;
            
            samplingDS1302();

            if (workingMode == 0) {        //如果工作于自动门状态
                samplingUlt();            //采样超声波模块
            }
        }

        if (flag500ms) {
            flag500ms = 0;

            if (workingMode == 1) {    //如果工作于密码门状态
                if (isOpen) {    //如果检测到门是打开的
                    if (cnt500ms == 10) {
                        cnt500ms = 0;
                        relay_off();
                        isOpen = 0;
                    } else {
                        cnt500ms++;
                    }
                }
            }
        }
    }
}

void sys_init() {
    tmr0_init(2);
    tmr1_specialInit();
    stc15_tmr2_init(1);        //!!!
    DS1302_init();
    EEPROM_read(password, 0, sizeof (password)); //addr=0
    if (strncmp(password, "000000", 6) == 0) {    //如果没有被初始化过
        strncpy(password, initPassword, 6);
        EEPROM_write(initPassword, 0, sizeof (initPassword));
    }
}

void samplingDS1302() {    //采样实时时间用于控制工作模式
    static uint8_t preSec;
    
    DS1302_getRealTime(&time);
    if (time.hour == 0x07 && time.minute == 0x00) {    //如果到了7:00
        workingMode = 0;    //工作于自动门状态
        dispMode = 0;        //!!!显示模式归0
        wrongTimes = 0;        //!!!
        passwdTmpIndex = 0;    //!!!
    } else if (time.hour == 0x22 && time.minute == 0x00) {    //如果到了22:00
        workingMode = 1;    //工作于密码门状态
    }

    if (dispMode == 0) {    //如果是显示模式0,则更新显示
        if (time.sec != preSec) {    //秒有变化则更新显示
            preSec = time.sec;
            refreshTimeDisplay();
        }
    }
}

void samplingUlt() {    //工作于自动门状态,由超声波测得的距离控制继电器的开闭
    static uint8_t ultCnt200ms = 0;
    uint8_t dis;

    dis = ult_getDis();
    if (isOpen == 0) {    //如果之前是关闭的状态
        if (dis < 30) {    //如果测量到的距离小于30cm
            relay_on();
            isOpen = 1;
        }
    } else if (isOpen == 1) {
        if (dis >= 30) {
            if (ultCnt200ms == 24) {
                ultCnt200ms = 0;
                relay_off();
                isOpen = 0;
            } else {
                ultCnt200ms++;
            }
        } else {
            ultCnt200ms = 0;
        }
    }
}

void keyAction(uint8_t keyCode) {    
    static uint8_t passwdTmp[7]; 

    if (workingMode == 0)    //如果工作于自动门状态,则对按键无响应
        return;

    if (keyCode == 'q') {    //如果按的是确认键
        if (passwdTmpIndex == 6) {    //如果输入了6位密码
            passwdTmpIndex = 0;    //!!!复位写索引
            if (dispMode == 1) {    //如果当前是密码验证界面
                if (strncmp(passwdTmp, password, 6) == 0) {    //如果密码匹配成功
                    
                    dispMode = 0;            //回到时间显示界面
                    refreshTimeDisplay();   //重新显示时间
                    relay_on();        //打开继电器
                    isOpen = 1;            //!!!!!!
                    wrongTimes = 0;        //!!!连续错误次数归0
                } else {    //密码匹配失败
                    if (wrongTimes >= 2) {    //如果连续错误次数达到3次
                        enBuzzer = 1;
                    } else {
                        wrongTimes++;
                    }
                    initDispMode1();    //清空输入的密码
                }
            } else if (dispMode == 2) {    //如果当前是旧密码验证界面
                if (strncmp(passwdTmp, password, 6) == 0) {    //如果密码匹配成功
                    //passwdTmpIndex = 0;    //复位
                    dispMode = 3;            //进入新密码输入界面
                    initDispMode3();
                    wrongTimes = 0;        //!!!连续错误次数归0                    
                } else {    //密码匹配失败
                    if (wrongTimes == 2) {    //如果错误次数达到3次
                        enBuzzer = 1;
                        
                        dispMode = 0;            //!!!回到时间显示界面
                        refreshTimeDisplay();
                        
                        wrongTimes = 0;
                    } else {
                        wrongTimes++;
                    }
                    initDispMode2();    //清空输入的密码
                }
            } else if (dispMode == 3) {    //如果当前是新密码输入界面
                strncpy(password, passwdTmp, sizeof (passwdTmp));    //更新新密码
                EEPROM_write(passwdTmp, 0, sizeof (passwdTmp));        //将新密码写入EEPROM
                dispMode = 0;    //回到实时时间显示界面
                refreshTimeDisplay();
            }
        }
    } else if (keyCode == 's') {    //如果按的是设置键
        if (dispMode == 0) {    //如果是实时显示界面
            dispMode = 2;        //进入旧密码验证界面
            initDispMode2();
        }
    } else if (keyCode == 'f') {    //如果按的是复位键
        strncpy(password, initPassword, 6);        //重新设置为初始密码
        EEPROM_write(initPassword, 0, sizeof (initPassword));
        wrongTimes = 0;        //!!!之前的错误次数归0
    } else if (keyCode == 't') {    //如果按的是退出键
        if (dispMode == 2 || dispMode == 3) {    //如果在旧密码验证界面或新密码输入界面
            passwdTmpIndex = 0;    //!!!
            dispMode = 0;
            refreshTimeDisplay();
        }
    } else if (0 <= keyCode && keyCode <= 9) {    //如果按的是0-9的数字键
        if (dispMode == 0) {    //如果之前是显示模式0,则按下任意数字键进入身份验证界面
            dispMode = 1;
            initDispMode1();
        }

        if (passwdTmpIndex < 6) {
            passwdTmp[passwdTmpIndex] = keyCode + '0';    //!!!是字符
            dspBuf[2 + passwdTmpIndex] = keyCode;    //更新显示
            passwdTmpIndex++;    //!!!
        }
    }
}

void refreshTimeDisplay() {
    dspBuf[0] = time.hour >> 4;
    dspBuf[1] = time.hour & 0x0F;
    dspBuf[2] = 11;    //分隔符
    dspBuf[3] = time.minute >> 4;
    dspBuf[4] = time.minute & 0x0F;
    dspBuf[5] = 11;
    dspBuf[6] = time.sec >> 4;
    dspBuf[7] = time.sec & 0x0F;
}

void initDispMode1() {
    dspBuf[0] = 11;        //分隔符
    dspBuf[1] = 11;
    dspBuf[2] = 10;
    dspBuf[3] = 10;
    dspBuf[4] = 10;
    dspBuf[5] = 10;
    dspBuf[6] = 10;
    dspBuf[7] = 10;
}

void initDispMode2() {
    dspBuf[0] = 10;        //不显示
    dspBuf[1] = 11;
    dspBuf[2] = 10;
    dspBuf[3] = 10;
    dspBuf[4] = 10;
    dspBuf[5] = 10;
    dspBuf[6] = 10;
    dspBuf[7] = 10;
}

void initDispMode3() {
    dspBuf[0] = 11;
    dspBuf[1] = 10;
    dspBuf[2] = 10;
    dspBuf[3] = 10;
    dspBuf[4] = 10;
    dspBuf[5] = 10;
    dspBuf[6] = 10;
    dspBuf[7] = 10;
}

void tmr0_ISR() interrupt 1 {
    static uint8_t cnt2ms = 0, cnt1 = 0;

    TL0 = tmr0LowByte;
    TH0 = tmr0HighByte;

    if (cnt2ms == 99) {
        cnt2ms = 0;
        flag200ms = 1;
    } else {
        cnt2ms++;
    }

    if (cnt1 == 249) {    //定时500ms
        cnt1 = 0;
        flag500ms = 1;
    } else {
        cnt1++;
    }

    if (cnt2ms % 25 == 0) {
        flag50ms = 1;
    }

    digitalTubeScan();
    if (cnt2ms & 1)
        keyScan();
}

/**
 * stc15系列单片机定时器2
 * 中断序号12
 * 作用:驱动蜂鸣器
 */
void tmr2_ISR() interrupt 12 {    //stc15单片机定时器2
    static uint16_t cnt1ms = 0;    //定3000ms

    if (enBuzzer) {    //如果蜂鸣器需要响
        buzzer_toggle();
        
        if (cnt1ms == 2999) {    //如果蜂鸣器响了3s
            enBuzzer = 0;        //禁止蜂鸣器响
            cnt1ms = 0;
            
        } else {
            cnt1ms++;
        }
    }
}






發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章