基于单片机的无线红外遥控密码锁

举报
DS小龙哥 发表于 2025/12/25 12:00:51 2025/12/25
【摘要】 项目开发背景随着社会对安全需求的日益增长,传统机械锁具在防护能力和使用便利性方面逐渐显现出局限性,例如钥匙易丢失、复制风险高以及缺乏灵活的访问控制机制。电子密码锁作为一种现代化解决方案,能够有效提升安全级别,并通过数字化管理减少物理钥匙的依赖。本项目基于单片机开发无线红外遥控密码锁,旨在融合本地与远程控制功能,满足用户对高效、智能安防系统的需求。在嵌入式系统领域,单片机以其低成本、高可靠性...

项目开发背景

随着社会对安全需求的日益增长,传统机械锁具在防护能力和使用便利性方面逐渐显现出局限性,例如钥匙易丢失、复制风险高以及缺乏灵活的访问控制机制。电子密码锁作为一种现代化解决方案,能够有效提升安全级别,并通过数字化管理减少物理钥匙的依赖。本项目基于单片机开发无线红外遥控密码锁,旨在融合本地与远程控制功能,满足用户对高效、智能安防系统的需求。

在嵌入式系统领域,单片机以其低成本、高可靠性和易于编程的特点,成为智能设备的核心控制单元。本系统采用AT89C52单片机作为主控芯片,负责协调键盘输入、红外信号处理、密码验证及驱动执行模块,实现全流程自动化管理。通过集成4×4矩阵键盘和LCD1602显示屏,用户可直观地进行密码输入与状态监控,增强了人机交互的友好性。

红外遥控技术的应用进一步扩展了系统的实用性,允许用户在无需直接接触设备的情况下进行远程操作。这种无线控制方式不仅提升了使用便利性,还适用于多种场景,例如在家庭或办公室环境中,用户可通过手持遥控器快速完成开锁,尤其适合行动不便或携带物品时的场景。

为确保密码数据的持久性与安全性,系统采用AT24C02 EEPROM存储器,可在掉电情况下永久保存用户设置的密码,并支持灵活修改。这一设计避免了因电源中断导致的数据丢失问题,同时通过密码验证机制驱动继电器模拟开锁,或在错误输入时触发蜂鸣器报警,从而构建一个可靠的整体安防体系。

该项目的开发体现了智能化安防技术的发展趋势,通过结合多种输入方式与稳定存储方案,不仅提升了锁具的防护性能,还为用户提供了便捷、可定制的使用体验。未来,这种系统可广泛应用于住宅、保险箱及办公场所,推动安全控制向更高效、人性化的方向演进。

设计实现的功能

(1) 通过4×4矩阵键盘输入密码,并在LCD1602液晶显示屏上实时显示输入状态(如数字或掩码符号)。
(2) 支持通过红外遥控器进行远程密码输入与控制命令发送。
(3) 允许用户修改密码,修改后的密码存储在AT24C02 EEPROM芯片中,确保掉电后数据不丢失。
(4) 执行密码验证:若输入密码与存储密码匹配,则驱动5V继电器模拟开锁;若不匹配,则触发有源蜂鸣器发出报警声。

项目硬件模块组成

(1)主控芯片:AT89C52单片机。
(2)输入模块:4×4矩阵键盘、红外遥控接收头。
(3)显示模块:LCD1602液晶显示屏。
(4)存储模块:AT24C02 EEPROM芯片。
(5)执行与报警:5V继电器模块、有源蜂鸣器。

设计意义

这个基于单片机的无线红外遥控密码锁设计具有重要的实际意义。它提供了一种可靠的电子安全控制方案,通过密码验证机制来管理访问权限,有效防止未授权进入,适用于家庭、办公室等需要基本安防的场所,提升了日常生活的安全性。

系统支持多种输入方式,包括本地4×4矩阵键盘和远程红外遥控,用户可以根据环境需求灵活选择操作模式,这大大增强了使用的便捷性和适应性,尤其适用于需要远程控制或隐蔽操作的场景。

密码可修改并存储在EEPROM存储器中,确保数据在断电后不丢失,这提高了系统的持久性和可靠性,用户能够根据需要随时更新密码,从而维护长期的安全保障。验证机制中,正确密码驱动继电器模拟开锁,错误则触发蜂鸣器报警,实现了快速响应和警示功能,在实际应用中能及时反馈操作状态,避免潜在风险。

设计思路

该系统以AT89C52单片机作为核心控制器,负责协调各个硬件模块实现密码锁功能。用户可以通过4×4矩阵键盘进行本地密码输入,同时支持红外遥控器进行远程输入与控制,单片机通过扫描键盘行列和解析红外信号来获取用户输入数据。

LCD1602液晶显示屏用于实时显示输入状态,例如密码位数、输入提示或错误信息,确保用户操作过程清晰可见。显示内容由单片机控制更新,初始界面可设置欢迎语或操作指南。

密码存储采用AT24C02 EEPROM芯片,通过I2C协议与单片机通信,实现密码的读写操作。用户可修改密码,新密码经验证后存入EEPROM,确保掉电后数据不丢失,增强了系统的可靠性。

密码验证环节中,单片机会比较输入密码与存储密码,若匹配则驱动5V继电器模块模拟开锁动作;若不匹配则触发有源蜂鸣器发出报警声,以提示用户输入错误。整个流程兼顾安全性与实用性,无需额外功能扩展。

框架图

系统框架图:

+-----------------------------+
|       AT89C52单片机         |
|   (主控芯片)               |
+-----------------------------+
             |
             | (数据/控制总线)
             |
    +--------+--------+--------+--------+--------+
    |        |        |        |        |        |
    v        v        v        v        v        v
