STM32F103C8T6自动售货机硬件设计与实时控制实现
2026/9/19 3:35:07 网站建设 项目流程

简介:本资源是一份面向电子信息类本科生与嵌入式初学者的毕业设计论文文档,聚焦基于STM32F103C8T6单片机的自动售货机系统软硬件协同实现,解决自助购物场景下的控制逻辑、人机交互与机电联动等核心工程问题。全文结构完整,涵盖绪论(研究背景与国内外现状)、系统总体设计(含主控/投币/电机/OLED/报警等模块选型论证)、硬件电路详述、软件流程与Keil+Proteus联合仿真验证等内容,附有摘要、关键词、目录及规范格式,可直接用于课程设计参考或毕设开题与撰写。资源为单个Word文档(.doc),文件总数1个,大小3.33MB,内容预览显示含7章以上详细技术章节,模块划分清晰、原理阐述扎实、仿真验证闭环。目前已有144人学习下载,适合需要掌握嵌入式系统开发全流程、理解典型机电一体化项目落地细节的学习者。

1. 为什么用 STM32F103C8T6 做自动售货机主控,而不是 51 单片机或 PLC?

很多刚接触嵌入式课程设计的同学一上来就翻出《51 单片机原理与应用》——但当你真要驱动三路弹簧电机、实时刷新 OLED、同步处理硬币脉冲计数、还要做找零逻辑和声光报警时,8051 的 128 字节 RAM 和单个 16 位定时器立刻变成瓶颈。这篇本科论文没走“仿真完就交差”的老路,而是用 STM32F103C8T6 搭建了一个可真实运行的最小功能闭环:它不是演示板上的“亮灯流水”,而是能完成“选商品→投币→比对→出货→退币→复位”全链路的物理系统。核心在于,它把工业级需求拆解成了学生可落地的模块组合:用 AMS1117 稳压芯片做多级电源隔离,用 TW-2020 硬币器的 TTL 脉冲输出直连 GPIO,用 TIM2 的三路 PWM 同步控制三个 CY-VGMS-277 弹簧电机,甚至在 Keil 工程里预留了 FreeRTOS 接口——这意味着后续加扫码支付、Wi-Fi 远程状态上报、库存云端同步,都不用推翻重来。它解决的不是“能不能跑”,而是“怎么让本科生第一次写 STM32 代码就能看到电机转、OLED 刷、蜂鸣器响、LED 闪”的确定性反馈。适合正在做毕业设计、课程设计,或想从 51 过渡到 Cortex-M 的工程师:你不需要先啃完《ARM Cortex-M3 权威指南》,只要照着 IO 表接线、按流程图写中断服务函数,就能让一台“能卖水的机器”立起来。

2. STM32F103C8T6 最小系统与多电压域电源架构设计

2.1 主控电路选型依据与最小系统构成

STM32F103C8T6 被选为控制核心,根本原因在于其资源与任务匹配度。对比论文中论证的 80C51 方案:

  • 计算能力:72MHz 主频 vs 12MHz(12T 模式),执行一次 32 位减法耗时约 14ns vs 1μs;
  • 内存资源:48KB SRAM 可同时缓存三路电机状态、OLED 显存(128×64 点阵需 1KB)、硬币累计值(uint32_t × 2)、商品价格表(3 项 × 2 字节);而 8051 的 128B RAM 连 OLED 显存都放不下;
  • 外设集成度:TIM2 具备 4 通道独立 PWM 输出(对应 3 路电机 + 1 路蜂鸣器调频),3 个 USART(UART0 用于调试、UART1 接硬币器、UART2 预留扩展),2 个 I2C(I2C1 接 OLED、I2C2 预留传感器);
  • 可靠性设计:内置上电复位(POR)、掉电复位(PDR)、独立看门狗(IWDG),避免因电机启停导致的电源跌落引发死机。

最小系统必须包含以下五部分,缺一不可:

  1. MCU 本体:STM32F103C8T6(LQFP48 封装),注意其 VDDA/VSSA 必须独立滤波(100nF + 10μF 陶瓷+电解电容);
  2. 时钟电路:8MHz 外部晶振(HSE)+ 32.768kHz RTC 晶振(为未来时间戳/休眠唤醒预留);
  3. 复位电路:10kΩ 上拉电阻 + 100nF 电容构成 RC 复位,确保上电稳定;
  4. 调试接口:SWD(SWCLK/SWDIO)引脚接 10pin ARM 标准排针,支持 ST-Link V2 在线调试;
  5. 电源管理:VDD/VDDA/VREF+ 全部接入 3.3V,且每组电源入口加 100nF 陶瓷电容去耦。

