[STM32U5] 【STM32U599J-DK测评】点灯按键跑起来

[复制链接]
 楼主| HonestQiao 发表于 2023-12-26 00:58 | 显示全部楼层 |阅读模式
<
#申请原创#STM32U599J-DK带了一块大大的屏幕,在点亮屏幕之前,先来玩板子的第一步,点个灯再说。

一、硬件了解
iShot_2023-12-25_23.40.39.png

在开发板上,有两个可以用户使用的灯和一个用户使用的按键。

从手册上,也可以详细的了解:
iShot_2023-12-26_00.30.40.png

关于这两个LED和按键的具体定义连接的GPIO,也可以从手册查看:
415386589add84800f.png

二、dts了解
点灯这活,用不上TouchGFX,所以我直接使用Zephyr点灯了。
在Zephyr中,STM32U599J-DK直接使用stm32u5a9j_dk的配置,对应的dts中有关于LED和按键的配置:
iShot_2023-12-26_00.33.45.png

为它们定义的别名如下:
808786589af187d943.png

在Zephyr中,可以用简短的别名,快速定位设备。

三、点灯代码
直接贴点两个灯的代码:
  1. #include <zephyr/kernel.h>
  2. #include <zephyr/drivers/gpio.h>

  3. /* 1000 msec = 1 sec */
  4. #define SLEEP_TIME_MS   1000

  5. // 定义设备
  6. #define LED0_NODE DT_ALIAS(led0)
  7. #define LED1_NODE DT_ALIAS(led1)

  8. // 定义设备变量
  9. static const struct gpio_dt_spec led0 = GPIO_DT_SPEC_GET(LED0_NODE, gpios);
  10. static const struct gpio_dt_spec led1 = GPIO_DT_SPEC_GET(LED1_NODE, gpios);


  11. int main(void)
  12. {
  13.         int ret;

  14.         // 初始化检查
  15.         if (!gpio_is_ready_dt(&led0)) {
  16.                 return 0;
  17.         }

  18.         ret = gpio_pin_configure_dt(&led0, GPIO_OUTPUT_ACTIVE);
  19.         if (ret < 0) {
  20.                 return 0;
  21.         }

  22.         if (!gpio_is_ready_dt(&led1)) {
  23.                 return 0;
  24.         }

  25.         ret = gpio_pin_configure_dt(&led1, GPIO_OUTPUT_ACTIVE);
  26.         if (ret < 0) {
  27.                 return 0;
  28.         }

  29.         // 设置初始状态:低电平
  30.         ret = gpio_pin_set_dt(&led0, 0);
  31.         if (ret < 0) {
  32.                 return 0;
  33.         }
  34.         // 设置初始状态:高电平
  35.         ret = gpio_pin_set_dt(&led1, 1);
  36.         if (ret < 0) {
  37.                 return 0;
  38.         }

  39.         while (1) {
  40.                 // 翻转状态
  41.                 ret = gpio_pin_toggle_dt(&led0);
  42.                 if (ret < 0) {
  43.                         return 0;
  44.                 }
  45.                 // 翻转状态
  46.                 ret = gpio_pin_toggle_dt(&led1);
  47.                 if (ret < 0) {
  48.                         return 0;
  49.                 }
  50.                 k_msleep(SLEEP_TIME_MS);
  51.         }
  52.         return 0;
  53. }


上述代码的逻辑,非常明确,具体步骤如下:
  • 通过宏定义DT_ALIAS 和设备别名,快速定位设备
  • 通过宏定义 GPIO_DT_SPEC_GET ,设置设备变量
  • 通过 gpio_is_ready_dt() 检查GPIO是否准备好
  • 通过gpio_pin_configure_dt()配置输入输出状态
  • 通过gpio_pin_set_dt()设置GPIO的状态
  • 通过gpio_pin_toggle_dt()翻转GPIO的状态
  • 在循环中,没翻转一次状态,就通过k_msleep()延时SLEEP_TIME_MS对应的时间


因为设置了两个灯的初始状态,一个是点亮,一个是熄灭,所以在循环中,翻转状态后,两个灯就形成交替亮灭的实际表现了。

上述代码,参考samples/basic/blinky进行,做好对应的prj.conf、CMakeLists.txt配置,然后使用下面的命令编译:
  1. west build -p=always -b stm32u5a9j_dk
编译完成后,使用下面的命令烧录:
  1. west flash
