回调函数 注册

##C语言回调函数–注册##
续接上一节
###回调函数数组简介及运行思路###
  回调函数的注册是把一个普通函数注册为一个回调函数的过程,本例中通过分析main函数执行过程,来详细了解回调函数注册思路。
main函数执行过程:
1、首先按照CBDemo格式声明结构体变量demo,用于注册回调函数,再对k赋值。
 按照Data格式声明结构体变量data,用于存储回调函数要用的数据,再对i,j赋值。
2、硬件初始化,包括LED、UART、Button。
3、使用RegisterCallback将Test函数注册为回调函数,传入参数为:注册回调函数的结构体demo、被注册函数Test、数据参数data。
注:RegisterCallback函数出传入三个重要参数;
  参数1:CBDemo *pDemo 是用于注册回调函数的结构体,该结构体包括CBTest类型回调函数和 void * 类型回调函数参数;
  参数2:CBTest Test为指向被注册函数的指针;
  参数3:void *p 传入回调函数被调用时使用的参数;
  在注册过程中将参数2即将被注册为回调的函数地址,赋值给参数1结构体中的–>cb元素;将参数3即回调函数被调用时使用的参数,赋值给参数1结构体中给的–>cbParam元素。

4、串口打印data中的i,j两个数据,由于只注册未执行,因此输出结果为:10,11。
5、通过demo.cb(demo.cbParam)调用回调函数,Test的到执行,因此输出结果为:11,12。
6、按照上述第3条步骤,使用RegisterCallback将Test2函数注册为回调函数.
7、串口打印demp中的k数据,由于只注册未执行,因此输出结果为:1。
8、通过demo.cb(demo.cbParam)调用回调函数,Test2的到执行,因此输出结果为:10。
运行结果


一、首先使用typedef声明执行函数的指针类型,返回值类型、参数类型
格式:typedef void(*CBTest)(void *p); 即:返回值(指针名)(参数列表)
例:typedef void(*CBTest)(void *p);

二、声明用于注册回调函数的结构体
格式:同正常结构体声明方法
例:

typedef struct _cbDemo CBDemo;

struct _cbDemo
{
    CBTest cb; 		//指向回调函数的指针
    void * cbParam; 	//指向参数的指针
    int k;
};

三、声明用于存储函数数据成员变量的结构体
格式:同正常结构体声明
例:

typedef struct _Data Data;
struct _Data    //包含i、j两个整形成员变量
{
    int i;
    int j;
};

四、声明要作为回调函数的两个函数:Test()和Test2()
格式:void Test(void *p),同正常函数声明,传入参数为指针。
例:

void Test(void *p)
{
    ((Data*)p)->i++;	
    ((Data*)p)->j++;
}
void Test2(void *p)
{
	((CBDemo*)p)->k = 10;
}

五、声明用于注册回调函数的函数
格式:void RegisterCallback(CBDemo *pDemo,CBTest Test , void *p),同正常函数声明过程。参数:pDemo:用于注册回调函数的结构体;test:要注册的回调函数;p:回调函数被调用时使用的参数。
例:

void RegisterCallback(CBDemo *pDemo,CBTest Test , void *p)
{
	pDemo ->cb = Test;  //结构体的cb指向回调函数
	pDemo ->cbParam = p; //结构体的cbParam指向参数
}

介绍部分到此为止。附main.c代码

#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "nrf_gpio.h"
#include "nrf_adc.h"
#include "app_uart.h"
#include "nrf_delay.h"
#include "app_error.h"
#include "app_timer.h"
#include "app_button.h"

#define  RX_PIN_NUMBER	11
#define  TX_PIN_NUMBER	9
#define  RTS_PIN_NUMBER	8
#define  CTS_PIN_NUMBER	10
#define UART_TX_BUF_SIZE 128 /**< UART TX buffer size. */
#define UART_RX_BUF_SIZE 128

#define LED0 18
#define LED1 19
#define BUTTON0 16
#define BUTTON1 17
#define BUTTONS_NUMBER 2

#define APP_TIMER_PRESCALER 0
#define APP_TIMER_MAX_TIMERS 8
#define APP_TIMER_OP_QUEUE_SIZE	8

uint32_t err_code;
static void lfclk_config(void);
void uart_error_handle(app_uart_evt_t * p_event);
void uart_init(void);
void button_event_handler(uint8_t pin_no, uint8_t button_action);
void app_button_user_init(void);

