当前位置:   article > 正文

基于STM32F103的FreeRTOS系列(一)·单片机设计模式介绍·裸机程序的设计模式_stm32 rtos 用裸机的方式编程

stm32 rtos 用裸机的方式编程

目录

1.  轮询模式

2.  前后台

3.  定时器驱动

4.  基于状态机


        裸机程序的设计模式可以分为:轮询、前后台、定时器驱动、基于状态机。

  • 轮询:周期性地查询各个模块或函数的状态,适用于简单且响应时间要求不高的系统,但无法有效解决复杂函数之间的相互影响问题。

  • 前后台:通过将关键任务放在前台处理,而非关键任务放在后台,以确保关键任务的优先执行。这种方式对优先级管理有效,但复杂函数之间的相互影响仍可能存在。

  • 定时器驱动:通过定时器周期性地触发任务执行,适合需要定期执行任务的场景,但不能解决函数间相互影响的问题。

  • 基于状态机:将系统的各种状态和状态转移定义清晰,通过状态切换来控制系统行为。这种方法理论上可以避免复杂函数之间的直接影响,但在实践中确实需要良好的设计和调试

        前面三种方法都无法解决一个问题:假设有A、B两个都很耗时的函数,无法降低它们相互之间的影响。第4种方法可以解决这个问题,但是实践起来有难度。

1.  轮询模式

         可以理解为我们stm32的正常顺序编程,一步一步来,若是前面的条件有延时或者执行时间过长,就会导致后面的条件执行往后推迟。

       在main函数中是一个while循环,里面依次调用2个函数,这两个函数相互之间有影响:如果“喂一口饭”太花时间,就会导致迟迟无法“回一个信息”;如果“回一个信息”太花时间,就会导致迟迟无法“喂下一口饭”。

        使用轮询模式编写程序看起来很简单,但是要求while循环里调用到的函数要执行得非常快,在复杂场景里反而增加了编程难度。

  1. void main()
  2. {
  3. while (1)
  4. {
  5. 喂一口饭();
  6. 回一个信息();
  7. }
  8. }

2.  前后台

        所谓“前后台”就是使用中断程序。当主程序在执行过程中,若是另一程序触发中断,优先中断的程序进行执行。

        会出现问题:中断程序要是执行过长,将会导致迟迟离不开中断,并且要是创建多个中断还会出现抢占优先级的情况。

  1. // 前后台程序
  2. void main()
  3. {
  4. while (1)
  5. {
  6. // 后台程序
  7. 喂一口饭();
  8. }
  9. }
  10. // 前台程序
  11. void 滴_中断()
  12. {
  13. 回一个信息();
  14. }

        在这个场景里,给同事回复信息非常及时:即使正在喂饭也会暂停下来去回复信息。“喂一口饭”无法影响到“回一个信息”。但是,如果“回一个信息”太花时间,就会导致 “喂一口饭”迟迟无法执行。

        继续改进,假设小孩吞下饭菜后会发出“啊”的一声,妈妈听到后才会喂下一口饭。喂饭、回复信息都是使用中断函数来处理。示例程序如下:

  1. // 前后台程序
  2. void main()
  3. {
  4. while (1)
  5. {
  6. // 后台程序
  7. }
  8. }
  9. // 前台程序
  10. void 滴_中断()
  11. {
  12. 回一个信息();
  13. }
  14. // 前台程序
  15. void 啊_中断()
  16. {
  17. 喂一口饭();
  18. }

        main函数中的while循环是空的,程序的运行靠中断来驱使。如果电脑声音“滴”、小孩声音“啊”不会同时、相近发出,那么“回一个信息”、“喂一口饭”相互之间没有影响。在不能满足这个前提的情况下,比如“滴”、“啊”同时响起,先“回一个信息”时就会耽误“喂一口饭”,这种场景下程序遭遇到了轮询模式的缺点:函数相互之间有影响。(中断之间抢占优先级)

