xusiwei1236 发表于 2022-5-22 19:57

【先楫HPM6750测评】GPIO点灯和按键控制

本帖最后由 xusiwei1236 于 2022-5-22 20:12 编辑

<h1>【先楫HPM6750测评】GPIO点灯和按键控制</h1>

<p>上篇帖子中,我们介绍了如何安装和激活SEGGER Embedded Studio,以及使用Embedded Studio进行编译、调试。本篇将会介绍如何点亮开发板上的三色LED灯,以及如何使用开发板上的LED控制三色LED灯。</p>

<h2>GPIO点灯</h2>

<h3>创建闪灯程序</h3>

<p>在hpm_sdk/samples子目录下创建gpio_led目录,将hello_world目录内的src目录和CMakeLists.txt复制到gpio_led目录下(当然,嫌麻烦直接在hello_world的基础上进行修改也是可以的),并将src/hello_world.c重命名为gpio_led.c,并将文件内容修改为:</p>

<pre>
<code>#include &lt;stdio.h&gt;
#include "board.h"
#include "hpm_gpio_drv.h"

#define LED_FLASH_PERIOD_IN_MS 500

int main(void)
{
    int u;
    board_init();
    board_init_led_pins();

    //board_timer_create(LED_FLASH_PERIOD_IN_MS, board_led_toggle);
    gpio_write_pin(BOARD_R_GPIO_CTRL, BOARD_R_GPIO_INDEX, BOARD_R_GPIO_PIN, 0);
    gpio_write_pin(BOARD_G_GPIO_CTRL, BOARD_G_GPIO_INDEX, BOARD_G_GPIO_PIN, 0);
    gpio_write_pin(BOARD_B_GPIO_CTRL, BOARD_B_GPIO_INDEX, BOARD_B_GPIO_PIN, 0);

    printf("gpio_led start...\\n");
    while(1)
    {
      gpio_write_pin(BOARD_R_GPIO_CTRL, BOARD_R_GPIO_INDEX, BOARD_R_GPIO_PIN, 0);
      board_delay_ms(LED_FLASH_PERIOD_IN_MS);
      gpio_write_pin(BOARD_R_GPIO_CTRL, BOARD_R_GPIO_INDEX, BOARD_R_GPIO_PIN, 1);
      board_delay_ms(LED_FLASH_PERIOD_IN_MS);
    }
    return 0;
}
</code></pre>

<p>CMakeLists.txt文件内容修改为:</p>

<pre>
<code># Copyright 2021 hpmicro
# SPDX-License-Identifier: BSD-3-Clause

cmake_minimum_required(VERSION 3.13)

find_package(hpm-sdk REQUIRED HINTS $ENV{HPM_SDK_BASE})

project(gpio_led)

sdk_compile_definitions(-DBOARD_SHOW_CLOCK=0)
sdk_app_src(src/gpio_led.c)
generate_ses_project()
</code></pre>

<h3>编译、运行闪灯程序</h3>

<p>在hpm_sdk\samples\gpio_led目录运行:<em>generate_project -b hpm6750evkmini -t flash_xip -f</em>命令生产项目文件。</p>

<p>使用SEGGER Embedded Studio打开生产的项目文件,如下图所示:</p>

<p></p>

<p>编译、运行后,就可以看到红色LED闪烁了:</p>

<p>66ff5423aef7ba2cf44ca5cff4fa4088<br />
&nbsp;</p>

<h3>三色LED原理图分析</h3>

<p>查阅原理图,可以找到三色LED相关的原理图如下:</p>

<p></p>

<p>可以看到三种颜色的控制管脚信息如下:</p>

<ul>
        <li>红色通过PWM1.P0控制,高电平点亮;</li>
        <li>绿色通过PWM1.P1控制,高电平点亮;</li>
        <li>蓝色通过PWM0.P7控制,高电平点亮;</li>
</ul>

<p>继续在原理图中搜索PWM1.P0、PWM1.P1和PWM0.P7,可以找到:</p>

<p></p>

<p>这里标号U1的就是HPM6750芯片,PWM1.P0、PWM1.P1和PWM0.P7和引脚标号的对应关系如下:</p>

<ul>
        <li>PWM1.P0对应PB19,控制红色;</li>
        <li>PWM1.P1对应PB18,控制绿色;</li>
        <li>PWM9.P7对应PB20,控制蓝色;</li>
</ul>

<p>上面的分析,这和board.h文件里面的代码一致:</p>

<pre>
<code>#define BOARD_R_GPIO_CTRL HPM_GPIO0
#define BOARD_R_GPIO_INDEX GPIO_DI_GPIOB
#define BOARD_R_GPIO_PIN 19
#define BOARD_G_GPIO_CTRL HPM_GPIO0
#define BOARD_G_GPIO_INDEX GPIO_DI_GPIOB
#define BOARD_G_GPIO_PIN 18
#define BOARD_B_GPIO_CTRL HPM_GPIO0
#define BOARD_B_GPIO_INDEX GPIO_DI_GPIOB
#define BOARD_B_GPIO_PIN 20
</code></pre>

