上篇文章,通過狀態機編程,實現了全自動洗衣機的邏輯控制,并通過串口打印的方式顯示各個狀態。
本篇,為了更加直觀的感受狀態機的運行,使用0.96寸OLED來顯示各個狀態,并搭配對應的動態圖標來體現洗衣機工作的各個狀態。
1 OLED圖片顯示
為了能方便的在OLED上顯示文字和圖片,可以借助一些圖形庫來幫我們顯示,這里使用的是U8g2圖形庫。
1.1 U8g2庫移植
U8g2庫在STM32上的移植,之前的文章已經介紹過,具體的移植過程可以參考這篇:
移植成功后,可以使用測試例程驗證U8g2庫的顯示效果。

1.2 圖片顯示
圖片相比較文字,可以展示更加豐富的內容,因此本篇通過簡單的單色圖片來展示洗衣機的工作狀態。
U8g2庫顯示圖片,可以使用u8g2_DrawXBM函數,需要先將圖片轉為數組。
可以使用這個在線網頁來進行圖片數據的轉換:https://tools.clz.me/image-to-bitmap-array
這里可以使用自己喜歡的圖片,進行展示,比如我選取了不同水量的洗衣機圖標來顯示洗衣機的當前水量,使用多張圖片的交替顯示產生洗衣機在清洗的動畫效果。

2 更多狀態輸出
OLED屏幕要想顯示洗衣機的工作狀態,就需要獲取狀態機的具體工作狀態。這里自定義了一些展示需要用到的數據,組成一個結構體,狀態機在運行過程中,對各個成員變量進行修改,然后OLED端獲取這些數據,再進行展示。
typedef struct
{
WASHER_STATUS washerStatus; /*洗衣機的工作狀態*/
int targetWaterLevel; /*洗衣機的目標水位*/
int targetWashTimes; /*洗衣機的目標清洗次數*/
int remainingTime; /*洗衣機的剩余工作時間(暫未使用)*/
int curWaterLevel; /*洗衣機當前的水位*/
bool hasNewData; /*是否有新的數據(用于告訴OLED是否刷新顯示)*/
}WASHER_OUTPUT_DATA;
對于OLED的展示邏輯,這里是在狀態機的每個循環結束后,調用下面的程序邏輯進行展示:
void show_washer_status(WASHER_OUTPUT_DATA washerOutPutData)
{
if (washerOutPutData.hasNewData)
{
WASHER_STATUS s = washerOutPutData.washerStatus;
printf("u8g2 get status:%d(%s)\r\n", s, washer_status_name[s]);
switch(s)
{
case WS_INIT: showWasherInit(&u8g2, washerOutPutData); break;
case WS_IDLE: showWasherIdle(&u8g2, washerOutPutData); break;
case WS_ADD_WATER: showWasherAddWater(&u8g2, washerOutPutData); break;
case WS_WASH: showWasherWash(&u8g2, washerOutPutData); break;
case WS_DRAIN_WATER: showWasherDrainWater(&u8g2, washerOutPutData); break;
case WS_SPIN_DRY: showWasherSpinDry(&u8g2, washerOutPutData); break;
case WS_PAUSE: showWasherPause(&u8g2, washerOutPutData); break;
case WS_DONE: showWasherDone(&u8g2, washerOutPutData); break;
default: break;
}
}
}
當此輪狀態循環有新的數據產生時,則根據狀態機的主狀態,分別顯示對應狀態下的圖片或動畫。
比如加水狀態,會根據當前加的水位,不斷更新圖片展示的水位:
void drawCurWaterLevel(u8g2_t *u8g2, int level)
{
switch(level)
{
case 0: u8g2_DrawXBM(u8g2,64, 16, 48, 48, pic_water_0); break;
case 1: u8g2_DrawXBM(u8g2,64, 16, 48, 48, pic_water_1); break;
case 2: u8g2_DrawXBM(u8g2,64, 16, 48, 48, pic_water_2); break;
case 3: u8g2_DrawXBM(u8g2,64, 16, 48, 48, pic_water_3); break;
case 4: u8g2_DrawXBM(u8g2,64, 16, 48, 48, pic_water_4); break;
case 5: u8g2_DrawXBM(u8g2,64, 16, 48, 48, pic_water_5); break;
case 6: u8g2_DrawXBM(u8g2,64, 16, 48, 48, pic_water_6); break;
case 7: u8g2_DrawXBM(u8g2,64, 16, 48, 48, pic_water_7); break;
default: break;
}
}
void showWasherAddWater(u8g2_t *u8g2, WASHER_OUTPUT_DATA data)
{
char strStatus[14] = "AddWater";
u8g2_ClearBuffer(u8g2);
u8g2_SetFont(u8g2,u8g2_font_ncenB10_tr);
u8g2_DrawStr(u8g2,0,15,strStatus);
drawCurWaterLevel(u8g2, data.curWaterLevel);
u8g2_SendBuffer(u8g2);
}
?對于主程序的結構,和上篇一樣,只是增加了OLED的顯示:
int main(void)
{
delay_init(); //延時函數初始化
LED_Init(); //初始化與LED連接的硬件接口
oled_init();
KEY_Init();
uart_init(115200);
TIM3_Int_Init(500-1,7200-1); //調用定時器使得50ms產生一個中斷
printf("hello\r\n");
while(1)
{
washer_run_loop();
WASHER_OUTPUT_DATA data = get_washer_output_data();
show_washer_status(data);
delay_ms(100);
}
}
在狀態機每運行一個循環,獲取一下具體的狀態數據,然后使用OLED將具體的狀態數據展示出來。
3 具體演示
再來對比看下這個狀態圖,實驗測試狀態機的執行。

