前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >如何将回调和中断服务函数进行结合?

如何将回调和中断服务函数进行结合?

作者头像
杨源鑫
发布2022-03-24 09:08:20
8070
发布2022-03-24 09:08:20
举报
文章被收录于专栏:嵌入式开发圈嵌入式开发圈

使用回调的方法可用于轻松创建灵活且可扩展的中断服务程序。开发人员可以使用多种方法以这种方式使用回调。 可以是以动态的形式分配回调,也可以以静态的形式分配回调,静态分配的回调的好处是不能在运行时进行更改,但动态分配对于在执行期间可能需要更改中断行为的应用程序非常有用。

假设我们有一个 UART 或 USART,可以在多个应用程序中重复使用。我们为它们设计一个硬件抽象层,这样的话我们可以将驱动程序代码与应用程序代码解耦,如下所示:

代码语言:javascript
复制
void Uart_Hal_Init(UartConfig_t const * const Config);
void Uart_Hal_BaudRateSet(UartChannel_t const Channel, UartConfig_t const * const Config);
uint8_t Uart_Hal_CharGet(UartChannel_t const Channel);
void Uart_Hal_CharPut(UartChannel_t const Channel, char const Ch);
uint8_t Uart_Hal_IsDataPresent(UartChannel_t const Channel);
void Uart_Hal_RegisterWrite(uint32_t const Address, uint32_t const Value);
uint32_t Uart_Hal_RegisterRead(uint32_t const Address);
void Uart_Hal_CallbackRegister(UartCallback_t const Function, void (*CallbackFunction)(void));

注意,这些接口具有可用于注册回调函数的方法。这种方式允许开发人员获取回调函数并将其分配给他们需要的中断,以便将其分配给这样的UART接收或传输中断。

在串口驱动程序中,我们在写代码的时候可能定义了几个不同的中断。例如,一个中断处理程序可能是:

代码语言:javascript
复制
void Uart1_ISR(void)
{
  HAL_UART_Transmit(&huart2, (uint8_t *)aRxBuffer, 1, 0xFFFF);
  CBUF_Push(RxDataBuffer, aRxBuffer[0]);
  HAL_UART_Receive_IT(&huart2, (uint8_t *)aRxBuffer, 1);
}

这段代码虽然是特定于应用程序的,但是我们希望的是它在中断服务函数触发的时候就开始工作,相反,我们可以如下设置我们的中断处理函数:

代码语言:javascript
复制
void Uart1_ISR(void)
{
    if(NULL != UART1_ISR->function)
        (*UART1_ISR->function)(); 
}

这里的用法是我们将使用一个函数指针来指定当中断触发时应该执行哪个函数。如果我们还没有分配中断,也就是函数指针被赋值为NULL。如果分配了函数指针,就会执行这个函数。分配给函数指针的函数在运行时使用以下HAL函数设置:

代码语言:javascript
复制
void Uart_Hal_CallbackRegister(UartCallback_t const Function, void (*CallbackFunction)(void));

我们可以使用以下这个例子为我们的应用程序定义回调函数:

代码语言:javascript
复制
void UserIsrFunction(void)
{
    HAL_UART_Transmit(&huart2, (uint8_t *)aRxBuffer, 1, 0xFFFF);
    CBUF_Push(RxDataBuffer, aRxBuffer[0]);
    HAL_UART_Receive_IT(&huart2, (uint8_t *)aRxBuffer, 1);
}

系统初始化代码然后进行以下调用以将函数分配给在中断服务处理程序中执行的函数指针:

代码语言:javascript
复制
Uart_Hal_CallbackRegister(Uart1_ISR, UserIsrFunction);

而拥有一个可以被调用以更改中断执行的函数的API可能看起来很危险,也可能是一个安全漏洞。具有API分配的替代方法是在编译时使用配置结构体来初始化函数指针。你会注意到Uart_Init函数具有以下形式:

代码语言:javascript
复制
void Uart_Init(UartConfig_t const * const Config);

配置结构体UartConfig_t可用于分配执行的功能。这里的优势是多方面的,例如:

  • 函数在编译时赋值
  • 分配是通过一个const表进行的
  • 可以进行函数指针分配,使其驻留在 ROM 与 RAM 中,这将使其在运行时不可更改

当然有几种不同的方法可以做到这一点,但我们的想法是使驱动程序代码保持不变,甚至可以作为预编译库提供。然后应用程序代码仍然可以轻松更改中断行为,而无需查看实现细节。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-12-19,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 嵌入式应用研究院 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档