+-------+ +-------+ +-------+ +-------+ +-------+ +-------+
| 4×4   | |红外   | |LCD1602| |AT24C02| |5V     | |有源   |
|矩阵键盘| |遥控   | |显示屏 | |EEPROM | |继电器 | |蜂鸣器 |
|       | |接收头 | |       | |       | |模块   | |       |
+-------+ +-------+ +-------+ +-------+ +-------+ +-------+
(输入)    (输入)    (显示)    (存储)    (执行)    (报警)

系统总体设计

该系统基于AT89C52单片机作为核心控制器,实现一个集成无线红外遥控和本地键盘输入的密码锁系统。系统通过协调多个硬件模块完成密码输入、验证、显示和执行功能,确保安全可靠的操作。

输入模块包括4×4矩阵键盘和红外遥控接收头,用户可通过键盘直接输入密码或使用红外遥控器进行远程操作。LCD1602液晶显示屏实时显示密码输入状态和系统提示信息,为用户提供直观的交互反馈。

密码数据存储在AT24C02 EEPROM芯片中,支持用户修改密码并保证掉电后数据不丢失。系统在验证密码时,若输入正确则驱动5V继电器模块模拟开锁动作;若错误则触发有源蜂鸣器发出报警信号,以增强安全性。

整个系统由AT89C52单片机统一管理,负责处理输入信号、控制显示内容、访问存储数据以及驱动执行模块,确保各部件协同工作,实现高效稳定的密码锁功能。

系统功能总结

功能 描述 硬件模块
本地密码输入与显示 用户通过4×4矩阵键盘输入密码,LCD1602液晶显示屏实时显示输入状态。 4×4矩阵键盘、LCD1602
远程密码输入与控制 支持通过红外遥控器进行远程密码输入与系统控制。 红外遥控接收头
密码存储与修改 密码可修改,并存储在AT24C02 EEPROM芯片中,确保掉电后数据不丢失。 AT24C02 EEPROM芯片
密码验证与执行 密码验证正确则驱动5V继电器模拟开锁;错误则触发有源蜂鸣器报警。 5V继电器模块、有源蜂鸣器
系统核心控制 AT89C52单片机作为主控芯片,协调输入、显示、存储和执行模块的整体运作。 AT89C52单片机

设计的各个功能模块描述

主控芯片模块采用AT89C52单片机作为系统核心控制器,负责协调整个密码锁的运行。它处理来自输入模块的密码数据,执行密码验证逻辑,控制显示模块的输出信息,管理存储模块的读写操作,并根据验证结果驱动执行与报警模块的动作。

输入模块包括4×4矩阵键盘和红外遥控接收头,用于接收用户密码输入。矩阵键盘提供本地密码输入方式,用户可通过按键输入数字密码;红外遥控接收头支持远程控制,允许用户通过红外遥控器进行密码输入和系统操作,实现无线遥控功能。

显示模块使用LCD1602液晶显示屏,实时显示密码输入状态和系统提示信息。例如,在用户输入密码时,屏幕会显示输入的数字或星号以隐藏真实密码,并在验证过程中给出正确或错误的反馈提示,确保用户操作直观明了。

存储模块基于AT24C02 EEPROM芯片,用于存储用户设置的密码数据。该模块支持密码修改功能,用户可通过输入新密码并保存到EEPROM中,且存储的数据在系统断电后不会丢失,保证了密码的持久性和安全性。

执行与报警模块由5V继电器模块和有源蜂鸣器组成。当密码验证正确时,继电器被驱动以模拟开锁动作;如果密码输入错误,系统会触发有源蜂鸣器发出报警声,提醒用户并增强安全防护。

上位机代码设计

#include <QApplication>
#include <QMainWindow>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QPushButton>
#include <QLineEdit>
#include <QLabel>
#include <QTextEdit>
#include <QSerialPort>
#include <QSerialPortInfo>
#include <QMessageBox>
#include <QTimer>
#include <QComboBox>

class RemoteLockController : public QMainWindow
{
    Q_OBJECT

public:
    RemoteLockController(QWidget *parent = nullptr) : QMainWindow(parent)
    {
        setupUI();
        setupSerialPort();
        setupConnections();
    }

private slots:
    void connectToDevice()
    {
        if(serialPort->isOpen()) {
            serialPort->close();
        }
        
        serialPort->setPortName(portComboBox->currentText());
        serialPort->setBaudRate(QSerialPort::Baud9600);
        serialPort->setDataBits(QSerialPort::Data8);
        serialPort->setParity(QSerialPort::NoParity);
        serialPort->setStopBits(QSerialPort::OneStop);
        serialPort->setFlowControl(QSerialPort::NoFlowControl);
        
        if(serialPort->open(QIODevice::ReadWrite)) {
            statusLabel->setText("已连接到: " + portComboBox->currentText());
            logTextEdit->append("系统: 连接成功");
        } else {
            statusLabel->setText("连接失败");
            logTextEdit->append("系统: 连接失败");
        }
    }

    void sendPassword()
    {
        QString password = passwordLineEdit->text();
        if(password.isEmpty()) {
            QMessageBox::warning(this, "警告", "密码不能为空");
            return;
        }
        
        if(serialPort->isOpen()) {
            QString command = "PASS:" + password + "\n";
            serialPort->write(command.toUtf8());
            logTextEdit->append("发送: " + command.trimmed());
        } else {
            QMessageBox::warning(this, "警告", "请先连接设备");
        }
    }

    void changePassword()
    {
        QString newPassword = newPasswordLineEdit->text();
        if(newPassword.isEmpty()) {
            QMessageBox::warning(this, "警告", "新密码不能为空");
            return;
        }
        
        if(serialPort->isOpen()) {
            QString command = "CHANGE:" + newPassword + "\n";
            serialPort->write(command.toUtf8());
            logTextEdit->append("发送: " + command.trimmed());
        } else {
            QMessageBox::warning(this, "警告", "请先连接设备");
        }
    }

    void unlockDoor()
    {
        if(serialPort->isOpen()) {
            QString command = "UNLOCK\n";
            serialPort->write(command.toUtf8());
            logTextEdit->append("发送: " + command.trimmed());
        } else {
            QMessageBox::warning(this, "警告", "请先连接设备");
        }
    }

