回调函数,函数指针的使用
一、声明一个函数数据类型
//声明一个函数数据类型(以便后面用于定义回调函数)
typedef void (*ARM_USART_SignalEvent_t) (uint32_t event);
二、声明一个结构体数据类型
//定义结构体
typedef struct _ARM_DRIVER_USART
{
int32_t (*Initialize) (ARM_USART_SignalEvent_t cb_event);
int32_t (*Send) (const void *data, uint32_t num);
int32_t (*Receive) ( void *data, uint32_t num);
} const ARM_DRIVER_USART;
此结构体数据类型包含了三个成员(三个指向函数的指针),其中第一个函数指针的形参也是一个函数指针,类型为我们第一步定义的 ARM_USART_SignalEvent_t 类型。
三、定义变量并且初始化
//定义 Driver_USART1 变量并且对其初始化
ARM_DRIVER_USART Driver_USART1 =
{
USART1_Initialize,
USART1_Send,
USART1_Receive,
};
定义了一个结构体变量,并且对三个成员进行初始化赋值。
四、定义的函数的实现
//定义的函数
//初始化函数的参数是一个函数指针
int32_t USART1_Initialize(ARM_USART_SignalEvent_t cb_event)
{
return USART_Initialize (cb_event, &USART1_Resources);
}
int32_t USART1_Send(const void *data, uint32_t num)
{
return USART_Send (data, num, &USART1_Resources);
}
int32_t USART1_Receive(void *data, uint32_t num)
{
return USART_Receive (data, num, &USART1_Resources);
}
第三步定义的三个结构体成员初始值是指向我们这里定义的三个函数。
五、上一步定义的初始化函数 USART1_Initialize 的参数是一个函数指针
//上一步定义的初始化函数 USART1_Initialize 的参数是一个函数指针,我们这里先定义好一个回调函数,以便后面调用的时候使用
//回调函数
void USART_callback(uint32_t event)
{
if (event & ARM_USART_EVENT_RECEIVE_COMPLETE)
{
/* 接收完成 */
uartflag = 1;
}
if (event & ARM_USART_EVENT_RX_TIMEOUT)
{
/* 接收超时 */
uartflag = 2;
}
if (event & ARM_USART_EVENT_SEND_COMPLETE )
{
/* 发送完成 */
uartflag = 4;
}
}
六、调用
Driver_USART1.Initialize(USART_callback); //相当于执行 USART1_Initialize(USART_callback);
Driver_USART1.Send(Rec,100); //相当于执行 USART1_Send(Rec,100);
Driver_USART1.Receive(Rec, 100); //相当于执行 USART1_Receive(Rec,100);
在初始化函数里面,我们会把回调函数赋值给串口资源,以便发生串口中断的时候就调用,
比如,在串口中断里面有一下代码:
uint32_t val, event;
switch (val)
{
case USART_SYNC_MODE_TX:
event |= ARM_USART_EVENT_SEND_COMPLETE;
break;
case USART_SYNC_MODE_RX:
event |= ARM_USART_EVENT_RECEIVE_COMPLETE;
break;
case USART_SYNC_MODE_TX_RX:
event |= ARM_USART_EVENT_TRANSFER_COMPLETE;
break;
default: break;
}
// Send Event
if ((event && usart->info->cb_event) != 0U)
{
usart->info->cb_event (event); // 相当于执行 USART_callback(event);
}
这样我们就可以根据 event 的值判断串口发生了什么。
以上代码分析是选取的安富莱的串口例程分析的:
BSP视频教程第21期:轻松一键实现串口DMA不定长收发,支持裸机和RTOS,含MDK和IAR两种玩法,比STM32CubeMX还方便(2022-07-24)
七、简单示例
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
// 定义异步事件的回调函数类型
typedef void (*CallbackFunc)(int);
// 模拟异步事件处理函数
void asyncEvent(CallbackFunc callback)
{
printf("开始处理异步事件...\n");
sleep(3); // 模拟异步操作耗时
printf("异步事件处理完成!\n");
// 调用回调函数通知异步事件完成
callback(42); // 传递事件结果 比如串口接收完成调用callback(1) 超时调用callback(2)
}
串口接收完成调用callback(1) 超时调用callback(2) 发送完成调用callback(3)
// 回调函数的实现
void callbackFunction(int result)
{
printf("收到回调通知,异步事件结果为:%d\n", result);
// 在此处进行进一步操作或处理异步事件结果
//这里判断 result 的值,如果为1表示接收完成,为2表示接收超时
}
这里判断 result 的值,如果为1表示接收完成,为2表示接收超时,为3表示发送完成,
int main()
{
printf("主程序开始\n");
// 调用异步事件处理函数,并传递回调函数
asyncEvent(callbackFunction);
printf("主程序结束\n");
return 0;
}