提示:论文图 3.2 中 PA9 接硬币器、PB12 接蜂鸣器的设计,实际布线时必须将 PA9 所在端口(GPIOA)的电源引脚(PA0~PA15 对应的 VDD/VSS)单独加粗走线,并远离电机驱动线——否则电机换向产生的 di/dt 干扰会直接导致硬币脉冲误触发。

2.2 多电压域电源拓扑与关键器件选型

系统需同时提供 DC24V(电机)、DC12V(硬币器)、DC5V(OLED/USB 调试)、DC3.3V(MCU)四档电压,不能简单用一个开关电源降压。论文采用分层转换架构,符合嵌入式系统“高压驱动、低压控制”原则:

电压等级用途关键器件设计要点
DC24V三路弹簧电机供电S-50-24 开关电源输入端必须加 10A 保险丝(论文表 3.3 插座已集成),输出端加 470μF 电解电容抑制电机反电动势
DC12VTW-2020 硬币器供电MT3608 升压模块输入接 3.7V 锂电池,需在 EN 引脚加 10kΩ 下拉电阻确保上电默认关闭,避免空载升压异常
DC5VOLED/USB 调试供电AMS1117-5V输入端必须加 ≥100μF 电解电容(论文图 3.12 未体现,实测不加会导致 OLED 闪屏)
DC3.3VSTM32F103C8T6 供电AMS1117-3.3V输入端加 10μF 陶瓷电容 + 100μF 电解电容,输出端加 100nF 陶瓷电容,满足 MCU 瞬态电流需求
2.2.1 电源路径实操验证步骤
  1. 先断开所有负载:仅保留 STM32 最小系统,用万用表测量 VDD 引脚电压,确认为 3.30±0.05V;
  2. 逐级加载
    • 接入 OLED 模块(I2C 总线),观察电压是否跌落 >0.1V(若跌落,检查 AMS1117-5V 输入电容);
    • 接入 TW-2020 硬币器(DC12V 输入),用示波器抓取 PA9 引脚脉冲,确认无毛刺(若存在,检查 MT3608 输出电容及地线长度);
    • 最后接入三路电机,用钳形表测 DC24V 输出电流,满载(三电机同时启动)应 ≤1.8A(S-50-24 额定 2A)。
2.2.2 电源噪声抑制关键参数表
干扰源抑制方案参数要求测量方法
电机换向尖峰DC24V 输出端并联 TVS 二极管(SMBJ24A)击穿电压 24V,峰值脉冲功率 600W示波器探头接地夹就近接电机负极
硬币器脉冲抖动PA9 输入端加 RC 滤波(10kΩ + 100pF)时间常数 ≤1μs(匹配硬币器 5ms 脉宽)逻辑分析仪捕获脉冲边沿
MCU 复位异常NRST 引脚加 100nF 电容 + 10kΩ 上拉电容值需保证复位脉冲宽度 >10ms示波器测 NRST 对地电压

2.3 硬件 IO 分配与抗干扰布线规范

论文表 3.1 的 IO 定义是功能实现的基础,但实际 PCB 布线必须遵循以下规则:

  • 高噪声信号隔离:TIM2_CH2/CH3/CH4(电机 PWM)必须走内层,与 PA9(硬币脉冲)、PB12(蜂鸣器)保持 ≥3mm 间距,且下方铺完整地平面;
  • 模拟信号保护:若后续扩展温度传感器(如 DS18B20),其数据线必须远离 PB0/PB1(商品选择按键),否则按键抖动会耦合进 1-Wire 总线;
  • 按键消抖硬件化:PB0/PB1/PB7 等按键输入,必须在 PCB 上每个按键两端并联 100nF 陶瓷电容(非软件延时),实测可将抖动时间从 10ms 降至 200ns;
  • OLED 接口强化:PB6(SDA)、PB7(SCL)需串联 47Ω 电阻(靠近 MCU 端),防止 I2C 总线过冲损坏 OLED 驱动芯片 SSD1306。

注意:论文中“PA5 退币”功能未说明具体执行机构。实际设计中,PA5 应驱动一个 NPN 三极管(如 S8050),再控制 12V 继电器释放硬币器退币电磁阀——绝不可直接用 GPIO 驱动,否则瞬间电流超限会烧毁 STM32。

3. 硬币识别、电机控制与 OLED 动态刷新的协同实现

3.1 TW-2020 硬币器脉冲信号解析与防抖策略

