如何在 Zephyr 中将中断输入更改为模拟输入并再次返回?

问题描述

我是 Zephyr 的新手,我尝试将我所有的嵌入式软件都交给 Zephyr。 我尝试了 Zephyr 文档和大量的谷歌搜索,但很难弄清楚如何做到这一点。 我试图了解“设备树”是如何工作的,以及如何在应用程序内部和外部 Zephyr 系统端使用它。 我试着通过样品,看看它们是如何组合在一起的。 现在我正在测试... zephyrproject/zephyr/samples/basic/button/。

我有一个输入(按钮)和一个可选输出(LED)。输入也可以是 ADC 多路复用器的模拟输入。 我稍微修改了一下,它做了它应该做的。 但我想改变它以做更多。 我也想让这个中断(除其他外)使 cpu 脱离深度睡眠。并在工作完成后重新进入深度睡眠。

问题_1: 如何禁用中断,并将输入从中断输入更改为模拟输入(在中断/回调处理程序中)并启动 ADC? 然后,在另一个线程中,我想读取 ADC 并将输入更改回中断输入,启用它,做任何我想做的事情,然后回到深度睡眠。

如何以“Zephyr 方式”完成此操作(因此它可以在不同平台上运行),我在我的 nrf52dk_nrf52832(没有 Zephyr)上执行此操作,并且它可以满足我的要求。

输入来自数字键盘,有一个输出,在按键时变高,然后返回到每个键不同的模拟电平,释放键时电平变为零。当然,我们的目标是解码按下的键,并用一行 io 来完成。

问题 2: 当/如果这适用于 Zephyr;我该怎么做才能使它成为合适的 Zephyr 设备驱动程序?

最好有示例来执行此操作,所有操作都在应用程序中完成。还有一个是用 Zephyr“key_pad_device_driver”完成的。

(在我的非 Zephyr 系统中,我在中断后稍等(大约 0.3 - 3 毫秒),然后读取 10 个模拟样本,丢弃两个最高值和两个最低值,然后如果两者之间的跨度这些都被接受了,我取它们的平均值并锁定按下的键。这工作得非常好)。

她是我的“button/src/main.c”的代码

/*
 * copyright (c) 2016 Open-RnD Sp. z o.o.
 * copyright (c) 2020 nordic Semiconductor ASA
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include <zephyr.h>
#include <device.h>
#include <drivers/gpio.h>
#include <sys/util.h>
#include <sys/printk.h>
#include <inttypes.h>

#define LED_ON_TIME 100

/*
 * Get button configuration from the devicetree sw0 alias.
 *
 * At least a GPIO device and pin number must be provided. The 'flags'
 * cell is optional.
 */

#define SW0_NODE    DT_ALIAS(sw0)

#if DT_NODE_HAS_STATUS(SW0_NODE,okay)
    #define SW0_GPIO_LABEL  DT_GPIO_LABEL(SW0_NODE,gpios)
    #define SW0_GPIO_PIN    DT_GPIO_PIN(SW0_NODE,gpios)
    #define SW0_GPIO_FLAGS  (GPIO_INPUT | DT_GPIO_FLAGS(SW0_NODE,gpios))
#else
    #error "Unsupported board: sw0 devicetree alias is not defined"
    #define SW0_GPIO_LABEL  ""
    #define SW0_GPIO_PIN    0
    #define SW0_GPIO_FLAGS  0
#endif

/* LED helpers,which use the led0 devicetree alias if it's available. */
static const struct device *initialize_led(void);

static struct gpio_callback button_cb_data;


K_SEM_DEFINE(kbd_pres_sem,1);   /* starts off "not available" */    // K_SEM_DEFINE(kbd_pres_sem,1,1);    /* starts off "available" */

void bp_cb(const struct device *dev,struct gpio_callback *cb,uint32_t pins)
{
    static int cp_cnt;

    printk("\n# bp_cb(): %d Button pressed at: %" PRIu32 "... ",cp_cnt++,k_cycle_get_32());
    k_sem_give(&kbd_pres_sem);  // Giving the semaphore increments its count,unless the count is already equal to the limit.
}

/*
 * The led0 devicetree alias is optional. If present,we'll use it
 * to turn on the LED whenever the button is pressed.
 */

#define LED0_NODE   DT_ALIAS(led0)