正常的洗衣流程
不考慮暫停這個狀態,洗衣機上點開始后,依次經歷空閑、加水、清洗、排水、甩干這幾個流程即結束,若清洗計數設置了不知1次,則加水、清洗、排水這3個動作會循環執行對應的次數。
洗衣流程中暫停再繼續
在洗衣機的運行狀態:加水、清洗、排水、甩干,通過暫停按鈕,可以暫停這些狀態的執行,此時狀態機會運行于暫停模式,再按繼續(暫停/繼續的一個按鈕),則會繼續執行洗衣工作。
暫停后修改水量或次數后再繼續
在洗衣過程中,如果想要修改洗衣的水量或次數,可以先通過暫停鍵來暫停洗衣機的運行,然后通過水位或次數按鈕,使狀態機從暫停狀態先切換到空閑狀態,進行水位或次數的調整后,再繼續,即會按照新的設置參數繼續運行洗衣程序。
比如本來的清洗水位是3,清洗次數是1,在第一次清洗的加水時按下暫停,再將清洗參數進行修改,比如水位設為5,次數設為2,再繼續后,會再次進入加水狀態,并將水位補到5后,繼續清洗,并清洗2遍結束。
注:本狀態機還有繼續優化的空間,比如:
水量只會補加,多了此輪清洗不會排出。比如先設置的水位是5,在加到3個時候,暫停并修改為2,再繼續后,判斷大于目標水位則會直接開始清洗,不會先由水位3再排水到水位2再清洗
任何清洗狀態(加水、清洗、排水)按下暫停調整水位后,再繼續,都會默認跳到加水重新新的清洗循環,如果是在排水狀態,調整了水位后,此次的水還沒有排位,就又重新加水開始洗,不太合理
以上3種測試方式的演示效果,可以再對比看下演示視頻:
https://www.bilibili.com/video/BV1xT411E7pY

4 總結
本篇在上篇全自動洗衣機的狀態機編程實例的基礎上,增加了OLED來更新直觀的展示洗衣機的工作狀態,并通過3種測試場景來展示洗衣機工作狀態機的執行。
-
STM32
+關注
關注
2288文章
10996瀏覽量
361908 -
洗衣機
+關注
關注
13文章
682瀏覽量
43827 -
狀態機
+關注
關注
2文章
493瀏覽量
28031
發布評論請先 登錄
FPGA設計洗衣機
基于單片機SPMC75的模擬全自動洗衣機的設計
基于STM32單片機的全自動洗衣機
STM32狀態機編程實例——全自動洗衣機(上)

評論