回调函数_数组
2016-05-12 09:28
447 查看
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; }
相关文章推荐
- 如何组织构建多文件 C 语言程序(二)
- 如何写好 C main 函数
- Mootools 1.2教程 函数
- autoit InputBox 函数
- 文件遍历排序函数
- Oracle 函数大全[字符串函数,数学函数,日期函数]第1/4页
- ASP下经常用的字符串等函数参考资料
- PostgreSQL教程(五):函数和操作符详解(1)
- DOS批处理 函数定义与用法
- asp Chr 函数 数字转字母的方法
- Lua中的函数精讲笔记
- Lua中的闭合函数、非全局函数与函数的尾调用详解
- Lua中调用C++函数示例
- Lua和C语言的交互详解
- Lua实现split函数
- Lua常用时间函数使用实例
- Lua函数与字符串处理简明总结
- Lua学习笔记之表和函数
- Lua中实现sleep函数功能的4种方法
- Lua函数用法研究