0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內(nèi)不再提示

基于STM32的無人售貨機系統(tǒng)設計

DS小龍哥-嵌入式技術 ? 來源:DS小龍哥-嵌入式技術 ? 作者:DS小龍哥-嵌入式技 ? 2023-05-17 16:29 ? 次閱讀

一、項目背景

隨著科技的發(fā)展和生活水平的提高,人們對于購物體驗的要求越來越高。傳統(tǒng)的商場、超市購物方式已經(jīng)無法滿足消費者的需求,因此無人售貨機應運而生。本文針對現(xiàn)有售貨機存在的缺陷,設計了一款基于STM32的無人售貨機系統(tǒng)。該系統(tǒng)采用STM32作為主控芯片,使用液晶屏顯示各種商品庫存與售價,用戶按下對應按鍵選擇購買指定商品,在矩陣鍵盤輸入賬號密碼付款。若付款成功,對應電機旋轉(zhuǎn)一定角度使商品出庫,同時修改庫存;若余額不足,則進行聲光提示。手機端還可查看消費流水、商品庫存情況,并進行補貨和充值操作。

image-20230517113951921

二、系統(tǒng)設計

2.1 系統(tǒng)硬件設計

該系統(tǒng)的核心部件是STM32主控芯片,它負責整個售貨機的控制和管理。液晶屏用于顯示商品信息、價格等,矩陣鍵盤用于用戶輸入賬號密碼進行支付。電機控制板用于控制商品出庫。

硬件組成:

主控芯片選:STM32F103ZET6 液晶屏選擇:2.8寸TFT-LCD屏 WIFI選擇:ESP8266-WIFI 與手機APP之間通信。模式配置為STA模塊。連接服務器。 電機旋轉(zhuǎn)角度:28BYJ48步進電機。 控制出貨機出貨物。 矩陣鍵盤:4X4的矩陣鍵盤。

2.2 系統(tǒng)軟件設計

軟件部分主要包括STM32程序和手機APP程序。STM32程序是售貨機的核心程序,負責控制各個部件的工作,實現(xiàn)售貨機的基本功能。APP程序可以通過與STM32通信來實現(xiàn)商品庫存查看、補貨、充值等功能。

STM32部分主要分為以下幾個模塊:

(1)初始化模塊:初始化各個部件的工作狀態(tài)和參數(shù)。 (2)商品選擇模塊:根據(jù)用戶按下的按鈕,選擇相應的商品。 (3)支付模塊:通過矩陣鍵盤輸入賬號密碼進行支付,并根據(jù)支付結(jié)果控制電機的工作狀態(tài)。 (4)庫存管理模塊:根據(jù)商品銷售情況,實時更新商品庫存信息。 (5)聲光提示模塊:在用戶付款失敗或余額不足時,通過蜂鳴器和LED燈進行聲光提示。

手機APP程序主要分為以下幾個模塊:

(1)用戶登錄模塊:用戶可以通過輸入賬號密碼登錄APP。 (2)商品查看模塊:用戶可以查看售貨機內(nèi)商品庫存情況。 (3)補貨模塊:商家可以通過APP進行補貨操作,將商品補充至指定數(shù)量。 (4)充值模塊:用戶可以通過APP進行賬戶充值操作。 (5)消費流水模塊:用戶和商家可以查看售貨機的消費記錄。

以上各模塊之間通過STM32和APP程序之間進行通信,實現(xiàn)整個系統(tǒng)的功能。

三、核心代碼實現(xiàn)

【1】步進電機控制代碼

以下是28BYJ48步進電機的代碼:

(1)定義一些宏和變量以便于控制步進電機:

