因此,我正在STM32上编写UART驱动程序,尽管我对布局结构有一定的想法,但我仍然想在实现之前进行澄清,并且还要考虑保持代码整洁的必要性且井井有条。
所以我有main.c
,sensor.c
(使用UART层的应用程序文件),hal_usart.c
(这是驱动程序文件)。
我听说过有关应用程序代码如何不了解驱动程序API的不同观点,并且有一天读了一篇文章,您可以使用函数指针将传感器代码与HAL驱动程序代码分离,但不确定如何做在这里,如果考虑到我仍在传递对USART_Handle结构的引用,该结构包含baudRate,parityControl,wordLength,对USART_TypeDef
的引用等信息,则将其解耦,
下面是我的想法的摘要:
// main.c
static USART_Handle pUSART;
int main(void) {
// initialize clocks/HAL
// ...initialize USART struct
// Get data via UART (calling application API)
GetData(&pUSART);
}
// sensor.c (application)
void GetData(USART_Handle *pUSART) {
HAL_USART_TX();
HAL_USART_RX(); // assuming data is stored in one of the struct members
}
// hal_usart.c (Driver file)
void HAL_USART_TX() {}
void HAL_USART_RX() {}
如果要在程序运行时更改指针,则函数指针的效用最大。或者换句话说,当您具有至少两个不同的功能,并且根据某种条件,您想要使用一个或另一个。
例如,假设您有一个例程,该例程使用一个串行端口读取传感器,并且用户可以从一个传感器切换到另一个传感器(两个串行端口,甚至两种不同的方法)。在这种情况下,传感器例程可以调用函数,以使用函数指针进行读取,并管理反向读取的数据。通过更改功能指针,主程序可以指示传感器例程使用一个或另一个传感器。
如果您不需要在运行时进行更改,则只需编写传感器例程,使其调用其他文件中定义的读取函数(外部)即可。传感器例程的文档仅必须声明必须在某个地方定义一个名为“ int sensor_get_data()”的例程。
这涉及根据来自“分离的驱动程序”的数据来往和设计,来设计自己的“内部协议”。例如,处理传感器的精确模型的传感器例程可能需要发送命令并接收响应。您可以编写用于构造命令并解码答案的传感器例程,并删除将所有它们包装在单个函数“ int sensor_get_data(int command)”中的低级详细信息。然后,您可以链接或包含传感器代码,并在主代码中实现功能sensor_get_data()。
main()不知道传感器的详细信息,它仅知道传感器代码在需要时将调用函数sensor_get_data()。但是,该功能可以使用UART,i2c或spi,而传感器例程甚至不会注意到这一点。此外,该例程可以使用这三个端口中的任何一个,也许基于用户可以在运行时修改的参数。
所有这些都可以称为“回调机制”,并且实现了声明和实现之间的某种分离,如另一个答案中所述。我描述的内容与此没有什么不同,但它是static-程序使用固定的回调进行编译,而不是在每次调用中都传递函数指针。
由于您想在嵌入式系统中分离应用程序代码和驱动程序代码,因此建议您研究如何在C嵌入式系统中实现回调函数。
这里是reference。