3.  定时器驱动

        定时器驱动模式,是前后台模式的一种,可以按照不用的频率执行各种函数。比如需要每2分钟给小孩喂一口饭,需要每5分钟给同事回复信息。那么就可以启动一个定时器,让它每1分钟产生一次中断,让中断函数在合适的时间调用对应函数。示例代码如下:

  1. // 前后台程序: 定时器驱动
  2. void main()
  3. {
  4. while (1)
  5. {
  6. // 后台程序
  7. }
  8. }
  9. // 前台程序: 每1分钟触发一次中断
  10. void 定时器_中断()
  11. {
  12. static int cnt = 0;
  13. cnt++;
  14. if (cnt % 2 == 0)
  15. {
  16. 喂一口饭();
  17. }
  18. else if (cnt % 5 == 0)
  19. {
  20. 回一个信息();
  21. }
  22. }
  • main函数中的while循环是空的,程序的运行靠定时器中断来驱使。
  • 定时器中断每1分钟发生一次,在中断函数里让cnt变量累加(代码第14行)。
  • 第15行:进行求模运算,如果对2取模为0,就“喂一口饭”。这相当于每发生2次中断就“喂一口饭”。
  • 第19行:进行求模运算,如果对5取模为0,就“回一个信息”。这相当于每发生5次中断就“回一个信息”。

        这种模式适合调用周期性的函数,并且每一个函数执行的时间不能超过一个定时器周期。如果“喂一口饭”很花时间,比如长达10分钟,那么就会耽误“回一个信息”;反过来也是一样的,如果“回一个信息”很花时间也会影响到“喂一口饭”;这种场景下程序遭遇到了轮询模式的缺点:函数相互之间有影响。

4.  基于状态机

        当“喂一口饭”、“回一个信息”都需要花很长的时间,无论使用前面的哪种设计模式,都会退化到轮询模式的缺点:函数相互之间有影响。可以使用状态机来解决这个缺点,示例代码如下:

  1. // 状态机
  2. void main()
  3. {
  4. while (1)
  5. {
  6. 喂一口饭();
  7. 回一个信息();
  8. }
  9. }

        在main函数里,还是使用轮询模式依次调用2个函数。

        关键在于这2个函数的内部实现:使用状态机,每次只执行一个状态的代码,减少每次执行的时间,代码如下:

  1. void 喂一口饭(void)
  2. {
  3. static int state = 0;
  4. switch (state)
  5. {
  6. case 0:
  7. {
  8. /* 舀饭 */
  9. /* 进入下一个状态 */
  10. state++;
  11. break;
  12. }
  13. case 1:
  14. {
  15. /* 喂饭 */
  16. /* 进入下一个状态 */
  17. state++;
  18. break;
  19. }
  20. case 2:
  21. {
  22. /* 舀菜 */
  23. /* 进入下一个状态 */
  24. state++;
  25. break;
  26. }
  27. case 3:
  28. {
  29. /* 喂菜 */
  30. /* 恢复到初始状态 */
  31. state = 0;
  32. break;
  33. }
  34. }
  35. }
  36. void 回一个信息(void)
  37. {
  38. static int state = 0;
  39. switch (state)
  40. {
  41. case 0:
  42. {
  43. /* 查看信息 */
  44. /* 进入下一个状态 */
  45. state++;
  46. break;
  47. }
  48. case 1:
  49. {
  50. /* 打字 */
  51. /* 进入下一个状态 */
  52. state++;
  53. break;
  54. }
  55. case 2:
  56. {
  57. /* 发送 */
  58. /* 恢复到初始状态 */
  59. state = 0;
  60. break;
  61. }
  62. }
  63. }

        以“喂一口饭”为例,函数内部拆分为4个状态:舀饭、喂饭、舀菜、喂菜。每次执行“喂一口饭”函数时,都只会执行其中的某一状态对应的代码。以前执行一次“喂一口饭”函数可能需要4秒钟,现在可能只需要1秒钟,就降低了对后面“回一个信息”的影响。

        同样的,“回一个信息”函数内部也被拆分为3个状态:查看信息、打字、发送。每次执行这个函数时,都只是执行其中一小部分代码,降低了对“喂一口饭”的影响。

        使用状态机模式,可以解决裸机程序的难题:假设有A、B两个都很耗时的函数,怎样降低它们相互之间的影响。但是很多场景里,函数A、B并不容易拆分为多个状态,并且这些状态执行的时间并不好控制。所以这并不是最优的解决方法,需要使用多任务系统。

FreeRTOS_时光の尘的博客-CSDN博客

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/寸_铁/article/detail/904874
推荐阅读
相关标签
  

闽ICP备14008679号