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。
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 指示灯的状态。与设计预期一致。