#申请原创#STM32U599J-DK带了一块大大的屏幕,在点亮屏幕之前,先来玩板子的第一步,点个灯再说。
一、硬件了解
在开发板上,有两个可以用户使用的灯和一个用户使用的按键。
从手册上,也可以详细的了解:
关于这两个LED和按键的具体定义连接的GPIO,也可以从手册查看:
二、dts了解
点灯这活,用不上TouchGFX,所以我直接使用Zephyr点灯了。
在Zephyr中,STM32U599J-DK直接使用stm32u5a9j_dk的配置,对应的dts中有关于LED和按键的配置:
为它们定义的别名如下:
在Zephyr中,可以用简短的别名,快速定位设备。
三、点灯代码
直接贴点两个灯的代码:
#include <zephyr/kernel.h>
#include <zephyr/drivers/gpio.h>
/* 1000 msec = 1 sec */
#define SLEEP_TIME_MS 1000
// 定义设备
#define LED0_NODE DT_ALIAS(led0)
#define LED1_NODE DT_ALIAS(led1)
// 定义设备变量
static const struct gpio_dt_spec led0 = GPIO_DT_SPEC_GET(LED0_NODE, gpios);
static const struct gpio_dt_spec led1 = GPIO_DT_SPEC_GET(LED1_NODE, gpios);
int main(void)
{
int ret;
// 初始化检查
if (!gpio_is_ready_dt(&led0)) {
return 0;
}
ret = gpio_pin_configure_dt(&led0, GPIO_OUTPUT_ACTIVE);
if (ret < 0) {
return 0;
}
if (!gpio_is_ready_dt(&led1)) {
return 0;
}
ret = gpio_pin_configure_dt(&led1, GPIO_OUTPUT_ACTIVE);
if (ret < 0) {
return 0;
}
// 设置初始状态:低电平
ret = gpio_pin_set_dt(&led0, 0);
if (ret < 0) {
return 0;
}
// 设置初始状态:高电平
ret = gpio_pin_set_dt(&led1, 1);
if (ret < 0) {
return 0;
}
while (1) {
// 翻转状态
ret = gpio_pin_toggle_dt(&led0);
if (ret < 0) {
return 0;
}
// 翻转状态
ret = gpio_pin_toggle_dt(&led1);
if (ret < 0) {
return 0;
}
k_msleep(SLEEP_TIME_MS);
}
return 0;
}
上述代码的逻辑,非常明确,具体步骤如下:
- 通过宏定义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配置,然后使用下面的命令编译:
west build -p=always -b stm32u5a9j_dk
编译完成后,使用下面的命令烧录:
也可以使用pyocd烧录:
pyocd flash --erase chip --target stm32u5a5zjtxq build/zephyr/zephyr.hex
烧录完成后,运行效果如下:
四、按键控制翻转的速度
下一步,我们把按键的功能,给添加进来,用按键控制交替的速度,也就是延时的时间,每按键一次,则延时时间变短,交替速度变快。
具体的代码如下:
#include <zephyr/kernel.h>
#include <zephyr/drivers/gpio.h>
/* 1000 msec = 1 sec */
#define SLEEP_TIME_MS 1000
#define SLEEP_TIME_MS_MIN 100
#define LED0_NODE DT_ALIAS(led0)
#define LED1_NODE DT_ALIAS(led1)
#define SW0_NODE DT_ALIAS(sw0)
static const struct gpio_dt_spec button = GPIO_DT_SPEC_GET_OR(SW0_NODE, gpios,
{0});
static struct gpio_callback button_cb_data;
int sleep_time = SLEEP_TIME_MS;
static const struct gpio_dt_spec led0 = GPIO_DT_SPEC_GET(LED0_NODE, gpios);
static const struct gpio_dt_spec led1 = GPIO_DT_SPEC_GET(LED1_NODE, gpios);
bool push_status = true;
void button_pressed(const struct device *dev, struct gpio_callback *cb,
uint32_t pins)
{
if (push_status) {
return;
}
push_status = true;
printk("Button pressed at %" PRIu32 "\n", k_cycle_get_32());
sleep_time -= 100;
if (sleep_time<SLEEP_TIME_MS_MIN) {
sleep_time = SLEEP_TIME_MS;
}
printk("Sleep time is at %d\n", sleep_time);
push_status = false;
}
int main(void)
{
int ret;
if (!gpio_is_ready_dt(&button)) {
printk("Error: button device %s is not ready\n",
button.port->name);
return 0;
}
ret = gpio_pin_configure_dt(&button, GPIO_INPUT);
if (ret != 0) {
printk("Error %d: failed to configure %s pin %d\n",
ret, button.port->name, button.pin);
return 0;
}
ret = gpio_pin_interrupt_configure_dt(&button,
GPIO_INT_EDGE_TO_ACTIVE);
if (ret != 0) {
printk("Error %d: failed to configure interrupt on %s pin %d\n",
ret, button.port->name, button.pin);
return 0;
}
gpio_init_callback(&button_cb_data, button_pressed, BIT(button.pin));
gpio_add_callback(button.port, &button_cb_data);
printk("Set up button at %s pin %d\n", button.port->name, button.pin);
if (!gpio_is_ready_dt(&led0)) {
return 0;
}
ret = gpio_pin_configure_dt(&led0, GPIO_OUTPUT_ACTIVE);
if (ret < 0) {
return 0;
}
if (!gpio_is_ready_dt(&led1)) {
return 0;
}
ret = gpio_pin_configure_dt(&led1, GPIO_OUTPUT_ACTIVE);
if (ret < 0) {
return 0;
}
ret = gpio_pin_set_dt(&led0, 0);
if (ret < 0) {
return 0;
}
ret = gpio_pin_set_dt(&led1, 1);
if (ret < 0) {
return 0;
}
push_status = false;
while (1) {
ret = gpio_pin_toggle_dt(&led0);
if (ret < 0) {
return 0;
}
ret = gpio_pin_toggle_dt(&led1);
if (ret < 0) {
return 0;
}
k_msleep(sleep_time);
}
return 0;
}
在上述代码中,按键处理的核心部分如下:
1. 定义:
#define SW0_NODE DT_ALIAS(sw0)
static const struct gpio_dt_spec button = GPIO_DT_SPEC_GET_OR(SW0_NODE, gpios,
{0});
static struct gpio_callback button_cb_data;
static const struct gpio_dt_spec led0 = GPIO_DT_SPEC_GET(LED0_NODE, gpios);
static const struct gpio_dt_spec led1 = GPIO_DT_SPEC_GET(LED1_NODE, gpios);
定义的方式,和按键的方式类似,不过对应按钮,多了一些专门的设置,如上面的button_cb_data,表示按键定义后的回调数据。
2. 按键按下后的处理
int sleep_time = SLEEP_TIME_MS;
bool push_status = true;
void button_pressed(const struct device *dev, struct gpio_callback *cb,
uint32_t pins)
{
if (push_status) {
return;
}
push_status = true;
printk("Button pressed at %" PRIu32 "\n", k_cycle_get_32());
sleep_time -= 100;
if (sleep_time<SLEEP_TIME_MS_MIN) {
sleep_time = SLEEP_TIME_MS;
}
printk("Sleep time is at %d\n", sleep_time);
push_status = false;
}
上述调用,会在按键按下后,被回调。
在这个调用中,会递减延时时间sleep_time,直到最小值后,再从最大值开始,往复循环。
3. 按键初始化检查和回调配置
if (!gpio_is_ready_dt(&button)) {
printk("Error: button device %s is not ready\n",
button.port->name);
return 0;
}
ret = gpio_pin_configure_dt(&button, GPIO_INPUT);
if (ret != 0) {
printk("Error %d: failed to configure %s pin %d\n",
ret, button.port->name, button.pin);
return 0;
}
ret = gpio_pin_interrupt_configure_dt(&button,
GPIO_INT_EDGE_TO_ACTIVE);
if (ret != 0) {
printk("Error %d: failed to configure interrupt on %s pin %d\n",
ret, button.port->name, button.pin);
return 0;
}
gpio_init_callback(&button_cb_data, button_pressed, BIT(button.pin));
gpio_add_callback(button.port, &button_cb_data);
printk("Set up button at %s pin %d\n", button.port->name, button.pin);
上述代码,和led一样做了初始化的检查,然后设置了对应的回调。
4. 循环部分使用设置的延时时间:
push_status = false;
while (1) {
ret = gpio_pin_toggle_dt(&led0);
if (ret < 0) {
return 0;
}
ret = gpio_pin_toggle_dt(&led1);
if (ret < 0) {
return 0;
}
k_msleep(sleep_time);
}
5. 实际效果
将上述代码保存后,然后编译烧录,实际运行的效果如下。
首先我们看一下串口的输出:
可以看到,按键一下,则sleep time就减少100,低于100,则回到1000。单位为ms。
LED灯实际闪烁的效果如下:
五、总结
好了,点灯和按键的处理,就到这里了。
感兴趣的话,还可以试试通过按键,进行PWM调光,也就是控制LED的亮点效果。
|