STM32開發,定時器和狀態機實現不一樣的跑馬燈

1 概述

1.1 資源概述

開發板:正點原子STM32F103 Nano開發板
CUBEMX版本:1.3.0
MDK版本:5.23
主控芯片型號:STM32F103RBT6
正點原子開發板

1.2 代碼移植

移植armfly安富萊的代碼,代碼名稱爲《V4-001_不一樣的流水燈(軟件定時器、狀態機)(V1.0)》,開發板的主控芯片爲STM32F103ZE,均屬於M3內核芯片,但是ZE的外設資源多很多,總共144個引腳。但是很可惜,他們的開發板基本沒有視頻教程,不太方便新人學習。但是代碼寫的是真的好。非常規範和工整。選擇這個程序進行移植時由於都是103芯片,時鐘相同,外部晶振也是相同的。程序也相對比較簡單。
安富萊開發板

1.3 實現功能

這個流水燈程序實現功能如下:
(1)上電時,LED1點亮,閃爍3次,閃爍頻率爲精確的1Hz。 — 狀態0 (持續3秒)。
(2)依次點亮4個LED中的一個, 實現流水燈的效果。— 狀態1 (持續5秒)。
(3)依次熄滅4個LED中的一個,實現第2種流水燈效果。 — 狀態2 (持續5秒)。
(4)(狀態0)–>(狀態1)–>(狀態2 ))–>(狀態1)–>(狀態2 )…
這個例子應用1個systick中斷實現幾個軟件定時器,用來控制LED指示燈的閃爍時間。主程序採用了狀態機編程方法。

2 軟件實現

2.1工程修改

1,修改.s啓動文件爲startup_stm32f10x_md.s。
修改S文件
2,修改器件爲STM32F103RB。
修改器件
3,修改內存容量,當從大容量芯片變更爲小容量芯片時容易報內存不足故障,這時需要修改。
修改內存容量
4,修改Define,這裏爲MD,而不是HD
修改define
5,修改下載器類型,這裏選擇STLINK
下載器類型
6,進入下載器設置,確認是否是中等容量flash
確認容量
7,修改代碼外設,不僅僅時GPIO,還有定時器,通訊等,都要改爲和目標板對應。如果時跨平臺還要修改時鐘等。
安富萊對應LED燈部分原理圖。
LED原理圖
安富萊對應程序代碼
LED外設
按照Nano開發板,改爲如下
GPIO修改
8,刪除多餘外設資源。STM32F103RB只有四個定時器,沒有TIM5,刪除。
刪除TIM5
9,編譯下載,建議改代碼時,改一塊編譯一次,否則錯誤太多不好查找原因更改。
編譯下載

2.2 main函數代碼

代碼非常規整,註釋也很到位,非常值得我們學習。

#include "bsp.h"				/* 底層硬件驅動 */

/* 定義例程名和例程發佈日期 */
#define EXAMPLE_NAME	"V4-001_不一樣的跑馬燈(軟件定時器、狀態機)"
#define EXAMPLE_DATE	"2015-08-30"
#define DEMO_VER		"1.0"

uint8_t g_MainStatus = 0;	/* 狀態機 */

static void status_0(void);
static void status_1(void);
static void status_2(void);

/*
*********************************************************************************************************
*	函 數 名: main
*	功能說明: c程序入口
*	形    參:無
*	返 回 值: 錯誤代碼(無需處理)
*********************************************************************************************************
*/
int main(void)
{
	/*
		ST固件庫中的啓動文件已經執行了 SystemInit() 函數,該函數在 system_stm32f4xx.c 文件,主要功能是
	配置CPU系統的時鐘,內部Flash訪問時序,配置FSMC用於外部SRAM
	*/
	bsp_Init();		/* 硬件初始化 */
	
	g_MainStatus = 0;	/* 初始狀態爲狀態0 */
	
	/* 狀態機大循環 */
	while (1)
	{
		switch (g_MainStatus)
		{
			case 0:			/* 上電執行一次。LED1閃爍3次,每次間隔1秒。3次後狀態機返回。*/
				status_0();	
				g_MainStatus = 1;	/* 轉移到狀態1 */
				break;
			
			case 1:			/* LED1 - LED4 依次流水顯示。每次點亮1個LED。狀態持續5秒後返回。 */
				status_1();		
				g_MainStatus = 2;	/* 轉移到狀態2 */
				break;
			
			case 2:
				status_2();	/* LED1 - LED4 依次流水顯示。每次點亮3個LED, 熄滅1個。狀態持續5秒後返回。*/
				g_MainStatus = 1;	/* 轉移到狀態1 */
				break;
		}	
	}
}

