0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

基于STM32的重力感应售货机系统设计

DS小龙哥-嵌入式技术 来源:DS小龙哥-嵌入式技术 作者:DS小龙哥-嵌入式技 2023-06-06 09:02 次阅读

一、项目介绍

随着智能物联网技术的不断发展,人们的生活方式和消费习惯也正在发生改变。如今越来越多的人习惯于在线购物、自助购物等新型消费模式,因此智能零售自助柜应运而生。

本项目设计开发一款基于STM32主控芯片的智能零售自助柜,通过重力传感器监测货柜内商品重量变化,并通过WiFi通信模块与手机端实现交互。用户可以通过输入账号密码,柜门自动打开,用户自取商品后关闭柜门,柜门锁定,系统根据重量变化判断用户拿取的商品并从账户自动扣费。同时,用户也可以通过手机端查看消费流水、商品库存,并进行补货和充值等操作。

智能零售自助柜的应用场景非常广泛,可以应用于商场、超市、酒店、机场、车站等各类场景。通过自助购物,可以提高消费者的消费体验和购物效率,同时也降低了商家的人力成本和物流成本。

image-20230530231109062

二、设计思路

【1】功能细节总结

(1)ESP8266配置成AP+TCP服务器模式与手机APP连接。

(2)手机APP可以完成用户的注册,充值功能,然后通过连接货柜将数据同步到货柜的存储芯片上(W25Q64-FLASH保存数据)。

(3)手机APP连接货柜之后,可以拉取数据显示,了解货柜现在的物品哪些已经售卖出去,哪些还没有售卖。,每个物品是放在一个货柜格子里,透明玻璃可以查看到物品。

【2】硬件选型

  1. 主控芯片:STM32F103RCT6是一款主流的32位ARM Cortex-M系列微控制器,具有高性能、低功耗和易于开发等特点,因此被选择作为该系统的主控芯片。
  2. 重力传感器:HX711重力传感器模块采用24位高精度芯片,能够精确测量重量,适用于该系统中货柜内商品的重量监测。
  3. SG90舵机:该系统需要控制柜门的打开和关闭,因此使用舵机来实现柜门控制。
  4. 矩阵键盘:用户需要输入账号密码进行登录,因此使用矩阵键盘作为输入设备。
  5. 显示屏:OLED显示屏具有低功耗、高对比度、快速响应等特点,适用于该系统中的桌面显示界面。
  6. WiFi模块:ESP8266-WIFI模块是一款成本低、体积小、性能稳定的WiFi通信模块,适合在该系统中与手机APP进行无线通信

【2】程序设计思路

  1. 初始化系统,包括各个外设的初始化,如WiFi模块、重力传感器HX711模块、矩阵键盘等;
  2. 用户输入账号密码,判断是否为有效用户;
  3. 根据重力传感器读取货柜内商品重量,判断用户拿取的商品并从账户自动扣费;
  4. 控制柜门打开和关闭,同时显示屏上显示相关提示信息
  5. 同步数据到手机APP。

【3】设备操作流程

  1. 用户输入账号密码,系统进行验证,判断是否为有效用户;
  2. 如果验证通过,屏幕上显示“登录成功”,并显示货柜内商品列表和对应价格;
  3. 用户选择需要购买的商品,系统根据重力传感器读取货柜内商品重量,并判断用户拿取的商品并从账户自动扣费;
  4. 系统控制电磁锁或舵机将柜门打开,用户自取商品后关闭柜门;
  5. 重力传感器监测到货柜内重量变化,系统自动判断用户拿取的商品种类和数量,并在显示屏上显示相关提示信息,如显示扣费金额;
  6. 控制柜门锁定,确保商品安全,同时在显示屏上显示“门已锁定”等相关提示信息;
  7. 同步扣费记录和商品库存信息到手机APP,以便用户查看消费流水和进行补货等操作。
  8. 如需要充值,用户可以在手机APP上进行余额充值操作。

三、代码实现

【1】OLED显示屏驱动代码

下面是OLED显示屏的测试代码。使用的SPI接口的OLED显示屏。

