很多人用按键处理时,只会单击(短按)和长按这两种,这是非常不正确的想法,也不能展示出个人的实力!!!
真正的按键高手可以使用按键处理算法来实现 单击,双击,三击,长按,2个按键组合新按键。这是非常有用的。
向你们平时使用的电脑按键,是不是有个组合按键,按下Fn + Esc
进行电脑快捷按键的开闭,其实MCU也可以使用组合按键,主要是你们的思想已经封闭了,弄不出来!!!!
本文就是我个人自创的按键最齐全的算法,实现了按键的所有功能,包括单击,双击,三击,短按,长按,组合按键。你想要的都有!!!!
好了,进入正题!!!
1。打开RA smart 配置工具
新建工程,打开原理图,配置按键IO口

两个按键分别是P410和P409

2。配置LED口

3个LED分别是
P214 P211 P210

3。配置串口9

串口RX 为 P109
TX为P110
对应串口9

4。生成工程代码

5。打开KEIL
修改核心代码
#include "usart9.h"
uint8_t U1_RxBuff[RXBUFFLENGTH];
uint16_t U1_Rxlen = 0;
uint16_t U1_RxlencntPre = 0;
static volatile bool uart_send_complete_flag = false;
void UART9_Init(void)
{
fsp_err_t err = FSP_SUCCESS;
err = R_SCI_UART_Open(&g_uart9_ctrl,&g_uart9_cfg);
assert(err == FSP_SUCCESS);
}
void uart9_Send_Byte(uint8_t ch)
{
/* 发送一个字节数据到UART */
R_SCI_UART_Write(g_uart9.p_ctrl, (uint8_t *)&ch, 1);
while(uart_send_complete_flag == false);
uart_send_complete_flag = false;
}
void uart9_Send_Bytes(uint8_t data, uint32_t len)
{
/ 发送一个字节数据到UART */
R_SCI_UART_Write(g_uart9.p_ctrl, data, len);
while(uart_send_complete_flag == false);
uart_send_complete_flag = false;
}
void uart9_Send_String_Length(uint8_t str,uint32_t strlen)
{
unsigned int k=0;
do
{
uart9_Send_Byte ((str + k));
k++;
} while(k < strlen);
}
void uart9_Send_String(uint8_t str)
{
unsigned int k=0;
do
{
uart9_Send_Byte ((str + k));
k++;
} while(*(str + k)!='\0');
}
void user_uart_clear(void)
{
memset(U1_RxBuff, 0, sizeof(U1_RxBuff));
U1_Rxlen = 0;
}
uint8_t user_uart_wait_receive(void)
{
if(U1_Rxlen == 0)
return REV_WAIT;
if(U1_Rxlen == U1_RxlencntPre)
{
U1_Rxlen = 0;
return REV_OK;
}
U1_RxlencntPre = U1_Rxlen;
return REV_WAIT;
}
void uart9_callback (uart_callback_args_t * p_args)
{
if(p_args->event == UART_EVENT_TX_COMPLETE)
{
uart_send_complete_flag = true;
}
if(p_args->event == UART_EVENT_RX_CHAR)
{
//SerialInput((uint8_t)p_args->data);
if(U1_Rxlen >= sizeof(U1_RxBuff)) U1_Rxlen = 0;
U1_RxBuff[U1_Rxlen++] = (uint8_t)p_args->data;
}
}
void uart_send(const char *s)
{
R_SCI_UART_Write(&g_uart9_ctrl, (uint8_t *)s, strlen(s));
while(uart_send_complete_flag == false);
uart_send_complete_flag = false;
}
void uart_write(char c)
{
R_SCI_UART_Write(&g_uart9_ctrl, (uint8_t *)&c, 1);
while(uart_send_complete_flag == false);
uart_send_complete_flag = false;
}
fsp_err_t uart_read(char c)
{
return R_SCI_UART_Read (&g_uart9_ctrl, (uint8_t) c, 1);
}
#define LED1_lighting_off R_IOPORT_PinWrite(&g_ioport_ctrl,LED1,BSP_IO_LEVEL_LOW)
#define LED1_lighting_up R_IOPORT_PinWrite(&g_ioport_ctrl,LED1,BSP_IO_LEVEL_HIGH)
#define LED2_lighting_off R_IOPORT_PinWrite(&g_ioport_ctrl,LED2,BSP_IO_LEVEL_LOW)
#define LED2_lighting_up R_IOPORT_PinWrite(&g_ioport_ctrl,LED2,BSP_IO_LEVEL_HIGH)
#define LED3_lighting_off R_IOPORT_PinWrite(&g_ioport_ctrl,LED3,BSP_IO_LEVEL_LOW)
#define LED3_lighting_up R_IOPORT_PinWrite(&g_ioport_ctrl,LED3,BSP_IO_LEVEL_HIGH)
static int led_state1 = 0;
static int led_state2 = 0;
static int led_state3 = 0;
void led1_on(void)
{
LED1_lighting_up;
led_state1 = 1;
}
void led1_off(void)
{
LED1_lighting_off;
led_state1 = 0;
}
void led2_on(void)
{
LED2_lighting_up;
led_state2 = 1;
}
void led2_off(void)
{
LED2_lighting_off;
led_state2 = 0;
}
void led3_on(void)
{
LED3_lighting_up;
led_state3 = 1;
}
void led3_off(void)
{
LED3_lighting_off;
led_state3 = 0;
}
int get_led1_status(void)
{
return led_state1;
}
int get_led2_status(void)
{
return led_state2;
}
int get_led3_status(void)
{
return led_state3;
}
uint8_t HAL_GPIO_ReadPin1(void)
{
bsp_io_level_t p_port_value_port_005;
uint8_t result = 0;
R_IOPORT_PinRead(&g_ioport_ctrl, BSP_IO_PORT_00_PIN_05, &p_port_value_port_005);
if(p_port_value_port_005) result = 1;
else result = 0;
return result;
}
#if 1
/* 重定向 printf 输出 */
#if defined GNUC && !defined clang
int _write(int fd, char *pBuffer, int size); //防止编译警告
int _write(int fd, char *pBuffer, int size)
{
(void)fd;
R_SCI_UART_Write(&g_uart9_ctrl, (uint8_t *)pBuffer, (uint32_t)size);
while(uart_send_complete_flag == false);
uart_send_complete_flag = false;
return size;
}
#else
int fputc(int ch, FILE *f)
{
(void)f;
R_SCI_UART_Write(&g_uart9_ctrl, (uint8_t *)&ch, 1);
while(uart_send_complete_flag == false);
uart_send_complete_flag = false;
return ch;
}
#endif
#endif
volatile uint32_t g_tick_count = 0;
volatile uint32_t g_tfime_ms = 0;
volatile uint32_t g_tfime_5ms = 0;
void hal_systick_init(void)
{
SysTick_Config(SystemCoreClock / TICKS_PER_SECONDS);
}
void SysTick_Handler(void)
{
g_tick_count += 1;
g_tfime_ms++;
g_tfime_5ms++;
if(g_tfime_5ms == 5)
{
g_tfime_5ms = 0;
//SerialTimer();
}
if(g_tfime_ms == 20)
{
g_tfime_ms = 0;
ebtn_APP_Key_Process();
}
}
uint32_t hal_systick_get(void)
{
return g_tick_count;
}
uint32_t HAL_GetTick(void)
{
return g_tick_count;
}
void HAL_Delay(uint32_t Delay)
{
#define HAL_MAX_DELAY 0xFFFFFFFFU
uint32_t tickstart = hal_systick_get();
uint32_t wait = Delay;
/* Add a freq to guarantee minimum wait */
if (wait < HAL_MAX_DELAY)
{
wait++;
}
while ((hal_systick_get() - tickstart) < wait)
{
}
}
#include <string.h>
#include "ebtn.h"
#define EBTN_FLAG_ONPRESS_SENT ((uint8_t)0x01) /*!< Flag indicates that on-press event has been sent /
#define EBTN_FLAG_IN_PROCESS ((uint8_t)0x02) /!< Flag indicates that button in process */
/* Default button group instance */
static ebtn_t ebtn_default;
/**
-
\brief Process the button information and state
-
\param[in] btn: Button instance to process
-
\param[in] old_state: old state
-
\param[in] new_state: new state
-
\param[in] mstime: Current milliseconds system time
*/
static void prv_process_btn(ebtn_btn_t *btn, uint8_t old_state, uint8_t new_state, ebtn_time_t mstime)
{
ebtn_t *ebtobj = &ebtn_default;
/* Check params set or not. */
if (btn->param == NULL)
{
return;
}
/* Button state has just changed */
if (new_state != old_state)
{
btn->time_state_change = mstime;
if (new_state)
{
btn->flags |= EBTN_FLAG_IN_PROCESS;
}
}
/* Button is still pressed /
if (new_state)
{
/
- Handle debounce and send on-press event
- This is when we detect valid press
/
if (!(btn->flags & EBTN_FLAG_ONPRESS_SENT))
{
/
- Run if statement when:
-
- Runtime mode is enabled -> user sets its own config for debounce
-
- Config debounce time for press is more than
0
/
if (ebtn_timer_sub(mstime, btn->time_state_change) >= btn->param->time_debounce)
{
/
- Check mutlti click limit reach or not.
*/
if ((btn->click_cnt > 0) && (ebtn_timer_sub(mstime, btn->click_last_time) >= btn->param->time_click_multi_max))
{
if (btn->event_mask & EBTN_EVT_MASK_ONCLICK)
{
ebtobj->evt_fn(btn, EBTN_EVT_ONCLICK);
}
btn->click_cnt = 0;
}
btn->keepalive_last_time = mstime;
btn->keepalive_cnt = 0;
btn->flags |= EBTN_FLAG_ONPRESS_SENT;
if (btn->event_mask & EBTN_EVT_MASK_ONPRESS)
{
ebtobj->evt_fn(btn, EBTN_EVT_ONPRESS);
}
btn->time_change = mstime;
}
}
else
{
while ((btn->param->time_keepalive_period > 0) && (ebtn_timer_sub(mstime, btn->keepalive_last_time) >= btn->param->time_keepalive_period))
{
btn->keepalive_last_time += btn->param->time_keepalive_period;
++btn->keepalive_cnt;
if (btn->event_mask & EBTN_EVT_MASK_KEEPALIVE)
{
ebtobj->evt_fn(btn, EBTN_EVT_KEEPALIVE);
}
}
if ((btn->click_cnt > 0) && (ebtn_timer_sub(mstime, btn->time_change) > btn->param->time_click_pressed_max))
{
if (btn->event_mask & EBTN_EVT_MASK_ONCLICK)
{
ebtobj->evt_fn(btn, EBTN_EVT_ONCLICK);
}
btn->click_cnt = 0;
}
}
}
/* Button is still released /
else
{
/
- We only need to react if on-press event has even been started.
- Do nothing if that was not the case
/
if (btn->flags & EBTN_FLAG_ONPRESS_SENT)
{
/
- Run if statement when:
-
- Runtime mode is enabled -> user sets its own config for debounce
-
- Config debounce time for release is more than
0
/
if (ebtn_timer_sub(mstime, btn->time_state_change) >= btn->param->time_debounce_release)
{
/ Handle on-release event */
btn->flags &= ~EBTN_FLAG_ONPRESS_SENT;
if (btn->event_mask & EBTN_EVT_MASK_ONRELEASE)
{
ebtobj->evt_fn(btn, EBTN_EVT_ONRELEASE);
}
if (ebtn_timer_sub(mstime, btn->time_change) >= btn->param->time_click_pressed_min &&
ebtn_timer_sub(mstime, btn->time_change) <= btn->param->time_click_pressed_max)
{
++btn->click_cnt;
btn->click_last_time = mstime;
}
else
{
if ((btn->click_cnt > 0) && (ebtn_timer_sub(mstime, btn->time_change) < btn->param->time_click_pressed_min))
{
if (btn->event_mask & EBTN_EVT_MASK_ONCLICK)
{
ebtobj->evt_fn(btn, EBTN_EVT_ONCLICK);
}
}
btn->click_cnt = 0;
}
if ((btn->click_cnt > 0) && (btn->click_cnt == btn->param->max_consecutive))
{
if (btn->event_mask & EBTN_EVT_MASK_ONCLICK)
{
ebtobj->evt_fn(btn, EBTN_EVT_ONCLICK);
}
btn->click_cnt = 0;
}
btn->time_change = mstime;
}
}
else
{
if (btn->click_cnt > 0)
{
if (ebtn_timer_sub(mstime, btn->click_last_time) >= btn->param->time_click_multi_max)
{
if (btn->event_mask & EBTN_EVT_MASK_ONCLICK)
{
ebtobj->evt_fn(btn, EBTN_EVT_ONCLICK);
}
btn->click_cnt = 0;
}
}
else
{
if (btn->flags & EBTN_FLAG_IN_PROCESS)
{
btn->flags &= ~EBTN_FLAG_IN_PROCESS;
}
}
}
}
}
int ebtn_init(ebtn_btn_t *btns, uint16_t btns_cnt, ebtn_btn_combo_t *btns_combo, uint16_t btns_combo_cnt, ebtn_get_state_fn get_state_fn, ebtn_evt_fn evt_fn)
{
ebtn_t *ebtobj = &ebtn_default;
if (evt_fn == NULL || get_state_fn == NULL
)
{
return 0;
}
memset(ebtobj, 0x00, sizeof(*ebtobj));
ebtobj->btns = btns;
ebtobj->btns_cnt = btns_cnt;
ebtobj->btns_combo = btns_combo;
ebtobj->btns_combo_cnt = btns_combo_cnt;
ebtobj->evt_fn = evt_fn;
ebtobj->get_state_fn = get_state_fn;
return 1;
}
/**
-
\brief Get all button state with get_state_fn.
-
\param[out] state_array: store the button state
*/
static void ebtn_get_current_state(bit_array_t *state_array)
{
ebtn_t *ebtobj = &ebtn_default;
ebtn_btn_dyn_t *target;
int i;
/* Process all buttons /
for (i = 0; i < ebtobj->btns_cnt; ++i)
{
/ Get button state */
uint8_t new_state = ebtobj->get_state_fn(&ebtobj->btns[i]);
// save state
bit_array_assign(state_array, i, new_state);
}
for (target = ebtobj->btn_dyn_head, i = ebtobj->btns_cnt; target; target = target->next, i++)
{
/* Get button state */
uint8_t new_state = ebtobj->get_state_fn(&target->btn);
bit_array_assign(state_array, i, new_state);
}
}
/**
- \brief Process the button state
- \param[in] btn: Button instance to process
- \param[in] old_state: all button old state
- \param[in] curr_state: all button current state
- \param[in] idx: Button internal key_idx
- \param[in] mstime: Current milliseconds system time
*/
static void ebtn_process_btn(ebtn_btn_t *btn, bit_array_t *old_state, bit_array_t *curr_state, int idx, ebtn_time_t mstime)
{
prv_process_btn(btn, bit_array_get(old_state, idx), bit_array_get(curr_state, idx), mstime);
}
/**
-
\brief Process the combo-button state
-
\param[in] btn: Button instance to process
-
\param[in] old_state: all button old state
-
\param[in] curr_state: all button current state
-
\param[in] comb_key: Combo key
-
\param[in] mstime: Current milliseconds system time
*/
static void ebtn_process_btn_combo(ebtn_btn_t *btn, bit_array_t *old_state, bit_array_t *curr_state, bit_array_t *comb_key, ebtn_time_t mstime)
{
BIT_ARRAY_DEFINE(tmp_data, EBTN_MAX_KEYNUM) = {0};
if (bit_array_num_bits_set(comb_key, EBTN_MAX_KEYNUM) == 0)
{
return;
}
bit_array_and(tmp_data, curr_state, comb_key, EBTN_MAX_KEYNUM);
uint8_t curr = bit_array_cmp(tmp_data, comb_key, EBTN_MAX_KEYNUM) == 0;
bit_array_and(tmp_data, old_state, comb_key, EBTN_MAX_KEYNUM);
uint8_t old = bit_array_cmp(tmp_data, comb_key, EBTN_MAX_KEYNUM) == 0;
prv_process_btn(btn, old, curr, mstime);
}
void ebtn_process_with_curr_state(bit_array_t *curr_state, ebtn_time_t mstime)
{
ebtn_t *ebtobj = &ebtn_default;
ebtn_btn_dyn_t *target;
ebtn_btn_combo_dyn_t *target_combo;
int i;
for (i = 0; i < ebtobj->btns_cnt; ++i)
{
ebtn_process_btn(&ebtobj->btns[i], ebtobj->old_state, curr_state, i, mstime);
}
for (target = ebtobj->btn_dyn_head, i = ebtobj->btns_cnt; target; target = target->next, i++)
{
ebtn_process_btn(&target->btn, ebtobj->old_state, curr_state, i, mstime);
}
for (i = 0; i < ebtobj->btns_combo_cnt; ++i)
{
ebtn_process_btn_combo(&ebtobj->btns_combo[i].btn, ebtobj->old_state, curr_state, ebtobj->btns_combo[i].comb_key, mstime);
}
for (target_combo = ebtobj->btn_combo_dyn_head; target_combo; target_combo = target_combo->next)
{
ebtn_process_btn_combo(&target_combo->btn.btn, ebtobj->old_state, curr_state, target_combo->btn.comb_key, mstime);
}
bit_array_copy_all(ebtobj->old_state, curr_state, EBTN_MAX_KEYNUM);
}
void ebtn_process(ebtn_time_t mstime)
{
BIT_ARRAY_DEFINE(curr_state, EBTN_MAX_KEYNUM) = {0};
ebtn_get_current_state(curr_state);
ebtn_process_with_curr_state(curr_state, mstime);
}
int ebtn_get_total_btn_cnt(void)
{
ebtn_t *ebtobj = &ebtn_default;
int total_cnt = 0;
ebtn_btn_dyn_t *curr = ebtobj->btn_dyn_head;
total_cnt += ebtobj->btns_cnt;
while (curr)
{
total_cnt++;
curr = curr->next;
}
return total_cnt;
}
int ebtn_get_btn_index_by_key_id(uint16_t key_id)
{
ebtn_t *ebtobj = &ebtn_default;
int i = 0;
ebtn_btn_dyn_t *target;
for (i = 0; i < ebtobj->btns_cnt; ++i)
{
if (ebtobj->btns[i].key_id == key_id)
{
return i;
}
}
for (target = ebtobj->btn_dyn_head, i = ebtobj->btns_cnt; target; target = target->next, i++)
{
if (target->btn.key_id == key_id)
{
return i;
}
}
return -1;
}
ebtn_btn_t *ebtn_get_btn_by_key_id(uint16_t key_id)
{
ebtn_t *ebtobj = &ebtn_default;
int i = 0;
ebtn_btn_dyn_t *target;
for (i = 0; i < ebtobj->btns_cnt; ++i)
{
if (ebtobj->btns[i].key_id == key_id)
{
return &ebtobj->btns[i];
}
}
for (target = ebtobj->btn_dyn_head, i = ebtobj->btns_cnt; target; target = target->next, i++)
{
if (target->btn.key_id == key_id)
{
return &target->btn;
}
}
return NULL;
}
int ebtn_get_btn_index_by_btn(ebtn_btn_t *btn)
{
return ebtn_get_btn_index_by_key_id(btn->key_id);
}
int ebtn_get_btn_index_by_btn_dyn(ebtn_btn_dyn_t *btn)
{
return ebtn_get_btn_index_by_key_id(btn->btn.key_id);
}
void ebtn_combo_btn_add_btn_by_idx(ebtn_btn_combo_t *btn, int idx)
{
bit_array_set(btn->comb_key, idx);
}
void ebtn_combo_btn_remove_btn_by_idx(ebtn_btn_combo_t *btn, int idx)
{
bit_array_clear(btn->comb_key, idx);
}
void ebtn_combo_btn_add_btn(ebtn_btn_combo_t *btn, uint16_t key_id)
{
int idx = ebtn_get_btn_index_by_key_id(key_id);
if (idx < 0)
{
return;
}
ebtn_combo_btn_add_btn_by_idx(btn, idx);
}
void ebtn_combo_btn_remove_btn(ebtn_btn_combo_t *btn, uint16_t key_id)
{
int idx = ebtn_get_btn_index_by_key_id(key_id);
if (idx < 0)
{
return;
}
ebtn_combo_btn_remove_btn_by_idx(btn, idx);
}
int ebtn_is_btn_active(const ebtn_btn_t *btn)
{
return btn != NULL && (btn->flags & EBTN_FLAG_ONPRESS_SENT);
}
int ebtn_is_btn_in_process(const ebtn_btn_t *btn)
{
return btn != NULL && (btn->flags & EBTN_FLAG_IN_PROCESS);
}
int ebtn_is_in_process(void)
{
ebtn_t *ebtobj = &ebtn_default;
ebtn_btn_dyn_t *target;
ebtn_btn_combo_dyn_t *target_combo;
int i;
for (i = 0; i < ebtobj->btns_cnt; ++i)
{
if (ebtn_is_btn_in_process(&ebtobj->btns[i]))
{
return 1;
}
}
for (target = ebtobj->btn_dyn_head, i = ebtobj->btns_cnt; target; target = target->next, i++)
{
if (ebtn_is_btn_in_process(&target->btn))
{
return 1;
}
}
for (i = 0; i < ebtobj->btns_combo_cnt; ++i)
{
if (ebtn_is_btn_in_process(&ebtobj->btns_combo[i].btn))
{
return 1;
}
}
for (target_combo = ebtobj->btn_combo_dyn_head; target_combo; target_combo = target_combo->next)
{
if (ebtn_is_btn_in_process(&target_combo->btn.btn))
{
return 1;
}
}
return 0;
}
int ebtn_register(ebtn_btn_dyn_t *button)
{
ebtn_t *ebtobj = &ebtn_default;
ebtn_btn_dyn_t *curr = ebtobj->btn_dyn_head;
ebtn_btn_dyn_t *last = NULL;
if (!button)
{
return 0;
}
if (ebtn_get_total_btn_cnt() >= EBTN_MAX_KEYNUM)
{
return 0;
}
if (curr == NULL)
{
ebtobj->btn_dyn_head = button;
return 1;
}
while (curr)
{
if (curr == button)
{
return 0;
}
last = curr;
curr = curr->next;
}
last->next = button;
return 1;
}
int ebtn_combo_register(ebtn_btn_combo_dyn_t *button)
{
ebtn_t *ebtobj = &ebtn_default;
ebtn_btn_combo_dyn_t *curr = ebtobj->btn_combo_dyn_head;
ebtn_btn_combo_dyn_t *last = NULL;
if (!button)
{
return 0;
}
if (curr == NULL)
{
ebtobj->btn_combo_dyn_head = button;
return 1;
}
while (curr)
{
if (curr == button)
{
return 0;
}
last = curr;
curr = curr->next;
}
last->next = button;
return 1;
}
/* -------------------------------- 初始化和处理函数 -------------------------------- */
/** ***************************************************************************
-
[url=home.php?mod=space&uid=2666770]@Brief[/url] easy_button初始化,在主函数中调用
-
[url=home.php?mod=space&uid=1902110]@NOTE[/url] 如果使用组合键,则需要在ebtn_init之后调用ebtn_combo_btn_add_btn添加组合键
*/
void ebtn_APP_Key_INIT(void)
{
// 初始化easy_button库
ebtn_init(btn_array, btn_array_size,
btn_combo_array, btn_combo_array_size,
ebtn_Get_State, ebtn_Event_Handler);
/* ---------------------------- 此处向组合键结构体数组静态添加按键 --------------------------- */
// 结构体数组索引值与ebtn_custom_config.c中组合键结构体数组btn_combo_array中的索引值一致
// 示例:四个组合键
// 为组合键1添加按键KEY_1和KEY_2
ebtn_combo_btn_add_btn(&btn_combo_array[0], KEY_1);
ebtn_combo_btn_add_btn(&btn_combo_array[0], KEY_2);
// // 为组合键2添加按键KEY_3和KEY_4
ebtn_combo_btn_add_btn(&btn_combo_array[1], KEY_3);
ebtn_combo_btn_add_btn(&btn_combo_array[1], KEY_4);
// // 为组合键3添加按键KEY_1和KEY_3
ebtn_combo_btn_add_btn(&btn_combo_array[2], KEY_1);
ebtn_combo_btn_add_btn(&btn_combo_array[2], KEY_3);
// // 为组合键4添加按键KEY_2和KEY_4
ebtn_combo_btn_add_btn(&btn_combo_array[3], KEY_2);
ebtn_combo_btn_add_btn(&btn_combo_array[3], KEY_4);
}
/* --------------------------------- 自定义配置部分结束 -------------------------------- */
/** ***************************************************************************
- @brief 处理按键事件,需要定期调用,建议以20ms为周期执行一次
- @note Tick时基为1ms
*/
void ebtn_APP_Key_Process(void)
{
ebtn_process(ebtn_custom_hal.Get_Tick()); // 获取时间处理按键事件
}
/* -------------------------------- 辅助部分 ------------------------------- */
/** ***************************************************************************
- @brief 检查按键是否激活
- [url=home.php?mod=space&uid=3142012]@param[/url] key_id: 按键ID
- [url=home.php?mod=space&uid=1141835]@Return[/url] uint8_t: 1-激活,0-未激活
*/
uint8_t ebtn_APP_Is_Key_Active(uint16_t key_id)
{
ebtn_btn_t *btn = ebtn_get_btn_by_key_id(key_id);
return ebtn_is_btn_active(btn);
}
/** ***************************************************************************
- @brief 检查是否有按键处于处理中
- @return uint8_t: 1-有按键处理中,0-无按键处理中
*/
uint8_t ebtn_APP_Is_Any_Key_In_Process(void)
{
return ebtn_is_in_process();
}
/** ***************************************************************************
-
@brief 获取指定按键的按键状态
-
@param key_id: 按键ID
-
@return uint8_t: 1-按下,0-松开
*/
uint8_t ebtn_APP_Get_Key_State(uint16_t key_id)
{
ebtn_btn_t *btn = ebtn_get_btn_by_key_id(key_id);
if (btn == NULL)
{
return 0;
}
return ebtn_Get_State(btn);
}
#include "ebtn_custom_callback.h"
volatile uint8_t key_count = 0;
/* ---------------------------- 此函数中可自定义按键状态检测方式 ---------------------------- */
/** ***************************************************************************
-
@brief 获取按键状态回调函数
-
此函数默认采用了查表检测,免去需要手动为每个按键添加检测方式
-
也可为特殊按键自定义检测方法
-
@note 查表检测需要配合ebtn_custom_config.c中的按键配置结构体数组使用
-
@param btn: easy_button按键结构体指针
-
@return 按键状态,0表示未按下,1表示按下
*/
uint8_t ebtn_Get_State(struct ebtn_btn *btn)
{
// 查表法检测
for (int i = 0; i < key_list_size; i++)
{
if (key_list[i].key_id == btn->key_id)
{
uint8_t pin_state = ebtn_custom_hal.Read_Pin(key_list[i].gpio_port, key_list[i].gpio_pin);
// 根据有效电平转换
if (key_list[i].active_level == pin_state)
{
pin_state = 1;
}
else
{
pin_state = 0;
}
return pin_state;
}
}
/* ----------------------------- 此处可自定义按键状态获取方式 ----------------------------- */
// 可自定义特殊按键的检测方式,如矩阵按键的检测
return 0; // 未找到按键ID,返回0
}
/* ------------------------------- 此函数可修改按键触发事件 ------------------------------- */
/** ***************************************************************************
-
@brief 按键事件处理回调函数,在此定义按键触发事件
-
推荐将不同按键或事件的处理逻辑拆分为独立的函数,并参考原有的 switch(ebtn->key) 结构,
-
在对应按键编号的 case 分支中调用相应的处理函数,以提升代码的可读性和可维护性
-
@param btn: easy_button按键结构体指针
-
@param evt: 事件类型
*/
void ebtn_Event_Handler(struct ebtn_btn btn, ebtn_evt_t evt)
{
switch (btn->key_id) // 按键ID
{
/ ---------------------------------- KEY1 ---------------------------------- /
case KEY_1:
/ ---------------------------------- 按下按键时 --------------------------------- /
if (evt == EBTN_EVT_ONPRESS)
{
}
/ ---------------------------------- 松开按键时 --------------------------------- /
else if (evt == EBTN_EVT_ONRELEASE)
{
}
/ ----------------------------- 短按按键时(可获取连击次数) ----------------------------- /
else if (evt == EBTN_EVT_ONCLICK)
{
/ ----------------------------------- 单击时 ---------------------------------- */
if (btn->click_cnt == 1)
{
printf("KEY_1 单击\r\n");
key_count++;
if(key_count>=7)key_count=0;
}
else if (btn->click_cnt == 2)
{
printf("KEY_1 双击\r\n");
key_count += 2;
if(key_count>=7)key_count=0;
}
else if (btn->click_cnt == 3)
{
printf("KEY_1 三击\r\n");
key_count += 3;
if(key_count>=7)key_count=0;
}
}
else if (evt == EBTN_EVT_KEEPALIVE)
{
if (btn->keepalive_cnt == 1)
{
key_count++;if(key_count>=7)key_count=0;
printf("KEY_1 长按\r\n");
}
}
break;
case KEY_2:
/* ---------------------------------- 按下按键时 --------------------------------- */
if (evt == EBTN_EVT_ONPRESS)
{
}
else if (evt == EBTN_EVT_ONRELEASE)
{
}
else if (evt == EBTN_EVT_ONCLICK)
{
if (btn->click_cnt == 1)
{
printf("KEY_2 单击\r\n");
key_count--;
if(key_count==0)key_count=0;
}
else if (btn->click_cnt == 2)
{
printf("KEY_2 双击\r\n");
key_count -= 2;
if(key_count==0)key_count=0;
}
else if (btn->click_cnt == 3)
{
printf("KEY_2 三击\r\n");
key_count -= 3;
if(key_count==0)key_count=0;
}
}
else if (evt == EBTN_EVT_KEEPALIVE)
{
if (btn->keepalive_cnt == 1)
{
printf("KEY_2 长按\r\n");
key_count--;
if(key_count==0)key_count=0;
}
}
break;
case COMBO_KEY_1:
/* ---------------------------------- 按下按键时 --------------------------------- /
if (evt == EBTN_EVT_ONPRESS)
{
printf("按组合按键KEY1 KEY2 \r\n");
}
/ ---------------------------------- 松开按键时 --------------------------------- */
else if (evt == EBTN_EVT_ONRELEASE)
{
//printf("松开KEY_1 和 KEY_2 组合按键\r\n");
}
break;
case COMBO_KEY_2:
/* ---------------------------------- 按下按键时 --------------------------------- /
if (evt == EBTN_EVT_ONPRESS)
{
}
/ ---------------------------------- 松开按键时 --------------------------------- */
else if (evt == EBTN_EVT_ONRELEASE)
{
}
break;
case COMBO_KEY_3:
/* ---------------------------------- 按下按键时 --------------------------------- /
if (evt == EBTN_EVT_ONPRESS)
{
}
/ ---------------------------------- 松开按键时 --------------------------------- */
else if (evt == EBTN_EVT_ONRELEASE)
{
}
break;
case COMBO_KEY_4:
/* ---------------------------------- 按下按键时 --------------------------------- /
if (evt == EBTN_EVT_ONPRESS)
{
}
/ ---------------------------------- 松开按键时 --------------------------------- */
else if (evt == EBTN_EVT_ONRELEASE)
{
}
break;
}
}
#include "ebtn_custom_config.h"
/** ***************************************************************************
- @brief 定义按键参数结构体
- [url=home.php?mod=space&uid=1352397]@ref[/url] ebtn_Custom_x.h
*/
ebtn_btn_param_t buttons_parameters = EBTN_PARAMS_INIT(
DEBOUNCE_TIME, // 按下防抖超时
RELEASE_DEBOUNCE_TIME, // 松开防抖超时
CLICK_AND_PRESS_MIN_TIME, // 按键最短时间
CLICK_AND_PRESS_MAX_TIME, // 按键最长时间
MULTI_CLICK_MAX_TIME, // 连续点击最大间隔(ms)
KEEPALIVE_TIME_PERIOD, // 长按报告事件间隔(ms)
MAX_CLICK_COUNT // 最大连续点击次数
);
/* --------------------------------- 此处修改按键 --------------------------------- */
// 所需的按键ID定义在ebtn_custom_config.h中增添
/** ***************************************************************************
- @brief 按键列表结构体数组,用于将按键ID与GPIO引脚以及触发电平进行绑定,
- 同时使用查表检测,免去需要为每个按键手动添加检测方式
- @note 此处填入所需的按键ID及其GPIO信息和触发时电平
*/
ebtn_custom_config_key_list_t key_list[] = {
// 示例:4个按键// KEY_4按键,PB12,低电平有效
};
/** ***************************************************************************
- @brief 按键结构体数组,用于将按键ID与按键参数进行绑定
- @note 此为静态注册方法,动态注册详见easy_button库Github仓库
*/
ebtn_btn_t btn_array[] = {
EBTN_BUTTON_INIT(KEY_1, &buttons_parameters),
EBTN_BUTTON_INIT(KEY_2, &buttons_parameters),
EBTN_BUTTON_INIT(KEY_3, &buttons_parameters),
EBTN_BUTTON_INIT(KEY_4, &buttons_parameters),
};
/** ***************************************************************************
- @brief 组合键结构体数组,用于将多个按键组合成一个按键进行事件判断
- @note 此为静态注册方法,动态注册详见easy_button库Github仓库
- @note 需要在ebtn_app.c的ebtn_APP_Key_INIT函数中使用ebtn_Combo_btn_add_btn向组合键结构体数组添加对应按键
- 其中结构体数组索引与此处结构体数组的索引顺序一致,详见ebtn_app.c
*/
ebtn_btn_combo_t btn_combo_array[] = {
EBTN_BUTTON_COMBO_INIT(COMBO_KEY_1, &buttons_parameters),
EBTN_BUTTON_COMBO_INIT(COMBO_KEY_2, &buttons_parameters),
EBTN_BUTTON_COMBO_INIT(COMBO_KEY_3, &buttons_parameters),
EBTN_BUTTON_COMBO_INIT(COMBO_KEY_4, &buttons_parameters),
};
/* -------------------------------- 自定义配置部分结束 ------------------------------- */
const uint8_t btn_array_size = EBTN_ARRAY_SIZE(btn_array);
const uint8_t btn_combo_array_size = EBTN_ARRAY_SIZE(btn_combo_array);
const uint8_t key_list_size = EBTN_ARRAY_SIZE(key_list);
#include "ebtn_custom_hal.h"
/* ------------------------------ 此处实现硬件抽象回调函数 ------------------------------ */
/** ***************************************************************************
-
@brief 读取GPIO电平,在ebtn_app.c中被使用,用于读取按键引脚的电平
-
@param GPIOx 指向GPIO端口的指针
-
@param GPIO_Pin GPIO引脚号
-
@return GPIO引脚的电平状态(0/1)
*/
uint8_t ebtn_HAL_Read_Pin(ioport_ctrl_t * const p_ctrl, bsp_io_port_pin_t pin)
{
bsp_io_level_t p_port_value_port;
R_IOPORT_PinRead(p_ctrl, pin, &p_port_value_port);
}
/** ***************************************************************************
-
@brief 获取系统滴答计数器值,用于为ebtn_process()函数提供时间基准
-
@note SysTick时基为1ms
-
@return 系统滴答计数器ms时间值
*/
uint32_t ebtn_HAL_Get_Tick(void)
{
return HAL_GetTick(); // 示例:STM32HAL库
}
/* -------------------------------- 自定义配置部分结束 ------------------------------- */
/** ***************************************************************************
- @brief ebtn_Custom回调函数结构体实例化
*/
ebtn_custom_hal_t ebtn_custom_hal = {
.Read_Pin = ebtn_HAL_Read_Pin,
.Get_Tick = ebtn_HAL_Get_Tick,
};
主函数添加核心代码
#include "hal_data.h"
#include "usart9.h"
#include "ebtn_app.h"
FSP_CPP_HEADER
void R_BSP_WarmStart(bsp_warm_start_event_t event);
FSP_CPP_FOOTER
/*******************************************************************************************************************//**
-
main() is generated by the RA Configuration editor and is used to generate threads if an RTOS is used. This function
-
is called by main() when no RTOS is used.
*********************************************************************************************************************/
void hal_entry(void)
{
/ TODO: add your own code here */
UART9_Init();
hal_systick_init();
ebtn_APP_Key_INIT();
while(1)
{
switch(key_count)
{
case 1:
led2_off();led3_off();
led1_on();HAL_Delay(200);
led1_off();HAL_Delay(200);
break;
case 2:
led1_off();led3_off();
led2_on();HAL_Delay(200);
led2_off();HAL_Delay(200);
break;
case 3:
led1_off();led2_off();
led3_on();HAL_Delay(200);
led3_off();HAL_Delay(200);
break;
case 4:
led1_on();led2_on();led3_on();HAL_Delay(200);
led1_off();led2_off();led3_off();HAL_Delay(200);
break;
case 5:
led1_on();led2_off();led3_on();HAL_Delay(200);
led1_off();led2_on();led3_off();HAL_Delay(200);
break;
case 6:
led1_on();led2_on();led3_on();
break;
default:
led1_off();led2_off();led3_off();
break;
}
}
#if BSP_TZ_SECURE_BUILD
/* Enter non-secure code */
R_BSP_NonSecureEnter();
#endif
}
/*******************************************************************************************************************//**
-
This function is called at various points during the startup process. This implementation uses the event that is
-
called right before main() to set up the pins.
-
@param[in] event Where at in the start up process the code is currently at
**********************************************************************************************************************/
void R_BSP_WarmStart (bsp_warm_start_event_t event)
{
if (BSP_WARM_START_RESET == event)
{
#if BSP_FEATURE_FLASH_LP_VERSION != 0
R_FACI_LP->DFLCTL = 1U;
#endif
}
if (BSP_WARM_START_POST_C == event)
{
R_IOPORT_Open(&IOPORT_CFG_CTRL, &IOPORT_CFG_NAME);
#if BSP_CFG_SDRAM_ENABLED
R_BSP_SdramInit(true);
#endif
}
}
#if BSP_TZ_SECURE_BUILD
FSP_CPP_HEADER
BSP_CMSE_NONSECURE_ENTRY void template_nonsecure_callable ();
/* Trustzone Secure Projects require at least one nonsecure callable function in order to build (Remove this if it is not required to build). */
BSP_CMSE_NONSECURE_ENTRY void template_nonsecure_callable ()
{
}
FSP_CPP_FOOTER
#endif

编译烧录代码到RA6M4板子

打开串口助手

可以看到实现了
KEY1的单击,双击,三击,长按
KEY2的单击,双击,三击,长按
KEY1和KEY2的组合按键
功能已经非常齐全,达到了第一水平!!!!!!
附件是烧录的hex文件,直接烧录,即可查看KEY1和KEY2效果
*附件:RA6M4_Button.zip