<h3>让三种颜色依次闪烁</h3>

<p>将gpio_led.c修改为:</p>

<pre>
<code>#include &lt;stdio.h&gt;
#include "board.h"
#include "hpm_gpio_drv.h"

#define LED_FLASH_PERIOD_IN_MS 500

int main(void)
{
    int u;
    board_init();
    board_init_led_pins();

    //board_timer_create(LED_FLASH_PERIOD_IN_MS, board_led_toggle);
    gpio_write_pin(BOARD_R_GPIO_CTRL, BOARD_R_GPIO_INDEX, BOARD_R_GPIO_PIN, 0);
    gpio_write_pin(BOARD_G_GPIO_CTRL, BOARD_G_GPIO_INDEX, BOARD_G_GPIO_PIN, 0);
    gpio_write_pin(BOARD_B_GPIO_CTRL, BOARD_B_GPIO_INDEX, BOARD_B_GPIO_PIN, 0);

    printf("gpio_led start...\\n");
    while(1)
    {
      gpio_write_pin(BOARD_R_GPIO_CTRL, BOARD_R_GPIO_INDEX, BOARD_R_GPIO_PIN, 1);
      board_delay_ms(LED_FLASH_PERIOD_IN_MS);
      gpio_write_pin(BOARD_R_GPIO_CTRL, BOARD_R_GPIO_INDEX, BOARD_R_GPIO_PIN, 0);
      board_delay_ms(LED_FLASH_PERIOD_IN_MS);

      gpio_write_pin(BOARD_G_GPIO_CTRL, BOARD_G_GPIO_INDEX, BOARD_G_GPIO_PIN, 1);
      board_delay_ms(LED_FLASH_PERIOD_IN_MS);
      gpio_write_pin(BOARD_G_GPIO_CTRL, BOARD_G_GPIO_INDEX, BOARD_G_GPIO_PIN, 0);
      board_delay_ms(LED_FLASH_PERIOD_IN_MS);

      gpio_write_pin(BOARD_B_GPIO_CTRL, BOARD_B_GPIO_INDEX, BOARD_B_GPIO_PIN, 1);
      board_delay_ms(LED_FLASH_PERIOD_IN_MS);
      gpio_write_pin(BOARD_B_GPIO_CTRL, BOARD_B_GPIO_INDEX, BOARD_B_GPIO_PIN, 0);
      board_delay_ms(LED_FLASH_PERIOD_IN_MS);
    }
    return 0;
}
</code></pre>

<p>重新编译、运行,</p>

<p>就可以看到红绿蓝依次闪烁了:</p>

<p>6e0913f7001c0ca5ccacc506086ec1be<br />
&nbsp;</p>

<h2>GPIO读取按键状态</h2>

<p>接下来,我们尝试使用GPIO读取PBUTN和WBUTN两个按键的状态,并输出到串口中。</p>

<p>首先需要在原理图中找到,按键相关的原理图:</p>

<p></p>

<p>循环读取并打印PBUTN和WBUTN按键状态的代码段:</p>

<pre>
<code>                uint32_t count = 0;
                while (1)
    {
      count++;
      uint8_t pbutn_value = gpio_read_pin(HPM_BGPIO, GPIO_DI_GPIOZ, 2);
      uint8_t wbutn_value = gpio_read_pin(HPM_BGPIO, GPIO_DI_GPIOZ, 3);
      printf("[%d] pbutn_value=%d, wbutn_value=%d\\n", count, pbutn_value, wbutn_value);
      board_delay_ms(500);
    }
</code></pre>

<h3>设置PZ02/PZ03引脚功能</h3>

<p>经测试发现,默认情况下,这两个按键分别是长按关机和长按休眠的功能。</p>

<p>可以使用如下代码段,将这两个引脚功能设置为普通GPIO,并设置为内部上拉状态:</p>

<pre>
<code>static void init_butn_as_gpio()
{
    uint32_t pad_ctl = IOC_PAD_PAD_CTL_PE_SET(1) | IOC_PAD_PAD_CTL_PS_SET(1);
    // 设置PZ02、PZ03为GPIO功能
    HPM_BIOC-&gt;PAD.FUNC_CTL = IOC_PZ02_FUNC_CTL_BGPIO_Z_02;
    HPM_BIOC-&gt;PAD.FUNC_CTL = IOC_PZ03_FUNC_CTL_BGPIO_Z_03;

    // 设置PZ02、PZ03为GPIO的模式为 内部上拉
    HPM_IOC-&gt;PAD.PAD_CTL = pad_ctl;
    HPM_IOC-&gt;PAD.PAD_CTL = pad_ctl;
}
</code></pre>

<h3>使用PBUTN和WBUTN按键控制三色LED的颜色</h3>

<p>本小节实现&mdash;&mdash;通过PBUTN和WBUTN两个按键,切换三色LED等的颜色:</p>