#include "stm32f10x.h"
 #include "OLED.h"   // OLED驱动库头文件void OLED_ShowString(uint8_t x, uint8_t y, uint8_t *str)
 {
     uint8_t i = 0;
     while(str[i] != '\\0'){
         if(x > OLED_WIDTH - 8){  // 满行自动换行
             x = 0;
             y++;
         }
         OLED_ShowChar(x, y, str[i]);  // 显示单个字符
         x += 8;  // 水平方向上的下一个字符
         i++;
     }
 }
 ​
 void OLED_SPI_SendByte(uint8_t data)
 {
     while(SPI_I2S_GetFlagStatus(OLED_SPI_PORT, SPI_I2S_FLAG_TXE) == RESET);  // 等待发送缓冲区空
     SPI_I2S_SendData(OLED_SPI_PORT, data);  // 通过SPI发送数据
 }
 ​
 void OLED_WriteCmd(uint8_t cmd)
 {
     OLED_DC_Clr();  // 将DC置为0,表示发送命令
     OLED_CS_Clr();  // 将CS置为0,选中OLED芯片
     OLED_SPI_SendByte(cmd);  // 发送命令
     OLED_CS_Set();  // 将CS置为1,取消OLED芯片选中
 }
 ​
 void OLED_WriteData(uint8_t data)
 {
     OLED_DC_Set();  // 将DC置为1,表示发送数据
     OLED_CS_Clr();  // 将CS置为0,选中OLED芯片
     OLED_SPI_SendByte(data);  // 发送数据
     OLED_CS_Set();  // 将CS置为1,取消OLED芯片选中
 }
 ​
 ​
 int main(void)
 {
     uint32_t i;
 ​
     // 初始化SPI接口
     SPI_InitTypeDef SPI_InitStructure;
     RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);  // 打开SPI1时钟
     SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;  // 设置SPI工作模式
     SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
     SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;  // 数据位宽8bit
     SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;  // 时钟极性为低电平
     SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;  // 时钟第一个边沿采样
     SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;  // 软件控制CS信号
     SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;  // 预分频系数为256
     SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;  // MSB先行
     SPI_InitStructure.SPI_CRCPolynomial = 7;  // CRC校验值
     SPI_Init(SPI1, &SPI_InitStructure);
     SPI_Cmd(SPI1, ENABLE);  // 使能SPI1// 初始化OLED显示屏
     OLED_Init();  // OLED初始化// 显示数字
     char str[] = "1234567890";
     OLED_ShowString(0, 0, (uint8_t *)str);  // 在(0,0)坐标处显示字符串while(1){
         for(i = 0; i < 10000000; i++);  // 延时等待
     }
 }
 ​

OLED_WriteCmd 函数用于向 OLED 显示屏发送命令,而 OLED_WriteData 函数用于向 OLED 显示屏发送数据。OLED_SPI_SendByte 函数是底层SPI数据传输的关键代码部分。

【2】HX711称重传感器代码

#include "stm32f10x.h"
 #include < stdio.h >
 #include "usart.h"#define HX711_SCK_GPIO_RCC  RCC_APB2Periph_GPIOB
 #define HX711_SCK_GPIO_PORT GPIOB
 #define HX711_SCK_GPIO_PIN  GPIO_Pin_13#define HX711_DOUT_GPIO_RCC  RCC_APB2Periph_GPIOB
 #define HX711_DOUT_GPIO_PORT GPIOB
 #define HX711_DOUT_GPIO_PIN  GPIO_Pin_15uint32_t read_HX711_data(void);
 void init_GPIO(void);
 void init_USART1(void);
 void USART1_SendChar(char ch);
 ​
 int main(void)
 {
     uint32_t hx711_value;
 ​
     init_GPIO();
     init_USART1();
 ​
     while(1){
         hx711_value = read_HX711_data();  // 读取 HX711 传感器数据
         printf("The weight is: %d g\\r\\n", hx711_value);  // 通过串口打印 HX711 传感器读取的数据
     }
 }
 ​
 // 从 HX711 传感器读取数据
 uint32_t read_HX711_data(void)
 {
     uint32_t weight = 0;
     uint8_t i;
 ​
     GPIO_SetBits(HX711_SCK_GPIO_PORT, HX711_SCK_GPIO_PIN);  // 拉高 SCK 管脚
     GPIO_ResetBits(HX711_DOUT_GPIO_PORT, HX711_DOUT_GPIO_PIN);  // 拉低 DOUT 管脚
     for(i = 0; i < 24; i++){
         GPIO_ResetBits(HX711_SCK_GPIO_PORT, HX711_SCK_GPIO_PIN);  // 拉低 SCK 管脚,使得 HX711 将数据推入 DOUT 管脚
         weight < <= 1;  // 左移一位,为下一次读取做准备
         if(GPIO_ReadInputDataBit(HX711_DOUT_GPIO_PORT, HX711_DOUT_GPIO_PIN)) weight++;  // 如果 DOUT 管脚为高电平,那么就在 weight 中保存 "1"
         GPIO_SetBits(HX711_SCK_GPIO_PORT, HX711_SCK_GPIO_PIN);  // 拉高 SCK 管脚,为下一次读取做准备
     }
     GPIO_ResetBits(HX711_SCK_GPIO_PORT, HX711_SCK_GPIO_PIN);  // 最后时刻需要拉低 SCK 管脚一次
 ​
     weight = (weight ^ 0x800000) - 0x800000;  // 将读出的24位二进制重量值转化为带符号数,这里我们只考虑单通道读取的情况(如有多个物理传感器需进行一定的计算处理)return weight;
 }
 ​
 // 初始化 GPIO 管脚
 void init_GPIO(void)
 {
     GPIO_InitTypeDef GPIO_InitStructure;
 ​
     RCC_APB2PeriphClockCmd(HX711_SCK_GPIO_RCC | HX711_DOUT_GPIO_RCC, ENABLE);  // 打开 SCK 和 DOUT 管脚时钟
 ​
     GPIO_InitStructure.GPIO_Pin = HX711_SCK_GPIO_PIN;
     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
     GPIO_Init(HX711_SCK_GPIO_PORT, &GPIO_InitStructure);  // 初始化 SCK 管脚
 ​
     GPIO_InitStructure.GPIO_Pin = HX711_DOUT_GPIO_PIN;
     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
     GPIO_Init(HX711_DOUT_GPIO_PORT, &GPIO_InitStructure);  // 初始化 DOUT 管脚
 }
 ​
 // 初始化 USART1
 void init_USART1(void)
 {
     USART_InitTypeDef USART_InitStructure;
 ​
     RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);  // 打开 USART1 时钟
 ​
     USART_InitStructure.USART_BaudRate = 115200;  // 波特率 115200
     USART_InitStructure.USART_WordLength = USART_WordLength_8b;  // 数据位 8 位
     USART_InitStructure.USART_StopBits = USART_StopBits_1;  // 停止位 1 位
     USART_InitStructure.USART_Parity = USART_Parity_No;  // 无奇偶校验
     USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;  // 无硬件流控制
     USART_InitStructure.USART_Mode = USART_Mode_Tx;  // 只启用串口发送USART_Init(USART1, &USART_InitStructure);  // 初始化 USART1
     USART_Cmd(USART1, ENABLE);  // 使能 USART1
 }
 ​
 // 通过 USART1 发送字符
 void USART1_SendChar(char ch)
 {
     while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);  // 等待发送缓冲区为空
     USART_SendData(USART1, (uint8_t)ch);  // 发送数据
 }
 ​