#define IN1 GPIO_Pin_0
#define IN2 GPIO_Pin_1
#define IN3 GPIO_Pin_2
#define IN4 GPIO_Pin_3
?
#define STEPS_PER_REVOLUTION 2048 //步數(shù)每圈
#define DELAY_MS 5 //控制轉(zhuǎn)速的延遲時間
?
GPIO_InitTypeDef GPIO_InitStructure;
?
int step_count = 0;
uint16_t steps[] = {IN1 | IN2 | IN3 | IN4,
          IN2 | IN3 | IN4,
          IN1 | IN2 | IN3,
          IN3 | IN4,
          IN1 | IN3 | IN4,
          IN2 | IN4,
          IN1 | IN2,
          IN4};
?
void delay_ms(uint32_t ms) {
  uint32_t i, j;
  for (i = 0; i < ms; i++) {
? ? ? ? ?for (j = 0; j < 1141; j++);
? ?  }
?}
??
?void setStep(int step) {
? ? ?GPIO_ResetBits(GPIOB, IN1 | IN2 | IN3 | IN4);
? ? ?GPIO_SetBits(GPIOB, steps[step]);
?}
??
?void forward(int steps_to_move) {
? ? ?int i;
? ? ?for (i = 0; i < steps_to_move; i++) {
? ? ? ? ?setStep(step_count % 8);
? ? ? ? ?step_count++;
? ? ? ? ?delay_ms(DELAY_MS);
? ?  }
?}
??
?void backward(int steps_to_move) {
? ? ?int i;
? ? ?for (i = 0; i < steps_to_move; i++) {
? ? ? ? ?setStep(step_count % 8);
? ? ? ? ?step_count--;
? ? ? ? ?delay_ms(DELAY_MS);
? ?  }
?}

在上面的代碼中,定義了四個引腳來控制步進電機,然后定義了一些函數(shù)來實現(xiàn)正反轉(zhuǎn)控制。

delay_ms函數(shù)用于延遲控制步進電機的轉(zhuǎn)速。STEPS_PER_REVOLUTION宏定義了每圈的步數(shù),DELAY_MS宏定義了控制轉(zhuǎn)速的延遲時間。

setStep函數(shù)根據(jù)傳入的步數(shù)設置引腳狀態(tài),接著forward和backward函數(shù)分別根據(jù)需要移動的步數(shù)控制步進電機的轉(zhuǎn)動方向,并調(diào)用setStep函數(shù)控制步進電機的步數(shù)。

最后,將forward和backward函數(shù)封裝成一個子函數(shù)來更方便地調(diào)用:

void control_stepper_motor(int steps_to_move, int direction) {
  if (direction == 1) {
    forward(steps_to_move);
   } else {
    backward(steps_to_move);
   }
}

這樣,就可以通過調(diào)用control_stepper_motor函數(shù)來實現(xiàn)正反轉(zhuǎn)控制28BYJ48步進電機了。

【2】矩陣鍵盤檢測代碼

以下是4x4電容矩陣鍵盤的示例代碼:

(1)定義一些宏和變量以便于控制電容矩陣鍵盤:

#define ROW1 GPIO_Pin_0
#define ROW2 GPIO_Pin_1
#define ROW3 GPIO_Pin_2
#define ROW4 GPIO_Pin_3
?
#define COL1 GPIO_Pin_4
#define COL2 GPIO_Pin_5
#define COL3 GPIO_Pin_6
#define COL4 GPIO_Pin_7
?
GPIO_InitTypeDef GPIO_InitStructure;
?
const uint8_t keys[4][4] = {
   {'1', '2', '3', 'A'},
   {'4', '5', '6', 'B'},
   {'7', '8', '9', 'C'},
   {'*', '0', '#', 'D'}
};

在上面的代碼中,定義了8個引腳來控制電容矩陣鍵盤,并使用一個二維數(shù)組來存儲每個按鍵對應的字符。

(2)需要編寫一個函數(shù)來檢測電容矩陣鍵盤是否有按下。

該函數(shù)需要通過輪詢掃描鍵盤來檢測按鍵,如果有按鍵按下,則返回該按鍵對應的字符:

