一、項(xiàng)目介紹
隨著智能物聯(lián)網(wǎng)技術(shù)的不斷發(fā)展,人們的生活方式和消費(fèi)習(xí)慣也正在發(fā)生改變。如今越來(lái)越多的人習(xí)慣于在線購(gòu)物、自助購(gòu)物等新型消費(fèi)模式,因此智能零售自助柜應(yīng)運(yùn)而生。
本項(xiàng)目設(shè)計(jì)開發(fā)一款基于STM32主控芯片的智能零售自助柜,通過(guò)重力傳感器監(jiān)測(cè)貨柜內(nèi)商品重量變化,并通過(guò)WiFi通信模塊與手機(jī)端實(shí)現(xiàn)交互。用戶可以通過(guò)輸入賬號(hào)密碼,柜門自動(dòng)打開,用戶自取商品后關(guān)閉柜門,柜門鎖定,系統(tǒng)根據(jù)重量變化判斷用戶拿取的商品并從賬戶自動(dòng)扣費(fèi)。同時(shí),用戶也可以通過(guò)手機(jī)端查看消費(fèi)流水、商品庫(kù)存,并進(jìn)行補(bǔ)貨和充值等操作。
智能零售自助柜的應(yīng)用場(chǎng)景非常廣泛,可以應(yīng)用于商場(chǎng)、超市、酒店、機(jī)場(chǎng)、車站等各類場(chǎng)景。通過(guò)自助購(gòu)物,可以提高消費(fèi)者的消費(fèi)體驗(yàn)和購(gòu)物效率,同時(shí)也降低了商家的人力成本和物流成本。
二、設(shè)計(jì)思路
【1】功能細(xì)節(jié)總結(jié)
(1)ESP8266配置成AP+TCP服務(wù)器模式與手機(jī)APP連接。
(2)手機(jī)APP可以完成用戶的注冊(cè),充值功能,然后通過(guò)連接貨柜將數(shù)據(jù)同步到貨柜的存儲(chǔ)芯片上(W25Q64-FLASH保存數(shù)據(jù))。
(3)手機(jī)APP連接貨柜之后,可以拉取數(shù)據(jù)顯示,了解貨柜現(xiàn)在的物品哪些已經(jīng)售賣出去,哪些還沒有售賣。,每個(gè)物品是放在一個(gè)貨柜格子里,透明玻璃可以查看到物品。
【2】硬件選型
- 主控芯片:STM32F103RCT6是一款主流的32位ARM Cortex-M系列微控制器,具有高性能、低功耗和易于開發(fā)等特點(diǎn),因此被選擇作為該系統(tǒng)的主控芯片。
- 重力傳感器:HX711重力傳感器模塊采用24位高精度芯片,能夠精確測(cè)量重量,適用于該系統(tǒng)中貨柜內(nèi)商品的重量監(jiān)測(cè)。
- SG90舵機(jī):該系統(tǒng)需要控制柜門的打開和關(guān)閉,因此使用舵機(jī)來(lái)實(shí)現(xiàn)柜門控制。
- 矩陣鍵盤:用戶需要輸入賬號(hào)密碼進(jìn)行登錄,因此使用矩陣鍵盤作為輸入設(shè)備。
- 顯示屏:OLED顯示屏具有低功耗、高對(duì)比度、快速響應(yīng)等特點(diǎn),適用于該系統(tǒng)中的桌面顯示界面。
- WiFi模塊:ESP8266-WIFI模塊是一款成本低、體積小、性能穩(wěn)定的WiFi通信模塊,適合在該系統(tǒng)中與手機(jī)APP進(jìn)行無(wú)線通信。
【2】程序設(shè)計(jì)思路
- 初始化系統(tǒng),包括各個(gè)外設(shè)的初始化,如WiFi模塊、重力傳感器HX711模塊、矩陣鍵盤等;
- 用戶輸入賬號(hào)密碼,判斷是否為有效用戶;
- 根據(jù)重力傳感器讀取貨柜內(nèi)商品重量,判斷用戶拿取的商品并從賬戶自動(dòng)扣費(fèi);
- 控制柜門打開和關(guān)閉,同時(shí)顯示屏上顯示相關(guān)提示信息;
- 同步數(shù)據(jù)到手機(jī)APP。
【3】設(shè)備操作流程
- 用戶輸入賬號(hào)密碼,系統(tǒng)進(jìn)行驗(yàn)證,判斷是否為有效用戶;
- 如果驗(yàn)證通過(guò),屏幕上顯示“登錄成功”,并顯示貨柜內(nèi)商品列表和對(duì)應(yīng)價(jià)格;
- 用戶選擇需要購(gòu)買的商品,系統(tǒng)根據(jù)重力傳感器讀取貨柜內(nèi)商品重量,并判斷用戶拿取的商品并從賬戶自動(dòng)扣費(fèi);
- 系統(tǒng)控制電磁鎖或舵機(jī)將柜門打開,用戶自取商品后關(guān)閉柜門;
- 重力傳感器監(jiān)測(cè)到貨柜內(nèi)重量變化,系統(tǒng)自動(dòng)判斷用戶拿取的商品種類和數(shù)量,并在顯示屏上顯示相關(guān)提示信息,如顯示扣費(fèi)金額;
- 控制柜門鎖定,確保商品安全,同時(shí)在顯示屏上顯示“門已鎖定”等相關(guān)提示信息;
- 同步扣費(fèi)記錄和商品庫(kù)存信息到手機(jī)APP,以便用戶查看消費(fèi)流水和進(jìn)行補(bǔ)貨等操作。
- 如需要充值,用戶可以在手機(jī)APP上進(jìn)行余額充值操作。
三、代碼實(shí)現(xiàn)
【1】OLED顯示屏驅(qū)動(dòng)代碼
下面是OLED顯示屏的測(cè)試代碼。使用的SPI接口的OLED顯示屏。
#include "stm32f10x.h"
#include "OLED.h" // OLED驅(qū)動(dòng)庫(kù)頭文件
?
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){ // 滿行自動(dòng)換行
x = 0;
y++;
}
OLED_ShowChar(x, y, str[i]); // 顯示單個(gè)字符
x += 8; // 水平方向上的下一個(gè)字符
i++;
}
}
?
void OLED_SPI_SendByte(uint8_t data)
{
while(SPI_I2S_GetFlagStatus(OLED_SPI_PORT, SPI_I2S_FLAG_TXE) == RESET); // 等待發(fā)送緩沖區(qū)空
SPI_I2S_SendData(OLED_SPI_PORT, data); // 通過(guò)SPI發(fā)送數(shù)據(jù)
}
?
void OLED_WriteCmd(uint8_t cmd)
{
OLED_DC_Clr(); // 將DC置為0,表示發(fā)送命令
OLED_CS_Clr(); // 將CS置為0,選中OLED芯片
OLED_SPI_SendByte(cmd); // 發(fā)送命令
OLED_CS_Set(); // 將CS置為1,取消OLED芯片選中
}
?
void OLED_WriteData(uint8_t data)
{
OLED_DC_Set(); // 將DC置為1,表示發(fā)送數(shù)據(jù)
OLED_CS_Clr(); // 將CS置為0,選中OLED芯片
OLED_SPI_SendByte(data); // 發(fā)送數(shù)據(jù)
OLED_CS_Set(); // 將CS置為1,取消OLED芯片選中
}
?
?
int main(void)
{
uint32_t i;
?
// 初始化SPI接口
SPI_InitTypeDef SPI_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE); // 打開SPI1時(shí)鐘
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; // 設(shè)置SPI工作模式
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; // 數(shù)據(jù)位寬8bit
SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low; // 時(shí)鐘極性為低電平
SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge; // 時(shí)鐘第一個(gè)邊沿采樣
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; // 軟件控制CS信號(hào)
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256; // 預(yù)分頻系數(shù)為256
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; // MSB先行
SPI_InitStructure.SPI_CRCPolynomial = 7; // CRC校驗(yàn)值
SPI_Init(SPI1, &SPI_InitStructure);
SPI_Cmd(SPI1, ENABLE); // 使能SPI1
?
// 初始化OLED顯示屏
OLED_Init(); // OLED初始化
?
// 顯示數(shù)字
char str[] = "1234567890";
OLED_ShowString(0, 0, (uint8_t *)str); // 在(0,0)坐標(biāo)處顯示字符串
?
while(1){
for(i = 0; i < 10000000; i++); // 延時(shí)等待
}
}
?