矩阵键盘为3x4
时间: 2025-07-30 15:18:35 浏览: 4
<think>我们正在设计一个基于51单片机的智能门禁系统,需要整合多个模块:AT24C64(EEPROM存储器)、OLED显示屏、蓝牙模块、舵机、薄膜键盘(3x4矩阵键盘)、超声波模块、信号灯XD10-6和DHT11温湿度传感器。下面将分步骤进行代码框架设计,并特别关注3x4矩阵键盘的代码实现。
### 系统设计思路
1. **系统初始化**:初始化各个模块,包括OLED、DHT11、超声波模块、舵机、矩阵键盘、蓝牙模块等。
2. **主循环**:
- 读取矩阵键盘输入,获取用户输入的密码。
- 通过蓝牙接收密码(可选)。
- 读取超声波模块检测门前是否有人。
- 读取DHT11获取环境温湿度。
- 将输入的密码与存储在AT24C64中的密码进行比对。
- 如果密码正确,则控制舵机转动(模拟开门),同时信号灯显示绿色;否则,信号灯显示红色,并提示错误。
- OLED显示系统状态、温湿度、输入密码的星号(或直接显示数字)等。
### 硬件连接(部分关键引脚说明,具体需根据实际电路连接)
- **矩阵键盘3x4**:通常连接至P1口(例如P1.0-P1.6,其中3行4列或4行3列,注意行列扫描方式)
- **OLED**:通常使用I2C接口,连接P2.0(SCL)、P2.1(SDA)
- **AT24C64**:I2C接口,与OLED共用I2C总线(注意地址不同)
- **蓝牙模块**:串口通信,连接P3.0(RXD)、P3.1(TXD)
- **舵机**:使用PWM控制,连接P3.2(或其他支持定时器输出的引脚)
- **超声波模块**:Trig连接P3.3,Echo连接P3.4
- **DHT11**:单总线,连接P3.5
- **信号灯XD10-6**:这是一个6位信号灯模块,可以使用6个IO口控制,例如P0口
### 代码框架
#### 1. 头文件及全局变量定义
```c
#include <reg52.h>
#include <intrins.h>
#include "oled.h" // OLED显示驱动
#include "i2c.h" // I2C通信,用于AT24C64和OLED(如果OLED使用I2C)
#include "dht11.h" // DHT11温湿度传感器
#include "delay.h" // 延时函数
// 矩阵键盘定义(假设3行4列,行线接P1.0-P1.2,列线接P1.3-P1.6)
#define KEY_PORT P1
sbit ROW1 = P1^0;
sbit ROW2 = P1^1;
sbit ROW3 = P1^2;
sbit COL1 = P1^3;
sbit COL2 = P1^4;
sbit COL3 = P1^5;
sbit COL4 = P1^6;
// 超声波模块
sbit Trig = P3^3;
sbit Echo = P3^4;
// 舵机控制
sbit Servo = P3^2; // 舵机信号线
// 信号灯XD10-6(假设使用P0口,6个灯分别接P0.0-P0.5)
#define SIGNAL_PORT P0
// 全局变量
unsigned char password[6] = {1,2,3,4,5,6}; // 默认密码
unsigned char input[6]; // 存储输入的密码
unsigned char count = 0; // 输入密码位数计数
bit door_open = 0; // 门状态标志
```
#### 2. 矩阵键盘扫描函数
```c
// 矩阵键盘扫描函数,返回按键值(0-9,*,#),0xFF表示无按键
unsigned char key_scan() {
unsigned char key_value = 0xFF;
// 第一行置低,其他行高
ROW1 = 0; ROW2 = 1; ROW3 = 1;
if (COL1 == 0) { delay_ms(10); if (COL1 == 0) key_value = '1'; }
if (COL2 == 0) { delay_ms(10); if (COL2 == 0) key_value = '2'; }
if (COL3 == 0) { delay_ms(10); if (COL3 == 0) key_value = '3'; }
if (COL4 == 0) { delay_ms(10); if (COL4 == 0) key_value = 'A'; } // A作为删除键
ROW1 = 1;
// 第二行置低
ROW2 = 0; ROW1 = 1; ROW3 = 1;
if (COL1 == 0) { delay_ms(10); if (COL1 == 0) key_value = '4'; }
if (COL2 == 0) { delay_ms(10); if (COL2 == 0) key_value = '5'; }
if (COL3 == 0) { delay_ms(10); if (COL3 == 0) key_value = '6'; }
if (COL4 == 0) { delay_ms(10); if (COL4 == 0) key_value = 'B'; } // B作为确认键
ROW2 = 1;
// 第三行置低
ROW3 = 0; ROW1 = 1; ROW2 = 1;
if (COL1 == 0) { delay_ms(10); if (COL1 == 0) key_value = '7'; }
if (COL2 == 0) { delay_ms(10); if (COL2 == 0) key_value = '8'; }
if (COL3 == 0) { delay_ms(10); if (COL3 == 0) key_value = '9'; }
if (COL4 == 0) { delay_ms(10); if (COL4 == 0) key_value = 'C'; } // C作为取消键
ROW3 = 1;
return key_value;
}
```
#### 3. 舵机控制函数
舵机控制通常使用PWM信号,周期为20ms,高电平时间在0.5ms-2.5ms之间对应0°-180°。
```c
// 舵机转动角度,angle:0-180
void servo_angle(unsigned char angle) {
unsigned int high_time = 500 + angle * 2000 / 180; // 计算高电平时间(单位us)
// 使用定时器产生PWM,这里简化使用延时模拟(实际应用需用定时器中断)
Servo = 1;
delay_us(high_time);
Servo = 0;
delay_us(20000 - high_time); // 整个周期20ms
}
```
#### 4. 超声波测距函数
```c
// 超声波测距,返回距离(单位:cm)
unsigned int ultrasonic_distance() {
unsigned int time = 0;
Trig = 1;
delay_us(12);
Trig = 0;
while (!Echo); // 等待高电平
while (Echo) { // 高电平期间计时
time++;
delay_us(1);
if (time > 30000) break; // 超时
}
return time / 58; // 计算距离(单位cm)
}
```
#### 5. AT24C64读写函数(略,使用I2C协议)
#### 6. 主函数框架
```c
void main() {
unsigned char key;
unsigned char i;
unsigned int distance;
unsigned char temp, humi;
// 初始化
OLED_Init();
DHT11_Init();
// 初始化定时器(用于舵机PWM、超声波计时等)
// 初始化串口(蓝牙)
// 初始化信号灯(全灭)
SIGNAL_PORT = 0xFF;
while (1) {
// 检测是否有人(超声波距离小于一定值,比如10cm)
distance = ultrasonic_distance();
if (distance < 10) {
// 显示输入密码界面
OLED_ShowString(0,0,"Input Password:");
// 矩阵键盘扫描
key = key_scan();
if (key != 0xFF) {
if (key >= '0' && key <= '9') { // 数字键
if (count < 6) {
input[count] = key - '0';
count++;
// OLED显示星号
OLED_ShowChar(0, 1 + count, '*');
}
} else if (key == 'A') { // 删除
if (count > 0) {
count--;
OLED_ShowChar(0, 1 + count, ' '); // 清除星号
}
} else if (key == 'B') { // 确认
// 验证密码
bit correct = 1;
for (i=0; i<6; i++) {
if (input[i] != password[i]) {
correct = 0;
break;
}
}
if (correct) {
door_open = 1;
servo_angle(90); // 开门
SIGNAL_PORT = 0xFE; // 第一个灯亮(绿色)
OLED_ShowString(0,2,"Open Door!");
delay_ms(2000);
// 关门(延时后自动关门)
delay_ms(5000); // 开门5秒
servo_angle(0); // 关门
door_open = 0;
SIGNAL_PORT = 0xFF; // 灯灭
} else {
SIGNAL_PORT = 0xFD; // 第二个灯亮(红色)
OLED_ShowString(0,2,"Wrong Password!");
delay_ms(2000);
}
// 清除输入
count = 0;
for (i=0; i<6; i++) input[i]=0;
OLED_ClearLine(1); // 清除输入行
} else if (key == 'C') { // 取消
count = 0;
for (i=0; i<6; i++) input[i]=0;
OLED_ClearLine(1); // 清除输入行
}
}
} else {
// 无人时,显示待机界面,如温湿度
DHT11_Read(&temp, &humi);
OLED_ShowString(0,0,"Temp: ");
OLED_ShowNum(0,6,temp,2);
OLED_ShowString(0,9,"C Humi: ");
OLED_ShowNum(0,16,humi,2);
OLED_ShowString(0,18,"%");
}
delay_ms(100); // 延时防止过于频繁
}
}
```
### 注意事项
1. 上述代码是一个框架,具体实现需要根据实际硬件连接和模块驱动进行调整。
2. 矩阵键盘扫描中,为了防止抖动,在检测到按键后需要延时去抖。
3. 舵机控制实际应用中应使用定时器中断产生PWM信号,避免使用延时导致主循环卡顿。
4. 超声波测距函数中的计时方式(使用while循环)会占用CPU,可以考虑使用外部中断和定时器来精确计时。
5. AT24C64的读写需要按照I2C协议实现,注意地址设置(默认地址0xA0)。
6. 蓝牙模块可以通过串口中断接收数据,实现远程开锁功能。
### 相关问题
1. 如何优化矩阵键盘的扫描效率?
2. 舵机控制中如何避免使用延时函数?
3. 超声波测距的精确计时方法有哪些?
4. 如何通过蓝牙修改门禁系统的密码?
5. 如何实现密码错误次数限制?</think>### 基于51单片机的智能门禁系统实现
下面提供一个整合AT24C64、OLED、蓝牙模块、舵机、薄膜键盘(3x4矩阵键盘)、超声波模块、信号灯XD10-6和DHT11的智能门禁系统代码框架。核心代码使用Keil C51语法编写,特别标注了矩阵键盘的实现部分。
```c
#include <reg52.h>
#include <intrins.h>
#include "oled.h" // OLED显示驱动
#include "i2c.h" // I2C通信(AT24C64和OLED共用)
#include "dht11.h" // 温湿度传感器
// 矩阵键盘定义(3x4薄膜键盘)
#define KEY_PORT P1 // 键盘连接端口
sbit ROW1 = P1^0; // 行线1
sbit ROW2 = P1^1; // 行线2
sbit ROW3 = P1^2; // 行线3
sbit COL1 = P1^4; // 列线1
sbit COL2 = P1^5; // 列线2
sbit COL3 = P1^6; // 列线3
sbit COL4 = P1^7; // 列线4
// 其他设备引脚定义
sbit Servo = P2^0; // 舵机控制
sbit Trig = P2^1; // 超声波Trig
sbit Echo = P2^2; // 超声波Echo
sbit LED_R = P3^0; // 信号灯红色
sbit LED_G = P3^1; // 信号灯绿色
// 全局变量
unsigned char password[6] = {1,2,3,4,5,6}; // 默认密码
unsigned char input[6]; // 输入密码缓存
unsigned char count = 0; // 输入位数计数
/****************** 矩阵键盘扫描函数 ******************/
unsigned char KeyScan() {
unsigned char key_value = 0;
// 扫描第一行
ROW1 = 0; ROW2 = 1; ROW3 = 1;
if (!COL1) key_value = '1';
if (!COL2) key_value = '2';
if (!COL3) key_value = '3';
if (!COL4) key_value = 'A'; // 功能键A
ROW1 = 1;
// 扫描第二行
ROW2 = 0; ROW1 = 1; ROW3 = 1;
if (!COL1) key_value = '4';
if (!COL2) key_value = '5';
if (!COL3) key_value = '6';
if (!COL4) key_value = 'B'; // 功能键B
ROW2 = 1;
// 扫描第三行
ROW3 = 0; ROW1 = 1; ROW2 = 1;
if (!COL1) key_value = '7';
if (!COL2) key_value = '8';
if (!COL3) key_value = '9';
if (!COL4) key_value = 'C'; // 功能键C
ROW3 = 1;
// 第四行扫描(特殊功能键)
ROW1 = 1; ROW2 = 1; ROW3 = 0;
if (!COL1) key_value = '*'; // 删除键
if (!COL2) key_value = '0';
if (!COL3) key_value = '#'; // 确认键
if (!COL4) key_value = 'D'; // 功能键D
ROW3 = 1;
return key_value;
}
/****************** 舵机控制函数 ******************/
void ServoControl(bit open) {
unsigned int i;
if (open) {
for (i = 0; i < 50; i++) { // 开门位置
Servo = 1;
delay_us(1500); // 1.5ms高电平
Servo = 0;
delay_ms(20);
}
} else {
for (i = 0; i < 50; i++) { // 关门位置
Servo = 1;
delay_us(500); // 0.5ms高电平
Servo = 0;
delay_ms(20);
}
}
}
/****************** 超声波测距函数 ******************/
unsigned int UltrasonicMeasure() {
unsigned int time = 0;
Trig = 1;
delay_us(12);
Trig = 0;
while (!Echo); // 等待高电平
while (Echo) {
time++;
delay_us(1);
if (time > 30000) break; // 超时
}
return time / 58; // 返回厘米距离
}
/****************** 主函数 ******************/
void main() {
unsigned char key;
unsigned char temp, humi;
// 初始化
OLED_Init();
DHT11_Init();
EA = 1; // 开启总中断
OLED_ShowString(0, 0, "Smart Door Lock");
OLED_ShowString(2, 0, "Pass:");
while (1) {
// 1. 检测超声波(是否有人靠近)
if (UltrasonicMeasure() < 30) {
OLED_ShowString(4, 0, "Input Password");
// 2. 矩阵键盘输入
key = KeyScan();
if (key != 0) {
if (key >= '0' && key <= '9') { // 数字键
if (count < 6) {
input[count] = key - '0';
OLED_ShowChar(2, 6 + count, '*'); // 显示星号
count++;
}
}
else if (key == '#') { // 确认键
// 3. 密码验证
bit match = 1;
for (unsigned char i = 0; i < 6; i++) {
if (input[i] != password[i]) {
match = 0;
break;
}
}
// 4. 执行开门操作
if (match) {
LED_G = 1; // 绿灯亮
ServoControl(1); // 开门
OLED_ShowString(4, 0, "Access Granted! ");
delay_ms(3000);
ServoControl(0); // 关门
LED_G = 0;
} else {
LED_R = 1; // 红灯亮
OLED_ShowString(4, 0, "Access Denied! ");
delay_ms(2000);
LED_R = 0;
}
// 清除输入
for (unsigned char i = 0; i < 6; i++) {
OLED_ShowChar(2, 6 + i, ' ');
input[i] = 0;
}
count = 0;
}
else if (key == '*') { // 删除键
if (count > 0) {
count--;
OLED_ShowChar(2, 6 + count, ' ');
input[count] = 0;
}
}
delay_ms(200); // 按键消抖
}
}
// 5. 显示温湿度
DHT11_Read(&temp, &humi);
OLED_ShowString(6, 0, "Temp:");
OLED_ShowNum(6, 6, temp, 2);
OLED_ShowString(7, 0, "Humi:");
OLED_ShowNum(7, 6, humi, 2);
delay_ms(100);
}
}
```
### 关键模块说明
1. **矩阵键盘实现(3x4)**
- 采用行列扫描法,通过控制行线电平变化检测列线状态
- 定义功能键:`#`确认、`*`删除、`A-D`特殊功能
- 消抖处理:检测到按键后延时200ms
- 返回ASCII码值,数字键直接转换为数值
2. **AT24C64 EEPROM集成**
```c
// 密码存储示例
void SavePassword() {
I2C_Start();
I2C_WriteByte(0xA0); // 器件地址
I2C_WriteByte(0x00); // 存储地址高位
I2C_WriteByte(0x10); // 存储地址低位
for (int i=0; i<6; i++) {
I2C_WriteByte(password[i]);
}
I2C_Stop();
}
```
3. **多模块协同逻辑**
```mermaid
graph TD
A[超声波检测有人] --> B[OLED提示输入密码]
B --> C[矩阵键盘输入]
C --> D{确认键按下?}
D -->|是| E[验证AT24C64存储的密码]
E -->|匹配| F[舵机开门/绿灯亮]
E -->|不匹配| G[红灯亮/报警]
F --> H[延时后自动关门]
```
### 注意事项
1. 需要根据实际硬件连接修改引脚定义
2. 舵机控制参数需根据具体型号调整PWM脉宽
3. AT24C64需通过I2C协议访问,注意器件地址0xA0
4. 超声波模块需在中断中实现精确计时
5. 蓝牙模块可通过串口中断实现:
```c
void UART_ISR() interrupt 4 {
if (RI) {
unsigned char cmd = SBUF;
if (cmd == 'O') ServoControl(1); // 蓝牙开门指令
RI = 0;
}
}
```
### 相关问题
1. 如何优化矩阵键盘的扫描效率?
2. 当需要存储多个密码时,AT24C64的地址如何分配?
3. 如何通过蓝牙模块实现远程开门功能?
4. 超声波模块测量误差较大的可能原因有哪些?
5. 如何添加温度补偿功能来提高DHT11的测量精度?
阅读全文
相关推荐


















