基于单片机的无线红外遥控密码锁
项目开发背景
随着社会对安全需求的日益增长,传统机械锁具在防护能力和使用便利性方面逐渐显现出局限性,例如钥匙易丢失、复制风险高以及缺乏灵活的访问控制机制。电子密码锁作为一种现代化解决方案,能够有效提升安全级别,并通过数字化管理减少物理钥匙的依赖。本项目基于单片机开发无线红外遥控密码锁,旨在融合本地与远程控制功能,满足用户对高效、智能安防系统的需求。
在嵌入式系统领域,单片机以其低成本、高可靠性和易于编程的特点,成为智能设备的核心控制单元。本系统采用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继电器模拟开锁,错误则触发有源蜂鸣器报警,有效保障了安全控制与实时警示。
整体而言,该系统结合了多种硬件模块,实现了高效、安全的密码锁控制,适用于家庭或工业场景,展现了单片机在嵌入式应用中的实用性与扩展潜力。
- 点赞
- 收藏
- 关注作者
评论(0)