在嵌入式 C 中,有一些固定/通用算法是很自然的,但不止一种可能的实现。这是由于几个产品展示,有时是选项,有时只是产品路线图策略的一部分,例如可选 RAM、不同 IP 集 MCU、升级频率等。
在我的大多数项目中,我通过将核心内容、算法和逻辑架构与实现外部状态评估、计时、内存存储等的实际功能解耦来处理这个问题。
自然地,我使用 C 函数指针机制,并为这些指针使用一组有意义的名称。例如
unsigned char (*ucEvalTemperature)(int *);
将温度存储在一个 int 中,返回是 OKness。
现在想象一下,对于产品的特定配置,我有一个
unsigned char ucReadI2C_TMP75(int *);
从 TMP75 设备读取 I2C 总线上的温度的功能和
unsigned char ucReadCh2_ADC(unsigned char *);
一种读取二极管压降的函数,由 ADC 读取,这是一种在非常广泛的范围内评估温度的方法。
这是相同的基本功能,但在不同的选项集产品上。
在某些配置中,我会将 ucEvalTemperature 设置为 ucReadI2C_TMP75,而在其他配置中,我将使用 ucReadCh2_ADC。在这种温和的情况下,为避免出现问题,我应该将参数类型更改为 int,因为指针的大小始终相同,但函数签名不是,编译器会抱怨。好吧……那不是杀手。
这个问题在可能需要不同参数集的函数上变得很明显。签名永远不会正确,编译器将无法解析我的 Fpointers。
所以,我有三种方法:
- 使用全局参数栈,所有函数都是 unsigned char Func(void);
- 对每个实现使用帮助函数,让我打开正确的分配以进行/调用;
- 使用 JMP / LCALL 程序集调用(这当然很可怕),可能会导致调用堆栈出现重大问题。
既不优雅,也不沉稳……你的方法/建议是什么?