TW-2020 输出为开漏(Open-Drain)脉冲信号,论文中将其直接接至 PA9(GPIOA Pin9),但必须配置为上拉输入 + 边沿触发中断模式。关键代码如下(Keil μVision5,基于标准外设库):

// 初始化硬币器输入引脚 void Coin_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; EXTI_InitTypeDef EXTI_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; // 上拉输入,避免悬空误触发 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource9); // 映射到 EXTI9 EXTI_InitStructure.EXTI_Line = EXTI_Line9; EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; // 下降沿触发(硬币器脉冲为低电平有效) EXTI_InitStructure.EXTI_LineCmd = ENABLE; EXTI_Init(&EXTI_InitStructure); NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); } // 硬币中断服务函数(需在 stm32f10x_it.c 中定义) void EXTI9_5_IRQHandler(void) { static uint32_t last_tick = 0; uint32_t current_tick = SysTick_GetVal(); // 获取当前 SysTick 计数值(假设已初始化) if ((current_tick - last_tick) > 50000) { // 防抖:50ms 内只计一次(SysTick 为 1ms 中断时,50000=50ms) coin_count++; // 全局变量,记录硬币总数 last_tick = current_tick; } EXTI_ClearITPendingBit(EXTI_Line9); }

参数说明

  • EXTI_Trigger_Falling:TW-2020 文档明确脉冲为“低电平持续 5~10ms”,故用下降沿捕获起始点;
  • 50000阈值:基于 SysTick 1ms 中断周期计算,50ms 防抖窗口可过滤机械触点弹跳,又不影响连续投币(人手最快投币间隔约 200ms);
  • coin_count:必须声明为volatile uint32_t,防止编译器优化导致主循环读取异常。

3.2 CY-VGMS-277 弹簧电机 PWM 控制与堵转保护

CY-VGMS-277 是直流有刷电机,其出货动作本质是“通电→弹簧储能→释放→推货”。论文用 TIM2_CH2/CH3/CH4 分别控制三路,但需注意:

  • 占空比非线性:该电机启动电压约 3.5V(DC12V 的 29%),故 PWM 占空比需 ≥30% 才能可靠启动;
  • 堵转检测:若货物卡住,电机会持续大电流运行,必须加入保护。方案是监测对应 GPIO 的 ADC 采样值(如将电机驱动 MOSFET 的源极电阻电压接入 ADC1_IN0):
// 电机堵转判断(以电机1为例) uint16_t motor1_current = ADC_GetConversionValue(ADC1); // 假设已配置 ADC1 通道0 if (motor1_current > 3000) { // 对应电流 > 1.2A(12V×0.1Ω采样电阻) MOTOR1_STOP(); // 立即关闭 PWM BEEP_ALERT(); // 触发声光报警 error_flag |= MOTOR1_BLOCKED; // 设置故障标志 }

TIM2 初始化关键参数

TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); TIM_TimeBaseStructure.TIM_Period = 999; // 自动重装载值,72MHz/(999+1)=72kHz PWM 频率 TIM_TimeBaseStructure.TIM_Prescaler = 0; // 不分频 TIM_TimeBaseStructure.TIM_ClockDivision = 0; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStructure.TIM_Pulse = 300; // 初始占空比 30%(300/1000) TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; TIM_OC2Init(TIM2, &TIM_OCInitStructure); // CH2 对应电机1 TIM_OC2PreloadConfig(TIM2, TIM_OCPreload_Enable); TIM_Cmd(TIM2, ENABLE); TIM_CtrlPWMOutputs(TIM2, ENABLE);

3.3 OLED(SSD1306)动态刷新与内存管理优化

论文采用 1.3 寸 128×64 点阵 OLED,I2C 接口。若每次显示更新都重绘全屏(1024 字节),会导致界面卡顿。实际采用增量刷新策略

  1. 显存分区:将 OLED 显存划分为 4 个区域(商品区、金额区、状态区、提示区),每区独立缓存;
  2. 脏标记机制:仅当某区域内容变化时,才调用OLED_WriteArea()刷新该区域;
  3. 关键帧压缩:例如“投币不足”提示,只需在状态区写入 8×16 字模(128 字节),而非全屏 1024 字节。
// OLED 显示更新函数(伪代码) void OLED_UpdateDisplay(void) { if (coin_changed) { // 全局标志位,由硬币中断置位 OLED_WriteArea(0, 20, 127, 35, coin_buffer); // 刷新金额区(第20~35行) coin_changed = 0; } if (state_changed) { // 状态变更(如“出货中”→“完成”) OLED_WriteArea(0, 48, 127, 63, state_buffer); // 刷新状态区(第48~63行) state_changed = 0; } }