<ul>
        <li>按PBUTN按键,颜色切换顺序为&mdash;&mdash;红、绿、蓝</li>
        <li>按WBUTN按键,颜色切换顺序为&mdash;&mdash;蓝、绿、红</li>
        <li>长按,则颜色会一直轮流切换</li>
        <li>松开,切换停止</li>
</ul>

<p>完整代码:</p>

<pre>
<code>#include &lt;stdio.h&gt;
#include "board.h"
#include "hpm_gpio_drv.h"

static void init_butn_as_gpio()
{
    uint32_t pad_ctl = IOC_PAD_PAD_CTL_PE_SET(1) | IOC_PAD_PAD_CTL_PS_SET(1);
    // 设置PZ02、PZ03为GPIO功能
    HPM_BIOC-&gt;PAD.FUNC_CTL = IOC_PZ02_FUNC_CTL_BGPIO_Z_02;
    HPM_BIOC-&gt;PAD.FUNC_CTL = IOC_PZ03_FUNC_CTL_BGPIO_Z_03;

    // 设置PZ02、PZ03为GPIO的模式为 内部上拉
    HPM_IOC-&gt;PAD.PAD_CTL = pad_ctl;
    HPM_IOC-&gt;PAD.PAD_CTL = pad_ctl;
}

void app_led_write(uint32_t index, uint8_t state)
{
    switch (index)
    {
    case 0:
      gpio_write_pin(BOARD_R_GPIO_CTRL, BOARD_R_GPIO_INDEX, BOARD_R_GPIO_PIN, state);
      break;
    case 1:
      gpio_write_pin(BOARD_G_GPIO_CTRL, BOARD_G_GPIO_INDEX, BOARD_G_GPIO_PIN, state);
      break;
    case 2:
      gpio_write_pin(BOARD_B_GPIO_CTRL, BOARD_B_GPIO_INDEX, BOARD_B_GPIO_PIN, state);
      break;
    default:
      /* Suppress the toolchain warnings */
      break;
    }
}

uint32_t app_led_next(uint32_t index)
{
    return (index + 1) % 3;
}

uint32_t app_led_prev(uint32_t index)
{
    return (index + 3 - 1) % 3;
}

int main(void)
{
    uint32_t current = 0, next = 0;

    board_init();
    board_init_led_pins();

                init_butn_as_gpio();
    while (1)
    {
      // 读取按键状态
      uint8_t pbutn_value = gpio_read_pin(HPM_BGPIO, GPIO_DI_GPIOZ, 2);
      uint8_t wbutn_value = gpio_read_pin(HPM_BGPIO, GPIO_DI_GPIOZ, 3);

      // 按键状态处理
      if (pbutn_value == 0) {
            printf("pbutn_value=%d, wbutn_value=%d\\n", pbutn_value, wbutn_value);
            next = app_led_next(current);
            app_led_write(current, 0);
            // app_led_write(next, 1);
            current = next;
      } else if (wbutn_value == 0) {
            printf("pbutn_value=%d, wbutn_value=%d\\n", pbutn_value, wbutn_value);
            next = app_led_prev(current);
            app_led_write(current, 0);
            // app_led_write(next, 1);
            current = next;
      }
      app_led_write(current, 1); // 放这里,第一次能够点亮红色

      // 延时,控制扫描频率
      board_delay_ms(100);
    }
    return 0;
}
</code></pre>

<p>效果演示:</p>

<p>8060b44877d78359f7dbdedc1deb9617<br />
&nbsp;</p>

<h2>补充说明</h2>

<p>点灯的过程中发现,SDK 0.9.0(sdk 0.10.0也有这个问题)里面hpm5760evkmini的LED亮灭的高低电平搞反了。我已经向先楫反馈了这个问题,从他们那里了解到HPM6750EVKMINI板子改版过,旧版本是低电平点亮,新版本是高电平点亮,这块的代码没有更新。他们说会在下一个版本中修复这个问题,目前解决这个问题需要修改几处代码,改动都很简单,具体可以参考我的这条提交记录:</p>

<p><a href="https://gitee.com/hpm6750/hpm_sdk/commit/bbc896e4a571e756e4cbac38afcc042409a7957f">https://gitee.com/hpm6750/hpm_sdk/commit/bbc896e4a571e756e4cbac38afcc042409a7957f</a></p>

<p>&nbsp;</p>

<h2>代码仓</h2>

<p>上面那个提交链接的代码仓:<a href="https://gitee.com/hpm6750/hpm_sdk">https://gitee.com/hpm6750/hpm_sdk</a></p>

<p>是我个人建立的用于测试HPM6750 SDK开发的,欢迎Star支持~</p>

<p>另外,我在码云创建了名为HPM6750的组织,该组织下还有其他代码仓,后续会随着新帖子的发布设置为公开,敬请期待~</p>

nmg 发表于 2022-5-23 09:47

<p><img height="48" src="https://bbs.eeworld.com.cn/static/editor/plugins/hkemoji/sticker/facebook/lol.gif" width="48" />厉害了,搞了个组织</p>
页: [1]
查看完整版本: 【先楫HPM6750测评】GPIO点灯和按键控制