    void readData()
    {
        QByteArray data = serialPort->readAll();
        if(!data.isEmpty()) {
            QString response = QString::fromUtf8(data).trimmed();
            logTextEdit->append("接收: " + response);
            
            if(response.contains("SUCCESS")) {
                QMessageBox::information(this, "成功", "操作成功");
            } else if(response.contains("ERROR")) {
                QMessageBox::warning(this, "错误", "操作失败");
            } else if(response.contains("ALARM")) {
                QMessageBox::critical(this, "警报", "密码错误触发警报");
            }
        }
    }

    void refreshPorts()
    {
        portComboBox->clear();
        QList<QSerialPortInfo> ports = QSerialPortInfo::availablePorts();
        for(const QSerialPortInfo &port : ports) {
            portComboBox->addItem(port.portName());
        }
    }

private:
    void setupUI()
    {
        QWidget *centralWidget = new QWidget(this);
        setCentralWidget(centralWidget);
        
        QVBoxLayout *mainLayout = new QVBoxLayout(centralWidget);
        
        // 连接设置区域
        QHBoxLayout *connectionLayout = new QHBoxLayout();
        portComboBox = new QComboBox();
        refreshButton = new QPushButton("刷新端口");
        connectButton = new QPushButton("连接设备");
        statusLabel = new QLabel("未连接");
        
        connectionLayout->addWidget(new QLabel("串口:"));
        connectionLayout->addWidget(portComboBox);
        connectionLayout->addWidget(refreshButton);
        connectionLayout->addWidget(connectButton);
        connectionLayout->addWidget(statusLabel);
        connectionLayout->addStretch();
        
        // 密码操作区域
        QHBoxLayout *passwordLayout = new QHBoxLayout();
        passwordLineEdit = new QLineEdit();
        passwordLineEdit->setPlaceholderText("输入密码");
        passwordLineEdit->setEchoMode(QLineEdit::Password);
        sendPasswordButton = new QPushButton("发送密码");
        
        passwordLayout->addWidget(new QLabel("密码验证:"));
        passwordLayout->addWidget(passwordLineEdit);
        passwordLayout->addWidget(sendPasswordButton);
        
        // 修改密码区域
        QHBoxLayout *changePasswordLayout = new QHBoxLayout();
        newPasswordLineEdit = new QLineEdit();
        newPasswordLineEdit->setPlaceholderText("输入新密码");
        newPasswordLineEdit->setEchoMode(QLineEdit::Password);
        changePasswordButton = new QPushButton("修改密码");
        
        changePasswordLayout->addWidget(new QLabel("修改密码:"));
        changePasswordLayout->addWidget(newPasswordLineEdit);
        changePasswordLayout->addWidget(changePasswordButton);
        
        // 控制区域
        QHBoxLayout *controlLayout = new QHBoxLayout();
        unlockButton = new QPushButton("远程开锁");
        
        controlLayout->addWidget(unlockButton);
        controlLayout->addStretch();
        
        // 日志区域
        logTextEdit = new QTextEdit();
        logTextEdit->setReadOnly(true);
        
        mainLayout->addLayout(connectionLayout);
        mainLayout->addLayout(passwordLayout);
        mainLayout->addLayout(changePasswordLayout);
        mainLayout->addLayout(controlLayout);
        mainLayout->addWidget(new QLabel("通信日志:"));
        mainLayout->addWidget(logTextEdit);
        
        setWindowTitle("无线红外遥控密码锁上位机");
        resize(600, 400);
        
        refreshPorts();
    }

    void setupSerialPort()
    {
        serialPort = new QSerialPort(this);
    }

    void setupConnections()
    {
        connect(connectButton, &QPushButton::clicked, this, &RemoteLockController::connectToDevice);
        connect(sendPasswordButton, &QPushButton::clicked, this, &RemoteLockController::sendPassword);
        connect(changePasswordButton, &QPushButton::clicked, this, &RemoteLockController::changePassword);
        connect(unlockButton, &QPushButton::clicked, this, &RemoteLockController::unlockDoor);
        connect(refreshButton, &QPushButton::clicked, this, &RemoteLockController::refreshPorts);
        connect(serialPort, &QSerialPort::readyRead, this, &RemoteLockController::readData);
    }

    QSerialPort *serialPort;
    QComboBox *portComboBox;
    QPushButton *refreshButton;
    QPushButton *connectButton;
    QLabel *statusLabel;
    QLineEdit *passwordLineEdit;
    QPushButton *sendPasswordButton;
    QLineEdit *newPasswordLineEdit;
    QPushButton *changePasswordButton;
    QPushButton *unlockButton;
    QTextEdit *logTextEdit;
};

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    
    RemoteLockController controller;
    controller.show();
    
    return app.exec();
}

#include "main.moc"

项目配置文件 (CMakeLists.txt):

cmake_minimum_required(VERSION 3.16)
project(RemoteLockController)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

find_package(Qt6 REQUIRED COMPONENTS Core Widgets SerialPort)

qt_standard_project_setup()

qt_add_executable(RemoteLockController main.cpp)

target_link_libraries(RemoteLockController Qt6::Core Qt6::Widgets Qt6::SerialPort)

项目配置文件替代方案 (qmake .pro文件):

QT += core widgets serialport

CONFIG += c++17

SOURCES += \
    main.cpp

HEADERS +=

# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

这个上位机程序提供了完整的密码锁控制功能,包括:

  • 串口连接管理
  • 密码验证
  • 密码修改
  • 远程开锁
  • 实时通信日志
  • 状态反馈显示

程序使用Qt框架开发,支持跨平台运行,通过串口与下位机AT89C52单片机进行通信。

模块代码设计

#include "stm32f10x.h"

