在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

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

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

3天內不再提示

STM32狀態機編程實例——全自動洗衣機(上)

碼農愛學習 ? 來源:碼農愛學習 ? 作者:碼農愛學習 ? 2022-09-06 08:47 ? 次閱讀

前面幾篇文章,以按鍵功能,介紹了狀態機的原理與按鍵狀態機實例,實現按鍵單擊、雙擊、長按等狀態的檢測

本篇,繼續使用狀態機編程,來實現一個更有趣的功能——全自動洗衣機。

1 全自動洗衣機功能分析

下面是一個全自動洗衣機的控制面板:

poYBAGMWC7WAK8BHAAH26778-Mc908.png

面板上有4個按鍵:

電源:控制洗衣機通電與斷電

水位:選擇洗衣時需要的水位,有1~8個水位

程序:選擇不同的洗衣模式,有1~10個模式

01:標準

02:輕柔

03:快速

...

10:桶風干

啟動/暫停:用于啟動或暫停洗衣任務

面板上還有一個數碼管,用于顯示當前的工作狀態與剩余時間,可顯示的工作模式有:

AA:浸泡

BB:洗滌

CC:漂洗

DD:脫水

本篇,就按照這款洗衣機的操作方式實現對應的洗衣機控制邏輯。需注意的是:

實際的洗衣機有水位檢測傳感器,本篇中,暫用時間延時模擬水位的增加,且默認開機時水位為0

實際的洗衣機中的洗衣模式,會根據不同的模式自動設置清洗次數每次清洗的時間以及清洗力度,本篇為了簡化起見,清洗模式的設置僅用于區分不同的清洗次數

某些特殊的清洗模式,如單獨的脫水,桶風干等,本篇暫不實現

對于狀態的顯示 ,本篇先以串口打印的實現展示,下篇使用OLED小屏幕來顯示不同清洗狀態的圖標等信息

2 畫狀態圖

根據上面分析的全自動洗衣機的功能,以及我們自己使用洗衣機時的經驗,可以畫出如下的全自動洗衣機的狀態圖:

pYYBAGMWC8CAUAu0AADA8uwfW3c243.png

首先是上電開機,洗衣機可能會開機自檢,檢測洗衣機的各個部件是否正常,次過程很短。

然后就處于空閑狀態,此時用戶可以設置水位與清洗模式,若不設置,則為默認的水位與洗衣模式。

接著觸發開始按鍵后,就開始清洗了,一般流程就是:加水、清洗、排水、甩干、結束。

根據不同的清洗模式,加水、清洗和排水這3個過程會循環執行一定的次數。

另外,在不同的工作階段,按下暫停鍵可以讓洗衣任務暫停,再按繼續可讓洗衣任務繼續。

3 編程實現

3.1 多按鍵檢測功能

本篇介紹的洗衣機的按鍵,僅需要檢測按鍵單擊即可,不需要雙擊與長按功能,因此,可使用之前文章介紹的最基礎的按鍵狀態機來為洗衣機狀態機提供按鍵事件。

之前介紹的按鍵狀態機,只有一個按鍵,本篇需要用到4個按鍵(除去電源鍵,3個也可以),因此,需要對按鍵狀態機稍加修改,實現按鍵狀態機的復用。

之前介紹的按鍵狀態機,使用了幾個全局變量來表示狀態,更合理的做法是將其封裝起來:

typedef struct {
	KEY_STATUS keyStatus;    //當前循環結束的(狀態機的)狀態
	KEY_STATUS nowKeyStatus; //當前狀態(每次循環后與pKeyFsmData->keyStatus保持一致)
	KEY_STATUS lastKeyStatus; //上次狀態(用于記錄前一狀態以區分狀態的來源)
	int keyIdx;
}KeyFsmData;

注意,額外增加了一個按鍵索引值,用來告訴狀態機要檢測哪個按鍵。

再將原來的按鍵狀態機程序,通過入參的形式將上述定義的結構體傳入,并通過函數返回的形式返回按鍵是否被按下。

這樣修改后的按鍵狀態機,就是一個獨立的模塊了,可以通過傳入不同的參數,實現不同按鍵的檢測。