char scan_keypad() {
  GPIO_ResetBits(GPIOC, ROW1 | ROW2 | ROW3 | ROW4);
  GPIO_SetBits(GPIOC, COL1 | COL2 | COL3 | COL4);
?
  if (GPIO_ReadInputDataBit(GPIOC, ROW1) == 0) {
    while (GPIO_ReadInputDataBit(GPIOC, ROW1) == 0);
    return keys[0][0];
   } else if (GPIO_ReadInputDataBit(GPIOC, ROW2) == 0) {
    while (GPIO_ReadInputDataBit(GPIOC, ROW2) == 0);
    return keys[1][0];
   } else if (GPIO_ReadInputDataBit(GPIOC, ROW3) == 0) {
    while (GPIO_ReadInputDataBit(GPIOC, ROW3) == 0);
    return keys[2][0];
   } else if (GPIO_ReadInputDataBit(GPIOC, ROW4) == 0) {
    while (GPIO_ReadInputDataBit(GPIOC, ROW4) == 0);
    return keys[3][0];
   }
?
  GPIO_ResetBits(GPIOC, ROW1 | ROW2 | ROW3 | ROW4);
  GPIO_SetBits(GPIOC, COL1 | COL2 | COL3 | COL4);
?
  if (GPIO_ReadInputDataBit(GPIOC, ROW1) == 0) {
    while (GPIO_ReadInputDataBit(GPIOC, ROW1) == 0);
    return keys[0][1];
   } else if (GPIO_ReadInputDataBit(GPIOC, ROW2) == 0) {
    while (GPIO_ReadInputDataBit(GPIOC, ROW2) == 0);
    return keys[1][1];
   } else if (GPIO_ReadInputDataBit(GPIOC, ROW3) == 0) {
    while (GPIO_ReadInputDataBit(GPIOC, ROW3) == 0);
    return keys[2][1];
   } else if (GPIO_ReadInputDataBit(GPIOC, ROW4) == 0) {
    while (GPIO_ReadInputDataBit(GPIOC, ROW4) == 0);
    return keys[3][1];
   }
?
  GPIO_ResetBits(GPIOC, ROW1 | ROW2 | ROW3 | ROW4);
  GPIO_SetBits(GPIOC, COL1 | COL2 | COL3 | COL4);
?
  if (GPIO_ReadInputDataBit(GPIOC, ROW1) == 0) {
    while (GPIO_ReadInputDataBit(GPIOC, ROW1) == 0);
    return keys[0][2];
   } else if (GPIO_ReadInputDataBit(GPIOC, ROW2) == 0) {
    while (GPIO_ReadInputDataBit(GPIOC, ROW2) == 0);
    return keys[1][2];
   } else if (GPIO_ReadInputDataBit(GPIOC, ROW3) == 0) {
    while (GPIO_ReadInputDataBit(GPIOC, ROW3) == 0);
    return keys[2][2];
   } else if (GPIO_ReadInputDataBit(GPIOC, ROW4) == 0) {
    while (GPIO_ReadInputDataBit(GPIOC, ROW4) == 0);
      return keys[3][2];
}
GPIO_ResetBits(GPIOC, ROW1 | ROW2 | ROW3 | ROW4);
GPIO_SetBits(GPIOC, COL1 | COL2 | COL3 | COL4);
?
if (GPIO_ReadInputDataBit(GPIOC, ROW1) == 0) {
  while (GPIO_ReadInputDataBit(GPIOC, ROW1) == 0);
  return keys[0][3];
} else if (GPIO_ReadInputDataBit(GPIOC, ROW2) == 0) {
  while (GPIO_ReadInputDataBit(GPIOC, ROW2) == 0);
  return keys[1][3];
} else if (GPIO_ReadInputDataBit(GPIOC, ROW3) == 0) {
  while (GPIO_ReadInputDataBit(GPIOC, ROW3) == 0);
  return keys[2][3];
} else if (GPIO_ReadInputDataBit(GPIOC, ROW4) == 0) {
  while (GPIO_ReadInputDataBit(GPIOC, ROW4) == 0);
  return keys[3][3];
}
?
return '?';
 }

