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++;
        }
    }
}






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