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

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

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

640.png

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

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接收或传输中断。


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

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);
}

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

void Uart1_ISR(void)
{
    if(NULL != UART1_ISR->function)
        (*UART1_ISR->function)(); 
}

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

void Uart_Hal_CallbackRegister(UartCallback_t const Function, void (*CallbackFunction)(void));

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

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);
}

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

Uart_Hal_CallbackRegister(Uart1_ISR, UserIsrFunction);

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

void Uart_Init(UartConfig_t const * const Config);

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


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


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

目录
相关文章
|
19天前
在 onerror 事件处理函数中停止接收数据
【10月更文挑战第26天】关闭 WebSocket 连接后,客户端将不再接收来自服务器的数据,同时服务器端也会收到连接关闭的通知。在实际应用中,需要根据具体的业务场景和错误处理需求来选择合适的方法来停止接收数据,以确保应用程序的稳定性和数据的一致性。
|
1月前
|
监控 API
Hook 线程与捕获线程执行异常
【10月更文挑战第11天】Hook 线程和捕获线程执行异常是多线程编程中不可或缺的技术。通过深入理解和掌握这些方法,我们可以提高程序的稳定性和可靠性,更好地应对各种异常情况。同时,在实际应用中要注意平衡性能和准确性,制定合理的异常处理策略,以确保程序的正常运行。
29 1
你的应用进入了中断状态,但无任何代码显示,因为所有线程之前都在执行外部代码
你的应用进入了中断状态,但无任何代码显示,因为所有线程之前都在执行外部代码
2740 0
你的应用进入了中断状态,但无任何代码显示,因为所有线程之前都在执行外部代码
|
3月前
处理串口线程数据的函数
【8月更文挑战第4天】处理串口线程数据的函数。
29 4
|
Linux Windows Ubuntu
时钟回调
时钟回调
387 1
|
前端开发
22 # 中断 promise 链
22 # 中断 promise 链
41 0
|
编译器
中断的解析
中断的解析
96 0
STM32中断与事件的理解
STM32中断与事件的理解
387 1
三种方式中断运行的线程?(interrupt 方法)
三种方式中断运行的线程?(interrupt 方法)
98 0
|
监控 安全 Java
关闭线程的正确方法:“优雅”的中断
前文从任务到线程:Java结构化并发应用程序中介绍了如何安排任务启动线程。 线程在启动之后,正常的情况下会运行到任务完成,但是有的情况下会需要提前结束任务,如用户取消操作等。
1399 0