你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【经验分享】STM32开发,定时器和状态机实现不一样的跑马灯

[复制链接]
STMCU小助手 发布时间:2022-5-5 17:23
1 概述
1.1 资源概述

开发板:正点原子STM32F103 Nano开发板
CUBEMX版本:1.3.0
MDK版本:5.23
主控芯片型号:STM32F103RBT6

]S`S0{0@XT2S[E%U}SE4][G.png

1.2 代码移植
移植armfly安富莱的代码,代码名称为《V4-001_不一样的流水灯(软件定时器、状态机)(V1.0)》,开发板的主控芯片为STM32F103ZE,均属于M3内核芯片,但是ZE的外设资源多很多,总共144个引脚。但是很可惜,他们的开发板基本没有视频教程,不太方便新人学习。但是代码写的是真的好。非常规范和工整。选择这个程序进行移植时由于都是103芯片,时钟相同,外部晶振也是相同的。程序也相对比较简单。

Z(295(080XPF)06IL3UL7[H.png

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。

20200421183228333.png

2,修改器件为STM32F103RB。
J`UNW1XV[54F`S[FAMY)1{2.png

3,确认内存容量,当从大容量芯片变更为小容量芯片时,如果程序很大,则需要精简程序。

%~F@KBN[50V0W`AX0AHS444.png

4,修改Define,这里为MD,而不是HD,这里时全局宏定义。

`{P{TGF`$UT1WN2SA6FR3W0.png

5,修改下载器类型,这里选择STLINK

GGR06M%KL9FKNVB{S$)XVRE.png

6,进入下载器设置,确认是否是中等容量flash

@DO4[A8E}@CZGV1($QCF))5.png

7,修改代码外设,不仅仅时GPIO,还有定时器,通讯等,都要改为和目标板对应。如果时跨平台还要修改时钟等。安富莱对应LED灯部分原理图。

