一、項目背景
隨著科技的發(fā)展和生活水平的提高,人們對于購物體驗的要求越來越高。傳統(tǒng)的商場、超市購物方式已經(jīng)無法滿足消費者的需求,因此無人售貨機應(yīng)運而生。本文針對現(xiàn)有售貨機存在的缺陷,設(shè)計了一款基于STM32的無人售貨機系統(tǒng)。該系統(tǒng)采用STM32作為主控芯片,使用液晶屏顯示各種商品庫存與售價,用戶按下對應(yīng)按鍵選擇購買指定商品,在矩陣鍵盤輸入賬號密碼付款。若付款成功,對應(yīng)電機旋轉(zhuǎn)一定角度使商品出庫,同時修改庫存;若余額不足,則進行聲光提示。手機端還可查看消費流水、商品庫存情況,并進行補貨和充值操作。
二、系統(tǒng)設(shè)計
2.1 系統(tǒng)硬件設(shè)計
該系統(tǒng)的核心部件是STM32主控芯片,它負責(zé)整個售貨機的控制和管理。液晶屏用于顯示商品信息、價格等,矩陣鍵盤用于用戶輸入賬號密碼進行支付。電機控制板用于控制商品出庫。
(資料圖)
硬件組成:
主控芯片選:STM32F103ZET6 液晶屏選擇:2.8寸TFT-LCD屏 WIFI選擇:ESP8266-WIFI 與手機APP之間通信。模式配置為STA模塊。連接服務(wù)器。 電機旋轉(zhuǎn)角度:28BYJ48步進電機。 控制出貨機出貨物。 矩陣鍵盤:4X4的矩陣鍵盤。
2.2 系統(tǒng)軟件設(shè)計
軟件部分主要包括STM32程序和手機APP程序。STM32程序是售貨機的核心程序,負責(zé)控制各個部件的工作,實現(xiàn)售貨機的基本功能。APP程序可以通過與STM32通信來實現(xiàn)商品庫存查看、補貨、充值等功能。
STM32部分主要分為以下幾個模塊:
(1)初始化模塊:初始化各個部件的工作狀態(tài)和參數(shù)。 (2)商品選擇模塊:根據(jù)用戶按下的按鈕,選擇相應(yīng)的商品。 (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ù)設(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ù)組來存儲每個按鍵對應(yīng)的字符。
(2)需要編寫一個函數(shù)來檢測電容矩陣鍵盤是否有按下。
該函數(shù)需要通過輪詢掃描鍵盤來檢測按鍵,如果有按鍵按下,則返回該按鍵對應(yīng)的字符:
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è)為低電平,所有列引腳都設(shè)為高電平,并檢測是否有按鍵按下。如果有按鍵按下,則返回該按鍵對應(yīng)的字符。 接下來,可以在主函數(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ù)來讀取鍵值。如果讀取到鍵值,則可以進行相應(yīng)的處理。
四、系統(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)良好的通信。審核編輯:湯梓紅
關(guān)鍵詞:
凡注有"實況網(wǎng)-重新發(fā)現(xiàn)生活"或電頭為"實況網(wǎng)-重新發(fā)現(xiàn)生活"的稿件,均為實況網(wǎng)-重新發(fā)現(xiàn)生活獨家版權(quán)所有,未經(jīng)許可不得轉(zhuǎn)載或鏡像;授權(quán)轉(zhuǎn)載必須注明來源為"實況網(wǎng)-重新發(fā)現(xiàn)生活",并保留"實況網(wǎng)-重新發(fā)現(xiàn)生活"的電頭。
熱點
- 基于51單片機的智能營養(yǎng)秤系統(tǒng)設(shè)計與實現(xiàn)
- 全球信息:東方通:二級市場股價是受宏觀經(jīng)濟、政策導(dǎo)向、資金量、投資者心態(tài)等諸多因素影響,有時會出現(xiàn)非理性波動
- 多面硬幣使用效果_多面硬幣
- 2023開封購買二手房提取住房公積金所需材料是什么?
- 今日熱議:夸女朋友優(yōu)秀的句子(如何夸女朋友好看不敷衍)
- (遇見中國)“方便”“速度”“勤奮”……吉爾吉斯斯坦姑娘金金眼中的中國關(guān)鍵詞|天天微速訊
- 因扎吉的逆襲,從變通開始 實時焦點
- 焦點速看:邊開邊充!瑞典率先打造世界首條永久性充電公路
- 軸承座概念股有哪些?軸承座股票一覽(2023/5/17)
- 易烊千璽法國聚餐路透照 順毛造型滿滿少年感 全球?qū)崟r
頭條
- 萬人說新疆丨課堂中的健身操讓孩子們歡樂無限|天天熱消息
- 【天天報資訊】高質(zhì)量發(fā)展調(diào)研行|科創(chuàng)引擎強勁,南京發(fā)展“成色更足”
- 新疆哪些出口產(chǎn)品更受歡迎?1—4月外貿(mào)進出口數(shù)據(jù)來了
- 中國星辰|北斗升空!他們用自主創(chuàng)新奮進世界一流
- 海外網(wǎng)評:中東歐博覽會再次證明中歐合作“是機遇不是風(fēng)險”_世界新資訊
- 環(huán)球視點!首次使用新場館、超5000種展品亮相 中國-中東歐國家博覽會亮點多多
- 日本民眾舉行集會 反對福島核污染水排海 天天頭條
- “四季看新疆”之“追著花兒看新疆”主題采訪活動5月16日啟動 消息
- 共同譜寫中國-中亞關(guān)系美好明天
- 不到5分鐘北京就誕生一家科技型企業(yè) 重點聚焦