这是我的button.h和button.c文件 /** * @File: flexible_button.h * @Author: MurphyZhao * @Date: 2018-09-29 * * Copyright (c) 2018-2019 MurphyZhao <[email protected]> * https://github.com/murphyzhao * All rights reserved. * License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Change logs: * Date Author Notes * 2018-09-29 MurphyZhao First add * 2019-08-02 MurphyZhao Migrate code to github.com/murphyzhao account * 2019-12-26 MurphyZhao Refactor code and implement multiple clicks * */ #ifndef __BUTTON_H__ #define __BUTTON_H__ #include "stdint.h" #include "key_app.h" #include "KEY.h" #define FLEX_BTN_SCAN_FREQ_HZ 50 // How often flex_button_scan () is called #define FLEX_MS_TO_SCAN_CNT(ms) (ms / (1000 / FLEX_BTN_SCAN_FREQ_HZ)) /* Multiple clicks interval, default 300ms */ #define MAX_MULTIPLE_CLICKS_INTERVAL (FLEX_MS_TO_SCAN_CNT(300)) /** * @brief 按钮事件枚举类型 * * 定义了各种按钮触发事件类型,包括: * - 按下(FLEX_BTN_PRESS_DOWN) * - 单击(FLEX_BTN_PRESS_CLICK) * - 双击(FLEX_BTN_PRESS_DOUBLE_CLICK) * - 重复点击(FLEX_BTN_PRESS_REPEAT_CLICK) * - 短按开始(FLEX_BTN_PRESS_SHORT_START) * - 短按抬起(FLEX_BTN_PRESS_SHORT_UP) * - 长按开始(FLEX_BTN_PRESS_LONG_START) * - 长按抬起(FLEX_BTN_PRESS_LONG_UP) * - 长按保持(FLEX_BTN_PRESS_LONG_HOLD) * - 长按保持后抬起(FLEX_BTN_PRESS_LONG_HOLD_UP) * - 最大值(FLEX_BTN_PRESS_MAX) * - 无事件(FLEX_BTN_PRESS_NONE) */ typedef enum { FLEX_BTN_PRESS_DOWN = 0, FLEX_BTN_PRESS_CLICK, FLEX_BTN_PRESS_DOUBLE_CLICK, FLEX_BTN_PRESS_REPEAT_CLICK, FLEX_BTN_PRESS_SHORT_START, FLEX_BTN_PRESS_SHORT_UP, FLEX_BTN_PRESS_LONG_START, FLEX_BTN_PRESS_LONG_UP, FLEX_BTN_PRESS_LONG_HOLD, FLEX_BTN_PRESS_LONG_HOLD_UP, FLEX_BTN_PRESS_MAX, FLEX_BTN_PRESS_NONE, } flex_button_event_t; /** * flex_button_t * * @brief Button data structure * Below are members that need to user init before scan. * * @member next * Internal use. * One-way linked list, pointing to the next button. * * @member usr_button_read * User function is used to read button vaule. * * @member cb * Button event callback function. * * @member scan_cnt * Internal use, user read-only. * Number of scans, counted when the button is pressed, plus one per scan cycle. * * @member click_cnt * Internal use, user read-only. * Number of button clicks * * @member max_multiple_clicks_interval * Multiple click interval. Default 'MAX_MULTIPLE_CLICKS_INTERVAL'. * Need to use FLEX_MS_TO_SCAN_CNT to convert milliseconds into scan cnts. * * @member debounce_tick * Debounce. Not used yet. * Need to use FLEX_MS_TO_SCAN_CNT to convert milliseconds into scan cnts. * * @member short_press_start_tick * Short press start time. Requires user configuration. * Need to use FLEX_MS_TO_SCAN_CNT to convert milliseconds into scan cnts. * * @member long_press_start_tick * Long press start time. Requires user configuration. * Need to use FLEX_MS_TO_SCAN_CNT to convert milliseconds into scan cnts. * * @member long_hold_start_tick * Long hold press start time. Requires user configuration. * * @member id * Button id. Requires user configuration. * When multiple buttons use the same button callback function, * they are used to distinguish the buttons. * Each button id must be unique. * * @member pressed_logic_level * Requires user configuration. * The logic level of the button pressed, each bit represents a button. * * @member event * Internal use, users can call 'flex_button_event_read' to get current button event. * Used to record the current button event. * * @member status * Internal use, user unavailable. * Used to record the current state of buttons. * */ typedef struct flex_button { struct flex_button* next; uint8_t (*usr_button_read)(void *); flex_button_response_callback cb; uint16_t scan_cnt; uint16_t click_cnt; uint16_t max_multiple_clicks_interval; uint16_t debounce_tick; uint16_t short_press_start_tick; uint16_t long_press_start_tick; uint16_t long_hold_start_tick; uint8_t id; uint8_t pressed_logic_level : 1; uint8_t event : 4; uint8_t status : 3; } flex_button_t; #ifdef __cplusplus extern "C" { #endif int32_t flex_button_register(flex_button_t *button); flex_button_event_t flex_button_event_read(flex_button_t* button); uint8_t flex_button_scan(void); void user_button_init(void); #ifdef __cplusplus } #endif #endif /* __FLEXIBLE_BUTTON_H__ */ /** * @File: flexible_button.c * @Author: MurphyZhao * @Date: 2018-09-29 * * Copyright (c) 2018-2019 MurphyZhao <[email protected]> * https://github.com/murphyzhao * All rights reserved. * License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Change logs: * Date Author Notes * 2018-09-29 MurphyZhao First add * 2019-08-02 MurphyZhao Migrate code to github.com/murphyzhao account * 2019-12-26 MurphyZhao Refactor code and implement multiple clicks * */ #include "button.h" #include "KEY.h" #include "string.h" #include "key_app.h" typedef enum { USER_BUTTON_UP = 0, // 对应 IoT Board 开发板的 PIN_KEY0 USER_BUTTON_LEFT, // 对应 IoT Board 开发板的 PIN_KEY1 USER_BUTTON_RIGHT, // 对应 IoT Board 开发板的 PIN_KEY2 USER_BUTTON_DOWN, USER_BUTTON_MID, // 对应 IoT Board 开发板的 PIN_WK_UP USER_BUTTON_MAX } user_button_t; static flex_button_t user_button[USER_BUTTON_MAX]; static uint8_t common_btn_read(void *arg) { uint8_t value = 0; flex_button_t *btn = (flex_button_t *)arg; switch (btn->id) { case USER_BUTTON_UP: value = key_scan().up; break; case USER_BUTTON_LEFT: value = key_scan().left; break; case USER_BUTTON_RIGHT: value =key_scan().right; break; case USER_BUTTON_DOWN: value = key_scan().down; break; case USER_BUTTON_MID: value = key_scan().mid; break; } return value; } // 配置项 说明 // id 按键编号 // usr_button_read 设置按键读值回调函数 // cb 设置按键事件回调函数 // pressed_logic_level 设置按键按下时的逻辑电平 // short_press_start_tick 短按起始 tick,使用 FLEX_MS_TO_SCAN_CNT 宏转化为扫描次数 // long_press_start_tick 长按起始 tick,使用 FLEX_MS_TO_SCAN_CNT 宏转化为扫描次数 // long_hold_start_tick 超长按起始 tick,使用 FLEX_MS_TO_SCAN_CNT 宏转化为扫描次数 // 注意,short_press_start_tick、long_press_start_tick 和 long_hold_start_tick 必须使用 FLEX_MS_TO_SCAN_CNT 将毫秒时间转化为扫描次数。 // user_button[i].short_press_start_tick = FLEX_MS_TO_SCAN_CNT(1500); 表示按键按下开始计时,1500 ms 后按键依旧是按下状态的话,就断定为短按开始。 //--------------------------------------------------改到这里了----------------------------- void user_button_init(void) { int i; memset(&user_button[0], 0x0, sizeof(user_button)); user_button[USER_BUTTON_UP].cb = up_btn_evt_cb; user_button[USER_BUTTON_LEFT].cb = left_btn_evt_cb; user_button[USER_BUTTON_RIGHT].cb = right_btn_evt_cb; user_button[USER_BUTTON_DOWN].cb = down_btn_evt_cb; user_button[USER_BUTTON_MID].cb = mid_btn_evt_cb; for (i = 0; i < USER_BUTTON_MAX; i ++) { user_button[i].id = i; user_button[i].usr_button_read = common_btn_read; user_button[i].pressed_logic_level = 0; user_button[i].short_press_start_tick = FLEX_MS_TO_SCAN_CNT(1500); user_button[i].long_press_start_tick = FLEX_MS_TO_SCAN_CNT(3000); user_button[i].long_hold_start_tick = FLEX_MS_TO_SCAN_CNT(4500); flex_button_register(&user_button[i]); } } #ifndef NULL #define NULL 0 #endif #define EVENT_SET_AND_EXEC_CB(btn, evt) \ do \ { \ btn->event = evt; \ if(btn->cb) \ btn->cb((flex_button_t*)btn); \ } while(0) /** * BTN_IS_PRESSED * * 1: is pressed * 0: is not pressed */ #define BTN_IS_PRESSED(i) (g_btn_status_reg & (1 << i)) enum FLEX_BTN_STAGE { FLEX_BTN_STAGE_DEFAULT = 0, FLEX_BTN_STAGE_DOWN = 1, FLEX_BTN_STAGE_MULTIPLE_CLICK = 2 }; typedef uint32_t btn_type_t; static flex_button_t *btn_head = NULL; /** * g_logic_level * * The logic level of the button pressed, * Each bit represents a button. * * First registered button, the logic level of the button pressed is * at the low bit of g_logic_level. */ btn_type_t g_logic_level = (btn_type_t)0; /** * g_btn_status_reg * * The status register of all button, each bit records the pressing state of a button. * * First registered button, the pressing state of the button is * at the low bit of g_btn_status_reg. */ btn_type_t g_btn_status_reg = (btn_type_t)0; static uint8_t button_cnt = 0; /** * @brief Register a user button * * @param button: button structure instance * @return Number of keys that have been registered, or -1 when error */ int32_t flex_button_register(flex_button_t *button) { flex_button_t *curr = btn_head; if (!button || (button_cnt > sizeof(btn_type_t) * 8)) { return -1; } while (curr) { if(curr == button) { return -1; /* already exist. */ } curr = curr->next; } /** * First registered button is at the end of the 'linked list'. * btn_head points to the head of the 'linked list'. */ button->next = btn_head; button->status = FLEX_BTN_STAGE_DEFAULT; button->event = FLEX_BTN_PRESS_NONE; button->scan_cnt = 0; button->click_cnt = 0; button->max_multiple_clicks_interval = MAX_MULTIPLE_CLICKS_INTERVAL; btn_head = button; /** * First registered button, the logic level of the button pressed is * at the low bit of g_logic_level. */ g_logic_level |= (button->pressed_logic_level << button_cnt); button_cnt ++; return button_cnt; } /** * @brief Read all key values in one scan cycle * * @param void * @return none */ static void flex_button_read(void) { uint8_t i; flex_button_t* target; /* The button that was registered first, the button value is in the low position of raw_data */ btn_type_t raw_data = 0; for(target = btn_head, i = button_cnt - 1; (target != NULL) && (target->usr_button_read != NULL); target = target->next, i--) { raw_data = raw_data | ((target->usr_button_read)(target) << i); } g_btn_status_reg = (~raw_data) ^ g_logic_level; } /** * @brief Handle all key events in one scan cycle. * Must be used after 'flex_button_read' API * * @param void * @return Activated button count */ static uint8_t flex_button_process(void) { uint8_t i; uint8_t active_btn_cnt = 0; flex_button_t* target; for (target = btn_head, i = button_cnt - 1; target != NULL; target = target->next, i--) { if (target->status > FLEX_BTN_STAGE_DEFAULT) { target->scan_cnt ++; if (target->scan_cnt >= ((1 << (sizeof(target->scan_cnt) * 8)) - 1)) { target->scan_cnt = target->long_hold_start_tick; } } switch (target->status) { case FLEX_BTN_STAGE_DEFAULT: /* stage: default(button up) */ if (BTN_IS_PRESSED(i)) /* is pressed */ { target->scan_cnt = 0; target->click_cnt = 0; EVENT_SET_AND_EXEC_CB(target, FLEX_BTN_PRESS_DOWN); /* swtich to button down stage */ target->status = FLEX_BTN_STAGE_DOWN; } else { target->event = FLEX_BTN_PRESS_NONE; } break; case FLEX_BTN_STAGE_DOWN: /* stage: button down */ if (BTN_IS_PRESSED(i)) /* is pressed */ { if (target->click_cnt > 0) /* multiple click */ { if (target->scan_cnt > target->max_multiple_clicks_interval) { EVENT_SET_AND_EXEC_CB(target, target->click_cnt < FLEX_BTN_PRESS_REPEAT_CLICK ? target->click_cnt : FLEX_BTN_PRESS_REPEAT_CLICK); /* swtich to button down stage */ target->status = FLEX_BTN_STAGE_DOWN; target->scan_cnt = 0; target->click_cnt = 0; } } else if (target->scan_cnt >= target->long_hold_start_tick) { if (target->event != FLEX_BTN_PRESS_LONG_HOLD) { EVENT_SET_AND_EXEC_CB(target, FLEX_BTN_PRESS_LONG_HOLD); } } else if (target->scan_cnt >= target->long_press_start_tick) { if (target->event != FLEX_BTN_PRESS_LONG_START) { EVENT_SET_AND_EXEC_CB(target, FLEX_BTN_PRESS_LONG_START); } } else if (target->scan_cnt >= target->short_press_start_tick) { if (target->event != FLEX_BTN_PRESS_SHORT_START) { EVENT_SET_AND_EXEC_CB(target, FLEX_BTN_PRESS_SHORT_START); } } } else /* button up */ { if (target->scan_cnt >= target->long_hold_start_tick) { EVENT_SET_AND_EXEC_CB(target, FLEX_BTN_PRESS_LONG_HOLD_UP); target->status = FLEX_BTN_STAGE_DEFAULT; } else if (target->scan_cnt >= target->long_press_start_tick) { EVENT_SET_AND_EXEC_CB(target, FLEX_BTN_PRESS_LONG_UP); target->status = FLEX_BTN_STAGE_DEFAULT; } else if (target->scan_cnt >= target->short_press_start_tick) { EVENT_SET_AND_EXEC_CB(target, FLEX_BTN_PRESS_SHORT_UP); target->status = FLEX_BTN_STAGE_DEFAULT; } else { /* swtich to multiple click stage */ target->status = FLEX_BTN_STAGE_MULTIPLE_CLICK; target->click_cnt ++; } } break; case FLEX_BTN_STAGE_MULTIPLE_CLICK: /* stage: multiple click */ if (BTN_IS_PRESSED(i)) /* is pressed */ { /* swtich to button down stage */ target->status = FLEX_BTN_STAGE_DOWN; target->scan_cnt = 0; } else { if (target->scan_cnt > target->max_multiple_clicks_interval) { EVENT_SET_AND_EXEC_CB(target, target->click_cnt < FLEX_BTN_PRESS_REPEAT_CLICK ? target->click_cnt : FLEX_BTN_PRESS_REPEAT_CLICK); /* swtich to default stage */ target->status = FLEX_BTN_STAGE_DEFAULT; } } break; } if (target->status > FLEX_BTN_STAGE_DEFAULT) { active_btn_cnt ++; } } return active_btn_cnt; } /** * flex_button_event_read * * @brief Get the button event of the specified button. * * @param button: button structure instance * @return button event */ flex_button_event_t flex_button_event_read(flex_button_t* button) { return (flex_button_event_t)(button->event); } /** * flex_button_scan * * @brief Start key scan. * Need to be called cyclically within the specified period. * Sample cycle: 5 - 20ms * * @param void * @return Activated button count */ uint8_t flex_button_scan(void) { flex_button_read(); return flex_button_process(); }
时间: 2025-07-22 22:34:52 浏览: 22
<think>我们正在解决CCS项目中移植flexible_button代码时出现的'unknown type name 'flex_button_response_callback''错误。
根据错误信息,编译器不知道flex_button_response_callback是什么类型。这通常是因为没有包含定义该类型的头文件,或者头文件路径没有正确配置。
在flexible_button库中,flex_button_response_callback是一个函数指针类型,它通常在flex_button.h中定义。因此,我们需要确保:
1. 在使用了该类型的源文件中包含了flex_button.h头文件。
2. 确保flex_button.h头文件在工程的包含路径中,或者其路径被正确添加到CCS的包含路径设置中。
步骤:
1. 检查源文件是否包含头文件:在使用了flex_button_response_callback的源文件顶部,应该有如下语句:
#include "flex_button.h"
如果没有,请添加。
2. 检查flex_button.h头文件是否存在于工程中,并且路径正确。如果头文件在某个子目录中,需要将该目录添加到包含路径。
3. 在CCS中添加包含路径的方法:
- 右键单击项目 -> Properties
- 在属性对话框中,选择Build -> ARM Compiler -> Include Options
- 在"Add dir to #include search path"中添加flex_button.h所在的目录(如果不在项目根目录下)
4. 如果以上步骤都做了,但仍然报错,则检查flex_button.h中是否确实定义了flex_button_response_callback类型。
打开flex_button.h,搜索flex_button_response_callback,应该能看到类似下面的定义:
typedef void (*flex_button_response_callback)(flex_button_t *btn);
如果没有,可能是库版本问题,需要更新或获取正确的flexible_button库。
5. 另外,注意头文件包含的顺序,有时会因为头文件依赖关系导致类型未定义。确保在包含flex_button.h之前没有使用该类型。
6. 如果flex_button.h中定义了该类型,但编译器仍然报错,可能是由于条件编译导致该类型定义未被包含。检查flex_button.h中是否有条件编译宏(如#ifdef)控制该类型的定义,并确保满足条件。
参考引用[1]中提到的解决思路,我们可以通过定义类型来绕过问题,但这通常不是推荐的方法,因为可能会与库的后续使用产生冲突。因此,优先采用包含正确头文件的方法。
因此,我们按照以下步骤操作:
步骤1:在源文件中包含头文件
步骤2:将头文件所在目录添加到包含路径
步骤3:检查头文件内容,确保类型定义存在
如果经过上述步骤问题仍然存在,请提供更多信息,例如flex_button.h的内容片段,以及工程目录结构。
下面我们模拟一个修复示例:
假设工程目录结构如下:
project/
main.c
flex_button/
flex_button.h
flex_button.c
在main.c中,我们需要这样包含头文件:
#include "flex_button/flex_button.h"
或者将flex_button目录添加到包含路径,然后在main.c中:
#include "flex_button.h"
然后在CCS中添加包含路径:${PROJECT_LOC}/flex_button
注意:${PROJECT_LOC}是CCS中表示项目根目录的变量。
如果问题还未解决,请检查flex_button.h中是否有如下定义(或类似):
typedef void (*flex_button_response_callback)(flex_button_t *btn);
如果没有,则可能需要更新库文件。
另外,注意flex_button_t类型是否定义,因为该回调函数的参数是flex_button_t指针,所以flex_button_t必须在此之前定义。
因此,在flex_button.h中,应该先有flex_button_t结构体的定义,然后才有回调函数类型的定义。
如果flex_button_t未定义,也会导致错误。所以确保头文件中的类型定义顺序正确。
综上所述,请按照上述步骤进行修复。</think>### 解决 CCS 项目中 `unknown type name 'flex_button_response_callback'` 错误
该错误表明编译器无法识别 `flex_button_response_callback` 类型,根本原因是 **类型声明缺失或未正确包含头文件**。以下是完整解决方案:
#### 原因分析
1. **头文件缺失**(最常见)
- `flex_button.h` 头文件中缺少 `flex_button_response_callback` 的类型声明
- 源文件未包含 `flex_button.h` 或包含路径错误
2. **条件编译限制**
- 类型声明可能被 `#ifdef` 条件编译宏包裹,未启用相关配置
3. **库版本不兼容**
- 使用的 SDK 版本与 `flex_button` 库版本不匹配
#### 解决方案步骤
##### 1. 添加缺失的类型声明(推荐)
在 `flex_button.h` 文件中添加以下类型定义:
```c
// 在 flex_button.h 中添加此声明
typedef void (*flex_button_response_callback)(flex_button_t *btn);
```
##### 2. 检查头文件包含
确保使用该类型的源文件包含头文件:
```c
#include "flex_button.h" // 必须包含此头文件
```
##### 3. 配置 CCS 包含路径
在 CCS 中设置头文件路径:
1. 右键工程 → `Properties`
2. 选择 `Build → ARM Compiler → Include Options`
3. 点击 `Add` 图标 → 添加 `flex_button.h` 所在目录
4. 应用设置并重新编译
##### 4. 启用条件编译(如需要)
如果库中有类似配置,在 `flex_button_cfg.h` 中启用回调支持:
```c
#define FLEX_BUTTON_ENABLE_CALLBACK 1 // 启用回调功能
```
##### 5. 验证类型定义
检查 `flex_button.h` 中是否存在完整定义链:
```c
typedef struct flex_button {
// 按钮结构体成员...
} flex_button_t;
// 回调函数类型声明必须在此之后
typedef void (*flex_button_response_callback)(flex_button_t *btn);
```
#### 排查流程图
```mermaid
graph TD
A[出现类型未定义错误] --> B{检查flex_button.h}
B -->|缺少类型声明| C[添加typedef声明]
B -->|已有声明| D{检查源文件包含}
D -->|未包含头文件| E[添加#include]
D -->|已包含| F{检查路径配置}
F -->|路径错误| G[配置CCS包含路径]
F -->|路径正确| H{检查条件编译}
H -->|宏未启用| I[启用FLEX_BUTTON_ENABLE_CALLBACK]
H -->|已启用| J[检查类型依赖关系]
```
#### 验证修复
1. 在调用处添加测试代码:
```c
// 测试回调函数声明
static void test_callback(flex_button_t *btn) {
printf("Button %d pressed\n", btn->id);
}
// 注册回调
flex_button_register_callback(test_callback);
```
2. 编译后应不再报类型未定义错误
> **关键点**:此类型通常是函数指针类型,用于处理按钮事件回调。其正确定义对按键功能至关重要[^1][^3]。
阅读全文
相关推荐

















