【开源】基于STM32的无线条码扫描仪控制系统设计
项目编号:STM32-T009
项目名称:基于STM32的无线条码扫描仪控制系统设计
【摘要】
本项目设计了一种基于STM32F103C8T6单片机的无线条码扫描仪控制系统,旨在实现物品的智能化录入与管理。系统采用GM65二维码读取模块,支持对预设二维码的高速识别,用户可通过按键切换“录入”与“取出”两种功能模式。在录入模式下,扫码器读取二维码信息,将商品名称、型号与编号等信息录入并显示在OLED屏幕上,完成物品登记;在取出模式下,扫描物品二维码,系统自动比对库存数据,若物品信息存在,则成功完成取出操作;如物品未录入,蜂鸣器发出报警,提示用户操作异常。系统还配备蓝牙模块,将录入与取出的所有记录实时传输至手机APP,实现远程查看与信息同步。该系统具有操作简单、识别准确、记录可追溯等优点,广泛适用于实验室、仓库、办公室等场景的物品管理,提升物品存取效率与信息化水平,具有良好的应用前景与实际价值。
【所用硬件】
1、STM32F103C8T6最小系统板
STM32F103C8T6最小系统板是基于意法半导体(ST)Cortex-M3内核的微控制器开发板,核心芯片为STM32F103C8T6,主频72MHz,具有64KB Flash和20KB SRAM,满足中等复杂度的嵌入式应用需求。该板集成USB、USART、SPI、I2C等通信接口,支持多种外设扩展。最小系统板包含必要的外围电路,如8MHz晶振、复位电路、电源管理(3.3V稳压),并提供GPIO引脚引出,方便连接传感器、显示屏等模块。其低功耗、高性能特性使其广泛应用于智能硬件、工业控制等领域。在本设计中,它作为主控单元,负责数据采集、处理及外设控制,确保电子秤系统的稳定运行。
2、OLED显示模块
OLED(有机发光二极管)显示屏模块是一种自发光显示器件,无需背光,具有高对比度、宽视角和快速响应的特点。本设计采用的OLED模块通常为0.96英寸或1.3英寸,分辨率为128×64像素,支持I2C或SPI通信协议,可直接与STM32等微控制器连接。其工作电压为3.3V~5V,功耗低,适合便携式设备。
3、轻触按键
轻触按键(Tactile Switch)是一种瞬时接触式机械开关,通过按压触发导通,松开后自动复位。其结构简单、体积小巧,通常采用金属弹片或导电橡胶实现触点通断,具有手感清晰、寿命长(可达10万次以上操作)的特点。工作电压和电流范围宽(如12V/50mA),可直接与STM32等微控制器的GPIO引脚连接,需配合上拉/下拉电阻使用以避免信号浮动。
4、GM65二维码读取模块
GM65二维码模块是一款高性能二维条码识读器,体积小巧、集成度高,常用于嵌入式系统中。它采用CMOS影像识别技术,支持多种一维、二维条码的快速解码,具备高速识读和较强的纠错能力,即使在低对比度、模糊或光照不佳的环境下也能稳定识别。该模块通过TTL串口或USB接口与主控设备通信,使用方便,广泛应用于物联网、移动支付、门禁控制、工业自动化等场景,具有响应速度快、识别率高和易于集成的特点。
5、蓝牙模块
HC-05蓝牙模块是一款常用的串口通信蓝牙模块,支持蓝牙2.0协议,采用主从一体设计,可通过AT指令自由配置工作模式。它通过UART接口与单片机或电脑连接,实现无线串口数据传输,使用方便、成本低廉、兼容性好。该模块传输稳定、距离可达10米左右,广泛应用于无线控制、小型物联网设备、智能小车和数据采集系统中,是嵌入式开发与蓝牙通信学习的常见选择。
【系统框架图】
【软件流程图】
【核心代码展示】
#include "app_task.h"
#include "main.h"
#include "m5310a.h"
#include "delay.h"
#include "usart.h"
#include "timer.h"
#include "esp8266.h"
#include "io.h"
#include "led.h"
#include "oled.h"
#include "sim800l.h"
#include "rtc.h"
#include "Encoder.h"
#include "beep.h"
#include "mpu6050.h"
#include "inv_mpu.h"
#include "adc.h"
#include "key.h"
#include "dth11.h"
#include "ds18b20.h"
#include "PAJ7620.h"
#include "max30102.h"
#include "stm32f10x_adc.h"
#include "HCSR04.h"
#include "rfid.h"
#include "redcod.h"
#include "IIC_1602.h"
#include "gps.h"
#include "FPM383C.h"
#include "car.h"
#include "HLW8032.h"u8 str[100];
USER user;
OLED oled;
TaskControlBlock TaskList[MAX_TASKS] = {0};
uint8_t RegisteredTasks = 0; // 已注册任务数
uint32_t SystemTick = 0; // 系统时间基准// 任务注册函数
int8_t Task_Register(uint8_t id, uint32_t interval, void (*task_func)(void *), void *param)
{if (RegisteredTasks >= MAX_TASKS)return -1;TaskList[RegisteredTasks].TaskID = id;TaskList[RegisteredTasks].PollingInterval = interval;TaskList[RegisteredTasks].TimerCounter = 0;TaskList[RegisteredTasks].RunFlag = 0;TaskList[RegisteredTasks].EnableFlag = 1;TaskList[RegisteredTasks].TaskHook = task_func;TaskList[RegisteredTasks].TaskParam = param;TaskList[RegisteredTasks].Delay = 0;RegisteredTasks++;return 0;
}// 任务使能控制
void Task_Enable(uint8_t id, uint8_t enable)
{for (int i = 0; i < RegisteredTasks; i++){if (TaskList[i].TaskID == id){TaskList[i].EnableFlag = enable;break;}}
}/*** @brief LED闪烁任务** @param pt*/
void Led_Task(void *pt)
{LED1 = !LED1;
}/*** @brief 按键任务** @param pt*/
void Key_Task(void *pt)
{switch (KEY_Scan(0)){case KEY1_PRICE:{if(oled.page == PAGE_HOME){oled.x = 1;}};break;case KEY2_PRICE:{if(oled.page == PAGE_HOME){oled.x = 2;}};break;case KEY3_PRICE:{ if(oled.page == PAGE_HOME){if(oled.x == 1){oled.page = PAGE_ENTER;oled.x=1;OLED_Clear();}else if(oled.x == 2){oled.page = PAGE_EXIT;oled.x=1;OLED_Clear();}}};break;case KEY4_PRICE:{if(oled.page == PAGE_ENTER || oled.page == PAGE_EXIT){oled.x=1;oled.page = PAGE_HOME;OLED_Clear();}};break;}
}/*** @brief OLED任务* * @param pt */
void OLED_Task(void *pt)
{if (oled.page == PAGE_HOME){/**无线扫描仪 */OLED_ShowChinese(16,0,5,16,1);OLED_ShowChinese(32,0,6,16,1);OLED_ShowChinese(48,0,7,16,1);OLED_ShowChinese(64,0,8,16,1);OLED_ShowChinese(80,0,9,16,1);if(oled.x == 1){/**录入模式 */OLED_ShowChinese(0,16,10,16,0);OLED_ShowChinese(16,16,11,16,0);OLED_ShowChinese(32,16,12,16,0);OLED_ShowChinese(48,16,13,16,0);}else{/**录入模式 */OLED_ShowChinese(0,16,10,16,1);OLED_ShowChinese(16,16,11,16,1);OLED_ShowChinese(32,16,12,16,1);OLED_ShowChinese(48,16,13,16,1);}if(oled.x == 2){/**取出模式 */OLED_ShowChinese(0,32,14,16,0);OLED_ShowChinese(16,32,15,16,0);OLED_ShowChinese(32,32,16,16,0);OLED_ShowChinese(48,32,17,16,0);}else{/**取出模式 */OLED_ShowChinese(0,32,14,16,1);OLED_ShowChinese(16,32,15,16,1);OLED_ShowChinese(32,32,16,16,1);OLED_ShowChinese(48,32,17,16,1);}}else if(oled.page == PAGE_ENTER){/**录入模式 */OLED_ShowChinese(32,0,10,16,1);OLED_ShowChinese(48,0,11,16,1);OLED_ShowChinese(64,0,12,16,1);OLED_ShowChinese(80,0,13,16,1);/**请刷二维码! */OLED_ShowChinese(16,32,22,16,1);OLED_ShowChinese(32,32,23,16,1);OLED_ShowChinese(48,32,24,16,1);OLED_ShowChinese(64,32,25,16,1);OLED_ShowChinese(80,32,26,16,1);OLED_ShowChinese(96,32,27,16,1);if(user.enter_flag == 1){user.enter_flag = 0;OLED_ShowString(0,16," ",16,1);OLED_ShowString(0,32," ",16,1);OLED_ShowString(0,48," ",16,1);/**编号: */OLED_ShowChinese(0,16,28,16,1);OLED_ShowChinese(16,16,29,16,1);OLED_ShowChinese(32,16,30,16,1);sprintf(str,"%d",user.commodity[user.num-1].number);OLED_ShowString(48,16,str,16,1);/**名称: */OLED_ShowChinese(0,32,31,16,1);OLED_ShowChinese(16,32,32,16,1);OLED_ShowChinese(32,32,33,16,1);sprintf(str,"%s",user.commodity[user.num-1].name);OLED_ShowString(48,32,str,16,1);/**型号: */OLED_ShowChinese(0,48,34,16,1);OLED_ShowChinese(16,48,35,16,1);OLED_ShowChinese(32,48,36,16,1);sprintf(str,"%s",user.commodity[user.num-1].modle);OLED_ShowString(48,48,str,16,1);OLED_Refresh();Delay_ms(3000);OLED_Clear();}}else if(oled.page == PAGE_EXIT){/**取出模式 */OLED_ShowChinese(32,0,14,16,1);OLED_ShowChinese(48,0,15,16,1);OLED_ShowChinese(64,0,16,16,1);OLED_ShowChinese(80,0,17,16,1);/**请刷二维码! */OLED_ShowChinese(16,32,22,16,1);OLED_ShowChinese(32,32,23,16,1);OLED_ShowChinese(48,32,24,16,1);OLED_ShowChinese(64,32,25,16,1);OLED_ShowChinese(80,32,26,16,1);OLED_ShowChinese(96,32,27,16,1);if(user.exit_flag == 1){user.exit_flag = 0;OLED_ShowString(0,16," ",16,1);OLED_ShowString(0,32," ",16,1);OLED_ShowString(0,48," ",16,1);/**取出成功! */OLED_ShowChinese(32,32,37,16,1);OLED_ShowChinese(48,32,38,16,1);OLED_ShowChinese(64,32,39,16,1);OLED_ShowChinese(80,32,40,16,1);OLED_ShowChinese(96,32,41,16,1);OLED_Refresh();Delay_ms(3000);OLED_Clear();}else if(user.exit_flag == 99){user.exit_flag = 0;OLED_ShowString(0,16," ",16,1);OLED_ShowString(0,32," ",16,1);OLED_ShowString(0,48," ",16,1);/**无此物! */OLED_ShowChinese(32,32,18,16,1);OLED_ShowChinese(48,32,19,16,1);OLED_ShowChinese(64,32,20,16,1);OLED_ShowChinese(80,32,21,16,1);OLED_Refresh();Delay_ms(3000);OLED_Clear();}}OLED_Refresh();
}void Task_Init(void)
{Task_Register(1, 1000, Led_Task, NULL);Task_Register(2, 1, Key_Task, NULL);Task_Register(3, 200, OLED_Task, NULL);}void Task_Run(void)
{for (int i = 0; i < RegisteredTasks; i++){if (TaskList[i].RunFlag && TaskList[i].EnableFlag){// 执行任务函数if (TaskList[i].TaskHook != NULL){TaskList[i].TaskHook(TaskList[i].TaskParam);}// 清除运行标志TaskList[i].RunFlag = 0;}}
}void TaskTime(void)
{static u32 tick_time = 0;tick_time++;// 遍历任务列表更新计数器for (int i = 0; i < RegisteredTasks; i++){if (TaskList[i].EnableFlag){TaskList[i].TimerCounter++;// 达到时间间隔时设置运行标志if (TaskList[i].TimerCounter >= TaskList[i].PollingInterval){TaskList[i].RunFlag = 1;TaskList[i].TimerCounter = 0;}}}
}
【原理图】
【硬件实物图】
【实物演示】
STM32-T009-无线条码扫描仪控制系统设计