也可以使用pyocd烧录:
  1. pyocd flash --erase chip --target stm32u5a5zjtxq build/zephyr/zephyr.hex


烧录完成后,运行效果如下:
01.gif

四、按键控制翻转的速度
下一步,我们把按键的功能,给添加进来,用按键控制交替的速度,也就是延时的时间,每按键一次,则延时时间变短,交替速度变快。

具体的代码如下:
  1. #include <zephyr/kernel.h>
  2. #include <zephyr/drivers/gpio.h>

  3. /* 1000 msec = 1 sec */
  4. #define SLEEP_TIME_MS   1000
  5. #define SLEEP_TIME_MS_MIN   100

  6. #define LED0_NODE DT_ALIAS(led0)
  7. #define LED1_NODE DT_ALIAS(led1)

  8. #define SW0_NODE        DT_ALIAS(sw0)
  9. static const struct gpio_dt_spec button = GPIO_DT_SPEC_GET_OR(SW0_NODE, gpios,
  10.                                                               {0});
  11. static struct gpio_callback button_cb_data;

  12. int sleep_time = SLEEP_TIME_MS;

  13. static const struct gpio_dt_spec led0 = GPIO_DT_SPEC_GET(LED0_NODE, gpios);
  14. static const struct gpio_dt_spec led1 = GPIO_DT_SPEC_GET(LED1_NODE, gpios);

  15. bool push_status = true;
  16. void button_pressed(const struct device *dev, struct gpio_callback *cb,
  17.                     uint32_t pins)
  18. {
  19.         if (push_status) {
  20.                 return;
  21.         }
  22.         push_status = true;
  23.         printk("Button pressed at %" PRIu32 "\n", k_cycle_get_32());
  24.         sleep_time -= 100;
  25.         if (sleep_time<SLEEP_TIME_MS_MIN) {
  26.                 sleep_time = SLEEP_TIME_MS;
  27.         }
  28.         printk("Sleep time is at %d\n", sleep_time);
  29.         push_status = false;
  30. }

  31. int main(void)
  32. {
  33.         int ret;


  34.         if (!gpio_is_ready_dt(&button)) {
  35.                 printk("Error: button device %s is not ready\n",
  36.                        button.port->name);
  37.                 return 0;
  38.         }

  39.         ret = gpio_pin_configure_dt(&button, GPIO_INPUT);
  40.         if (ret != 0) {
  41.                 printk("Error %d: failed to configure %s pin %d\n",
  42.                        ret, button.port->name, button.pin);
  43.                 return 0;
  44.         }

  45.         ret = gpio_pin_interrupt_configure_dt(&button,
  46.                                               GPIO_INT_EDGE_TO_ACTIVE);
  47.         if (ret != 0) {
  48.                 printk("Error %d: failed to configure interrupt on %s pin %d\n",
  49.                         ret, button.port->name, button.pin);
  50.                 return 0;
  51.         }

  52.         gpio_init_callback(&button_cb_data, button_pressed, BIT(button.pin));
  53.         gpio_add_callback(button.port, &button_cb_data);
  54.         printk("Set up button at %s pin %d\n", button.port->name, button.pin);

  55.         if (!gpio_is_ready_dt(&led0)) {
  56.                 return 0;
  57.         }

  58.         ret = gpio_pin_configure_dt(&led0, GPIO_OUTPUT_ACTIVE);
  59.         if (ret < 0) {
  60.                 return 0;
  61.         }

  62.         if (!gpio_is_ready_dt(&led1)) {
  63.                 return 0;
  64.         }

  65.         ret = gpio_pin_configure_dt(&led1, GPIO_OUTPUT_ACTIVE);
  66.         if (ret < 0) {
  67.                 return 0;
  68.         }

  69.         ret = gpio_pin_set_dt(&led0, 0);
  70.         if (ret < 0) {
  71.                 return 0;
  72.         }
  73.         ret = gpio_pin_set_dt(&led1, 1);
  74.         if (ret < 0) {
  75.                 return 0;
  76.         }

  77.         push_status = false;
  78.         while (1) {
  79.                 ret = gpio_pin_toggle_dt(&led0);
  80.                 if (ret < 0) {
  81.                         return 0;
  82.                 }
  83.                 ret = gpio_pin_toggle_dt(&led1);
  84.                 if (ret < 0) {
  85.                         return 0;
  86.                 }
  87.                 k_msleep(sleep_time);
  88.         }
  89.         return 0;
  90. }