在上面的代碼中,使用輪詢的方式掃描鍵盤。首先將所有行引腳都設為低電平,所有列引腳都設為高電平,并檢測是否有按鍵按下。如果有按鍵按下,則返回該按鍵對應的字符。 接下來,可以在主函數(shù)中循環(huán)調(diào)用scan_keypad函數(shù)來讀取鍵值:

int main(void) {
  char key = '?';
?
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
?
  GPIO_InitStructure.GPIO_Pin = ROW1 | ROW2 | ROW3 | ROW4;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(GPIOC, &GPIO_InitStructure);
?
  GPIO_InitStructure.GPIO_Pin = COL1 | COL2 | COL3 | COL4;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(GPIOC, &GPIO_InitStructure);
?
  while (1) {
    key = scan_keypad();
?
    if (key != '?') {
      // 處理讀取到的鍵值
     }
   }
}

在上面的代碼中,首先初始化了8個引腳,并通過循環(huán)調(diào)用scan_keypad函數(shù)來讀取鍵值。如果讀取到鍵值,則可以進行相應的處理。

四、系統(tǒng)測試與驗證

為了驗證系統(tǒng)的可行性和穩(wěn)定性,在硬件搭建完成后,進行了一系列測試。

(1)測試了系統(tǒng)的整體運行邏輯。通過模擬用戶選擇商品、支付、出貨等情況,驗證系統(tǒng)的基本功能。測試結(jié)果顯示系統(tǒng)能夠穩(wěn)定運行,能夠滿足用戶的購物需求。

(2)測試了系統(tǒng)的庫存管理功能。通過模擬商品銷售情況,驗證系統(tǒng)的庫存信息是否能夠?qū)崟r更新。測試結(jié)果表明系統(tǒng)能夠準確地處理庫存信息。

(3)測試了手機端APP程序的功能。通過模擬用戶登錄、查看商品庫存、進行補貨、充值和查看消費流水等操作,驗證APP程序的功能。測試結(jié)果顯示APP程序能夠正常運行,并且與STM32主控芯片之間能夠?qū)崿F(xiàn)良好的通信。

審核編輯:湯梓紅

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內(nèi)容侵權或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 芯片
    +關注

    關注

    452

    文章

    50027

    瀏覽量

    419842
  • 單片機
    +關注

    關注

    6026

    文章

    44460

    瀏覽量

    631209
  • STM32
    +關注

    關注

    2263

    文章

    10849

    瀏覽量

    353879
  • APP
    APP
    +關注

    關注

    33

    文章

    1563

    瀏覽量

    72278
