Arduino DIY 计算器:1602 LCD + 4×4 矩阵键盘完整教程
核心物料清单
- Arduino Uno ×1(任意版本)
- 1602 字符型 LCD(HD44780 兼容) ×1 - 16列×2行,带背光
- 4×4 矩阵薄膜键盘 ×1 - 16键(0-9, A-D, *, #)
- 面包板、跳线、9V 电池盒 若干
- 10kΩ 电位器 ×1 - LCD 对比度调节(原文未列但实测必需)
引脚分配表
| 功能 | Arduino 引脚 | 备注 |
|---|---|---|
| 键盘 Row 0-3 | D0, D1, D2, D3 | ⚠ D0/D1 为硬件串口,上传代码时需断开键盘 |
| 键盘 Col 0-3 | D4, D5, D6, D7 | |
| LCD RS | D8 | 寄存器选择 |
| LCD EN | D9 | 使能 |
| LCD D4-D7 | D10, D11, D12, D13 | 4位数据模式 |
| LCD V0 | 电位器中间脚 | 两端接 5V/GND,调节对比度 |
| LCD VDD/RW/A/K | 5V/GND/GND/5V | 供电、写模式、背光 |
电路连接要点
- 键盘 8 根线直接插入 D0-D7,上传代码前必须拔掉键盘,否则串口冲突导致上传失败
- LCD 采用 4 位数据模式,节省 4 个 IO 口
- 电位器调节对比度直到字符清晰可见
- 建议外接 9V 电池供电,脱离 USB 也可独立运行
代码架构与核心库
依赖库
LiquidCrystal.h- Arduino 官方内置Keypad.h- Chris--A/Keypad(库管理器可直接安装)
按键映射与状态机
// 4x4 键盘映射
char keys[4][4] = {
{'7','8','9','D'},
{'4','5','6','C'},
{'1','2','3','B'},
{'*','0','#','A'}
};
// 状态变量
long Num1=0, Num2=0, Number=0; // 操作数1/2、当前输入
char action = 0; // 运算符 + - * /
boolean result = false; // 是否显示结果
核心流程
DetectButtons():按键扫描 → 数字累积(Number = Number*10 + digit) → 运算符键(A-D)存入Num1清零Number记录actionCalculateResult():#键触发,根据action执行四则运算DisplayResult():LCD 第一行显示算式(如12+34=46),第二行显示当前输入/结果*键清零复位
完整代码(已整理优化)
#include <LiquidCrystal.h>
#include <Keypad.h>
const byte ROWS = 4, COLS = 4;
char keys[ROWS][COLS] = {
{'7','8','9','D'},
{'4','5','6','C'},
{'1','2','3','B'},
{'*','0','#','A'}
};
byte rowPins[ROWS] = {0,1,2,3};
byte colPins[COLS] = {4,5,6,7};
Keypad kpd = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);
const int rs=8, en=9, d4=10, d5=11, d6=12, d7=13;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
long Num1=0, Num2=0, Number=0;
char key, action=0;
boolean result=false;
void setup() {
lcd.begin(16,2);
lcd.print("DIY Calculator");
lcd.setCursor(0,1);
lcd.print("-CircuitDigest");
delay(2000);
lcd.clear();
}
void loop() {
key = kpd.getKey();
if (key != NO_KEY) DetectButtons();
if (result) CalculateResult();
DisplayResult();
}
void DetectButtons() {
lcd.clear();
if (key == '*') { Num1=Num2=Number=0; result=false; return; }
if (key == '#') { Num2=Number; result=true; return; }
if (key >= '0' && key <= '9') {
if (Number == 0) Number = key - '0';
else Number = Number * 10 + (key - '0');
return;
}
if (key >= 'A' && key <= 'D') {
Num1 = Number; Number = 0;
action = (key=='A')?'+' : (key=='B')?'-' : (key=='C')?'*' : '/';
delay(100);
}
}
void CalculateResult() {
switch(action) {
case '+': Number = Num1 + Num2; break;
case '-': Number = Num1 - Num2; break;
case '*': Number = Num1 * Num2; break;
case '/': Number = (Num2!=0) ? Num1 / Num2 : 0; break;
}
result = false; // 显示后复位,允许继续运算
}
void DisplayResult() {
lcd.setCursor(0,0);
lcd.print(Num1); lcd.print(action); lcd.print(Num2);
if (result) { lcd.print(" ="); lcd.print(Number); }
lcd.setCursor(0,1);
lcd.print(Number);
}
常见问题与改进建议
| 问题 | 解决方案 |
|---|---|
上传报错 avrdude: stk500_getsync() | 上传前拔掉键盘 D0/D1 连线,上传完成后再插回 |
| LCD 无显示/全黑/乱码 | 调节对比度电位器;检查 D4-D7 接线顺序;确认共地 |
| 按键无响应/重复触发 | Keypad 库自带去抖,若仍有问题可在 DetectButtons 增加 delay(50) |
| 除法结果为整数 | 变量为 long 类型,如需小数改为 float 并修改显示格式 |
| 连续运算异常 | 当前逻辑显示结果后 result=false,可修改为保留结果作为下一运算的 Num1 |
进阶扩展功能
- 科学计算器:增加
sin/cos/tan/log/^等功能键,需扩展键盘或长按组合键 - 历史记录:利用 EEPROM 存储最近 10 条计算记录,上电恢复
- 单位换算:集成长度/重量/温度换算模式
- 图形化界面:移植至 ST7735/ILI9341 TFT 彩屏,绘制按钮、动画
- 语音播报:接入 DFPlayer Mini 模块,按键/结果语音提示
教学价值总结
本项目完整覆盖了 矩阵键盘扫描、LCD 4位模式驱动、有限状态机设计、字符串与数值转换、实时交互逻辑 等嵌入式核心技能,是 Arduino 进阶入门的经典实战。代码结构清晰,极易在此基础上迭代扩展更复杂的交互系统。
制造工艺
- 擀面杖:从伊特鲁里亚起源到现代工艺的演变
- 现代保龄球瓶的演变与工艺
- 防范 USB HID 攻击:Arduino Leonardo 键盘模拟演示
- 使用 Arduino Uno 轻松编程 Atmel AT89 系列单片机——分步指南
- DIY 蓝牙控制 Arduino 间谍小车
- Arduino 解码遥控接收机 PPM 信号——分步指南
- FlickMote:基于手势的智能家居红外遥控器
- DIY Arduino TV-B-Gone:万能关机遥控器
- 自制大尺寸LED主时钟带闹钟功能 — 12米外清晰可见
- 将 MIDI 键盘变身智能钢琴导师:Arduino + LED 灯带 + MuseScore
- Find Me:基于 Arduino 与蓝牙的智能寻物器制作指南
- Arduino Uno 控制 25kHz 4 针 PWM 风扇 - 硬件、代码与测试