在上述代码中,按键处理的核心部分如下:
1. 定义:
  1. #define SW0_NODE        DT_ALIAS(sw0)
  2. static const struct gpio_dt_spec button = GPIO_DT_SPEC_GET_OR(SW0_NODE, gpios,
  3.                                                               {0});
  4. static struct gpio_callback button_cb_data;

  5. static const struct gpio_dt_spec led0 = GPIO_DT_SPEC_GET(LED0_NODE, gpios);
  6. static const struct gpio_dt_spec led1 = GPIO_DT_SPEC_GET(LED1_NODE, gpios);
定义的方式,和按键的方式类似,不过对应按钮,多了一些专门的设置,如上面的button_cb_data,表示按键定义后的回调数据。

2. 按键按下后的处理
  1. int sleep_time = SLEEP_TIME_MS;
  2. bool push_status = true;
  3. void button_pressed(const struct device *dev, struct gpio_callback *cb,
  4.                     uint32_t pins)
  5. {
  6.         if (push_status) {
  7.                 return;
  8.         }
  9.         push_status = true;
  10.         printk("Button pressed at %" PRIu32 "\n", k_cycle_get_32());
  11.         sleep_time -= 100;
  12.         if (sleep_time<SLEEP_TIME_MS_MIN) {
  13.                 sleep_time = SLEEP_TIME_MS;
  14.         }
  15.         printk("Sleep time is at %d\n", sleep_time);
  16.         push_status = false;
  17. }
上述调用,会在按键按下后,被回调。
在这个调用中,会递减延时时间sleep_time,直到最小值后,再从最大值开始,往复循环。

3. 按键初始化检查和回调配置
  1. if (!gpio_is_ready_dt(&button)) {
  2.                 printk("Error: button device %s is not ready\n",
  3.                        button.port->name);
  4.                 return 0;
  5.         }

  6.         ret = gpio_pin_configure_dt(&button, GPIO_INPUT);
  7.         if (ret != 0) {
  8.                 printk("Error %d: failed to configure %s pin %d\n",
  9.                        ret, button.port->name, button.pin);
  10.                 return 0;
  11.         }

  12.         ret = gpio_pin_interrupt_configure_dt(&button,
  13.                                               GPIO_INT_EDGE_TO_ACTIVE);
  14.         if (ret != 0) {
  15.                 printk("Error %d: failed to configure interrupt on %s pin %d\n",
  16.                         ret, button.port->name, button.pin);
  17.                 return 0;
  18.         }

  19.         gpio_init_callback(&button_cb_data, button_pressed, BIT(button.pin));
  20.         gpio_add_callback(button.port, &button_cb_data);
  21.         printk("Set up button at %s pin %d\n", button.port->name, button.pin);
上述代码,和led一样做了初始化的检查,然后设置了对应的回调。

4. 循环部分使用设置的延时时间:
  1.         push_status = false;
  2.         while (1) {
  3.                 ret = gpio_pin_toggle_dt(&led0);
  4.                 if (ret < 0) {
  5.                         return 0;
  6.                 }
  7.                 ret = gpio_pin_toggle_dt(&led1);
  8.                 if (ret < 0) {
  9.                         return 0;
  10.                 }
  11.                 k_msleep(sleep_time);
  12.         }


5. 实际效果
将上述代码保存后,然后编译烧录,实际运行的效果如下。
首先我们看一下串口的输出:
iShot_2023-12-26_00.53.31.png

可以看到,按键一下,则sleep time就减少100,低于100,则回到1000。单位为ms。

LED灯实际闪烁的效果如下:
02.gif

五、总结
好了,点灯和按键的处理,就到这里了。
感兴趣的话,还可以试试通过按键,进行PWM调光,也就是控制LED的亮点效果。

MessageRing 发表于 2024-1-12 16:48 | 显示全部楼层
自带屏幕长什么样啊
 楼主| HonestQiao 发表于 2024-1-18 15:33 | 显示全部楼层
之前的文章发过:【STM32U599J-DK测评】华丽的开箱 - STM32/STM8单片机论坛 - ST MCU意法半导体官方技术支持论坛 - 21ic电子技术开**坛

6570765a8d4578898c.png
您需要登录后才可以回帖 登录 | 注册

本版积分规则

42

主题

110

帖子

2

粉丝
快速回复 在线客服 返回列表 返回顶部