Button and Code Transmission User Guide
Button and RF Code Transmission Guide*
This document mainly introduces how to use button operations on the 8002 and how to use GPIO to simulate the wireless 433M RF protocol for communication.
FlexibleButton is a compact and flexible button processing library based on standard C language. It supports single click, repeated click, short press, long press, automatic debouncing, and allows free configuration of combination buttons. It can be used in interrupt and low-power scenarios. To adapt to the 8002 low-power scenario and the use of combination keys, it has been re-wrapped for ease of use.
Directory Structure*
remote_control
├── app.mk
├── app.name
├── BUTTON.md
├── flexible_button.c
├── flexible_button.h
├── Kconfig
├── lvp_app_remote_control.c
├── lvp_button.c
├── lvp_button.h
└── ReadMe
-
Related File Introduction
-
flexible_button.c,flexible_button.hare the source code of the standard C language button library. Open Source Address -
lvp_button.c,lvp_button.hare the re-wrapped implementations for using theflexible_buttonunder Lvp low-power scenarios. -
lvp_app_remote_control.cis the APP application.
Button Related Usage Interfaces*
To use lvp_button.c, simply define the following three steps in the APP application.
Step 1: Define the required GPIO pins.
static GX_BUTTON_CONFIG btn_table[] = {
/* Button GPIO Button Name Active Level Long Press Longer Press Longest Press */
{3, "KEY1", 0, 1000, 3000, 7000},
{4, "KEY2", 0, 1000, 3000, 7000},
};
Step 2: Define the button event callback.
static int button_state = 0; // 0 means no button pressed, 1 means KEY1 single click, 2 means KEY2 double click, 3 means KEY1 and KEY2 pressed simultaneously. Redefine according to the project.
static void common_btn_evt_cb(void *arg)
{
// This callback is within an interrupt, so do not perform time-consuming actions
GX_BUTTON_STATE *btn_event = (GX_BUTTON_STATE *)arg;
printf("combination = %d, id_1 = %d, id_2 = %d, event = %s\n", btn_event->combination_button, btn_event->id_1, btn_event->id_2, enum_event_string[btn_event->event]);
// KEY1 single click event
if ((btn_event->id_1 == 3) && (btn_event->combination_button == 0) && (btn_event->event == FLEX_BTN_PRESS_CLICK)) {
button_state = 1;
}
// KEY2 double click event
if ((btn_event->id_1 == 4) && (btn_event->combination_button == 0) && (btn_event->event == FLEX_BTN_PRESS_DOUBLE_CLICK
)) {
button_state = 2;
}
// KEY1 and KEY2 pressed simultaneously
if ((btn_event->id_1 == 3 && btn_event->id_2 == 4) && (btn_event->combination_button == 1) && (btn_event->event == FLEX_BTN_PRESS_DOWN)) {
button_state = 3;
}
}
Step 3: Initialize the buttons. Note: Since a timer is used, the button initialization must be called every time after recovering from low-power mode.
lvp_button_init(btn_table, ARRAY_SIZE(btn_table), common_btn_evt_cb);
Explanation of btn_event
Each callback trigger will have a corresponding button event.
typedef struct button_state {
int combination_button; // If 1, it represents a combination button (currently only supports two-button combinations). Then both id_1 and id_2 below are valid. If 0, it represents a single button, only id_1 is valid.
unsigned char id_1;
unsigned char id_2;
unsigned char event; // CLICK, SHORT_START, LONG_START, LONG_HOLD_UP
}GX_BUTTON_STATE;
Event table. All button event triggers will generate the following events, such as press, click, double click, long press, etc.
typedef enum
{
FLEX_BTN_PRESS_DOWN = 0, // Press down event
FLEX_BTN_PRESS_CLICK, // Single click event
FLEX_BTN_PRESS_DOUBLE_CLICK, // Double click event
FLEX_BTN_PRESS_REPEAT_CLICK, // Repeat click event, use click_cnt in flex_button_t to determine the number of clicks
FLEX_BTN_PRESS_SHORT_START, // Short press start event
FLEX_BTN_PRESS_SHORT_UP, // Short press release event
FLEX_BTN_PRESS_LONG_START, // Long press start event
FLEX_BTN_PRESS_LONG_UP, // Long press release event
FLEX_BTN_PRESS_LONG_HOLD, // Long press hold event
FLEX_BTN_PRESS_LONG_HOLD_UP, // Long press hold release event
FLEX_BTN_PRESS_MAX, // Maximum duration
FLEX_BTN_PRESS_NONE,
} flex_button_event_t;
About RF Code Transmission*
The code transmission protocol follows the wireless 433M RF communication method.
Head: H 4.8ms ; L 1.5ms
4.8ms
________________ ______
_____| |______|
1.5ms
Data0: H 360us ; L 720us
360us
__ ______
_____| |______|
720us
Data1: H 720us ; L 360us
720us
______ ______
_____| |__|
360us
Transmitter Data Composition Description
ALL data: 5bytes ID(4) + CMD(1)
LAST ID LOW 8 Bits IS CHANNEL 0≦ CHANNEL≦ 0xff
Encoding Definition Content
| Button Definition | Button Type | Key Value | Function |
|---|---|---|---|
| Up | Single Key | 0x88 | Up |
| Down | Single Key | 0xcc | Down |
- Code Transmission Related Interfaces
Address Code:
To avoid RF interference, each address is required to be unique. Therefore, the unique ID from the 8002 Flash is used, and after CRC32 validation, 20 bits are taken as the address code.
unsigned int rf_address = 0x00AEE471;
void getUniqueId(void)
{
unsigned char buf[16];
int ret_len;
gx_spinor_flash_init();
gx_spinor_flash_getuid(buf, 16 , &ret_len);
for (int j = 0; j < 16;j++) {
printf("%02X ", buf[j]);
}
printf("\n");
rf_address = crc32(0, buf, ret_len);
// return (((temp>>20)^temp)&0x000ffff);
}
- Code Transmission Protocol Implementation
Note: The commonly used delay interface gx_udelay has a fixed overhead time. As the delay time increases, the error gradually decreases; however, for precise delays, the error can be relatively large.
For more precise delays, please refer to: High-Precision Delay Usage Guide.
// Code transmission rules. Note: When transmitting, interrupts must be disabled, otherwise the timing error will be significant.
// This function should be re-implemented according to the specific project.
int rf_send_code(unsigned int code)
{
if(code == 0x00) return -1;
LvpAudioInSuspend();
while (gx_snpu_get_state() == GX_SNPU_BUSY);
uint32_t irq_state = gx_lock_irq_save();
gx_gpio_set_direction(RF_GPIO, GX_GPIO_DIRECTION_OUTPUT);
gx_gpio_set_level(RF_GPIO, GX_GPIO_LEVEL_LOW);
unsigned int send_code = code; // The address and data code to be sent
#ifdef DEBUG_PRINTF
printf("rf_address = %#x send_code = %#x\n",rf_address, send_code);
#endif
// rf_address = 0x00AEE471;
for(int j = 0;j < SEND_TIMES;j++){
// Send the preamble code
gx_gpio_set_level(RF_GPIO, GX_GPIO_LEVEL_HIGH);
gx_udelay(4720);
gx_gpio_set_level(RF_GPIO, GX_GPIO_LEVEL_LOW);
gx_udelay(1420);
// Send the address code
for(int i = 31;i >= 0;i--){
if(rf_address & (1 << i)){
gx_gpio_set_level(RF_GPIO, GX_GPIO_LEVEL_HIGH);
gx_udelay(640);
gx_gpio_set_level(RF_GPIO, GX_GPIO_LEVEL_LOW);
gx_udelay(280);
}else{
gx_gpio_set_level(RF_GPIO, GX_GPIO_LEVEL_HIGH);
gx_udelay(280);
gx_gpio_set_level(RF_GPIO, GX_GPIO_LEVEL_LOW);
gx_udelay(640);
}
}
for(int i = 0;i < 8;i++){
if(send_code & (1 << i)){
gx_gpio_set_level(RF_GPIO, GX_GPIO_LEVEL_HIGH);
gx_udelay(640);
gx_gpio_set_level(RF_GPIO, GX_GPIO_LEVEL_LOW);
gx_udelay(280);
}else{
gx_gpio_set_level(RF_GPIO, GX_GPIO_LEVEL_HIGH);
gx_udelay(280);
gx_gpio_set_level(RF_GPIO, GX_GPIO_LEVEL_LOW);
gx_udelay(640);
}
}
// Since interrupts are disabled, the button scanning timer is stopped. Therefore, the button scanning actions must be compensated based on the time spent transmitting, otherwise button presses during transmission may be lost.
flex_button_scan();
flex_button_scan();
flex_button_scan();
if (button_state != 0) // Indicates that a new button was triggered during transmission, so exit the current transmission and proceed to the next round.
{
printf("break send code irq %d, %d\n", j, button_state);
return 0;
}
}
gx_gpio_set_level(RF_GPIO, GX_GPIO_LEVEL_HIGH);
gx_gpio_set_level(RF_GPIO, GX_GPIO_LEVEL_LOW);
gx_unlock_irq_restore(irq_state);
LvpAudioInResume();
return 0;
}