打印
[活动]

极海半导体-G32A1465开发板测评 02-嵌入式开源组件Multi-Button移植测试

[复制链接]
159|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 lemonhub 于 2025-1-4 14:43 编辑

极海半导体-G32A1465开发板测评 02-嵌入式开源组件Multi-Button移植测试

准备目标硬件(开发板/芯片/模组)
本教程将使用极海G32A1465开发板进行示例移植。调试ARM Cortex M核还需要仿真器,如果您的开发板或者芯片模组没有板载仿真器,就需要连接外置的仿真器,如DAPLink]、JLINK之类的。

Multi-Button
项目的仓库地址:https://github.com/0x1abin/MultiButto
MuliButton 支持如下的按钮事件:



SDK 介绍
SDK 包括
  • 板载驱动包 Boards 文件夹,如基本的 LED、 Button 及 COM 口的驱动等;
  • 多个必要的库 Libraries 文件夹,如 G32A1465 标准库、外设驱动库等;
  • 多个例程 Examples 文件夹,如 ADC采样、 CAN/CANFD 收发、 CRC校验等;
  • 中间件文件在 Middlewares 文件夹内,是 G32A1465 评估板提供的 demo 所使用到的第三方工具或源码;
  • 数据手册 Documents 文件夹,点击链接进入官网下载数据手册、原理图及用户手册等资料;
  • 设备包 Package 文件夹,用于安装 Keil 等 IDE 的设备包;
  • 此外还包含 G32A1xxx_SDK_um.chm 用户手册,便于查找 SDK 对应的部件说明和相关解决方案。
开发环境搭建
极海 Geehy 为开发者提供了十分友好的开发平台和编译环境,便于初学者上手测试,一般提供了KEIL和IAR两种常见的嵌入式开发环境。
1. 以 Keil MDK IDE 作为编译软件,创建工程。默认已经安装 Keil MDK IDE 软件,下载 G32A1465_SDK 压缩包,双击安装 Package 文件夹中的 Geehy.G32A1xxx_DFP.1.0.1.pack Keil 设备支持包。
2.创建工程模板,我们选择 G32A1465_SDK里面的Examples的工程模板作为基础。
(一般拿到新开发板寻找GPIO案例作为测试基础,但是这个SDK里面,GPIO被命名成了PINS;本次测试我们以PINS_Led工程作为基础案例,然后一步步添加代码,完成测评)。

3.复制PINS_Led的Project工程文件到新创建的文件夹中,同时复制Boards、Libraries、Middlewares等文件夹。
4.重构工程架构如果直接打开工程会发现缺少大量的文件,因为我修改了文件的路径,因此需要重新配置工程文件与头文件。
添加相关文件,修改之后效果