// LCD1602引脚定义
#define LCD_RS_PIN  GPIO_Pin_0
#define LCD_RW_PIN  GPIO_Pin_1
#define LCD_EN_PIN  GPIO_Pin_2
#define LCD_D4_PIN  GPIO_Pin_3
#define LCD_D5_PIN  GPIO_Pin_4
#define LCD_D6_PIN  GPIO_Pin_5
#define LCD_D7_PIN  GPIO_Pin_6
#define LCD_PORT    GPIOA

// 矩阵键盘引脚定义
#define KEY_ROW1    GPIO_Pin_0
#define KEY_ROW2    GPIO_Pin_1
#define KEY_ROW3    GPIO_Pin_2
#define KEY_ROW4    GPIO_Pin_3
#define KEY_COL1    GPIO_Pin_4
#define KEY_COL2    GPIO_Pin_5
#define KEY_COL3    GPIO_Pin_6
#define KEY_COL4    GPIO_Pin_7
#define KEY_ROW_PORT GPIOB
#define KEY_COL_PORT GPIOB

// 红外接收引脚
#define IR_PIN      GPIO_Pin_8
#define IR_PORT     GPIOA

// 继电器和蜂鸣器引脚
#define RELAY_PIN   GPIO_Pin_13
#define BUZZER_PIN  GPIO_Pin_14
#define OUTPUT_PORT GPIOC

// EEPROM地址定义
#define EEPROM_ADDR 0xA0
#define PASSWORD_ADDR 0x00

// 全局变量
uint8_t input_password[6] = {0};
uint8_t stored_password[6] = {0};
uint8_t input_index = 0;
uint32_t ir_value = 0;

// 延时函数
void delay_ms(uint16_t ms) {
    uint32_t i;
    for(i = 0; i < ms * 8000; i++);
}

// LCD1602写命令
void lcd_write_cmd(uint8_t cmd) {
    GPIO_ResetBits(LCD_PORT, LCD_RS_PIN); // RS=0
    GPIO_ResetBits(LCD_PORT, LCD_RW_PIN); // RW=0
    
    // 高4位
    GPIO_WriteBit(LCD_PORT, LCD_D4_PIN, (cmd >> 4) & 0x01 ? Bit_SET : Bit_RESET);
    GPIO_WriteBit(LCD_PORT, LCD_D5_PIN, (cmd >> 5) & 0x01 ? Bit_SET : Bit_RESET);
    GPIO_WriteBit(LCD_PORT, LCD_D6_PIN, (cmd >> 6) & 0x01 ? Bit_SET : Bit_RESET);
    GPIO_WriteBit(LCD_PORT, LCD_D7_PIN, (cmd >> 7) & 0x01 ? Bit_SET : Bit_RESET);
    
    GPIO_SetBits(LCD_PORT, LCD_EN_PIN);
    delay_ms(2);
    GPIO_ResetBits(LCD_PORT, LCD_EN_PIN);
    delay_ms(2);
    
    // 低4位
    GPIO_WriteBit(LCD_PORT, LCD_D4_PIN, (cmd >> 0) & 0x01 ? Bit_SET : Bit_RESET);
    GPIO_WriteBit(LCD_PORT, LCD_D5_PIN, (cmd >> 1) & 0x01 ? Bit_SET : Bit_RESET);
    GPIO_WriteBit(LCD_PORT, LCD_D6_PIN, (cmd >> 2) & 0x01 ? Bit_SET : Bit_RESET);
    GPIO_WriteBit(LCD_PORT, LCD_D7_PIN, (cmd >> 3) & 0x01 ? Bit_SET : Bit_RESET);
    
    GPIO_SetBits(LCD_PORT, LCD_EN_PIN);
    delay_ms(2);
    GPIO_ResetBits(LCD_PORT, LCD_EN_PIN);
    delay_ms(2);
}

// LCD1602写数据
void lcd_write_data(uint8_t dat) {
    GPIO_SetBits(LCD_PORT, LCD_RS_PIN); // RS=1
    GPIO_ResetBits(LCD_PORT, LCD_RW_PIN); // RW=0
    
    // 高4位
    GPIO_WriteBit(LCD_PORT, LCD_D4_PIN, (dat >> 4) & 0x01 ? Bit_SET : Bit_RESET);
    GPIO_WriteBit(LCD_PORT, LCD_D5_PIN, (dat >> 5) & 0x01 ? Bit_SET : Bit_RESET);
    GPIO_WriteBit(LCD_PORT, LCD_D6_PIN, (dat >> 6) & 0x01 ? Bit_SET : Bit_RESET);
    GPIO_WriteBit(LCD_PORT, LCD_D7_PIN, (dat >> 7) & 0x01 ? Bit_SET : Bit_RESET);
    
    GPIO_SetBits(LCD_PORT, LCD_EN_PIN);
    delay_ms(2);
    GPIO_ResetBits(LCD_PORT, LCD_EN_PIN);
    delay_ms(2);
    
    // 低4位
    GPIO_WriteBit(LCD_PORT, LCD_D4_PIN, (dat >> 0) & 0x01 ? Bit_SET : Bit_RESET);
    GPIO_WriteBit(LCD_PORT, LCD_D5_PIN, (dat >> 1) & 0x01 ? Bit_SET : Bit_RESET);
    GPIO_WriteBit(LCD_PORT, LCD_D6_PIN, (dat >> 2) & 0x01 ? Bit_SET : Bit_RESET);
    GPIO_WriteBit(LCD_PORT, LCD_D7_PIN, (dat >> 3) & 0x01 ? Bit_SET : Bit_RESET);
    
    GPIO_SetBits(LCD_PORT, LCD_EN_PIN);
    delay_ms(2);
    GPIO_ResetBits(LCD_PORT, LCD_EN_PIN);
    delay_ms(2);
}

