回调函数_数组

来源:互联网 发布:淘宝网舞蹈练功棉服 编辑:程序博客网 时间:2024/06/12 00:16

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"); }   //回调函数CreateFilevoid OpenFile() { printf("OpenFile\n"); }       //回调函数OpenFilevoid SaveFile() { printf("SaveFile\n"); }       //回调函数SaveFilevoid 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;}
1 0
原创粉丝点击