false

false

EN

一、让BLE跑起来  

        在我们创建了第一个ble_app_example的工程之后,默认工程的代码只是对BLE协议栈的初始化,然后设置一个广播就结束了。默认的代码下载到板子中跑起来后,在手机上安装这个路径的apk:tools\GRToolBox\GRToolbox-V1.20.apk,然后手机上就可以搜索到“Goodix_Tem”的蓝牙设备了。  

 二、代码跑起来  

        main.c文件中,main函数的工程的代码如下: 

  int main (void)

{
// Initialize user peripherals.
app_periph_init();
    
// Initialize ble stack.
ble_stack_init(&s_app_ble_callback, &heaps_table);/*< init ble stack*/
// loop
while (1)
{
//刷新log缓存
app_log_flush();
//睡眠策略调度功能,此函数会导致CPU进入睡眠,后面的代码没办法执行,我们先把他注释掉,方便我们后面的操作。
pwr_mgmt_schedule();
}
}


三、添加GPIO功能控制 

         我们先了解一下GPIO:GR551x的数字GPIO有32个,分为2组,其中GPIO_0~GPIO_15为第0组,GPIO_16~GPIO_31为第1组,分别对应的电源域为VDDIO1,VDDIO0;如果要外接Flash,则VDDIO0的电压只能接1.8V,VDDIO0域对应的GPIO电压也是1.8V,如果不需要外接Flash则,可以是1.8-3.3V;VDDIO1的电压可以外接其他电压源,所以VDDIO1可以接1.8V,2.8V,3.3V等,对应的GPIO口的电压就是VDDIO1的电压。所以在使用开发板的GPIO_0~GPIO_15时需要将J6的跳线帽插上,否则可能无法使用,可以支持1.8V和3.3V电压。      

            

        在修改软件之前都是硬件先行,我们需要先打开Demo板的原理图,确认一下硬件资源对应的管脚;打开documentation\01_chip_kit_docs\GR5515-SK-BASIC-REVB Schematic_V0_92.pdf,找到了LED2的电路及管脚分配为GPIO_4,低电平点亮,高电平熄灭;再找一下Down按键,对应的为GPIO_13,低电平触发按键。 

             

            

            

            

         在detasheet中,GPIO_4和GPIO_13都是多功能复用脚,我们现在只作为普通的数字GPIO使用;在开发指南中,我们知道跟底层硬件相关的代码都在drivers目录中,可以进入看到hal封装和LL封装的头文件和.c源文件;现在我们想用一下LL封装的函数,通过按下Down按键来开关LED2。

         GPIO口的操作无非包含三部分 :初始化,读操作,写操作;我们需要读取按键KEY的状态,然后点亮LED需要配置GPIO口做输出功能,然后能够输出高低电平就可以了;根据这个需求我们找到LL层封装的几个函数:我们只要按照要求调用这几个函数就可以实现KEY按键的检测及LED的点亮了。

error_status_t ll_gpio_init(gpio_regs_t *GPIOx, ll_gpio_init_t *p_gpio_init)                 //初始化函数  __STATIC_INLINE uint32_t ll_gpio_is_input_pin_set(gpio_regs_t *GPIOx, uint32_t pin_mask)  //读取GPIO口的状态__STATIC_INLINE void ll_gpio_set_output_pin(gpio_regs_t *GPIOx, uint32_t pin_mask)    //设置GPIO口输出高函数

__STATIC_INLINE void ll_gpio_reset_output_pin(gpio_regs_t *GPIOx, uint32_t pin_mask)  //设置GPIO口输出低函数__STATIC_INLINE void ll_gpio_toggle_pin(gpio_regs_t *GPIOx, uint32_t pin_mask)


         首先在main.c中加入头文件包含#include "gr55xx_ll_gpio.h",然后为了写代码的方便,我们把底层的操作用define重新定义一下,代码如下:

#define LED2_PORT       GPIO0
#define LED2_PIN        LL_GPIO_PIN_4
#define LED2_SET()      ll_gpio_set_output_pin(LED2_PORT, LED2_PIN)
#define LED2_CLR()      ll_gpio_reset_output_pin(LED2_PORT, LED2_PIN)
#define LED2_TOG()      ll_gpio_toggle_pin(LED2_PORT, LED2_PIN)
#define DOWN_KEY_PORT   GPIO0
#define DOWN_KEY_PIN    LL_GPIO_PIN_13

         GPIO_PIN_RESET定义为0,输出为0时点亮LED,GPIO_PIN_SET定义为1,输出1时关闭LED; LED2_PORT定义了当前GPIO所在的分组为GPIO0,根据规格书和LL层定义可以知道GPIO分了2个组,当前pin4和pin13为第0组; LED2_PIN定义了当前管脚所在的pin脚为4脚。 LED2_SET(),LED2_CLR(),LED2_TOG()这3个定义分别定义了当前GPIO的置1,清0,反转等操作。 我们定义两个函数,初始化函数来初始化GPIO的配置,以及两个状态设置和读取函数用来读取KEY的状态和设置LED的输出,如下图:配置的设置可以参看头文件中结构体ll_gpio_init_t的类型来定义,GPIO口的复用功能查找GPIO口的复用表: 