// LCD1602初始化
void lcd_init(void) {
    delay_ms(15);
    lcd_write_cmd(0x33);
    delay_ms(5);
    lcd_write_cmd(0x32);
    delay_ms(5);
    lcd_write_cmd(0x28); // 4位模式,2行显示
    lcd_write_cmd(0x0C); // 显示开,光标关
    lcd_write_cmd(0x06); // 写入数据后光标右移
    lcd_write_cmd(0x01); // 清屏
    delay_ms(2);
}

// LCD显示字符串
void lcd_display_string(uint8_t x, uint8_t y, char *str) {
    uint8_t addr;
    if(y == 0) addr = 0x80 + x;
    else addr = 0xC0 + x;
    lcd_write_cmd(addr);
    while(*str) {
        lcd_write_data(*str++);
    }
}

// 矩阵键盘扫描
uint8_t key_scan(void) {
    uint8_t row, col, key_val = 0;
    GPIO_InitTypeDef GPIO_InitStructure;
    
    // 设置列为输出,行为输入
    GPIO_InitStructure.GPIO_Pin = KEY_COL1 | KEY_COL2 | KEY_COL3 | KEY_COL4;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(KEY_COL_PORT, &GPIO_InitStructure);
    
    GPIO_InitStructure.GPIO_Pin = KEY_ROW1 | KEY_ROW2 | KEY_ROW3 | KEY_ROW4;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_Init(KEY_ROW_PORT, &GPIO_InitStructure);
    
    // 列扫描
    for(col = 0; col < 4; col++) {
        GPIO_SetBits(KEY_COL_PORT, KEY_COL1 | KEY_COL2 | KEY_COL3 | KEY_COL4);
        GPIO_ResetBits(KEY_COL_PORT, (KEY_COL1 << col));
        delay_ms(10);
        
        // 行检测
        if(GPIO_ReadInputDataBit(KEY_ROW_PORT, KEY_ROW1) == 0) {
            key_val = 1 + col;
            while(GPIO_ReadInputDataBit(KEY_ROW_PORT, KEY_ROW1) == 0);
            break;
        }
        if(GPIO_ReadInputDataBit(KEY_ROW_PORT, KEY_ROW2) == 0) {
            key_val = 5 + col;
            while(GPIO_ReadInputDataBit(KEY_ROW_PORT, KEY_ROW2) == 0);
            break;
        }
        if(GPIO_ReadInputDataBit(KEY_ROW_PORT, KEY_ROW3) == 0) {
            key_val = 9 + col;
            while(GPIO_ReadInputDataBit(KEY_ROW_PORT, KEY_ROW3) == 0);
            break;
        }
        if(GPIO_ReadInputDataBit(KEY_ROW_PORT, KEY_ROW4) == 0) {
            key_val = 13 + col;
            while(GPIO_ReadInputDataBit(KEY_ROW_PORT, KEY_ROW4) == 0);
            break;
        }
    }
    return key_val;
}

// I2C初始化
void i2c_init(void) {
    RCC->APB2ENR |= 1 << 3; // 使能GPIOB时钟
    RCC->APB1ENR |= 1 << 21; // 使能I2C1时钟
    
    // PB6-SCL, PB7-SDA
    GPIOB->CRL &= 0x00FFFFFF;
    GPIOB->CRL |= 0xFF000000; // 推挽输出,50MHz
    GPIOB->ODR |= 0xC0; // 输出高电平
    
    I2C1->CR1 |= 1 << 15; // 软件复位
    I2C1->CR1 &= ~(1 << 15);
    
    I2C1->CR2 = 36; // 36MHz
    I2C1->CCR = 180; // 100kHz
    I2C1->TRISE = 37; // 最大上升时间
    I2C1->CR1 |= 1 << 0; // 使能I2C
}

// I2C起始信号
void i2c_start(void) {
    I2C1->CR1 |= 1 << 8; // 产生起始条件
    while(!(I2C1->SR1 & 0x0001)); // 等待起始条件完成
}

// I2C停止信号
void i2c_stop(void) {
    I2C1->CR1 |= 1 << 9; // 产生停止条件
    while(I2C1->SR2 & 0x0002); // 等待总线空闲
}

// I2C发送一个字节
void i2c_send_byte(uint8_t dat) {
    I2C1->DR = dat;
    while(!(I2C1->SR1 & 0x0002)); // 等待数据传输完成
}

// I2C接收一个字节
uint8_t i2c_read_byte(void) {
    while(!(I2C1->SR1 & 0x0004)); // 等待接收完成
    return I2C1->DR;
}

// EEPROM写一个字节
void eeprom_write_byte(uint8_t addr, uint8_t dat) {
    i2c_start();
    i2c_send_byte(EEPROM_ADDR);
    i2c_send_byte(addr);
    i2c_send_byte(dat);
    i2c_stop();
    delay_ms(10); // 等待写入完成
}

// EEPROM读一个字节
uint8_t eeprom_read_byte(uint8_t addr) {
    uint8_t dat;
    i2c_start();
    i2c_send_byte(EEPROM_ADDR);
    i2c_send_byte(addr);
    i2c_start();
    i2c_send_byte(EEPROM_ADDR | 0x01);
    dat = i2c_read_byte();
    i2c_stop();
    return dat;
}

// 保存密码到EEPROM
void save_password(uint8_t *pwd) {
    uint8_t i;
    for(i = 0; i < 6; i++) {
        eeprom_write_byte(PASSWORD_ADDR + i, pwd[i]);
    }
}

// 从EEPROM读取密码
void read_password(uint8_t *pwd) {
    uint8_t i;
    for(i = 0; i < 6; i++) {
        pwd[i] = eeprom_read_byte(PASSWORD_ADDR + i);
    }
}