代码执行流程说明:

(1)通过 init_GPIO() 函数初始化 SCK 和 DOUT 两个 GPIO 管脚,并通过 init_USART1() 函数初始化 USART1 串口。其中,初始化 SCK 管脚为输出模式,DOUT 管脚为输入模式,USART1 算是串口助手,用于将数据打印输出。

(2)read_HX711_data() 函数用于向 HX711 传感器发出读取数据的指令,并将返回的数据进行处理(将24位二进制重量值转化为带符号数)后返回。

(3)在主函数的 while 循环中,不断调用 read_HX711_data() 函数读取 HX711 传感器的数据,并通过串口打印出来。

【3】SG90舵机控制代码

下面是SG90舵机的控制代码,可以按照指定的角度旋转。

#include "stm32f10x.h"
 #include "delay.h"#define GPIO_PORT           GPIOA
 #define GPIO_PIN            GPIO_Pin_1
 #define RCC_APB2Periph_GPIO RCC_APB2Periph_GPIOA
 #define PWM_FREQ            50void servoInit(void)
 {
     GPIO_InitTypeDef GPIO_InitStructure;
     TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
     TIM_OCInitTypeDef TIM_OCInitStructure;
 ​
     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIO, ENABLE);
 ​
     GPIO_InitStructure.GPIO_Pin = GPIO_PIN;
     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
     GPIO_Init(GPIO_PORT, &GPIO_InitStructure);
 ​
     TIM_TimeBaseStructure.TIM_Period = 9999; //计数器最大值
     TIM_TimeBaseStructure.TIM_Prescaler = (72 * 2) - 1; //时钟分频,72是系统时钟频率,2是倍频
     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 = 0;
     TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
     TIM_OC1Init(TIM2, &TIM_OCInitStructure);
 ​
     TIM_Cmd(TIM2, ENABLE);
 }
 ​
 void servoSetAngle(uint8_t angle)
 {
     uint16_t pwmVal = (uint16_t)(500 + angle * 10.0 / 9.0);
 ​
     TIM_SetCompare1(TIM2, pwmVal);
     delay_ms(100);
 }
 ​
 int main(void)
 {
     SystemInit();
     delay_init();
 ​
     servoInit();
 ​
     while(1)
     {
         servoSetAngle(0);
         delay_ms(1000);
 ​
         servoSetAngle(90);
         delay_ms(1000);
 ​
         servoSetAngle(180);
          delay_ms(1000);
     }
 }