//LED2的GPIO初始化
void gpio_led_init(void)
{
    ll_gpio_init_t gpio_config = LL_GPIO_DEFAULT_CONFIG;//将配置设为默认配置
    gpio_config.pin = LED2_PIN;//设置对应的pin脚为4
    gpio_config.mode = LL_GPIO_MODE_OUTPUT;//设置模式为输出模式
    gpio_config.pull = LL_GPIO_PULL_NO;//设置管脚没有上拉,作为输出功能无影响
    gpio_config.mux = LL_GPIO_MUX_7;//查GPIO口复用功能表,设置为普通GPIO口需要配置为MUX7   
    gpio_config.trigger = LL_GPIO_TRIGGER_NONE;//此接口不作为输入,不用设置触发方式
    
    int err = ll_gpio_init(LED2_PORT, &gpio_config);//调用LL层的初始化函数进行初始化
    if(ERROR == err)//如果初始化失败则打印log
    {
        printf("LED2 init failed, err = 0x%x\n", err);
    }
    LED2_SET();//初始化关闭LED2
}
void gpio_key_init(void)
{
    ll_gpio_init_t gpio_config;
    gpio_config.pin = DOWN_KEY_PIN;//设置对应的pin脚为13
    gpio_config.mode = LL_GPIO_MODE_INPUT;//设置模式为输入模式
    gpio_config.pull = LL_GPIO_PULL_UP;//设置管脚为上拉,外部没有硬件上拉, //作为输入脚一般会让他保持某一个稳定的状态
    gpio_config.mux = LL_GPIO_MUX_7;//查GPIO口复用功能表,设置为普通GPIO口需要配置为MUX7
    gpio_config.trigger = LL_GPIO_TRIGGER_NONE;//普通输入无用,设为中断口才起作用
    int err = ll_gpio_init(DOWN_KEY_PORT, &gpio_config);//调用LL层的初始化函数进行初始化
    if(ERROR == err)
    {
        printf("key init failed, err = 0x%x\n", err);
    }
}
void gpio_led_onoff(bool flag)
{
    if(flag)
    {
        LED2_CLR();//点亮LED2
        printf("LED2 turn on\n");
    }
    else
    {
        LED2_SET();//关闭LED2
        printf("LED2 turn off\n");
    }
}

//按键的读取,为了做消抖,定义了两个全局的按键状态变量,以及按键的读取函数如下:
bool gkey_gpio_down = false;
bool gkey_gpio_up = true;
bool gpio_key_status()
{
    unsigned int value = 0;
    value = ll_gpio_is_input_pin_set(DOWN_KEY_PORT, DOWN_KEY_PIN);
    if(0 == value)
    {
        hal_delay(10);
        value = ll_gpio_is_input_pin_set(DOWN_KEY_PORT, DOWN_KEY_PIN);
        if(0 == value)
        {
            if(gkey_gpio_up)
            {
                gkey_gpio_down = true;
                gkey_gpio_up = false;
                return true;
            }
        }
    }
    else
    {
        gkey_gpio_down = false;
        gkey_gpio_up = true;
        return false;
    }
    return false;
}

        写完上面的代码,基本上完成了一半,剩下的就是将这些添加到主函数中调用了,然后调试验证了。在主函数中,我们添加代码如下: 

int main (void)
{
    // Initialize user peripherals.
    app_periph_init();
    
    // Initialize ble stack.
    ble_stack_init(&s_app_ble_callback, &heaps_table);/*< init ble stack*/
    app_log_flush(); //log初始化函数,我放到这里来了,我认为放到这里更合理,且我gpio_led_init函数用了printf函数
    hal_init(); //hal层初始化,按键消抖会用到hal层的delay函数
    gpio_led_init(); //LED接口初始化
    gpio_key_init(); //KEY接口初始化
    bool flag = false;
    // loop
    while (1)
    {
        if(gpio_key_status())             //读取按键状态
        {
            printf("Down Key press!\n");
            flag = !flag;
                
            if(flag)
            {
                gpio_led_onoff(true);    //点亮LED
            }
            else
            {
                gpio_led_onoff(false);  //熄灭LED     
            }
        }
    }
}

         写好代码编译后就可以烧录到Demo板子中进行调试了,同时打开串口工具按照如下设置即可看到log。

            

0条评论

您的评论