// 红外接收初始化
void ir_init(void) {
    RCC->APB2ENR |= 1 << 2; // 使能GPIOA时钟
    RCC->APB1ENR |= 1 << 0; // 使能TIM2时钟
    
    // PA8输入
    GPIOA->CRH &= 0xFFFFFFF0;
    GPIOA->CRH |= 0x00000004; // 浮空输入
    
    // TIM2初始化
    TIM2->PSC = 71; // 1MHz
    TIM2->ARR = 10000; // 10ms
    TIM2->CCMR1 |= 1 << 0; // CC1为输入,映射到TI1
    TIM2->CCER |= 1 << 0; // CC1使能
    TIM2->DIER |= 1 << 0; // 更新中断使能
    TIM2->DIER |= 1 << 1; // CC1中断使能
    TIM2->CR1 |= 1 << 0; // 使能TIM2
    
    NVIC->ISER[0] |= 1 << 28; // 使能TIM2中断
}

// 红外解码
void ir_decode(void) {
    uint32_t i, j;
    uint32_t data = 0;
    
    if(GPIO_ReadInputDataBit(IR_PORT, IR_PIN) == 0) {
        delay_ms(1);
        if(GPIO_ReadInputDataBit(IR_PORT, IR_PIN) == 0) {
            // 确认引导码
            while(GPIO_ReadInputDataBit(IR_PORT, IR_PIN) == 0);
            for(i = 0; i < 4; i++) {
                for(j = 0; j < 8; j++) {
                    while(GPIO_ReadInputDataBit(IR_PORT, IR_PIN) == 0);
                    delay_ms(1);
                    if(GPIO_ReadInputDataBit(IR_PORT, IR_PIN)) {
                        data |= (1 << (i * 8 + j));
                        while(GPIO_ReadInputDataBit(IR_PORT, IR_PIN));
                    }
                }
            }
            ir_value = data;
        }
    }
}

// 继电器控制
void relay_control(uint8_t state) {
    if(state) {
        GPIO_SetBits(OUTPUT_PORT, RELAY_PIN);
    } else {
        GPIO_ResetBits(OUTPUT_PORT, RELAY_PIN);
    }
}

// 蜂鸣器控制
void buzzer_control(uint8_t state) {
    if(state) {
        GPIO_SetBits(OUTPUT_PORT, BUZZER_PIN);
    } else {
        GPIO_ResetBits(OUTPUT_PORT, BUZZER_PIN);
    }
}

// 密码验证
uint8_t verify_password(void) {
    uint8_t i;
    for(i = 0; i < 6; i++) {
        if(input_password[i] != stored_password[i]) {
            return 0;
        }
    }
    return 1;
}

// 系统初始化
void system_init(void) {
    RCC->APB2ENR |= 1 << 2; // 使能GPIOA时钟
    RCC->APB2ENR |= 1 << 3; // 使能GPIOB时钟
    RCC->APB2ENR |= 1 << 4; // 使能GPIOC时钟
    
    // LCD初始化
    GPIOA->CRL = 0x33333333; // PA0-PA7推挽输出
    
    // 输出控制初始化
    GPIOC->CRH &= 0x00FFFFFF;
    GPIOC->CRH |= 0x33000000; // PC13,PC14推挽输出
    
    lcd_init();
    i2c_init();
    ir_init();
    
    // 读取存储的密码
    read_password(stored_password);
}

int main(void) {
    uint8_t key, i;
    
    system_init();
    lcd_display_string(0, 0, "Password Lock");
    lcd_display_string(0, 1, "Input:******");
    
    while(1) {
        // 键盘输入
        key = key_scan();
        if(key != 0 && input_index < 6) {
            if(key <= 9) { // 数字键
                input_password[input_index] = key;
                lcd_write_cmd(0xC0 + 6 + input_index);
                lcd_write_data('*');
                input_index++;
            } else if(key == 14) { // 删除键
                if(input_index > 0) {
                    input_index--;
                    input_password[input_index] = 0;
                    lcd_write_cmd(0xC0 + 6 + input_index);
                    lcd_write_data(' ');
                }
            } else if(key == 15) { // 确认键
                if(input_index == 6) {
                    if(verify_password()) {
                        relay_control(1);
                        lcd_display_string(0, 1, "Open Success!    ");
                        delay_ms(2000);
                        relay_control(0);
                    } else {
                        buzzer_control(1);
                        lcd_display_string(0, 1, "Error! Try Again");
                        delay_ms(2000);
                        buzzer_control(0);
                    }
                    // 清空输入
                    for(i = 0; i < 6; i++) {
                        input_password[i] = 0;
                    }
                    input_index = 0;
                    lcd_display_string(0, 1, "Input:******");
                }
            } else if(key == 16) { // 修改密码键
                if(input_index == 6) {
                    save_password(input_password);
                    read_password(stored_password);
                    lcd_display_string(0, 1, "Pwd Changed!     ");
                    delay_ms(2000);
                    for(i = 0; i < 6; i++) {
                        input_password[i] = 0;
                    }
                    input_index = 0;
                    lcd_display_string(0, 1, "Input:******");
                }
            }
        }
        
        // 红外输入处理
        ir_decode();
        if(ir_value != 0) {
            // 根据红外码值处理
            // 这里需要根据实际遥控器编码进行映射
            // 简化处理:直接当作数字输入
            if(ir_value >= 0x00 && ir_value <= 0x09 && input_index < 6) {
                input_password[input_index] = ir_value;
                lcd_write_cmd(0xC0 + 6 + input_index);
                lcd_write_data('*');
                input_index++;
            }
            ir_value = 0;
        }
        
        delay_ms(100);
    }
}

// TIM2中断服务函数
void TIM2_IRQHandler(void) {
    if(TIM2->SR & 0x0001) { // 更新中断
        TIM2->SR &= ~0x0001;
    }
    if(TIM2->SR & 0x0002) { // CC1中断
        TIM2->SR &= ~0x0002;
        ir_decode();
    }
}

项目核心代码

#include "stm32f10x.h"

// 密码长度定义
#define PASSWORD_LENGTH 6

// 系统状态枚举
typedef enum {
    MODE_NORMAL,
    MODE_SETTING_VERIFY_OLD,
    MODE_SETTING_INPUT_NEW,
    MODE_SETTING_CONFIRM_NEW
} SystemMode;