bool key_press_check(KeyFsmData *pKeyFsmData)
{
	bool bPress = false;
		
	switch(pKeyFsmData->keyStatus)
	{
//省略...

對于本篇需要的4個按鍵的檢測,就可以定義4個數據結構體,分別調用4次狀態機函數即可,實現代碼的復用。

KeyFsmData pKey0FsmData;
KeyFsmData pKey1FsmData;
KeyFsmData pKey2FsmData;
KeyFsmData pKey3FsmData;

void key_check_init(KeyFsmData *pKeyFsmData, int keyIdx)
{
	pKeyFsmData->keyStatus = KS_RELEASE;
	pKeyFsmData->lastKeyStatus = KS_RELEASE;
	pKeyFsmData->nowKeyStatus = KS_RELEASE;
	pKeyFsmData->keyIdx = keyIdx;
}

void multi_key_check_init()
{
	key_check_init(&pKey0FsmData, 0);
	key_check_init(&pKey1FsmData, 1);
	key_check_init(&pKey2FsmData, 2);
	key_check_init(&pKey3FsmData, 3);
}

int g_keyPressIdx = -1;
void multi_key_check()
{
	bool key0 = key_press_check(&pKey0FsmData);
	bool key1 = key_press_check(&pKey1FsmData);
	bool key2 = key_press_check(&pKey2FsmData);
	bool key3 = key_press_check(&pKey3FsmData);
	
	if (key0 | key1 | key2 | key3)
	{
		//printf("key0:%d, key1:%d, key2:%d, key3:%d, \r\n", key0, key1, key2, key3);
		
		if (key0)
		{
			g_keyPressIdx = 0;
		}
		else if (key1)
		{
			g_keyPressIdx = 1;
		}
		else if (key2)
		{
			g_keyPressIdx = 2;
		}
		else if (key3)
		{
			g_keyPressIdx = 3;
		}
	}
}

int get_press_key_idx()
{
	int idx = g_keyPressIdx;
	g_keyPressIdx = -1;
	
	return idx;
}

其中,multi_key_check函數,放到50ms周期的定時器中斷服務函數中,使按鍵狀態機程序運行起來。

get_press_key_idx函數,用于洗衣機程序來獲取不同按鍵的按下事件,每次獲取后,將按鍵事件清除(g_keyPressIdx設為無效值-1)

3.2 洗衣功能

按照上面繪制的洗衣機狀態圖,使用switch-case法編寫對應的程序即可:

#define WASHER_STATUS_ENUM(STATUS)                     \
	STATUS(WS_INIT)         /*開機初始化自檢*/         \
	STATUS(WS_IDLE)         /*空閑(等待模式設置)狀態*/ \
	STATUS(WS_ADD_WATER)    /*加水狀態*/               \
	STATUS(WS_WASH)         /*清洗狀態*/               \
	STATUS(WS_DRAIN_WATER)  /*排水狀態*/               \
	STATUS(WS_SPIN_DRY)     /*甩干狀態*/               \
	STATUS(WS_PAUSE)        /*暫停狀態*/               \
	STATUS(WS_NUM)          /*狀態總數(無效狀態)*/ 

typedef enum
{
	WASHER_STATUS_ENUM(ENUM_ITEM)
}WASHER_STATUS;

const char* washer_status_name[] = {
	WASHER_STATUS_ENUM(ENUM_STRING)
};

WASHER_STATUS g_washerStatus = WS_INIT;    //當前循環結束的(狀態機的)狀態
WASHER_STATUS g_nowWasherStatus = WS_INIT; //當前狀態(每次循環后與pKeyFsmData->keyStatus保持一致)
WASHER_STATUS g_lastWasherStatus = WS_INIT; //上次狀態(用于記錄前一狀態以區分狀態的來源)

int g_WorkLoopCnt = 0;
int g_WaterLevel = 5; //1~8
int g_WashMode = 2; //暫定為清洗次數:1~3
int g_curWashCnt = 0;

void washer_run_loop()
{
	switch(g_washerStatus)
	{
		/*開機初始化自檢*/ 
		case WS_INIT:
			g_washerStatus = washer_do_init();
			break;
		
		/*空閑(等待模式設置)狀態*/
		case WS_IDLE:
			g_washerStatus = washer_do_idle();
			break;
		
		/*加水狀態*/
		case WS_ADD_WATER:
			g_washerStatus = washer_do_add_water();
			break;
		
		/*清洗狀態*/
		case WS_WASH:
			g_washerStatus = washer_do_wash();
			break;
		
		/*排水狀態*/
		case WS_DRAIN_WATER:
			g_washerStatus = washer_do_drain_water();
			break;
		
		/*甩干狀態*/
		case WS_SPIN_DRY:
			g_washerStatus = washer_do_spin_dry();
			break;
		
		/*暫停狀態*/
		case WS_PAUSE:
			g_washerStatus = washer_do_pause();
			break;
		
		default: break;
	}
	
	if (g_washerStatus != g_nowWasherStatus)
	{
		g_lastWasherStatus = g_nowWasherStatus;
		g_nowWasherStatus = g_washerStatus;
		//printf("new washer status:%d(%s)\r\n", g_washerStatus, washer_status_name[g_washerStatus]);
	}
}

這里將洗衣機不同狀態時的處理邏輯,都分別使用函數來實現,并將其返回值作為下一個要跳轉的狀態。

各個狀態的處理函數如下:

/*開機初始化自檢*/ 
WASHER_STATUS washer_do_init()
{
	WASHER_STATUS nextStatus = WS_INIT;
	
	g_WorkLoopCnt++;
	if (10 == g_WorkLoopCnt) //自檢結束
	{
		printf("default water level:%d\r\n", g_WaterLevel);
		printf("default wash mode:%d\r\n", g_WashMode);
		printf("washer idle...\r\n");
		
		g_WorkLoopCnt = 0;
		nextStatus = WS_IDLE;
	}
	
	return nextStatus;
}

/*空閑(等待模式設置)狀態*/
WASHER_STATUS washer_do_idle()
{
	WASHER_STATUS nextStatus = WS_IDLE;
	
	const WASHER_KEY key = check_key_press();
	switch(key)
	{
		case W_KEY_START_PAUSE:
			g_WorkLoopCnt = 0;
			nextStatus = WS_ADD_WATER;
			printf("add water...\r\n");
		break;
		
		case W_KEY_WATER_LEVEL:
			g_WaterLevel = (g_WaterLevel == 8) ? 1 : (g_WaterLevel+1);
			printf("set water level:%d\r\n", g_WaterLevel);
		break;
			
		case W_KEY_WASH_MODE:
			g_WashMode = (g_WashMode == 3) ? 1 : (g_WashMode+1);
			printf("set wash mode:%d\r\n", g_WashMode);
		break;
		
		default: break;
	}
	
	return nextStatus;
}

/*加水狀態*/
WASHER_STATUS washer_do_add_water()
{
	WASHER_STATUS nextStatus = WS_ADD_WATER;
	
	const WASHER_KEY key = check_key_press();
	if (key == W_KEY_START_PAUSE)
	{
		nextStatus = WS_PAUSE;
		printf("[%s] pause...\r\n", __func__);
	}
	else
	{
		g_WorkLoopCnt++;
		if (g_WaterLevel == (g_WorkLoopCnt / 10)) //加水結束
		{
			g_WorkLoopCnt = 0;
			nextStatus = WS_WASH;
			printf("[%s] done\r\n", __func__);
			printf("wash...\r\n");
		}
	}
	
	return nextStatus;
}

/*清洗狀態*/
WASHER_STATUS washer_do_wash()
{
	WASHER_STATUS nextStatus = WS_WASH;
	
	const WASHER_KEY key = check_key_press();
	if (key == W_KEY_START_PAUSE)
	{
		nextStatus = WS_PAUSE;
		printf("[%s] pause...\r\n", __func__);
	}
	else
	{
		g_WorkLoopCnt++;
		if (6 == (g_WorkLoopCnt / 10)) //清洗結束
		{
			g_WorkLoopCnt = 0;
			nextStatus = WS_DRAIN_WATER;
			printf("[%s] done\r\n", __func__);
			printf("drain water...\r\n");
		}
	}
	
	return nextStatus;
}

/*排水狀態*/
WASHER_STATUS washer_do_drain_water()
{
	WASHER_STATUS nextStatus = WS_DRAIN_WATER;
	
	const WASHER_KEY key = check_key_press();
	if (key == W_KEY_START_PAUSE)
	{
		nextStatus = WS_PAUSE;
		printf("[%s] pause...\r\n", __func__);
	}
	else
	{
		g_WorkLoopCnt++;
		if (3 == (g_WorkLoopCnt / 10)) //排水結束
		{
			printf("[%s] done\r\n", __func__);
			g_curWashCnt++;
			printf("current wash and drain count:%d(target:%d)\r\n", g_curWashCnt, g_WashMode);
			g_WorkLoopCnt = 0;
			if (g_WashMode == g_curWashCnt)
			{
				printf("spin dry...\r\n");
				nextStatus = WS_SPIN_DRY;
			}
			else
			{
				printf("add water...\r\n");
				nextStatus = WS_ADD_WATER;
			}
		}
	}
	
	return nextStatus;
}

/*甩干狀態*/
WASHER_STATUS washer_do_spin_dry()
{
	WASHER_STATUS nextStatus = WS_SPIN_DRY;
	
	const WASHER_KEY key = check_key_press();
	if (key == W_KEY_START_PAUSE)
	{
		nextStatus = WS_PAUSE;
		printf("[%s] pause...\r\n", __func__);
	}
	else
	{
		g_WorkLoopCnt++;
		if (100 == g_WorkLoopCnt) //甩干結束
		{
			g_WorkLoopCnt = 0;
			nextStatus = WS_IDLE;
			printf("[%s] done\r\n", __func__);
			printf("enter idle mode\r\n");
		}
	}
	
	return nextStatus;
}

/*暫停狀態*/
WASHER_STATUS washer_do_pause()
{
	WASHER_STATUS nextStatus = WS_PAUSE;
	
	const WASHER_KEY key = check_key_press();
	if (key != W_KEY_NULL)
	{
		switch (g_lastWasherStatus)
		{
			case WS_ADD_WATER:   nextStatus = WS_ADD_WATER;   printf("resume...\r\n"); break;
			case WS_WASH:        nextStatus = WS_WASH;        printf("resume...\r\n"); break;
			case WS_DRAIN_WATER: nextStatus = WS_DRAIN_WATER; printf("resume...\r\n"); break;
			case WS_SPIN_DRY:    nextStatus = WS_SPIN_DRY;    printf("resume...\r\n"); break;
			default: break;
		}
	}
	
	return nextStatus;
}

對于按鍵的獲取,這里定義了幾個對應的功能按鍵,并從按鍵狀態機函數中獲取按鍵索引,再轉為洗衣機程序所需的對應功能按鍵:

typedef enum
{
	W_KEY_NULL,        //沒有按鍵按下
	W_KEY_POWER,       //電源鍵按下
	W_KEY_WATER_LEVEL, //水位鍵按下
	W_KEY_WASH_MODE,   //清洗模式鍵按下
	W_KEY_START_PAUSE  //啟動/暫停鍵按下
}WASHER_KEY;

WASHER_KEY check_key_press()
{
	WASHER_KEY washerKey = W_KEY_NULL;
	int idx = get_press_key_idx();
	if (idx != -1)
	{
		switch(idx)
		{
			case 0: washerKey = W_KEY_POWER; break; //電源鍵按下
			case 1: washerKey = W_KEY_WATER_LEVEL; break; //水位鍵按下
			case 2: washerKey = W_KEY_WASH_MODE; break; //清洗模式鍵按下
			case 3: washerKey = W_KEY_START_PAUSE; break; //啟動/暫停鍵按下
			default: break;
		}
		//printf("%s idx:%d -> washerKey:%d\r\n", __func__, idx, washerKey);
	}
	
	return washerKey;
}

洗衣機狀態機主程序,可以放到main函數中,每隔100ms調用一次,使其運行起來:

int main(void)
{	
	delay_init();
	KEY_Init();
	uart_init(115200);
	TIM3_Int_Init(500-1,7200-1); //調用定時器使得50ms產生一個中斷

	printf("hello\r\n");
	
	while(1)
	{
		washer_run_loop();
		delay_ms(100);
	}
}

3.3 測試

將代碼燒寫到STM32板子中,通過3個按鍵(電源鍵暫不使用)操作,并通過串口打印,查看全自動洗衣機的運行情況:

pYYBAGMWC-qASN8PAAFUuY1S-UY987.png

4 總結

本篇實現了一款全自動洗衣機的基礎洗衣控制流程,可實現不同水位與清洗次數的設置,以及任務的暫停與繼續。此外,通過對之前按鍵狀態機的進一步優化修改,實現了按鍵狀態機的復用,實現多個按鍵的檢測。下篇文章將進一步進行功能優化,添加OLED小屏幕實現不同狀態的可視化展示。


審核編輯:湯梓紅

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

    關注

    2270

    文章

    10921

    瀏覽量

    356963
  • 洗衣機
    +關注

    關注

    13

    文章

    680

    瀏覽量

    43360
  • 狀態機
    +關注

    關注

    2

    文章

    492

    瀏覽量

    27613
收藏 人收藏

    評論

    相關推薦

    STM32狀態機編程實例——全自動洗衣機(下)

    本篇在上篇全自動洗衣機狀態機編程實例的基礎,增加了OLED來更新直觀的展示
    的頭像 發表于 09-07 08:47 ?3459次閱讀
    <b class='flag-5'>STM32</b><b class='flag-5'>狀態機</b><b class='flag-5'>編程</b><b class='flag-5'>實例</b>——<b class='flag-5'>全自動</b><b class='flag-5'>洗衣機</b>(下)

    FPGA設計洗衣機

    本帖最后由 eehome 于 2013-1-5 09:59 編輯 設計一個全自動洗衣機控制器,它具有三閥門分別是冷水、 設計一個全自動洗衣機控制器,它具有三閥門分別是冷水、 設計
    發表于 05-04 20:35

    跪求畢業設計:全自動洗衣機系統設計!!!

    急需!!!全自動洗衣機系統設計與研究
    發表于 04-29 23:38

    跪求 全自動洗衣機系統 proteus仿真!!!

    本人做畢業設計 全自動洗衣機系統研究與設計跪請各位幫忙!!!
    發表于 05-01 18:50

    全自動洗衣機原理與維修資料

    給大家分享下全自動洗衣機原理與維修資料。
    發表于 03-17 20:34

    全自動洗衣機

    單片全自動洗衣機
    發表于 04-12 13:11

    轉: 全自動洗衣機控制系統

    全自動洗衣機控制系統
    發表于 08-03 16:55

    洗衣機為什么能自動運行呢

    知識點:全自動洗衣機、程序、計算機如今,洗衣機已經進入千家萬戶,人們再也不用面對一大堆臟衣服發愁了,只要把臟衣服、洗衣粉放到洗衣機里,接通電
    發表于 09-02 06:52

    如何去實現一種基于單片全自動洗衣機模擬系統設計

    基于單片全自動洗衣機模擬系統實現的功能是什么?如何去實現一種基于單片全自動洗衣機模擬系統
    發表于 01-17 08:13

    基于單片SPMC75的模擬全自動洗衣機的設計

    基于單片SPMC75的模擬全自動洗衣機的設計 洗衣機是一種在家庭生活中不可缺少的家用電器,全自動
    發表于 10-26 14:22 ?1670次閱讀

    全自動洗衣機控制電路

    全自動洗衣機控制電路,PCB學習好資料,歡迎下載學習。
    發表于 03-23 09:50 ?0次下載

    全自動洗衣機

    介紹全自動洗衣機單片控制系統的外文期刊,適合學術方面的閱讀。
    發表于 05-06 14:37 ?7次下載

    全自動洗衣機程序

    全自動洗衣機程序全自動洗衣機程序全自動洗衣機程序
    發表于 05-19 16:40 ?27次下載

    AT89C51單片實現全自動洗衣機功能的設計方案

    51單片洗衣機控制板及C語言程序,該控制板單片采用AT89C51單片,所設計全自動洗衣機
    發表于 07-02 15:49 ?9448次閱讀
    AT89C51單片<b class='flag-5'>機</b>實現<b class='flag-5'>全自動</b><b class='flag-5'>洗衣機</b>功能的設計方案

    基于STM32單片全自動洗衣機

    1.基于STM32單片的一種全自動洗衣機,該系統除了具備洗滌,漂洗,脫水,甩干功能外,還具有洗滌時間設置,水位檢測,烘干功能。 2.具有藍牙通信功能,可通過手機app對
    的頭像 發表于 11-02 10:22 ?9045次閱讀
    主站蜘蛛池模板: 黄色网网址| 国产日本在线播放| 欧美18性欧美丶黑吊| 哪里可以看免费毛片| 中文字幕在线观看你懂的 | 天天看天天爽| 在线永久免费播放视频| 国产二区三区| 国产午夜大片| 黄色www| 毛片免| 你懂的在线看| 人碰人操| 日本亚洲欧美国产日韩ay高清| 特级全毛片| 在线观看免费观看| 濑亚美莉iptd619在线观看| 视频在线观看高清免费大全| 又黑又长黑人欧美三级| 天堂8资源8在线| 182tv免费视视频线路一二三| 国内精品第一页| 两性色午夜视频免费老司机| www日| 五月sese| 狠狠干精品| 亚洲欧美色鬼久久综合| 伊人婷婷色香五月综合缴激情| 不卡视频免费在线观看| 高清不卡免费一区二区三区| 曰本毛片| 五月婷婷婷婷| 色婷婷久久免费网站| 日本免费观看网站| 国产青青草| 久久精品伊人波多野结| 97久草| h视频在线免费看| 男人j进入女人j在线视频| 东京毛片| 欧美视频区|