typedef void(*CBTest)(void *p);	
typedef struct _cbDemo CBDemo;
struct _cbDemo
{
	CBTest cb;
	void *cbParam;
	int k;
};
typedef struct _Data Data;
struct _Data
{
	int i;
	int j;
};
void Test(void *p)
{
	((Data*)p)->i++;
	((Data*)p)->j++;
}
void Test2(void *p)
{
	((CBDemo*)p)->k = 10;
}
void RegisterCallback(CBDemo *pDemo,CBTest Test,void *p)
{
	pDemo->cb = Test;
	pDemo->cbParam = p;
}

int main()
{
	CBDemo demo;
	Data data;
	data.i = 10;
	data.j = 11;
	demo.k = 1;
	nrf_gpio_cfg_output(LED0);
	nrf_gpio_cfg_output(LED1);  
	lfclk_config();  
	uart_init();
	app_button_user_init();
	
	RegisterCallback(&demo,Test,&data);
	printf("%d,%d\n\r",data.i,data.j);
	nrf_delay_ms(10);
	demo.cb(demo.cbParam);
	printf("%d,%d\n\r",data.i,data.j);
	nrf_delay_ms(10);
	RegisterCallback(&demo,Test2,&demo);
	printf("%d\n",demo.k);
	nrf_delay_ms(10);
	demo.cb(demo.cbParam);
	printf("%d\n\r",demo.k);
	nrf_delay_ms(10);
	while(1)
    {
    }
}

void uart_error_handle(app_uart_evt_t * p_event)
{
    if (p_event->evt_type == APP_UART_COMMUNICATION_ERROR)
    {
    	APP_ERROR_HANDLER(p_event->data.error_communication);
    }
    else if (p_event->evt_type == APP_UART_FIFO_ERROR)
    {
    	APP_ERROR_HANDLER(p_event->data.error_code);
    }
}

void uart_init(void)
{
    const app_uart_comm_params_t comm_params =
    {
	    RX_PIN_NUMBER,
	    TX_PIN_NUMBER,
	    RTS_PIN_NUMBER,
	    CTS_PIN_NUMBER,
	    APP_UART_FLOW_CONTROL_DISABLED,
	    false,
	    UART_BAUDRATE_BAUDRATE_Baud115200
	};
   APP_UART_FIFO_INIT(&comm_params,
   UART_RX_BUF_SIZE,
   UART_TX_BUF_SIZE,
   uart_error_handle,
   APP_IRQ_PRIORITY_LOW,
   err_code);

APP_ERROR_CHECK(err_code);
}
void button_event_handler(uint8_t pin_no, uint8_t button_action)
{
	static uint8_t i = 0; 
	printf("%d\n\r",i++);
}
void app_button_user_init(void)
{
	uint32_t timer_ticks = APP_TIMER_TICKS(100, APP_TIMER_PRESCALER);
	APP_TIMER_INIT(APP_TIMER_PRESCALER, APP_TIMER_MAX_TIMERS, APP_TIMER_OP_QUEUE_SIZE, false);
	static app_button_cfg_t P_button[BUTTONS_NUMBER] =
	{
		{
			BUTTON0,
			APP_BUTTON_ACTIVE_LOW,
			NRF_GPIO_PIN_NOPULL,
			button_event_handler
		},
		{
			BUTTON1,
			APP_BUTTON_ACTIVE_LOW,
			NRF_GPIO_PIN_NOPULL,
			button_event_handler
		}
	};
	err_code = app_button_init((app_button_cfg_t *)P_button,BUTTONS_NUMBER,timer_ticks);
	err_code = app_button_enable();
}
static void lfclk_config(void)
{
    NRF_CLOCK->LFCLKSRC = (CLOCK_LFCLKSRC_SRC_Xtal << CLOCK_LFCLKSRC_SRC_Pos);
    NRF_CLOCK->EVENTS_LFCLKSTARTED  = 0;
    NRF_CLOCK->TASKS_LFCLKSTART = 1;
    while (NRF_CLOCK->EVENTS_LFCLKSTARTED == 0)
    {
   	 //Do nothing.
    }
    NRF_CLOCK->EVENTS_LFCLKSTARTED = 0;
}

个人见解,仅供参考,希望能够与诸位共同讨论分析

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值