/*
*********************************************************************************************************
*	函 數 名: status_0
*	功能說明: 狀態0  上電執行一次。LED1閃爍3次,每次間隔1秒。3次後狀態機返回。
*	形    參:無
*	返 回 值: 無
*********************************************************************************************************
*/
static void status_0(void)
{
	/* 關閉LED */
	bsp_LedOff(1);
	bsp_LedOff(2);
	bsp_LedOff(3);
	bsp_LedOff(4);
	
	/* 點亮 LED1 */
	bsp_LedOn(1);
	
	bsp_StartTimer(0, 3000);		/* 定時器0是3000ms 單次定時器 */		
	bsp_StartAutoTimer(1, 500);		/* 定時器1是500ms 自動重裝定時器, 控制LED1按1Hz頻率翻轉閃爍 */
	while (1)
	{			
		bsp_Idle();		/* CPU空閒時執行的函數,在 bsp.c */
		
		/* 這個地方可以插入其他任務 */		
		
		/* bsp_CheckTimer()檢查定時器1時間是否到。函數形參表示軟件定時器的ID, 值域0 - 3 */
		if (bsp_CheckTimer(1))		
		{
			bsp_LedToggle(1);		/* 間隔500ms 翻轉一次 LED1 */
		}
		
		/* 檢查定時器0時間是否到 */
		if (bsp_CheckTimer(0))
		{
			/* 3秒定時到後退出本狀態 */
			break;
		}
	}
	
	/* 任務結束時,應該關閉定時器,因爲他們會佔用後臺的資源 */
	//bsp_StopTimer(0);	 單次定時器如果超時到過一次後,可以不必關閉
	bsp_StopTimer(1);
}

/*
*********************************************************************************************************
*	函 數 名: status_1
*	功能說明: 狀態1。 LED1 - LED4 依次流水顯示。每次點亮1個LED。狀態持續5秒後返回。
*	形    參:無
*	返 回 值: 無
*********************************************************************************************************
*/
static void status_1(void)
{
	uint8_t led_no = 1;		/* LED指示燈序號 1-4 */
	
	bsp_StartTimer(0, 5000);		/* 定時器0是5000ms 單次定時器 */
	bsp_StartAutoTimer(1, 200);		/* 定時器1是500ms 自動重裝定時器, 控制LED1按1Hz頻率翻轉閃爍 */
	bsp_LedOn(1);
	led_no = 1;
	while (1)
	{			
		bsp_Idle();		/* CPU空閒時執行的函數,在 bsp.c */
		
		/* 這個地方可以插入其他任務 */		
		
		/* 檢查定時器0時間是否到 */
		if (bsp_CheckTimer(0))
		{
			break;
		}

		if (bsp_CheckTimer(1))		/* 檢查自動定時器2,間隔200ms翻轉一次LED1 */
		{
			/* 先關閉所有的LED,然後在打開其中一個 */
			bsp_LedOff(1);
			bsp_LedOff(2);
			bsp_LedOff(3);
			bsp_LedOff(4);
			
			if (++led_no == 5)
			{
				led_no = 1;
			}

			bsp_LedOn(led_no);	/* 點亮其中一個LED */	
		}		
	}
	
	/* 任務結束時,應該關閉定時器,因爲他們會佔用後臺的資源 */
	//bsp_StopTimer(0);	 單次定時器如果超時到過一次後,可以不必關閉
	bsp_StopTimer(1);
}

/*
*********************************************************************************************************
*	函 數 名: status_2
*	功能說明: 狀態2.  LED1 - LED4 依次流水顯示。每次點亮3個LED, 熄滅1個。狀態持續5秒後返回。
*	形    參:無
*	返 回 值: 無
*********************************************************************************************************
*/
static void status_2(void)
{
	uint8_t led_no = 1;		/* LED指示燈序號 1-4 */
	
	bsp_StartTimer(0, 5000);		/* 定時器0是5000ms 單次定時器 */
	bsp_StartAutoTimer(1, 200);		/* 定時器1是500ms 自動重裝定時器, 控制LED1按1Hz頻率翻轉閃爍 */
	bsp_LedOn(1);
	led_no = 1;
	while (1)
	{			
		bsp_Idle();		/* CPU空閒時執行的函數,在 bsp.c */
		
		/* 這個地方可以插入其他任務 */		
		
		/* 檢查定時器0時間是否到 */
		if (bsp_CheckTimer(0))
		{
			break;
		}

		if (bsp_CheckTimer(1))		/* 檢查自動定時器2,間隔200ms翻轉一次LED1 */
		{
			/* 先打開所有的LED,然後在關閉其中一個 */
			bsp_LedOn(1);
			bsp_LedOn(2);
			bsp_LedOn(3);
			bsp_LedOn(4);
			
			if (++led_no == 5)
			{
				led_no = 1;
			}

			bsp_LedOff(led_no);	/* 點亮其中一個LED */			
		}		
	}
	
	/* 任務結束時,應該關閉定時器,因爲他們會佔用後臺的資源 */
	//bsp_StopTimer(0);	 單次定時器如果超時過一次後,可以不必執行stop函數
	bsp_StopTimer(1);
}

實驗完整代碼已經同步上傳

3 實驗結果

下載完程序之後,復位運行程序。觀察開發板上的LED1-LED4 指示燈的狀態。與設計預期一致。
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章