基于单片机的超市储物柜设计
一、设计背景
在当今快节奏的生活中,超市已成为人们日常生活不可或缺的购物场所。随着超市规模的不断扩大和商品种类的日益丰富,消费者在购物过程中携带的物品也越来越多,这给购物带来了诸多不便。为了提升消费者的购物体验,超市储物柜应运而生。
传统的超市储物柜大多采用机械锁或简单的电子锁,存在着安全性不高、操作繁琐、管理不便等问题。而基于单片机的超市储物柜设计,能够有效解决这些问题,它具有智能化程度高、安全性好、操作简便、易于管理等优点,能够更好地满足超市和消费者的需求。
二、系统硬件设计
(一)单片机选择
选用 STC89C52 单片机作为系统的核心控制器。STC89C52 是一种低功耗、高性能的 8 位微控制器,具有丰富的 I/O 端口、内置定时器 / 计数器、串行通信接口等资源,能够满足超市储物柜的控制需求,而且价格低廉,易于购买和使用。
(二)存储单元设计
存储单元是超市储物柜的重要组成部分,采用电磁锁作为每个储物格的锁具。电磁锁具有结构简单、响应速度快、安全性高等特点,能够通过单片机的控制实现锁的开启和关闭。每个储物格配备一个红外传感器,用于检测储物格内是否有物品,以便单片机进行相应的处理。
(三)输入模块设计
输入模块包括键盘和指纹识别模块。键盘采用 4×4 矩阵键盘,用于用户输入密码、选择储物格等操作。指纹识别模块采用光学指纹传感器,能够采集用户的指纹信息并进行识别,提高了储物柜的安全性。当用户使用指纹识别时,指纹识别模块将识别结果传输给单片机,单片机根据识别结果控制电磁锁的开启。
(四)显示模块设计
显示模块采用 LCD1602 液晶显示屏,用于显示储物柜的操作提示、储物格状态、密码等信息。LCD1602 具有显示清晰、功耗低、接口简单等优点,能够为用户提供直观的操作界面。
(五)报警模块设计
报警模块由蜂鸣器和 LED 指示灯组成。当出现异常情况,如密码输入错误次数过多、强行打开储物格等,单片机将控制蜂鸣器发出警报声,同时 LED 指示灯闪烁,提醒超市工作人员及时处理。
三、系统软件设计
(一)主程序设计
主程序是系统的核心,负责统筹各个模块的工作。主程序首先进行系统初始化,包括单片机端口初始化、LCD1602 初始化、键盘初始化、指纹识别模块初始化等。初始化完成后,系统进入待机状态,等待用户操作。当用户进行存物或取物操作时,主程序将根据用户的输入调用相应的子程序进行处理。
(二)存物子程序设计
当用户选择存物操作时,存物子程序被调用。首先,系统检测是否有空闲的储物格,如果有,LCD1602 显示提示信息,要求用户输入密码或进行指纹识别。用户完成输入后,系统将密码或指纹信息存储在单片机的 EEPROM 中,并记录对应的储物格编号。然后,单片机控制相应的电磁锁打开,同时 LCD1602 显示 “请存放物品” 的提示信息。当红外传感器检测到物品已放入储物格后,用户关闭储物格门,电磁锁自动锁闭,存物过程完成。
(三)取物子程序设计
当用户选择取物操作时,取物子程序被调用。LCD1602 显示提示信息,要求用户输入密码或进行指纹识别。用户完成输入后,系统将输入的信息与存储在 EEPROM 中的信息进行比对。如果比对成功,单片机控制相应的电磁锁打开,同时 LCD1602 显示 “请取出物品” 的提示信息。当红外传感器检测到物品已取出后,用户关闭储物格门,电磁锁自动锁闭,系统删除存储的密码或指纹信息,取物过程完成。如果比对失败,系统提示用户重新输入,若连续多次输入错误,报警模块将启动。
(四)中断服务程序设计
系统设置了外部中断和定时器中断。外部中断用于检测键盘输入和指纹识别模块的信号,当有输入时,触发外部中断,单片机暂停当前任务,转而去处理输入信息。定时器中断用于实现系统的定时功能,如定时检测储物格状态、定时关闭 LCD1602 背光等,以降低系统功耗。
四、系统功能实现
(一)存物功能
用户可以通过键盘输入密码或指纹识别的方式开启空闲储物格,将物品存入后,储物格自动锁闭,系统记录相关信息。
(二)取物功能
用户通过输入正确的密码或进行指纹识别,能够开启对应的储物格,取出物品后,储物格自动锁闭,系统删除相关信息。
(三)报警功能
当出现密码输入错误次数过多、强行打开储物格等异常情况时,系统将发出警报声和灯光提示。
(四)状态显示功能
LCD1602 能够实时显示储物柜的操作提示、储物格的使用状态(空闲或占用)、密码等信息,方便用户操作和超市工作人员管理。
(五)数据存储功能
系统采用 EEPROM 存储用户的密码或指纹信息以及储物格的状态信息,即使在断电的情况下,数据也不会丢失,保证了系统的可靠性。
五、系统调试与优化
(一)硬件调试
硬件调试主要包括各个模块的连接测试和功能测试。首先,检查各个模块之间的连线是否正确,确保没有短路、断路等情况。然后,分别对单片机、键盘、LCD1602、电磁锁、红外传感器、指纹识别模块、报警模块等进行测试,看是否能够正常工作。如果发现问题,及时排查并解决。
(二)软件调试
软件调试采用分步调试的方法,先对主程序和各个子程序进行单独调试,检查程序的逻辑是否正确、是否能够实现预期的功能。然后,进行整体调试,将各个模块的程序结合起来,测试系统的整体性能。在调试过程中,使用仿真器和示波器等工具进行辅助,观察程序的运行状态和信号的变化,及时发现并修正程序中的错误。
(三)系统优化
根据调试过程中发现的问题,对系统进行优化。在硬件方面,优化电路设计,减少干扰,提高系统的稳定性。在软件方面,优化程序代码,提高程序的运行效率,缩短响应时间。同时,增加一些实用的功能,如设置储物时间限制、自动提醒用户取物等,提升系统的用户体验。
六、结论与展望
(一)结论
本基于单片机的超市储物柜设计方案,通过合理的硬件选型和软件设计,实现了存物、取物、报警、状态显示和数据存储等功能。系统具有结构简单、成本低廉、操作简便、安全性高、可靠性强等优点,能够满足超市的使用需求。
(二)展望
随着科技的不断发展,未来可以对该超市储物柜进行进一步的改进和完善。例如,增加无线通信功能,实现与超市管理系统的联网,方便工作人员进行远程管理和监控;采用更先进的生物识别技术,如人脸识别、虹膜识别等,提高系统的安全性和便捷性;引入物联网技术,实现对储物柜的智能化管理,如自动统计储物数量、预测储物需求等。相信通过不断的创新和改进,超市储物柜将在人们的日常生活中发挥更加重要的作用。
宏定义部分
#include <reg52.h>
#include <intrins.h>// 引脚定义
#define LCD1602_DB P0
sbit LCD1602_RS = P2^0;
sbit LCD1602_RW = P2^1;
sbit LCD1602_E = P2^2;// 矩阵键盘引脚定义
sbit KEY_ROW0 = P3^0;
sbit KEY_ROW1 = P3^1;
sbit KEY_ROW2 = P3^2;
sbit KEY_ROW3 = P3^3;
sbit KEY_COL0 = P3^4;
sbit KEY_COL1 = P3^5;
sbit KEY_COL2 = P3^6;
sbit KEY_COL3 = P3^7;// 电磁锁引脚定义(假设8个储物格)
sbit LOCK0 = P1^0;
sbit LOCK1 = P1^1;
sbit LOCK2 = P1^2;
sbit LOCK3 = P1^3;
sbit LOCK4 = P1^4;
sbit LOCK5 = P1^5;
sbit LOCK6 = P1^6;
sbit LOCK7 = P1^7;// 红外传感器引脚定义
sbit INFRARED0 = P2^3;
sbit INFRARED1 = P2^4;
sbit INFRARED2 = P2^5;
sbit INFRARED3 = P2^6;
sbit INFRARED4 = P2^7;
sbit INFRARED5 = P3^8;
sbit INFRARED6 = P3^9;
sbit INFRARED7 = P3^10;// 报警模块引脚定义
sbit BUZZER = P2^8;
sbit ALARM_LED = P2^9;// 存储芯片相关定义(假设使用AT24C02)
#define AT24C02_ADDR 0xA0
sbit SDA = P3^11;
sbit SCL = P3^12;// 宏定义
#define uchar unsigned char
#define uint unsigned int
#define MAX_LOCK 8 // 储物格数量
#define PASSWORD_LENGTH 4 // 密码长度
#define ERROR_MAX 3 // 最大错误次数
LCD1602 相关函数
// 写命令到LCD1602
void lcd_write_cmd(uchar cmd)
{LCD1602_RS = 0;LCD1602_RW = 0;LCD1602_DB = cmd;LCD1602_E = 1;delay_us(5);LCD1602_E = 0;delay_ms(2);
}// 写数据到LCD1602
void lcd_write_data(uchar dat)
{LCD1602_RS = 1;LCD1602_RW = 0;LCD1602_DB = dat;LCD1602_E = 1;delay_us(5);LCD1602_E = 0;delay_ms(2);
}// LCD1602初始化
void lcd_init()
{lcd_write_cmd(0x38); // 8位数据,2行显示,5*7点阵lcd_write_cmd(0x0c); // 开显示,不显示光标lcd_write_cmd(0x06); // 光标自动右移,不滚动lcd_write_cmd(0x01); // 清屏delay_ms(2);
}// 在指定位置显示字符
void lcd_show_char(uchar x, uchar y, uchar dat)
{if(y == 0)lcd_write_cmd(0x80 + x);elselcd_write_cmd(0xc0 + x);lcd_write_data(dat);
}// 在指定位置显示字符串
void lcd_show_string(uchar x, uchar y, uchar *str)
{uint i = 0;if(y == 0)lcd_write_cmd(0x80 + x);elselcd_write_cmd(0xc0 + x);while(str[i] != '\0'){lcd_write_data(str[i]);i++;}
}
矩阵键盘相关函数
// 按键扫描
uchar key_scan()
{uchar key_value = 0xff;KEY_ROW0 = 0;KEY_ROW1 = 1;KEY_ROW2 = 1;KEY_ROW3 = 1;if(KEY_COL0 == 0){delay_ms(10);if(KEY_COL0 == 0)key_value = '1';while(KEY_COL0 == 0);}if(KEY_COL1 == 0){delay_ms(10);if(KEY_COL1 == 0)key_value = '2';while(KEY_COL1 == 0);}if(KEY_COL2 == 0){delay_ms(10);if(KEY_COL2 == 0)key_value = '3';while(KEY_COL2 == 0);}if(KEY_COL3 == 0){delay_ms(10);if(KEY_COL3 == 0)key_value = 'A';while(KEY_COL3 == 0);}KEY_ROW0 = 1;KEY_ROW1 = 0;KEY_ROW2 = 1;KEY_ROW3 = 1;if(KEY_COL0 == 0){delay_ms(10);if(KEY_COL0 == 0)key_value = '4';while(KEY_COL0 == 0);}if(KEY_COL1 == 0){delay_ms(10);if(KEY_COL1 == 0)key_value = '5';while(KEY_COL1 == 0);}if(KEY_COL2 == 0){delay_ms(10);if(KEY_COL2 == 0)key_value = '6';while(KEY_COL2 == 0);}if(KEY_COL3 == 0){delay_ms(10);if(KEY_COL3 == 0)key_value = 'B';while(KEY_COL3 == 0);}KEY_ROW0 = 1;KEY_ROW1 = 1;KEY_ROW2 = 0;KEY_ROW3 = 1;if(KEY_COL0 == 0){delay_ms(10);if(KEY_COL0 == 0)key_value = '7';while(KEY_COL0 == 0);}if(KEY_COL1 == 0){delay_ms(10);if(KEY_COL1 == 0)key_value = '8';while(KEY_COL1 == 0);}if(KEY_COL2 == 0){delay_ms(10);if(KEY_COL2 == 0)key_value = '9';while(KEY_COL2 == 0);}if(KEY_COL3 == 0){delay_ms(10);if(KEY_COL3 == 0)key_value = 'C';while(KEY_COL3 == 0);}KEY_ROW0 = 1;KEY_ROW1 = 1;KEY_ROW2 = 1;KEY_ROW3 = 0;if(KEY_COL0 == 0){delay_ms(10);if(KEY_COL0 == 0)key_value = '*';while(KEY_COL0 == 0);}if(KEY_COL1 == 0){delay_ms(10);if(KEY_COL1 == 0)key_value = '0';while(KEY_COL1 == 0);}if(KEY_COL2 == 0){delay_ms(10);if(KEY_COL2 == 0)key_value = '#';while(KEY_COL2 == 0);}if(KEY_COL3 == 0){delay_ms(10);if(KEY_COL3 == 0)key_value = 'D';while(KEY_COL3 == 0);}return key_value;
}
存储芯片 AT24C02 相关函数
// 起始信号
void i2c_start()
{SDA = 1;SCL = 1;delay_us(5);SDA = 0;delay_us(5);SCL = 0;
}// 停止信号
void i2c_stop()
{SDA = 0;SCL = 1;delay_us(5);SDA = 1;delay_us(5);
}// 发送应答信号
void i2c_ack(bit ack)
{SCL = 0;SDA = ack;delay_us(5);SCL = 1;delay_us(5);SCL = 0;SDA = 1;
}// 等待应答
bit i2c_wait_ack()
{bit ack_bit;SCL = 0;SDA = 1;delay_us(5);SCL = 1;ack_bit = SDA;delay_us(5);SCL = 0;return ack_bit;
}// 发送一个字节
void i2c_send_byte(uchar dat)
{uchar i;for(i = 0; i < 8; i++){SCL = 0;SDA = (dat & 0x80) >> 7;dat <<= 1;delay_us(5);SCL = 1;delay_us(5);}SCL = 0;
}// 接收一个字节
uchar i2c_receive_byte()
{uchar i, dat = 0;SDA = 1;for(i = 0; i < 8; i++){SCL = 0;delay_us(5);SCL = 1;dat <<= 1;dat |= SDA;delay_us(5);}SCL = 0;return dat;
}// 向AT24C02写入一个字节
void at24c02_write_byte(uchar addr, uchar dat)
{i2c_start();i2c_send_byte(AT24C02_ADDR);if(i2c_wait_ack()){i2c_stop();return;}i2c_send_byte(addr);i2c_wait_ack();i2c_send_byte(dat);i2c_wait_ack();i2c_stop();delay_ms(10);
}// 从AT24C02读取一个字节
uchar at24c02_read_byte(uchar addr)
{uchar dat;i2c_start();i2c_send_byte(AT24C02_ADDR);i2c_wait_ack();i2c_send_byte(addr);i2c_wait_ack();i2c_start();i2c_send_byte(AT24C02_ADDR + 1);i2c_wait_ack();dat = i2c_receive_byte();i2c_ack(1);i2c_stop();return dat;
}// 初始化存储的数据
void init_storage()
{uchar i, j;for(i = 0; i < MAX_LOCK; i++){lock_state[i] = at24c02_read_byte(i);for(j = 0; j < PASSWORD_LENGTH; j++){password[i][j] = at24c02_read_byte(i * PASSWORD_LENGTH + MAX_LOCK + j);}}
}// 保存数据到存储芯片
void save_data()
{uchar i, j;for(i = 0; i < MAX_LOCK; i++){at24c02_write_byte(i, lock_state[i]);for(j = 0; j < PASSWORD_LENGTH; j++){at24c02_write_byte(i * PASSWORD_LENGTH + MAX_LOCK + j, password[i][j]);}}
}