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 指示灯的状态。与设计预期一致。
在这里插入图片描述

发布了12 篇原创文章 · 获赞 3 · 访问量 3030

猜你喜欢

转载自blog.csdn.net/weixin_46623350/article/details/105664772