UserConfig 用户模块外设配置代码 (主要有芯片外设配置文件、rt-thread接口配置文件、finsh-port等
CmsisDrivers CMSIS底层驱动代码
BoardDrivers 板级驱动代码 board.c
PeriphDrivers 芯片底层标准库代码
Middlewares 中间件代码 (RT-Thread OSIF FINSH SEGGER-RTT Multi-button)
ModuleDrivers 模块驱动代码
Application ——》main.c(主函数) g32a1xx_int.c(中断服务函数)
4.移植Multi-button组件
下载Multi-button程序,创建文件夹添加到工程中。
5. 编写程序
使用方法
1.先申请一个按键结构
struct Button button1;
2.初始化按键对象,绑定按键的GPIO电平读取接口read_button_pin() ,后一个参数设置有效触发电平
button_init(&button1, read_button_pin, 0, 0);
3.注册按键事件
button_attach(&button1, SINGLE_CLICK, Callback_SINGLE_CLICK_Handler);
button_attach(&button1, DOUBLE_CLICK, Callback_DOUBLE_Click_Handler);
...
4.启动按键
button_start(&button1);
5.设置一个5ms间隔的定时器循环调用后台处理函数
while(1) {    ...    if(timer_ticks == 5)     {        timer_ticks = 0;​        button_ticks();    }}
根据官方使用方法编写bsp_button.c完成配置(主要完成按键初始化、按键回调函数、获取gpio电平)
#include "main.h"

//按键的结构变量定义与使用  定义两个2个按键
enum Button_IDs {
    btn1_id=1,
    btn2_id=2,
};
struct Button btn1;
struct Button btn2;


/* 私有变量-------------------------------------------------------------------*/
static const char* tag = "bsp_button";

uint8_t read_button_GPIO(uint8_t button_id)
{
  // you can share the GPIO read function with multiple Buttons
  switch(button_id)
  {
    case btn1_id:
      return ((PINS_ReadPinsInput(KEY1_GPIO_BASE) >> KEY1_PIN) & 0x01U); //read BUTTON_KEY1
                 
    case btn2_id:
      return ((PINS_ReadPinsInput(KEY2_GPIO_BASE) >> KEY2_PIN) & 0x01U);; //read BUTTON_KEY2
    default:
      return 0;
  }
}


/*!
* [url=home.php?mod=space&uid=247401]@brief[/url]   Pins module initialization button
*/
void PINS_Btn_Init(void)
{
    /* Enable PMC clock*/
    CLOCK_SYS_ConfigModuleClock(PMC_CLK, NULL);
    /* Set pin mode */
    PINS_SetMuxModeSel(KEY1_PORT_BASE, KEY1_PIN, PM_MUX_AS_GPIO);
    PINS_SetMuxModeSel(KEY2_PORT_BASE, KEY2_PIN, PM_MUX_AS_GPIO);
    /* Set pin interrupt */
    PINS_SetPinIntSel(KEY1_PORT_BASE, KEY1_PIN, PM_INT_RISING_EDGE);
    PINS_SetPinIntSel(KEY2_PORT_BASE, KEY2_PIN, PM_INT_RISING_EDGE);
    /* Set input direction*/
    PINS_SetPinDir(KEY1_GPIO_BASE, KEY1_PIN, 0);
    PINS_SetPinDir(KEY2_GPIO_BASE, KEY2_PIN, 0);

    PINS_ClrPinInt**Cmd(KEY1_PORT_BASE, KEY1_PIN);
    PINS_ClrPinInt**Cmd(KEY2_PORT_BASE, KEY2_PIN);
}




/**
  * [url=home.php?mod=space&uid=247401]@brief[/url]  multi-button callback handler
  * @param  none
  * @retval none
**/
static void BTN1_PRESS_DOWN_Handler(void* btn)
{
    LOGW(tag,"---> key1 press down! <---\r\n");
}
static void BTN1_PRESS_UP_Handler(void* btn)
{
    LOGW(tag,"---> key1 press up! <---\r\n");
}
static void BTN1_PRESS_REPEAT_Handler(void* btn)
{
    LOGW(tag,"---> key1 press repeat! <---\r\n");
}
static void BTN1_SINGLE_Click_Handler(void* btn)
{
    LOGW(tag,"---> key1 press signle  click!! <---\r\n");
}
static void BTN1_DOUBLE_Click_Handler(void* btn)
{
    LOGW(tag,"---> key1 press double  click! <---\r\n");
}
static void BTN1_LONG_PRESS_START_Handler(void* btn)
{
    LOGW(tag,"---> key1 long press start! <---\r\n");
}
static void BTN1_LONG_PRESS_HOLD_Handler(void* btn)
{
    LOGW(tag,"***> key1 long press hold! <***\r\n");
}
static void BTN2_PRESS_DOWN_Handler(void* btn)
{
    LOGW(tag,"---> key2 press down! <---\r\n");
}
static void BTN2_PRESS_UP_Handler(void* btn)
{
    LOGW(tag,"---> key2 press up! <---\r\n");
}
static void BTN2_PRESS_REPEAT_Handler(void* btn)
{
    LOGW(tag,"---> key2 press repeat! <---\r\n");
}
static void BTN2_SINGLE_Click_Handler(void* btn)
{
    LOGW(tag,"---> key2 press signle  click!! <---\r\n");
}
static void BTN2_DOUBLE_Click_Handler(void* btn)
{
    LOGW(tag,"---> key2 press double  click! <---\r\n");
}
static void BTN2_LONG_PRESS_START_Handler(void* btn)
{
    LOGW(tag,"---> key2 long press start! <---\r\n");
}
static void BTN2_LONG_PRESS_HOLD_Handler(void* btn)
{
    LOGW(tag,"***> key2 long press hold! <***\r\n");
}

//----------------------------------------------------------------------------------
//函 数 名: multi_key_config
//功能说明: 初始化按键对象,配置回调函数
//形    参: 无
//返 回 值: 无
//----------------------------------------------------------------------------------
void multi_key_config(void)
{
    /* button_init */
    button_init(&btn1, read_button_GPIO,0, btn1_id);
    button_init(&btn2, read_button_GPIO,0, btn2_id);
    /* button_attach */
    button_attach(&btn1, PRESS_DOWN,       BTN1_PRESS_DOWN_Handler);
    button_attach(&btn1, PRESS_UP,         BTN1_PRESS_UP_Handler);
    button_attach(&btn1, PRESS_REPEAT,     BTN1_PRESS_REPEAT_Handler);
    button_attach(&btn1, SINGLE_CLICK,     BTN1_SINGLE_Click_Handler);
    button_attach(&btn1, DOUBLE_CLICK,     BTN1_DOUBLE_Click_Handler);
    button_attach(&btn1, LONG_PRESS_START, BTN1_LONG_PRESS_START_Handler);
    button_attach(&btn1, LONG_PRESS_HOLD,  BTN1_LONG_PRESS_HOLD_Handler);

    button_attach(&btn2, PRESS_DOWN,       BTN2_PRESS_DOWN_Handler);
    button_attach(&btn2, PRESS_UP,         BTN2_PRESS_UP_Handler);
    button_attach(&btn2, PRESS_REPEAT,     BTN2_PRESS_REPEAT_Handler);
    button_attach(&btn2, SINGLE_CLICK,     BTN2_SINGLE_Click_Handler);
    button_attach(&btn2, DOUBLE_CLICK,     BTN2_DOUBLE_Click_Handler);
    button_attach(&btn2, LONG_PRESS_START, BTN2_LONG_PRESS_START_Handler);
    button_attach(&btn2, LONG_PRESS_HOLD,  BTN2_LONG_PRESS_HOLD_Handler);
    /* button_start */
    button_start(&btn1);
    button_start(&btn2);
}
5.定时器外设配置
1. 基本定时功能
在 MCU(微控制器单元)中,定时器最基本的作用是进行时间测量和定时控制。它可以精确地计算时间间隔。
2. 产生精确的时间延迟
MCU 在执行很多任务时需要精确的时间延迟。脉冲宽度调制(PWM)控制 PWM 是一种对模拟信号电平进行数字编码的方法。在电机控制、调光等应用中广泛使用。定时器在 MCU 中可以用来产生 PWM 信号。以电机控制为例,通过改变 PWM 信号的占空比可以控制电机的转速。
3. 事件计数
定时器可以用于对外部事件进行计数。比如对外部传感器产生的脉冲信号进行计数。
4. 多任务调度的时间基准
在复杂的 MCU 应用中,可能会同时运行多个任务。定时器可以作为多任务调度的时间基准。
在极海G32A系列中,提供了大量的定时器外设资源,包括:
可配置的定时器(CFGTMR)
低功耗定时器(LPTMR)
低功耗周期中断定时器(LPITMR)
外部看门狗定时器(EWDT)
软件看门狗定时器(WDT)
实时时钟(RTC)
在Multi-button中,需要“设置一个5ms间隔的定时器循环调用后台处理函数”,一般可以选择在主函数继续轮训处理,但是一般不这样子做,可以使用定时器去实现。在本次实验中,我们选择了低功耗周期中断定时器(LPITMR)进行配置。
编写bsp_lpitmr.c和 user_lpitmr_config.c
在G32A系列开发中,官方的SDK将外设资源的配置和使用进行分离处理,一般当使用外设时,需要编写config文件和外设资源初始化的程序。(这和之前极海半导体APM32系列的代码有一定的区别,可能需要一段时间去学习)
bsp_lpitmr 定时器外设资源初始化与服务函数编写
user_lpitmr_config 定时器外设配置文件
#include "main.h"

/*!
* @brief LPITMR interrupt server routine
*/
void LPITMR_Irq(void)
{
    if(LPITMR_ReadInterruptFlagTimerChannels(LPITMR_INSTANCE, LPITMR_CHANNEL1_MASK))
    {
        /* Clear LPITMR channel1 interrupt flagure */
        LPITMR_ClearInterruptFlagTimerChannels(LPITMR_INSTANCE, LPITMR_CHANNEL1_MASK);
         button_ticks();
    }
}

/*!
* @brief LPITMR instance initialize
*/
void LPITMR_Initialize(void)
{
    LPITMR_DeInit(LPITMR_INSTANCE);
    LPITMR_Init(LPITMR_INSTANCE, &g_lpitmrConfig);
    LPITMR_ChannelInit(LPITMR_INSTANCE, LPITMR_CHANNEL1, &g_lpitmrChannelConfig);

    LPITMR_StartTimerChannels(LPITMR_INSTANCE, LPITMR_CHANNEL1);

    INT_SYS_InstallHandler(LPITMR_Ch1_IRQn, LPITMR_Irq, NULL);
    INT_SYS_EnableIRQ(LPITMR_Ch1_IRQn);
}

user_lpitmr_config.c 配置文件 (.period = 5000U 说明定时5ms .period = 500000U 说明定时500ms)
/* Includes */
#include "user_lpitmr_config.h"


LPITMR_USER_CONFIG_T g_lpitmrConfig =
{
    .runInDebugEn = false,
    .runInDozeEn = false,
};

LPITMR_USER_CHANNEL_CONFIG_T g_lpitmrChannelConfig =
{
    .timerMode = LPITMR_PERIODIC_COUNTER,
    .periodUnits = LPIT_PERIOD_UNITS_MICROSECONDS,
    .period = 5000U, //500000U==>500ms  5ms==>5000
    .triggerSrc = LPITMR_TRIG_SRC_INTERNAL,
    .triggerSelect = 0U,
    .reloadOnTriggerEn = true,
    .stopOnInterruptEn = true,
    .startOnTriggerEn = true,
    .channelChainEn = false,
    .interruptEn = true
};

/**@} end of group LPITMR_Timer_Variables */
/**@} end of group LPITMR_Timer */
/**@} end of group Examples */


6.编写主程序
/*
*  极海半导体-Geehy-G32A146X开发板软硬件资料
    * Change Logs:
    * Date           Author       Notes
    * 2024-12-30      Coderend     mdk-template (log_printf)
    * 2024-12-31      Coderend     rt-thread +finsh         
*/
/* 包含头文件-----------------------------------------------------------------*/
#include "main.h"

/* 私有宏定义-----------------------------------------------------------------*/

/* 私有变量-------------------------------------------------------------------*/
static const char* tag = "main";

static void board_hardware_init(void);
/** @addtogroup G32A1465_Examples
  @{
  */

static void board_information_log(void)
{
        LOGI(tag,"Geehy-G32A1465 mdk-template testing[ok]! \r\n");
      LOGI(tag,"Geehy-G32A1465 rt-thread finsh testing[ok]! \r\n");
        LOGI(tag,"Geehy-G32A1465 SEGGER-RTT testing[ok]! \r\n");
        LOGE(tag,"Geehy-G32A1465 by coderend 2025.01.03 testing[ok]! \r\n");
}

static void board_led_init(void)
{
        PINS_Led_Init();
      LOGI(tag,"Geehy-G32A1465 board_led_init[ok]! \r\n");
}

static void board_button_init(void)
{
        PINS_Btn_Init();
    LOGI(tag,"Geehy-G32A1465 board_button_init[ok]! \r\n");
}
static void board_comuart_init(void)
{
        COM_Init();
      LOGI(tag,"Geehy-G32A1465 board_comuart_init[ok]! \r\n");
}


static void board_read_pins(void)
{
      LOGW(tag,"Green led pins output status: %d\r\n",(PINS_ReadPinsOutput(LED_GREEN_GPIO_BASE)&0x8000)>>LED_GREEN_PIN);
    LOGW(tag,"Blue led pins output status: %d\r\n",(PINS_ReadPinsOutput(LED_BLUE_GPIO_BASE)&0x10000)>>LED_BLUE_PIN);
    LOGW(tag,"Red led pins output status: %d\r\n\r\n",(PINS_ReadPinsOutput(LED_RED_GPIO_BASE)&0x1)>>LED_RED_PIN);
}
static void board_led_turnoff(void)
{
        PINS_WritePin(LED_GPIO, BLUE_LED_PIN, 1);
        PINS_WritePin(LED_GPIO, GREEN_LED_PIN, 1);
        PINS_WritePin(LED_GPIO, RED_LED_PIN, 1);
}
static void board_redled_turnon(void)
{
        PINS_ClrPins(LED_RED_GPIO_BASE, 1U << LED_RED_PIN);
        PINS_SetPins(LED_GREEN_GPIO_BASE, 1U << LED_GREEN_PIN);
        PINS_SetPins(LED_BLUE_GPIO_BASE, 1U << LED_BLUE_PIN);
}

static void board_lpitmr_config(void)
{
        LPITMR_Initialize();
}
/*!
* @brief   board_hardware_init
*/
static void board_hardware_init(void)
{
    /* Initialize clock */
  CLOCK_SYS_Init(&g_clockConfig);
    /* Initialize ComUART */
    board_comuart_init();
    /* Initialize LED_PINS */
    board_led_init();
    /* Initialize Button */
    board_button_init();
    /* Initialize LPITMR */
    board_lpitmr_config();
   
}
/*!
* @brief   Main function
*/
int main(void)
{
   
        board_hardware_init();
        board_information_log();
    /* Turn on all LEDs */
    PINS_WritePins(LED_GPIO,WHITE_LED_PIN);
        board_read_pins();
      multi_key_config();
    while (1)
    {

    }
}

7.完整代码见仓库。
下载代码
板子支持JLINK下载,并提供了接口,因此本次实验使用JLINK下载,当然使用DAPlink同样可以,只要接上对应的接口。
注意问题:如果刚开始点击JLINK选项时,可能会弹出需要选择芯片的情况,但是jlink目前不支持这个芯片,出现这个情况的原因是选择了JATG模块,因此我们需要改成SW模式,然后修改成M4系列芯片,才能出现ARM CoreSight SW-DP才能能够正常下载。
下载程序完成之后,观察串口打印信息
RT-Thread移植Multi-button
在上次的RT-Thread工程模板中,添加multi-button文件,创建定时器任务和按键检测任务。
定时器,是指从指定的时刻开始,经过一定的指定时间后触发一个事件,例如定个时间提醒第二天能够按时起床。定时器有硬件定时器和软件定时器之分:
1)硬件定时器是芯片本身提供的定时功能。一般是由外部晶振提供给芯片输入时钟,芯片向软件模块提供一组配置寄存器,接受控制输入,到达设定时间值后芯片中断控制器产生时钟中断。硬件定时器的精度一般很高,可以达到纳秒级别,并且是中断触发方式。
2)软件定时器是由操作系统提供的一类系统接口,它构建在硬件定时器基础之上,使系统能够提供不受数目限制的定时器服务。
RT-Thread 操作系统提供软件实现的定时器,以时钟节拍(OS Tick)的时间长度为单位,即定时数值必须是 OS Tick 的整数倍,例如一个 OS Tick 是 10ms,那么上层软件定时器只能是 10ms,20ms,100ms 等,而不能定时为 15ms。RT-Thread 的定时器也基于系统的节拍,提供了基于节拍整数倍的定时能力。
RT-Thread 定时器
RT-Thread 的定时器提供两类定时器机制:第一类是单次触发定时器,这类定时器在启动后只会触发一次定时器事件,然后定时器自动停止。第二类是周期触发定时器,这类定时器会周期性的触发定时器事件,直到用户手动的停止,否则将***持续执行下去。
另外,根据超时函数执行时所处的上下文环境,RT-Thread 的定时器可以分为 HARD_TIMER 模式与 SOFT_TIMER 模式,如下图。
HARD_TIMER 模式
HARD_TIMER 模式的定时器超时函数在中断上下文环境中执行,可以在初始化 / 创建定时器时使用参数 RT_TIMER_FLAG_HARD_TIMER 来指定。
在中断上下文环境中执行时,对于超时函数的要求与中断服务例程的要求相同:执行时间应该尽量短,执行时不应导致当前上下文挂起、等待。例如在中断上下文中执行的超时函数它不应该试图去申请动态内存、释放动态内存等。
RT-Thread 定时器默认的方式是 HARD_TIMER 模式,即定时器超时后,超时函数是在系统时钟中断的上下文环境中运行的。在中断上下文中的执行方式决定了定时器的超时函数不应该调用任何会让当前上下文挂起的系统函数;也不能够执行非常长的时间,否则会导致其他中断的响应时间加长或抢占了其他线程执行的时间。
SOFT_TIMER 模式
SOFT_TIMER 模式可配置,通过宏定义 RT_USING_TIMER_SOFT 来决定是否启用该模式。该模式被启用后,系统会在初始化时创建一个 timer 线程,然后 SOFT_TIMER 模式的定时器超时函数在都会在 timer 线程的上下文环境中执行。可以在初始化 / 创建定时器时使用参数 RT_TIMER_FLAG_SOFT_TIMER 来指定设置 SOFT_TIMER 模式。
前面介绍了 RT-Thread 定时器并对定时器的工作机制进行了概念上的讲解,本节将深入到定时器的各个接口,帮助读者在代码层次上理解 RT-Thread 定时器。
在系统启动时需要初始化定时器管理系统。可以通过下面的函数接口完成:
  • void rt_system_timer_init(void);
