# M2A01_Simpron
**Repository Path**: EDI-Systems/M2A01_Simpron
## Basic Information
- **Project Name**: M2A01_Simpron
- **Description**: Small yet powerful state machine coroutine library
- **Primary Language**: C
- **License**: Unlicense
- **Default Branch**: main
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 1
- **Created**: 2020-09-01
- **Last Updated**: 2024-09-02
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# RMS 羽量级状态机
Click **[HERE](README.md)** for English version.
**RMS** 是一个为4位和8位经济型微控制器设计的羽量级状态机协程库。
- 的经多个项目验证的4位和8位机专用系统
- 容忍任何使用C编译器的古怪架构
- 无需为每个协程准备单独的运行栈
- 完全无需编写汇编或者移植代码
- 极度简单并几乎不消耗任何内存
- 显式暴露任务状态以鼓励形式化思考
## 如何使用此RMS“内核”?
在RMS中,所有任务都是`void task(void)`或`int task(void)`,并且它们共享**单个线程堆栈**。每个任务都存在多个状态。进入每个任务后,RMS跳转到与当前状态对应的位置并开始执行。在编写任务函数时,需定义其状态,并确保状态机主体以`RMS_BEGIN(...);`开始,以`RMS_END();`结束,使用`RMS_EXECUTE():{...}`执行每个状态。
当需要让出其他任务时,调用`RMS_YIELD();`。执行当前任务的另一个循环时,调用`RMS_CONTINUE();`。必须在任何任务执行结束之前调用`RMS_YIELD();`或`RMS_CONTINUE();`,否则将会发生错误。RMS还提供了`RMS_CATCH():{...}`来捕获异常或无效状态,以及`RMS_WAIT(...);`来等待特定条件。
当任务为`int task(void)`而不是`void task(void)`时,须使用`RMS_YIELD_RV(...);`代替`RMS_YIELD();`,使用 `RMS_WAIT_RV(...,...);`代替`RMS_WAIT(...);`。
## RMS可能的编程风格?
通过这组宏,程序员可以自由地以任何风格编写应用程序,包括**事件触发的调度**、**优先级驱动的调度**,或**仅使用表驱动的调度**。所有任务执行都是从运行到完成,因此单个线程内不可能发生抢占。但是,可以将**中断处理程序**编写为任务(甚至是托管多个任务的线程;关于此用法,请参见**2009年的RTSS文章**“*Sloth: Threads as Interrupts*”)来规避此限制,并且通过硬件中断嵌套实现多个抢占优先级。
对于中断激活检测,建议为每个中断保留一个标志,并在相应的任务执行中检测此标志是否被设置。如果未设置正在等待的标志,任务可以立即让出,以允许执行其他任务;如果设置了,则任务可以清除它并继续进行中断处理。通过这种方式可以实现不旋转(但仍低频率地轮询标志)的延迟。
另一个限制是任务让出只能在任务函数内部进行,而不能在其子函数中进行。这个限制是因为所有任务共享同一个栈,这在低端系统中,所有任务都相对简单,这个问题就不那么严重。
## 为什么不实现一个更完整、“臃肿”的框架?
在低端微控制器编程中,每一个bit都很重要。通常首先是RAM用尽,然后是Flash,最后是CPU。这与高端平台不同,在高端平台中CPU通常是瓶颈。RAM通常取决于你声明了多少变量,因此可以很容易控制。然而,Flash则不同,无休止的错误修复和新功能会缓慢而稳定地消耗储备。如果你一开始就采用一个臃肿的框架,然后发现在最后修复错误时Flash空间不足,你可能就无药可救了。定时器等也是同理,如8051只有两个定时器,如果系统垄断了一个,那么你就只剩下一个定时器了。考虑到这些因素,RMS被设计为不强制要求许多功能,同时又足够灵活,允许程序员以一种简单、特定于项目且内存效率高的方式实现这些功能。
## 这难道不是山寨版Protothreads吗?
尽管技术上有相似之处,RMS选择公开任务的内部状态,迫使程序员**形式化**地思考系统并将不同状态分离到各自的执行中。这在设计需要严格认证的工业产品时非常有用,因为你需要将预定义的状态转换图转化为代码,而这种状态转换图的正确性可以很方便地用UPPAAL等工具验证。此外,这种设计(1)不会受到执行中可能存在的switch-cases的意外冲突的影响,(2)不需要编译器特定的扩展,(3)每个任务最少只需要1字节(在编译器允许的状况下,甚至少于1字节)的RAM,相比之下Protothreads需要两字节或更多。
## 快速演示
### 只需将其复制并粘贴到C文件中,然后使用任何C编译器进行编译
```C
#include "stdio.h"
#include "time.h"
#include "rms.h"
#define TASK1_CATCH (0U)
#define TASK1_STATE1 (1U)
#define TASK1_STATE2 (2U)
#define TASK2_STATE1 (0U)
#define TASK2_STATE2 (1U)
int Task1_Start=0;
void Delay(int Sec)
{
clock_t Start;
clock_t Time;
Start=clock();
Time=(clock_t)Sec*CLOCKS_PER_SEC;
while((clock()-Start)