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。
2,修改器件爲STM32F103RB。
3,修改內存容量,當從大容量芯片變更爲小容量芯片時容易報內存不足故障,這時需要修改。
4,修改Define,這裏爲MD,而不是HD
5,修改下載器類型,這裏選擇STLINK
6,進入下載器設置,確認是否是中等容量flash
7,修改代碼外設,不僅僅時GPIO,還有定時器,通訊等,都要改爲和目標板對應。如果時跨平臺還要修改時鐘等。
安富萊對應LED燈部分原理圖。
安富萊對應程序代碼
按照Nano開發板,改爲如下
8,刪除多餘外設資源。STM32F103RB只有四個定時器,沒有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 指示燈的狀態。與設計預期一致。