如果需要使用 SOFT_TIMER,则系统初始化时,应该调用下面这个函数接口:
  • void rt_system_timer_thread_init(void);
定时器控制块中含有定时器相关的重要参数,在定时器各种状态间起到纽带的作用。定时器的相关操作如下图所示,对定时器的操作包含:创建 / 初始化定时器、启动定时器、运行定时器、删除 / 脱离定时器,所有定时器在定时超时后都会从定时器链表中被移除,而周期性定时器会在它再次启动时被加入定时器链表,这与定时器参数设置相关。在每次的操作系统时钟中断发生时,都会对已经超时的定时器状态参数做改变。
/*
*  极海半导体-Geehy-G32A146X开发板软硬件资料
    * Change Logs:
    * Date           Author       Notes
    * 2024-12-30      Coderend     mdk-template (log_printf)
    * 2024-12-31      Coderend     rt-thread +finsh         
*/
/* 包含头文件-----------------------------------------------------------------*/
#include "main.h"

/* 私有宏定义-----------------------------------------------------------------*/

/* 私有变量-------------------------------------------------------------------*/
static const char* tag = "main";
static struct rt_timer key_timer;
static rt_thread_t led_thread = RT_NULL;
void led_thread_entry(void* parameter);
static void Key_thread_Callback(void* parameter)
{
        button_ticks();

}
/*!
* @brief   LED thread entry function
*/
void led_thread_entry(void* parameter)
{
    while (1)
    {
        LED_Toggle(LED_GREEN);
        LOGI(tag,"LED_GREEN LED_Toggle \r\n");
        rt_thread_delay(1000);
        LED_Toggle(LED_RED);
        LOGI(tag,"LED_RED LED_Toggle \r\n");
        rt_thread_delay(1000);
        LED_Toggle(LED_BLUE);
        LOGI(tag,"LED_BLUE LED_Toggle \r\n");
        rt_thread_delay(1000);
    }
}