JHZX71M(Q(}R0@SDYID%C{7.png

安富莱对应程序代码,安富莱将硬件驱动整合成bsp文件,并在bsp文件下细分硬件分支。

E@965R7}EG`{OX1ENM80H8G.png

按照Nano开发板,改为如下

3H1)RSX9T694II$Z62]UII3.png

8,删除多余外设资源。STM32F103RB只有四个定时器,没有TIM5,删除。

20200421200017935.png

9,编译下载,建议改代码时,改一块编译一次,否则错误太多不好查找原因更改。

UMJDHD}JG5II5`%}7`I~P]I.png

2.2 main函数代码
代码非常规整,注释也很到位,非常值得我们学习。在后续研究中,我依据相关的状态机知识,重新改写了状态机部分的函数,定了了状态和事件两个枚举变量,并定义了对应的二维数组,使事件和状态对应起来。另外原来的代码,使用BEEP作为错误处理函数,但是在初始化中并未对BEEP进行声明,因此增加了BEEP的相关初始化,并在第一个状态中,将BEEP的状态与LED1的状态保持相同,实现相同的翻转功能。状态机的状态切换有点类似于RTOS系统中的任务切换,在此代码中,也采用了类似RTOS的时间片的概念,当事件到达时,退出当前的状态,切换到下一个状态。

  1. #include "bsp.h"                                /* 底层硬件驱动 */

  2. /* 定义例程名和例程发布日期 */
  3. #define EXAMPLE_NAME        "V4-001_不一样的跑马灯(软件定时器、状态机)"
  4. #define EXAMPLE_DATE        "2015-08-30"
  5. #define DEMO_VER                "1.0"

  6. static void status_0(void);
  7. static void status_1(void);
  8. static void status_2(void);

  9. #define MAX_STATUS 3
  10. #define MAX_EVENT 3

  11. enum status_led//定义状态
  12. {
  13. status0 = 0,
  14. status1,
  15. status2
  16. };

  17. enum event_led//定义事件
  18. {
  19. switch0 = 0,
  20. switch1,
  21. switch2
  22. };

  23. int led_flow[MAX_STATUS][MAX_EVENT] =   //状态机的二维数组,当前事件+触发事件=下一个状态
  24. {
  25. [status0][switch0] = status1,
  26. [status1][switch1] = status2,
  27. [status2][switch2] = status1,
  28. };

  29. int led_next_status(int status,int switchled)  //转态转移函数
  30. {
  31. return led_flow[status][switchled];
  32. }

  33. int main(void)
  34. {
  35.         
  36.         int next_status = status0; //初始 状态
  37.         int event = switch0;        /* 初始事件 */        

  38.         bsp_Init();                /* 硬件初始化 */
  39.         
  40.         /* 状态机大循环 */
  41.         while (1)
  42.         {
  43.                 switch (next_status)
  44.                 {
  45.                         case status0:                        /* 上电执行一次。LED1闪烁3次,每次间隔1秒。3次后状态机返回。*/
  46.                                 status_0();        
  47.                                 event = switch0;        /* 触发新的事件0 */
  48.                                 break;
  49.                         
  50.                         case status1:                        /* LED1 - LED8 依次流水显示。每次点亮1个LED。状态持续5秒后返回。 */
  51.                                 status_1();               
  52.                                 event = switch1;        /* 触发新的事件1 */
  53.                                 break;
  54.                         
  55.                         case status2:
  56.                                 status_2();        /* LED1 - LED8 依次流水显示。每次点亮3个LED, 熄灭1个。状态持续5秒后返回。*/
  57.                                 event = switch2;        /* 触发新的事件2 */
  58.                                 break;
  59.                 }        
  60.                 next_status = led_next_status(next_status,event);//状态转移
  61.         }
  62. }

  63. /*
  64. *********************************************************************************************************
  65. *        函 数 名: status_0
  66. *        功能说明: 状态0  上电执行一次。LED1闪烁3次,每次间隔1秒。3次后状态机返回。
  67. *        形    参:无
  68. *        返 回 值: 无
  69. *********************************************************************************************************
  70. */
  71. static void status_0(void)
  72. {
  73.         /* 关闭LED */
  74.         bsp_LedOff(1);
  75.         bsp_LedOff(2);
  76.         bsp_LedOff(3);
  77.         bsp_LedOff(4);
  78.         bsp_LedOff(5);
  79.         bsp_LedOff(6);
  80.         bsp_LedOff(7);
  81.         bsp_LedOff(8);        
  82.         /* 点亮 LED1 */
  83.         bsp_LedOn(1);
  84.         bsp_BeepOn();
  85.         
  86.         bsp_StartTimer(0, 3000);                /* 定时器0是3000ms 单次定时器 */               
  87.         bsp_StartAutoTimer(1, 500);                /* 定时器1是500ms 自动重装定时器, 控制LED1按1Hz频率翻转闪烁 */
  88.         while (1)
  89.         {                        
  90.                 bsp_Idle();                /* CPU空闲时执行的函数,在 bsp.c */
  91.                
  92.                 /* 这个地方可以插入其他任务 */               
  93.                
  94.                 /* bsp_CheckTimer()检查定时器1时间是否到。函数形参表示软件定时器的ID, 值域0 - 3 */
  95.                 if (bsp_CheckTimer(1))               
  96.                 {
  97.                         bsp_LedToggle(1);                /* 间隔500ms 翻转一次 LED1 */
  98.                         bsp_BeepToggle();                /* 间隔500ms 响一次BEEP */        
  99.                 }
  100.                
  101.                 /* 检查定时器0时间是否到 */
  102.                 if (bsp_CheckTimer(0))
  103.                 {
  104.                         /* 3秒定时到后退出本状态 */
  105.                         break;
  106.                 }
  107.         }
  108.         
  109.         /* 任务结束时,应该关闭定时器,因为他们会占用后台的资源 */
  110.         //bsp_StopTimer(0);         单次定时器如果超时到过一次后,可以不必关闭
  111.         bsp_StopTimer(1);
  112. }

  113. /*
  114. *********************************************************************************************************
  115. *        函 数 名: status_1
  116. *        功能说明: 状态1。 LED1 - LED4 依次流水显示。每次点亮1个LED。状态持续5秒后返回。
  117. *        形    参:无
  118. *        返 回 值: 无
  119. *********************************************************************************************************
  120. */
  121. static void status_1(void)
  122. {
  123.         uint8_t led_no = 1;                /* LED指示灯序号 1-4 */
  124.         
  125.         bsp_StartTimer(0, 5000);                /* 定时器0是5000ms 单次定时器 */
  126.         bsp_StartAutoTimer(1, 200);                /* 定时器1是500ms 自动重装定时器, 控制LED1按1Hz频率翻转闪烁 */
  127.         bsp_LedOn(1);
  128.         led_no = 1;
  129.         while (1)
  130.         {                        
  131.                 bsp_Idle();                /* CPU空闲时执行的函数,在 bsp.c */
  132.                
  133.                 /* 这个地方可以插入其他任务 */               
  134.                
  135.                 /* 检查定时器0时间是否到 */
  136.                 if (bsp_CheckTimer(0))
  137.                 {
  138.                         break;
  139.                 }

  140.                 if (bsp_CheckTimer(1))                /* 检查自动定时器2,间隔200ms翻转一次LED1 */
  141.                 {
  142.                         /* 先关闭所有的LED,然后在打开其中一个 */
  143.                         bsp_LedOff(1);
  144.                         bsp_LedOff(2);
  145.                         bsp_LedOff(3);
  146.                         bsp_LedOff(4);
  147.                         bsp_LedOff(5);
  148.                         bsp_LedOff(6);
  149.                         bsp_LedOff(7);
  150.                         bsp_LedOff(8);
  151.                         bsp_BeepOff();                        
  152.                         if (++led_no == 9)
  153.                         {
  154.                                 led_no = 1;
  155.                         }

  156.                         bsp_LedOn(led_no);        /* 点亮其中一个LED */        
  157.                 }               
  158.         }
  159.         
  160.         /* 任务结束时,应该关闭定时器,因为他们会占用后台的资源 */
  161.         //bsp_StopTimer(0);         单次定时器如果超时到过一次后,可以不必关闭
  162.         bsp_StopTimer(1);
  163. }

  164. /*
  165. *********************************************************************************************************
  166. *        函 数 名: status_2
  167. *        功能说明: 状态2.  LED1 - LED4 依次流水显示。每次点亮3个LED, 熄灭1个。状态持续5秒后返回。
  168. *        形    参:无
  169. *        返 回 值: 无
  170. *********************************************************************************************************
  171. */
  172. static void status_2(void)
  173. {
  174.         uint8_t led_no = 1;                /* LED指示灯序号 1-4 */
  175.         
  176.         bsp_StartTimer(0, 5000);                /* 定时器0是5000ms 单次定时器 */
  177.         bsp_StartAutoTimer(1, 200);                /* 定时器1是500ms 自动重装定时器, 控制LED1按1Hz频率翻转闪烁 */
  178.         bsp_LedOn(1);
  179.         led_no = 1;
  180.         while (1)
  181.         {                        
  182.                 bsp_Idle();                /* CPU空闲时执行的函数,在 bsp.c */
  183.                
  184.                 /* 这个地方可以插入其他任务 */               
  185.                
  186.                 /* 检查定时器0时间是否到 */
  187.                 if (bsp_CheckTimer(0))
  188.                 {
  189.                         break;
  190.                 }

  191.                 if (bsp_CheckTimer(1))                /* 检查自动定时器2,间隔200ms翻转一次LED1 */
  192.                 {
  193.                         /* 先打开所有的LED,然后在关闭其中一个 */
  194.                         bsp_LedOn(1);
  195.                         bsp_LedOn(2);
  196.                         bsp_LedOn(3);
  197.                         bsp_LedOn(4);               
  198.                         bsp_LedOn(5);
  199.                         bsp_LedOn(6);
  200.                         bsp_LedOn(7);
  201.                         bsp_LedOn(8);               
  202.                         bsp_BeepOff();                        
  203.                         if (++led_no == 9)
  204.                         {
  205.                                 led_no = 1;
  206.                         }

  207.                         bsp_LedOff(led_no);        /* 点亮其中一个LED */                        
  208.                 }               
  209.         }
  210.         
  211.         /* 任务结束时,应该关闭定时器,因为他们会占用后台的资源 */
  212.         //bsp_StopTimer(0);         单次定时器如果超时过一次后,可以不必执行stop函数
  213.         bsp_StopTimer(1);
  214. }
复制代码

3 实验结果
下载完程序之后,复位运行程序。观察开发板上的LED1-LED4 指示灯的状态。与设计预期一致。后续增加8个灯后,实现了8个灯的流水灯。

20200421205005361.gif


收藏 评论0 发布时间:2022-5-5 17:23

举报

0个回答
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版