#if DT_NODE_HAS_STATUS(LED0_NODE,okay) && DT_NODE_HAS_PROP(LED0_NODE,gpios)
    #define LED0_GPIO_LABEL DT_GPIO_LABEL(LED0_NODE,gpios)
    #define LED0_GPIO_PIN   DT_GPIO_PIN(LED0_NODE,gpios)
    #define LED0_GPIO_FLAGS (GPIO_OUTPUT | DT_GPIO_FLAGS(LED0_NODE,gpios))
#endif

K_SEM_DEFINE(led_blink_sem,1);  /* starts off "not available" */    // K_SEM_DEFINE(led_blink_sem,1);   /* starts off "available" */
const struct device *button;
const struct device *led;

void main(void)
{
    int ret;
    int bp_cnt = 0;;

    if((button = device_get_binding(SW0_GPIO_LABEL)) == NULL){
        printk("Error: didn't find %s device\n",SW0_GPIO_LABEL);
        return;
    }

    if((ret = gpio_pin_configure(button,SW0_GPIO_PIN,SW0_GPIO_FLAGS)) != 0){
        printk("Error %d: Failed to configure %s pin %d\n",ret,SW0_GPIO_LABEL,SW0_GPIO_PIN);
        return;
    }

    if((ret = gpio_pin_interrupt_configure(button,GPIO_INT_EDGE_TO_ACTIVE)) != 0){
        printk("Error %d: Failed to configure interrupt on %s pin %d edg %x\n",GPIO_INT_EDGE_TO_ACTIVE);
        return;
    }

    gpio_init_callback(&button_cb_data,bp_cb,BIT(SW0_GPIO_PIN));
    gpio_add_callback(button,&button_cb_data);
    printk("\tSet up button at %s pin %d edg 0x%x\n",GPIO_INT_EDGE_TO_ACTIVE);

    led = initialize_led();

    printk("\tPress the button,");
    while(1){
        k_sem_take(&kbd_pres_sem,K_FOREVER);   // Taking the semaphore decrements its count,unless the semaphore is unavailable (i.e. at zero).
        printk("# main(): %d Button press detected at: %" PRIu32 "... ",bp_cnt++,k_cycle_get_32());
        k_sem_give(&led_blink_sem);     // Giving the semaphore increments its count,unless the count is already equal to the limit.
    }
}

#ifdef LED0_GPIO_LABEL
    void led_handler(void)
    {
        int lb_cnt = 0;
        
        printk("\t######## led_handler: Start #########\n");

        while(1){
            gpio_pin_set(led,LED0_GPIO_PIN,1);    // ledd off
            k_sem_take(&led_blink_sem,K_FOREVER);  // Taking the semaphore decrements its count,unless the semaphore is unavailable (i.e. at zero).

            printk(" # led_handler(): %d Led blink",lb_cnt++);
        
            gpio_pin_set(led,0);    // ledd on

            k_msleep(LED_ON_TIME);  // k_msleep(3000);

        }
    }

    #define STACKSIZE 1024  /* size of stack area used by each thread */
    #define PRIORITY 7  /* scheduling priority used by each thread */

    K_THREAD_DEFINE(led_handler_id,STACKSIZE,led_handler,NULL,PRIORITY,0);

#endif  /* LED0_GPIO_LABEL */

static const struct device *initialize_led(void)
{
    #ifdef LED0_GPIO_LABEL
        const struct device *led;
        int ret;

        led = device_get_binding(LED0_GPIO_LABEL);
        if (led == NULL) {
            printk("Didn't find LED device %s\n",LED0_GPIO_LABEL);
            return NULL;
        }

        ret = gpio_pin_configure(led,LED0_GPIO_FLAGS);
        if (ret != 0) {
            printk("Error %d: Failed to configure LED device %s pin %d flg %x\n",LED0_GPIO_LABEL,LED0_GPIO_FLAGS);
            return NULL;
        }

        printk("\tSet up LED at %s pin %d flg 0x%x\n",LED0_GPIO_FLAGS);

        return led;
        
    #else  /* !defined(LED0_GPIO_LABEL) */
        printk("No LED device was defined\n");
        return NULL;
    #endif  /* LED0_GPIO_LABEL */
}

Zephyr 应用程序还有一些配置内容,但对于能够回答这个问题的应用程序,我认为现在并不重要。 但我认为答案确实需要一些配置才能起作用。

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)