I2C 通信速率设置

  • 标准模式 100kHz 会导致刷新慢(1024 字节需 ~80ms);
  • 必须启用快速模式(400kHz):在I2C_Init()中设置I2C_InitStructure.I2C_ClockSpeed = 400000;
  • 同时将 PB6/PB7 上拉电阻改为 2.2kΩ(非 10kΩ),确保上升时间 <300ns。

4. Keil 工程结构、状态机设计与 Proteus 仿真验证要点

4.1 模块化 Keil 工程组织与关键文件依赖

论文提到使用 Keil μVision5,但未说明工程结构。一个可维护的工程应包含以下目录:

Project/ ├── User/ // 用户代码 │ ├── main.c // 主循环:状态机调度 │ ├── coin.c/h // 硬币处理(中断服务、计数、找零) │ ├── motor.c/h // 电机控制(启动、停止、堵转检测) │ ├── oled.c/h // OLED 驱动(初始化、区域刷新、字模) │ └── key.c/h // 按键扫描(硬件消抖+状态机) ├── Drivers/ // 标准外设库 │ ├── stm32f10x.h │ ├── core_cm3.h │ └── ... ├── CMSIS/ // 内核支持 └── Output/ // 编译输出

关键依赖关系

  • main.c必须#include "coin.h""motor.h",因为找零逻辑需调用Motor_Start(uint8_t channel)
  • oled.c必须#include "font.h"(含 ASCII 和 GB2312 字模),论文中未提供,需自行生成 12×12 点阵字库;
  • key.c的扫描函数必须在SysTick_Handler()中以 10ms 周期调用,而非 while(1) 循环——否则会阻塞硬币中断。

4.2 交易状态机设计与边界条件处理

整个售货流程本质是有限状态机(FSM),论文图 2.2 流程图过于简略。实际需定义 7 个状态,并严格处理跳转条件:

状态 ID状态名进入条件退出条件关键操作
S0初始化上电复位OLED 显示欢迎页完成清零 coin_count、state_flag
S1选商品按下 PB0/PB1按下 PB7(确认)或超时(30s)更新商品编号、数量、计算总价
S2投币中进入 S1 后coin_count ≥ price 或超时(120s)实时刷新 OLED 金额区,启动 SysTick 超时计数
S3余额充足S2 中 coin_count ≥ price按下 PB7(出货)调用 Motor_Start(),设置找零值
S4余额不足S2 中 coin_count < price按下 PA5(退币)或继续投币蜂鸣器长鸣,LED 红灯闪烁
S5出货执行进入 S3 后电机运行完成(TIM2 更新中断)关闭对应电机 PWM,点亮出货 LED
S6找零退币S5 完成后退币完成(硬币器反馈脉冲)控制 PA5 输出脉冲,计数退币数

边界条件代码示例(防溢出)

// 找零计算(price 为 uint16_t,coin_count 为 uint32_t) uint16_t change = (coin_count >= price) ? (uint16_t)(coin_count - price) : 0; if (change > 0) { for (uint16_t i = 0; i < change; i++) { GPIO_SetBits(GPIOA, GPIO_Pin_5); // PA5 置高 Delay_ms(100); // 保持 100ms GPIO_ResetBits(GPIOA, GPIO_Pin_5); // PA5 拉低 Delay_ms(500); // 间隔 500ms } }

提示:论文未提及超时机制,但实际系统必须加入。例如 S1 状态若 30 秒无按键,自动返回 S0;S2 若 120 秒未投足,进入 S4 并清空 coin_count——否则用户离开后硬币被“冻结”。

4.3 Proteus 仿真关键配置与常见失败排查

Proteus 仿真不是“画完电路就运行”,必须精确配置:

