2026.9.7
之前一直不太理解回调的含义,属于是理解回调也能看懂,但是不知道为什么这么用(感觉根本原因应该是我不理解它的具体运作过程)今天突然理解了就记录一下。
当我们需要完成一个通信模块的时候就会涉及到收发这部分,当我们调用Test_Send()这部分的时候就发出了一帧,同时从机将会接收到主机发出的数据帧。
但是从机应该怎么接收呢?如果使用Test_Recv()来接收,总不能一直循环这个函数,不仅浪费资源,也会有丢帧的可能性。发送是由上层主动发起的,我们也无法预测什么时候会收到数据帧数。
因此使用硬件触发中断。
- 报文来了
- 硬件触发中断
- 中断中读取对应帧
但是中断服务函数一般是在Bsp层,当我们在Bsp层读出了数据帧之后应该怎么处理对应数据?(这个问题其实就是,如何将Bsp层的数据传给上层),因此可以通过函数指针来做接口。
因此在接收中断服务中,触发回调函数,将对应的结构体指针传入Service层(其中包含了CAN帧ID等信息 + 数据信息)。之后的回复帧或者是数据处理就有上层来完成。
因此使用回调函数的核心其实就是中断中的那个函数指针,分隔开了上下层,相当于下层的一个接口,连接着上层的函数。
PS:函数指针理解:和变量定义很像,主要用于存储函数入口的地址。
typedef BOOL (can_callback_t)(ST_CAN_FRAME pFrame);//can_callback_t变量名称
其实就是 typedef BOOL (p)(ST_CAN_pFrame);
当 p = test();//p = &(test());
当定义BspCanRxCallBackReg(CAN_ID id, p fun);//Bsp层
BspCanRxCallBackReg(CAN0, TestRead);//Service层,TestRead为对应数据处理函数
定义TestRead(ST_CAN_FRAME pFrame);//Service层
在UART通信中,一般情况下除了直接使用中断接收然后直接处理数据,还可以使用DMA进行数据搬运,区别主要在于一个是CPU直接搬运,另一种是DMA搬运不占用CPU资源。但是都是需要利用中断触发。但是DMA也是一种有限资源,启动DMA也是需要成本的,因此当每次传输的数据不是很多的时候可以直接用中断,如果每次都需要传输大量的数据,就可以尝试使用DMA。
浙公网安备 33010602011771号