审核编辑:汤梓红

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 传感器
    +关注

    关注

    2525

    文章

    48137

    浏览量

    740285
  • 物联网
    +关注

    关注

    2870

    文章

    41671

    浏览量

    358474
  • STM32
    +关注

    关注

    2240

    文章

    10675

    浏览量

    348872
  • WIFI
    +关注

    关注

    81

    文章

    5163

    浏览量

    199470
收藏 人收藏

    评论

    相关推荐

    【FPGA设计实例】自动售货机VHDL程序与仿真

    本帖最后由 eehome 于 2013-1-5 09:56 编辑 自动售货机VHDL程序与仿真(1)自动售货机VHDL程序如下:--文件名:pl_auto1.vhd。--功能:货物信息存储
    发表于 03-05 15:03

    LabVIEW售货机(人机交互实验版)

    售货机是基于NI的PXI控制器(LabVIEW软件实现)的人机交互性售货机。该售货机为试验版,正式版由于保密性不提供。本帖主要目的是给学习LabVIEW编程语言的朋友参考下,过程可能存在不合理或者有误的地方,希望学习的朋友可以
    发表于 09-21 15:26

    无线远程对自动售货机的管理

    现在很多支付商家都在推举1分钱购买自动售货机的饮料,那么这些自动售货机是怎么普及过来的呢? 随时随地可见的自动售货机俨然成为了我们的一种从商场转到小卖部,从小卖部转到个人的快捷交易平台。自动售卖机
    发表于 07-26 09:06

    被无线远程控制管理的自动售货机

    现在很多支付商家都在推举1分钱购买自动售货机的饮料,那么这些自动售货机是怎么普及过来的呢? 随时随地可见的自动售货机俨然成为了我们的一种从商场转到小卖部,从小卖部转到个人的快捷交易平台。自动售卖机
    发表于 07-28 09:23

    4G无线工业路由器自动售货机的应用

    方案需求自动售货机的应用日渐广泛,如城市街头、酒店、机场、居民社区、娱乐公共场所、办公大楼、商场、学校等场所,便捷式的服务和管理渐渐深入工作生活。自动售货机的管理逐步趋于无线管理方式,主要通过互联网
    发表于 11-29 23:47

    嵌入式自动售货机能实现什么功能?

    我们知道,智能设备的根本在于嵌入式系统的开发应用(嵌入式系统开发流程),随着电子技术不断的发展,很多智能化设备逐步取代了人工劳动,自动售货机就是其中一种基于嵌入式系统的智能化设备(什么
    发表于 04-17 08:14

    基于80C51单片机的自动售货机设计

    公司出品的80C51单片机为核心的自动售货机,并且着重详细地介绍了自动售货机的整体系统设计方案、硬件选择基础、软件使用方法及技巧。以80C51作为CPU处理单元连接各个功能模块;以4*4矩阵键盘
    发表于 12-02 07:30

    自动售货机短信报警系统

    关键词 ZWG-03A 智能短信设备、自动售货机、短信报警摘 要 本文介绍 ZWG-03A 在自动售货机短信报警系统中的应用
    发表于 11-04 11:18 86次下载

    智能自动售货机售货

    英特尔打造核心技术智能自动售货机售货 .
    发表于 12-28 18:09 0次下载

    PLC售货机

    使用三菱PLC,拥有售货机简单功能,可用,无错误
    发表于 06-24 14:36 10次下载

    一种基于 PLC 的自动售货机系统的设计

    一种基于 PLC 的自动售货机系统的设计王晓丽摘要:设计一种可编程序控制器 PLC 控制的自动售货机控制系统
    的头像 发表于 03-29 10:12 1.3w次阅读

    基于Zigbee和物联网的自动售货机系统

    结合Zigbee技术、物联网技术和手机扫码支付技术,以STM32和Arduino为主控芯片,设计了一种自动售货机系统系统可实现购买商品的线上/线下支付,运营商通过短信可及时了解
    发表于 04-26 10:17 25次下载

    32-基于单片机的售货机系统

    基于单片机的售货机系统
    发表于 11-18 09:51 14次下载
    32-基于单片机的<b class='flag-5'>售货机</b><b class='flag-5'>系统</b>

    物联卡智能售货机的优势是什么

    自动售货机大家都不陌生了,自动售货机不需要专人看守,节省了人力,而且可以24小时工作,当夜深人静突然肚子饿得时候就发挥了大作用。
    发表于 06-10 17:44 810次阅读

    基于ARM硬件的智能售货机终端

    启扬智能为售货机行业提供了基于ARM架构搭载Android系统的智能售货机硬件解决方案。
    的头像 发表于 07-27 15:18 680次阅读
    基于ARM硬件的智能<b class='flag-5'>售货机</b>终端