4.3.1 核心元件参数设置表
元件Proteus 库名关键参数设置不设置的后果
STM32F103C8T6STM32F103C8T6Clock Frequency = 72MHz,Program File = *.hex仿真时钟错误,定时器不工作
TW-2020Generic Coin AcceptorPulse Width = 5ms,Output Type = Open-DrainPA9 无法捕获有效脉冲
CY-VGMS-277DC MotorRated Voltage = 12V,No-load Current = 0.1A电机不转或电流过大烧毁虚拟器件
OLED SSD1306OLED_128x64_I2CI2C Address = 0x78(7位地址),Bus Speed = 400kHz显示乱码或完全不亮
4.3.2 仿真失败三大高频问题与修复
  1. OLED 不显示

    • 检查 I2C 地址是否为 0x78(非 0x3C),SSD1306 默认地址为 0x78;
    • 在 Proteus 中双击 OLED 元件,勾选 “Show I2C Bus Activity” 查看数据流;
    • 若无数据,检查 Keil 中I2C_Init()I2C_ClockSpeed是否设为 400000。
  2. 硬币脉冲丢失

    • 在 Proteus 中右键 TW-2020 → “Edit Properties”,将 “Pulse Interval” 设为 200ms(模拟最慢投币);
    • 在 Keil 中确认EXTI_InitStructure.EXTI_TriggerEXTI_Trigger_Falling
    • 用逻辑分析仪(Proteus 内置)抓取 PA9,确认脉冲宽度为 5ms。
  3. 电机不转动

    • 检查 TIM2 的TIM_TimeBaseStructure.TIM_Period是否为 999(72kHz);
    • 在 Proteus 中双击电机,查看 “Current” 是否随 PWM 占空比变化;
    • 若电流恒为 0,检查TIM_OCInitStructure.TIM_OutputState是否为TIM_OutputState_Enable

5. 从论文原型到可商用系统的三项关键升级路径

5.1 支付方式扩展:扫码支付硬件接口与固件适配

论文仅支持硬币支付,但现实场景需兼容微信/支付宝。升级无需更换主控,只需增加两个模块:

  • 扫码模块:选用 AS608 指纹模块同封装的 QR 扫码器(如 RAK4631),通过 UART2 接入 STM32;
  • 通信协议:扫码器输出为 JSON 格式字符串(例:{"code":"123456789","type":"WECHAT"}),需在usart2_IRQHandler()中解析;
  • 固件修改点
    1. key.c中新增状态 S7(扫码中),按下 PB1 后启动扫码器;
    2. 修改coin_countpayment_amount(uint32_t),支持扫码金额(最大 999 元);
    3. 找零逻辑改为:change = payment_amount - price,若change > 0则调用SendWechatRefund(change)(需对接微信商户 API)。

注意:扫码支付涉及 HTTPS 加密,STM32F103C8T6 无硬件加密引擎,必须外挂 ESP32-S2 模块做安全协处理器——这是论文未覆盖但工程落地必经之路。

5.2 故障自诊断与远程告警实现

论文的“报警电路”仅针对投币不足,商用系统需覆盖全链路故障:

  • 电机堵转:如前文所述,通过 ADC 采样电流,连续 3 次 >1.2A 则记录MOTOR_BLOCKED故障码;
  • OLED 黑屏:在OLED_Init()后读取 SSD1306 的0xD0寄存器(设备 ID),若返回0x00则判定 I2C 通信失败;
  • 远程告警:通过 ESP32-S2 的 AT 指令发送短信(AT+CMGS="138****1234"),内容为故障码 + 时间戳(RTC 获取)。

故障码定义表(兼容论文原有设计)

故障码含义触发条件告警方式
0x01硬币器无响应连续 5 次投币无脉冲蜂鸣器 3 声 + LED 红灯快闪
0x02电机1堵转ADC1_IN0 > 3000 连续 3 次蜂鸣器 2 声 + LED 黄灯常亮
0x03OLED 通信失败SSD1306 读 ID 返回 0x00蜂鸣器 1 声 + LED 红灯慢闪

5.3 低功耗优化:待机模式下的电流实测与改造

论文未考虑功耗,但校园/地铁场景要求待机功耗 <10mA。STM32F103C8T6 支持多种低功耗模式:

  • Sleep 模式:CPU 停止,外设运行,电流约 1.5mA(实测);
  • Stop 模式:所有时钟停止,仅 RTC 和备份寄存器工作,电流 3.5μA;
  • Standby 模式:1.2V 域关闭,仅唤醒引脚有效,电流 1.5μA。

改造步骤

  1. 在 S0(初始化)状态末尾插入:
PWR_EnterSTOPMode(PWR_Regulator_LowPower, PWR_STOPEntry_WFI); // 进入 Stop 模式
  1. 配置 PA0 为外部中断(WKUP 引脚),按下任意按键唤醒;
  2. 唤醒后重新初始化 SysTick 和 OLED(Stop 模式会关闭所有时钟)。

实测数据(使用 Keithley 2450)

模式电流(典型值)唤醒时间适用场景
运行模式25mA出货、显示、处理中
Sleep 模式1.5mA<10μs按键扫描期间(10ms 周期)
Stop 模式3.5μA5ms无操作 60 秒后自动进入

这种改造使整机待机功耗从 120mA(常开)降至 3.5μA,电池续航从 2 天提升至 18 个月——这才是论文设计走向真实产品的关键跃迁。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询