// 全局变量
uint8_t storedPassword[PASSWORD_LENGTH] = {1, 2, 3, 4, 5, 6}; // 默认密码
uint8_t inputBuffer[PASSWORD_LENGTH];
uint8_t inputIndex = 0;
uint8_t newPassword[PASSWORD_LENGTH];
SystemMode currentMode = MODE_NORMAL;

// 外设初始化函数声明
void GPIO_Init(void);
void LCD_Init(void);
void Keyboard_Init(void);
void EEPROM_Init(void);
void Infrared_Init(void);
void Timer_Init(void);

// 功能模块函数声明
uint8_t Keyboard_Scan(void);
uint8_t Infrared_GetKey(void);
void LCD_Clear(void);
void LCD_DisplayString(char *str);
void LCD_DisplayChar(char c);
void EEPROM_Write(uint16_t addr, uint8_t data);
uint8_t EEPROM_Read(uint16_t addr);
void Relay_Control(uint8_t state);
void Buzzer_Control(uint8_t state);
void Delay_ms(uint32_t ms);

// 密码管理函数
void ReadPasswordFromEEPROM(void);
void WritePasswordToEEPROM(void);
uint8_t VerifyPassword(uint8_t *input, uint8_t *stored);
void ProcessKey(uint8_t key);
void CheckPassword(void);
void EnterSettingMode(void);
void ExitSettingMode(void);
void ResetInputBuffer(void);

int main(void)
{
    // 系统初始化
    SystemInit();
    GPIO_Init();
    LCD_Init();
    Keyboard_Init();
    EEPROM_Init();
    Infrared_Init();
    Timer_Init();
    
    // 从EEPROM读取存储的密码
    ReadPasswordFromEEPROM();
    
    // 初始显示
    LCD_Clear();
    LCD_DisplayString("Enter Password:");
    LCD_DisplayString("\n* for Settings");
    
    while(1)
    {
        uint8_t key;
        
        // 扫描矩阵键盘
        key = Keyboard_Scan();
        if(key != 0xFF)
        {
            ProcessKey(key);
            Delay_ms(200); // 去抖动延时
        }
        
        // 处理红外遥控
        key = Infrared_GetKey();
        if(key != 0xFF)
        {
            ProcessKey(key);
        }
        
        // 根据当前模式更新显示
        switch(currentMode)
        {
            case MODE_NORMAL:
                if(inputIndex == 0)
                {
                    LCD_Clear();
                    LCD_DisplayString("Enter Password:");
                }
                break;
                
            case MODE_SETTING_VERIFY_OLD:
                LCD_Clear();
                LCD_DisplayString("Verify Old Pwd:");
                break;
                
            case MODE_SETTING_INPUT_NEW:
                LCD_Clear();
                LCD_DisplayString("Enter New Pwd:");
                break;
                
            case MODE_SETTING_CONFIRM_NEW:
                LCD_Clear();
                LCD_DisplayString("Confirm New Pwd:");
                break;
        }
    }
}

void GPIO_Init(void)
{
    // 使能GPIO时钟
    RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN | 
                    RCC_APB2ENR_IOPCEN | RCC_APB2ENR_IOPDEN;
    
    // 配置继电器控制引脚(PC0)为推挽输出
    GPIOC->CRL &= ~GPIO_CRL_MODE0;
    GPIOC->CRL |= GPIO_CRL_MODE0_0;
    GPIOC->CRL &= ~GPIO_CRL_CNF0;
    
    // 配置蜂鸣器控制引脚(PC1)为推挽输出
    GPIOC->CRL &= ~GPIO_CRL_MODE1;
    GPIOC->CRL |= GPIO_CRL_MODE1_0;
    GPIOC->CRL &= ~GPIO_CRL_CNF1;
    
    // 初始状态关闭
    Relay_Control(0);
    Buzzer_Control(0);
}

void Timer_Init(void)
{
    // 基本定时器配置
    RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;
    TIM2->PSC = 7200 - 1;     // 10kHz
    TIM2->ARR = 10000 - 1;    // 1s
    TIM2->CR1 |= TIM_CR1_ARPE;
    TIM2->CR1 |= TIM_CR1_CEN;
}

void ProcessKey(uint8_t key)
{
    switch(key)
    {
        case 0x0A: // '*'键 - 进入设置模式
            if(currentMode == MODE_NORMAL)
            {
                EnterSettingMode();
            }
            else
            {
                // 设置模式下按'*'取消
                currentMode = MODE_NORMAL;
                ResetInputBuffer();
                LCD_Clear();
                LCD_DisplayString("Settings Canceled");
                Delay_ms(1000);
                LCD_Clear();
                LCD_DisplayString("Enter Password:");
            }
            break;
            
        case 0x0B: // '#'键 - 确认输入
            if(currentMode == MODE_NORMAL)
            {
                CheckPassword();
            }
            else if(currentMode == MODE_SETTING_VERIFY_OLD)
            {
                if(VerifyPassword(inputBuffer, storedPassword))
                {
                    currentMode = MODE_SETTING_INPUT_NEW;
                    ResetInputBuffer();
                    LCD_Clear();
                    LCD_DisplayString("Enter New Pwd:");
                }
                else
                {
                    Buzzer_Control(1);
                    LCD_Clear();
                    LCD_DisplayString("Wrong Password!");
                    Delay_ms(1000);
                    Buzzer_Control(0);
                    currentMode = MODE_NORMAL;
                    ResetInputBuffer();
                    LCD_Clear();
                    LCD_DisplayString("Enter Password:");
                }
            }
            else if(currentMode == MODE_SETTING_INPUT_NEW)
            {
                // 保存新密码到临时缓冲区
                for(int i = 0; i < PASSWORD_LENGTH; i++)
                {
                    newPassword[i] = inputBuffer[i];
                }
                currentMode = MODE_SETTING_CONFIRM_NEW;
                ResetInputBuffer();
                LCD_Clear();
                LCD_DisplayString("Confirm New Pwd:");
            }
            else if(currentMode == MODE_SETTING_CONFIRM_NEW)
            {
                // 验证两次输入的新密码是否一致
                uint8_t match = 1;
                for(int i = 0; i < PASSWORD_LENGTH; i++)
                {
                    if(inputBuffer[i] != newPassword[i])
                    {
                        match = 0;
                        break;
                    }
                }
                
                if(match)
                {
                    // 保存新密码
                    for(int i = 0; i < PASSWORD_LENGTH; i++)
                    {
                        storedPassword[i] = newPassword[i];
                    }
                    WritePasswordToEEPROM();
                    LCD_Clear();
                    LCD_DisplayString("Password Changed!");
                    Delay_ms(1000);
                    ExitSettingMode();
                }
                else
                {
                    Buzzer_Control(1);
                    LCD_Clear();
                    LCD_DisplayString("Password Mismatch!");
                    Delay_ms(1000);
                    Buzzer_Control(0);
                    currentMode = MODE_SETTING_INPUT_NEW;
                    ResetInputBuffer();
                    LCD_Clear();
                    LCD_DisplayString("Enter New Pwd:");
                }
            }
            break;
            
        default: // 数字键0-9
            if(key >= 0 && key <= 9)
            {
                if(inputIndex < PASSWORD_LENGTH)
                {
                    inputBuffer[inputIndex++] = key;
                    LCD_DisplayChar('*');
                    
                    // 自动验证(可选)
                    if(inputIndex == PASSWORD_LENGTH && currentMode == MODE_NORMAL)
                    {
                        CheckPassword();
                    }
                }
            }
            break;
    }
}

