STM32开发,定时器和状态机实现不一样的跑马灯
-
1 概述
-
1.1 资源概述
-
1.2 代码移植
-
1.3 实现功能
-
2 软件实现
-
2.1工程修改
-
2.2 main函数代码
-
3 实验结果
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函数代码
代码非常规整,注释也很到位,非常值得我们学习。
1#include "bsp.h" /* 底层硬件驱动 */ 2 3/* 定义例程名和例程发布日期 */ 4#define EXAMPLE_NAME "V4-001_不一样的跑马灯(软件定时器、状态机)" 5#define EXAMPLE_DATE "2015-08-30" 6#define DEMO_VER "1.0" 7 8uint8_t g_MainStatus = 0; /* 状态机 */ 9 10static void status_0(void); 11static void status_1(void); 12static void status_2(void); 13 14/* 15********************************************************************************************************* 16* 函 数 名: main 17* 功能说明: c程序入口 18* 形 参:无 19* 返 回 值: 错误代码(无需处理) 20********************************************************************************************************* 21*/ 22int main(void) 23{ 24 /* 25 ST固件库中的启动文件已经执行了 SystemInit() 函数,该函数在 system_stm32f4xx.c 文件,主要功能是 26 配置CPU系统的时钟,内部Flash访问时序,配置FSMC用于外部SRAM 27 */ 28 bsp_Init(); /* 硬件初始化 */ 29 30 g_MainStatus = 0; /* 初始状态为状态0 */ 31 32 /* 状态机大循环 */ 33 while (1) 34 { 35 switch (g_MainStatus) 36 { 37 case 0: /* 上电执行一次。LED1闪烁3次,每次间隔1秒。3次后状态机返回。*/ 38 status_0(); 39 g_MainStatus = 1; /* 转移到状态1 */ 40 break; 41 42 case 1: /* LED1 - LED4 依次流水显示。每次点亮1个LED。状态持续5秒后返回。 */ 43 status_1(); 44 g_MainStatus = 2; /* 转移到状态2 */ 45 break; 46 47 case 2: 48 status_2(); /* LED1 - LED4 依次流水显示。每次点亮3个LED, 熄灭1个。状态持续5秒后返回。*/ 49 g_MainStatus = 1; /* 转移到状态1 */ 50 break; 51 } 52 } 53} 54 55/* 56********************************************************************************************************* 57* 函 数 名: status_0 58* 功能说明: 状态0 上电执行一次。LED1闪烁3次,每次间隔1秒。3次后状态机返回。 59* 形 参:无 60* 返 回 值: 无 61********************************************************************************************************* 62*/ 63static void status_0(void) 64{ 65 /* 关闭LED */ 66 bsp_LedOff(1); 67 bsp_LedOff(2); 68 bsp_LedOff(3); 69 bsp_LedOff(4); 70 71 /* 点亮 LED1 */ 72 bsp_LedOn(1); 73 74 bsp_StartTimer(0, 3000); /* 定时器0是3000ms 单次定时器 */ 75 bsp_StartAutoTimer(1, 500); /* 定时器1是500ms 自动重装定时器, 控制LED1按1Hz频率翻转闪烁 */ 76 while (1) 77 { 78 bsp_Idle(); /* CPU空闲时执行的函数,在 bsp.c */ 79 80 /* 这个地方可以插入其他任务 */ 81 82 /* bsp_CheckTimer()检查定时器1时间是否到。函数形参表示软件定时器的ID, 值域0 - 3 */ 83 if (bsp_CheckTimer(1)) 84 { 85 bsp_LedToggle(1); /* 间隔500ms 翻转一次 LED1 */ 86 } 87 88 /* 检查定时器0时间是否到 */ 89 if (bsp_CheckTimer(0)) 90 { 91 /* 3秒定时到后退出本状态 */ 92 break; 93 } 94 } 95 96 /* 任务结束时,应该关闭定时器,因为他们会占用后台的资源 */ 97 //bsp_StopTimer(0); 单次定时器如果超时到过一次后,可以不必关闭 98 bsp_StopTimer(1); 99} 100 101/* 102********************************************************************************************************* 103* 函 数 名: status_1 104* 功能说明: 状态1。 LED1 - LED4 依次流水显示。每次点亮1个LED。状态持续5秒后返回。 105* 形 参:无 106* 返 回 值: 无 107********************************************************************************************************* 108*/ 109static void status_1(void) 110{ 111 uint8_t led_no = 1; /* LED指示灯序号 1-4 */ 112 113 bsp_StartTimer(0, 5000); /* 定时器0是5000ms 单次定时器 */ 114 bsp_StartAutoTimer(1, 200); /* 定时器1是500ms 自动重装定时器, 控制LED1按1Hz频率翻转闪烁 */ 115 bsp_LedOn(1); 116 led_no = 1; 117 while (1) 118 { 119 bsp_Idle(); /* CPU空闲时执行的函数,在 bsp.c */ 120 121 /* 这个地方可以插入其他任务 */ 122 123 /* 检查定时器0时间是否到 */ 124 if (bsp_CheckTimer(0)) 125 { 126 break; 127 } 128 129 if (bsp_CheckTimer(1)) /* 检查自动定时器2,间隔200ms翻转一次LED1 */ 130 { 131 /* 先关闭所有的LED,然后在打开其中一个 */ 132 bsp_LedOff(1); 133 bsp_LedOff(2); 134 bsp_LedOff(3); 135 bsp_LedOff(4); 136 137 if (++led_no == 5) 138 { 139 led_no = 1; 140 } 141 142 bsp_LedOn(led_no); /* 点亮其中一个LED */ 143 } 144 } 145 146 /* 任务结束时,应该关闭定时器,因为他们会占用后台的资源 */ 147 //bsp_StopTimer(0); 单次定时器如果超时到过一次后,可以不必关闭 148 bsp_StopTimer(1); 149} 150 151/* 152********************************************************************************************************* 153* 函 数 名: status_2 154* 功能说明: 状态2. LED1 - LED4 依次流水显示。每次点亮3个LED, 熄灭1个。状态持续5秒后返回。 155* 形 参:无 156* 返 回 值: 无 157********************************************************************************************************* 158*/ 159static void status_2(void) 160{ 161 uint8_t led_no = 1; /* LED指示灯序号 1-4 */ 162 163 bsp_StartTimer(0, 5000); /* 定时器0是5000ms 单次定时器 */ 164 bsp_StartAutoTimer(1, 200); /* 定时器1是500ms 自动重装定时器, 控制LED1按1Hz频率翻转闪烁 */ 165 bsp_LedOn(1); 166 led_no = 1; 167 while (1) 168 { 169 bsp_Idle(); /* CPU空闲时执行的函数,在 bsp.c */ 170 171 /* 这个地方可以插入其他任务 */ 172 173 /* 检查定时器0时间是否到 */ 174 if (bsp_CheckTimer(0)) 175 { 176 break; 177 } 178 179 if (bsp_CheckTimer(1)) /* 检查自动定时器2,间隔200ms翻转一次LED1 */ 180 { 181 /* 先打开所有的LED,然后在关闭其中一个 */ 182 bsp_LedOn(1); 183 bsp_LedOn(2); 184 bsp_LedOn(3); 185 bsp_LedOn(4); 186 187 if (++led_no == 5) 188 { 189 led_no = 1; 190 } 191 192 bsp_LedOff(led_no); /* 点亮其中一个LED */ 193 } 194 } 195 196 /* 任务结束时,应该关闭定时器,因为他们会占用后台的资源 */ 197 //bsp_StopTimer(0); 单次定时器如果超时过一次后,可以不必执行stop函数 198 bsp_StopTimer(1); 199} 200
实验完整代码已经同步上传
3 实验结果
下载完程序之后,复位运行程序。观察开发板上的LED1-LED4 指示灯的状态。与设计预期一致。