static void board_information_log(void)
{
        LOGI(tag,"Geehy-G32A1465 rt-thread finsh testing[ok]! \r\n");
        LOGI(tag,"Geehy-G32A1465 SEGGER-RTT testing[ok]! \r\n");
        LOGE(tag,"Geehy-G32A1465 by coderend 2024.12.30 testing[ok]! \r\n");
}

static void board_led_init(void)
{
    PINS_Led_Init();
    LOGI(tag,"Geehy-G32A1465 board_led_init[ok]! \r\n");
}

static void board_button_init(void)
{
    PINS_Btn_Init();
    LOGI(tag,"Geehy-G32A1465 board_button_init[ok]! \r\n");
}
/*!
* @brief   Main function
*嵌入式开源组件Multi-Button移植测试
* @param   None
*
* @retval  None
*/
int main(void)
{   
      /* 调用这句进行初始化以及打印开机信息【Demo start!】*/
    segger_rtt_init("Geehy-G32A1465-SEGGER-RTT-Tempalte [ok] \r\n");  
    board_information_log();
    /* Initialize LED_PINS */
    board_led_init();
    /* Initialize Button */
    board_button_init();
    /* Create thread */
    multi_key_config();
    led_thread = rt_thread_create("led1",
                                  led_thread_entry,
                                  RT_NULL,
                                  256,
                                  3,
                                  20);

    /* Startup thread */
    rt_thread_startup(led_thread);
   
    rt_timer_init(&key_timer, "key_timer",   /* 定时器名字是 key_time */
                  Key_thread_Callback, /* 超时时回调的处理函数 */
                  RT_NULL, /* 超时函数的入口参数 */
                  5, /* 定时长度为5个 OS Tick */
                  RT_TIMER_FLAG_PERIODIC); /* 周期定时器 */
    rt_timer_start(&key_timer);
}

移植测试结果


使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

18

主题

71

帖子

0

粉丝