回调函数 数组

##C语言回调函数–数组##
续接上一节
###回调函数数组简介###
  本人理解的回调函数数组,实际上是用于存储回调函数及对应信息的函数表。这个数组用于存储所有的回调函数,新注册的回调函数也要增加到这个数组(函数表)中。根据上述的特点,回调函数非常适用于嵌入式系统中菜单、功能选择、GUI等功能的编写。

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

typedef  void (*PFUNCMD)();  

二、声明回调函数数组(函数表)的结构类型
格式:typedef struct CmdEntry {} CmdEntry; 即 结构体 {结构体内容} 结构体名
例:

typedef struct CmdEntry
{
	PFUNCMD pfuncmd;		//定义函数指针,用于接收函数的入口地址
	char cHelp[HELP_LEN];
} CmdEntry;

三、声明回调函数原型
格式:同正常函数声明方法
例:

void CreateFile()  {printf("CreateFile\n");}

四、声明执行功能的命令函数原型
格式:循环函数表,执行函数表中的回调函数
例:

void CmdRunning()
{
	int iCmdNum;
	while(1)
	{
		ShowHelp();	//“帮助信息”显示初始化
		printf("Please select!\n\r");
		//iCmdNum = 1;2
		scanf("%d",&iCmdNum);
		if(iCmdNum>=0 && iCmdNum<TABLE_LEN && cmdArray[iCmdNum].pfuncmd)
		{
			cmdArray[iCmdNum].pfuncmd();
		}
		else
		{
			printf("Your selection doesn't exist!\n\r");
		}
		nrf_delay_ms(1000);
	}
}

五、声明一个具有向函数表中增加回调函数功能的注册函数
  如果采用上述方式注册函数,则必须在这个文件的函数表中修改源代码,但是在很多时候,需要扩展菜单功能时不允许随意修改源码,那么唯一的解决方法就是为系统增加一个可动态扩展的接口函数。
格式:同正常函数声明方法,函数中循环遍历函数表,找到空位置,将新的回调函数即指针赋值给回调函数数组中的元素。
例:

void AddCmd(CmdEntry cmdentry)
{
    int i;
    for(i = 0; (i < TABLE_LEN) && cmdArray[i].pfuncmd; i++)
    {
    	;
    }
    // 找到空的功能条目位置
    if(TABLE_LEN == i)
    {
   	 printf("Sorry,Table is full!");
    }
    else
    {
    	cmdArray[i] = cmdentry;
    }
}

介绍部分到此为止。附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

#define HELP_LEN 64  // 函数说明的最大长度 
#define TABLE_LEN 10 // 函数表中的最大的函数个数

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(*PFUNCMD)();	//声明回调函数类型
typedef struct CmdEntry
{
	PFUNCMD pfuncmd;	// 定义函数指针,用于接收函数的入口地址
	char cHelp[HELP_LEN];
}CmdEntry;

void CreateFile() { printf("CreateFile\n"); }	//回调函数CreateFile
void OpenFile() { printf("OpenFile\n"); } 		//回调函数OpenFile
void SaveFile() { printf("SaveFile\n"); }		//回调函数SaveFile
void AddFile() { printf("AddFile\n\r");}		//回调函数AddFile,待向函数表中新增的回调函数

 // 定义结构体数组(函数表)并初始化  
static CmdEntry cmdArray[TABLE_LEN] =
{
	{&CreateFile,"CreateFile HELP"},	   // 取CreatFile()函数地址,帮助信息
	{&OpenFile,"OpenFile HELP"},			// 取OpenFile()函数地址,帮助信息
	{&SaveFile,"SaveFile HELP"},			// 取SaveFile()函数地址,帮助信息
	 // <标注1>在这里添加函数					
	{0,0}									// 退出
};
//显示函数表中的内容
void ShowHelp()
{
	int i;
	for(i=0;(i<TABLE_LEN)&&cmdArray[i].pfuncmd;i++)
	{
		printf("%d\t%s\n\r",i,cmdArray[i].cHelp);
	}
}
//执行功能的命令函数
void CmdRunning()
{
	int iCmdNum;
	while(1)
	{
		ShowHelp();		//“帮助信息”显示初始化
		printf("Please select!\n\r");
		//iCmdNum = 1;2
		scanf("%d",&iCmdNum);
		if(iCmdNum>=0 && iCmdNum<TABLE_LEN && cmdArray[iCmdNum].pfuncmd)
		{
			cmdArray[iCmdNum].pfuncmd();
		}
		else
		{
			printf("Your selection doesn't exist!\n\r");
		}
		nrf_delay_ms(1000);
	}
}
/*
 *如果采用上述方式注册函数,则必须在这个文件的函数表中
 *修改源代码,但是在很多时候,需要扩展菜单功能时不允
 *许随意修改源码,那么唯一的解决方法就是为系统增加一
 *个可动态扩展的接口函数。
*/
void AddCmd(CmdEntry cmdentry)
{
	int i;
	for(i=0;(i<TABLE_LEN) && cmdArray[i].pfuncmd;i++)
	{ ; }
	 // 找到空的功能条目位置
	if(TABLE_LEN == i) {printf("Sorry,Table if full!\n\r");}
	else {cmdArray[i] = cmdentry;}
}

int main()
{

		nrf_gpio_cfg_output(LED0);
		nrf_gpio_cfg_output(LED1);  
		lfclk_config();  
		uart_init();
		app_button_user_init();
		nrf_delay_ms(100);
		//×¢²áÒ»¸öеĻص÷µ½º¯Êý±íÖÐ
		CmdEntry CmdAdd = 
		{
			AddFile,
			"AddFile Help"
		};
		AddCmd(CmdAdd);
		
		CmdRunning();
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、付费专栏及课程。

余额充值