void CheckPassword(void)
{
    if(VerifyPassword(inputBuffer, storedPassword))
    {
        Relay_Control(1);
        LCD_Clear();
        LCD_DisplayString("Access Granted!");
        Delay_ms(3000); // 保持开锁状态3秒
        Relay_Control(0);
    }
    else
    {
        Buzzer_Control(1);
        LCD_Clear();
        LCD_DisplayString("Access Denied!");
        Delay_ms(1000);
        Buzzer_Control(0);
    }
    
    ResetInputBuffer();
    LCD_Clear();
    LCD_DisplayString("Enter Password:");
}

void EnterSettingMode(void)
{
    currentMode = MODE_SETTING_VERIFY_OLD;
    ResetInputBuffer();
    LCD_Clear();
    LCD_DisplayString("Verify Old Pwd:");
}

void ExitSettingMode(void)
{
    currentMode = MODE_NORMAL;
    ResetInputBuffer();
    LCD_Clear();
    LCD_DisplayString("Enter Password:");
}

void ResetInputBuffer(void)
{
    for(int i = 0; i < PASSWORD_LENGTH; i++)
    {
        inputBuffer[i] = 0;
    }
    inputIndex = 0;
}

uint8_t VerifyPassword(uint8_t *input, uint8_t *stored)
{
    for(int i = 0; i < PASSWORD_LENGTH; i++)
    {
        if(input[i] != stored[i])
        {
            return 0;
        }
    }
    return 1;
}

void ReadPasswordFromEEPROM(void)
{
    for(int i = 0; i < PASSWORD_LENGTH; i++)
    {
        storedPassword[i] = EEPROM_Read(i);
        // 如果EEPROM中无数据,使用默认密码
        if(storedPassword[i] > 9) 
        {
            storedPassword[i] = i + 1;
        }
    }
}

void WritePasswordToEEPROM(void)
{
    for(int i = 0; i < PASSWORD_LENGTH; i++)
    {
        EEPROM_Write(i, storedPassword[i]);
    }
}

void Relay_Control(uint8_t state)
{
    if(state)
    {
        GPIOC->BSRR = GPIO_BSRR_BS0; // 置位PC0
    }
    else
    {
        GPIOC->BSRR = GPIO_BSRR_BR0; // 复位PC0
    }
}

void Buzzer_Control(uint8_t state)
{
    if(state)
    {
        GPIOC->BSRR = GPIO_BSRR_BS1; // 置位PC1
    }
    else
    {
        GPIOC->BSRR = GPIO_BSRR_BR1; // 复位PC1
    }
}

void Delay_ms(uint32_t ms)
{
    for(uint32_t i = 0; i < ms; i++)
    {
        for(uint32_t j = 0; j < 7200; j++)
        {
            __NOP();
        }
    }
}

// 以下函数假设已在其他模块中实现
// 这里只提供声明,实际开发时需要具体实现
/*
void LCD_Init(void) { }
void Keyboard_Init(void) { }
void EEPROM_Init(void) { }
void Infrared_Init(void) { }
uint8_t Keyboard_Scan(void) { return 0xFF; }
uint8_t Infrared_GetKey(void) { return 0xFF; }
void LCD_Clear(void) { }
void LCD_DisplayString(char *str) { }
void LCD_DisplayChar(char c) { }
void EEPROM_Write(uint16_t addr, uint8_t data) { }
uint8_t EEPROM_Read(uint16_t addr) { return 0; }
*/

总结

该系统以AT89C52单片机为核心,成功实现了无线红外遥控密码锁的设计。通过集成4×4矩阵键盘和红外遥控接收头,用户可灵活选择本地或远程方式输入密码,同时LCD1602液晶屏实时显示操作状态,提升了交互便利性。

密码管理功能支持用户修改并存储于AT24C02 EEPROM芯片中,确保数据在掉电后不丢失,增强了系统的可靠性和长期使用价值。执行模块中,密码验证正确后驱动5V继电器模拟开锁,错误则触发有源蜂鸣器报警,有效保障了安全控制与实时警示。

整体而言,该系统结合了多种硬件模块,实现了高效、安全的密码锁控制,适用于家庭或工业场景,展现了单片机在嵌入式应用中的实用性与扩展潜力。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。