收藏 人收藏

    評論

    相關推薦

    LabVIEW售貨機(人機交互實驗版)

    售貨機是基于NI的PXI控制器(LabVIEW軟件實現(xiàn))的人機交互性售貨機。該售貨機為試驗版,正式版由于保密性不提供。本帖主要目的是給學習LabVIEW編程語言的朋友參考下,過程可能存在不合理或者有誤的地方,希望學習的朋友可以
    發(fā)表于 09-21 15:26

    無線遠程對自動售貨機的管理

    現(xiàn)在很多支付商家都在推舉1分錢購買自動售貨機的飲料,那么這些自動售貨機是怎么普及過來的呢? 隨時隨地可見的自動售貨機儼然成為了我們的一種從商場轉(zhuǎn)到小賣部,從小賣部轉(zhuǎn)到個人的快捷交易平臺。自動售賣機
    發(fā)表于 07-26 09:06

    被無線遠程控制管理的自動售貨機

    現(xiàn)在很多支付商家都在推舉1分錢購買自動售貨機的飲料,那么這些自動售貨機是怎么普及過來的呢? 隨時隨地可見的自動售貨機儼然成為了我們的一種從商場轉(zhuǎn)到小賣部,從小賣部轉(zhuǎn)到個人的快捷交易平臺。自動售賣機
    發(fā)表于 07-28 09:23

    嵌入式自動售貨機能實現(xiàn)什么功能?

    我們知道,智能設備的根本在于嵌入式系統(tǒng)的開發(fā)應用(嵌入式系統(tǒng)開發(fā)流程),隨著電子技術不斷的發(fā)展,很多智能化設備逐步取代了人工勞動,自動售貨機就是其中一種基于嵌入式系統(tǒng)的智能化設備(什么
    發(fā)表于 04-17 08:14

    基于80C51單片機的自動售貨機設計

    公司出品的80C51單片機為核心的自動售貨機,并且著重詳細地介紹了自動售貨機的整體系統(tǒng)設計方案、硬件選擇基礎、軟件使用方法及技巧。以80C51作為CPU處理單元連接各個功能模塊;以4*4矩陣鍵盤
    發(fā)表于 12-02 07:30

    RK3399核心板在無人售貨機的應用有哪些呢

    RK3399核心板具有哪些特性呢?RK3399核心板在無人售貨機的應用有哪些呢?
    發(fā)表于 03-07 07:07

    自動售貨機短信報警系統(tǒng)

    關鍵詞 ZWG-03A 智能短信設備、自動售貨機、短信報警摘 要 本文介紹 ZWG-03A 在自動售貨機短信報警系統(tǒng)中的應用
    發(fā)表于 11-04 11:18 ?86次下載

    智能自動售貨機售貨

    英特爾打造核心技術智能自動售貨機售貨 .
    發(fā)表于 12-28 18:09 ?0次下載

    PLC售貨機

    使用三菱PLC,擁有售貨機簡單功能,可用,無錯誤
    發(fā)表于 06-24 14:36 ?11次下載

    一種基于 PLC 的自動售貨機系統(tǒng)的設計

    一種基于 PLC 的自動售貨機系統(tǒng)的設計王曉麗摘要:設計一種可編程序控制器 PLC 控制的自動售貨機控制系統(tǒng)
    的頭像 發(fā)表于 03-29 10:12 ?1.3w次閱讀

    自動售貨機方案/設計/開發(fā)/項目

    隨著物聯(lián)網(wǎng)和大數(shù)據(jù)時代的到來,人工智能的興起,智能設備已環(huán)繞在人們衣食住行的各個方面。自助售貨機解決方案是解決線上消費和線下體驗的核心樞紐,加上定制化的運營模式和大數(shù)據(jù)的收集分析,讓傳統(tǒng)細分行業(yè)零售
    發(fā)表于 11-10 12:50 ?47次下載
    自動<b class='flag-5'>售貨機</b>方案/設計/開發(fā)/項目

    32-基于單片機的售貨機系統(tǒng)

    基于單片機的售貨機系統(tǒng)
    發(fā)表于 11-18 09:51 ?15次下載
    32-基于單片機的<b class='flag-5'>售貨機</b><b class='flag-5'>系統(tǒng)</b>

    基于ARM硬件的智能售貨機終端

    啟揚智能為售貨機行業(yè)提供了基于ARM架構搭載Android系統(tǒng)的智能售貨機硬件解決方案。
    的頭像 發(fā)表于 07-27 15:18 ?988次閱讀
    基于ARM硬件的智能<b class='flag-5'>售貨機</b>終端

    藍牙芯片售貨機方案

    藍牙售貨機是一種自動售貨機,通過藍牙技術實現(xiàn)與移動設備的交互,提供便捷的購物體驗。它主要由主機、貨架、付款臺和控制系統(tǒng)組成。主機是售貨機的核心部分,里面包含了所有的電子元件和機械部件。
    的頭像 發(fā)表于 02-28 16:39 ?573次閱讀

    自動售貨機MDB電源供電系統(tǒng)要求

    自動售貨機MDB協(xié)議中文解析(五)MDB電源供電系統(tǒng)要求
    發(fā)表于 09-09 10:46 ?0次下載