18video性欧美19sex,欧美高清videosddfsexhd,性少妇videosexfreexxx片中国,激情五月激情综合五月看花,亚洲人成网77777色在线播放

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

nRF Connect SDK Basic

jf_14701710 ? 來(lái)源:jf_14701710 ? 作者:jf_14701710 ? 2025-08-20 10:41 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

用戶在使用 nRF connect SDK 的時(shí)候經(jīng)常會(huì)操作的外設(shè)有GPIO,I2C,SPI,UART。我們就以 nRF connect SDK 2.7.0 中的例程代碼 nrfsamplesbluetoothperipheral_lbs 為基礎(chǔ),來(lái)演示上述外設(shè)的簡(jiǎn)單使用。使用的硬件是開(kāi)發(fā)板 nRF52840 DK.

準(zhǔn)備工作

首先我們?cè)谠镜墓こ棠夸浀?boards 文件夾里,添加文件 nrf52840dk_nrf52840.overlay。通過(guò)這個(gè)文件我們可以修改 devicetree。 編譯完成后,我們可以查看 buildzephyrzephyr.dts,以確認(rèn)devicetree 的更改是否生效。

我們還可以通過(guò)修改 prj.conf 來(lái)修改 Kconfig。編譯完成后,我們可以查看 buildzephyr.config 以確認(rèn) Kconfig 的更改是否生效。

wKgZPGilNdmACeSdAABK1LsANgo21.jpeg

GPIO 控制

首先我們演示如何刪除原有的按鍵和LED的 node 。按照下面的代碼,來(lái)修改 devicetree,就可以刪除 button3 和 led3。

/ {
    aliases {
        /delete-property/ sw3;
        /delete-property/ led3;
    };
};


/delete-node/ &button3;
/delete-node/ &led3;

接著我們來(lái)更改控制 led2 的管腳。這里我們用 P0.04 控制 led2。

&led2 {
    gpios = ;
};

最后我們添加一個(gè)用戶 GPIO 。這里添加了一個(gè)名為 user_gpios 的 node。然后又定義了 user_io0,它是 user_gpios 的 subnode。

/ {
    user_gpios {
        compatible = "gpio-leds";
        user_io0: user_io0 {
            gpios = ;
            label = "user gpio 0";
        };
    };
};

我們不僅在 devicetree 里添加這個(gè) GPIO ,還要在 main.c 里添加代碼使用這個(gè)GPIO。下面這句代碼中,我們聲明了結(jié)構(gòu)體變量 user_gpio0,并用宏 GPIO_DT_SPEC_GET 根據(jù) devicetree 里的定義初始化它。

const struct gpio_dt_spec user_gpio_0 = GPIO_DT_SPEC_GET(DT_NODELABEL(user_io0),gpios);

下面這段代碼中 gpio_is_ready_dt 是用來(lái)檢查 GPIO 的狀態(tài)是否是就緒。用函數(shù) gpio_pin_configure_dt 把 user_gpio_0 配置成輸出。gpio_pin_toggle_dt 用來(lái)翻轉(zhuǎn) GPIO。

if (!gpio_is_ready_dt(&user_gpio_0)) {
    printk("%s: device not ready.n", user_gpio_0.port->name);
    return 0;
}
gpio_pin_configure_dt(&user_gpio_0, GPIO_OUTPUT_ACTIVE);

for (index = 0; index < 100; index++) {
    gpio_pin_toggle_dt(&user_gpio_0);
    k_sleep(K_MSEC(100));
}

從下面的代碼可以看出翻轉(zhuǎn) GPIO 這個(gè)操作有兩種 API 可以調(diào)用。二者的主要區(qū)別是 gpio_pin_toggle_dt 不需要指明引腳 。

/**
 * @brief Toggle pin level from a @p gpio_dt_spec.
 *
 * This is equivalent to:
 *
 *     gpio_pin_toggle(spec->port, spec->pin);
 *
 * @param spec GPIO specification from devicetree
 * @return a value from gpio_pin_toggle()
 */
static inline int gpio_pin_toggle_dt(const struct gpio_dt_spec *spec)
{
    return gpio_pin_toggle(spec->port, spec->pin);
}

I2C 設(shè)備控制

Nordic 的芯片中 I2C 接口是由外設(shè) TWI 來(lái)實(shí)現(xiàn)的,I2C master 由 TWIM 實(shí)現(xiàn), I2C master 由 TWIS 實(shí)現(xiàn)。這里將演示如何用一個(gè) TWIM 來(lái)連接兩個(gè) I2C slave 設(shè)備。

首先我們還是先修改 devicetree。我們使用 i2c1 這個(gè) node。 一方面按照應(yīng)用的要求修改這個(gè) node 的 propertise,另一方面在這個(gè) node 里創(chuàng)建兩個(gè) sub-node。

i2c 的時(shí)鐘頻率通過(guò) clock-frequency 來(lái)定義。

i2c 的引腳通過(guò) pinctrl-0 和 pinctrl-1 定義。我們將在后面分析 i2c1_default 和 i2c1_sleep 的定義。

這兩個(gè) sub-node 一個(gè)是 user_i2c_sensor,另一個(gè)是 user_i2c_eeprom。這兩個(gè) sub-node 通過(guò) propertise reg 來(lái)定義各自的 I2C 地址。

&i2c1 {
    status = "ok";
    clock-frequency = ;
    pinctrl-0 = < &i2c1_default >;
    pinctrl-1 = < &i2c1_sleep >;
    pinctrl-names = "default", "sleep";
    user_i2c_sensor: user_i2c_sensor@0 {
        compatible = "i2c-user-define";
        reg = ;
    };
    user_i2c_eeprom: user_i2c_eeprom@0 {
        compatible = "i2c-user-define";
        reg = ;
    };
};

i2c1_default 和 i2c1_sleep的定義如下。TWIM_SDA 信號(hào)使用的是引腳 P0.04,TWIM_SCL 信號(hào)使用的是引腳 P0.03。

&pinctrl {
    i2c1_default: i2c1_default {
        group1 {
            psels = ,
                ;
        };
    };

    i2c1_sleep: i2c1_sleep {
        group1 {
            psels = ,
                ;
            low-power-enable;
        };
    };

};

修改 prj.conf 添加 CONFIG_I2C=y

修改完 devicetree 我們?cè)趤?lái)添加操作 i2c 的代碼。分別定義 i2c1_sensor 和 i2c1_eeprom,它們對(duì)應(yīng)剛才 i2c1 的兩個(gè)子節(jié)點(diǎn)。

const struct i2c_dt_spec i2c1_sensor = I2C_DT_SPEC_GET(DT_NODELABEL(user_i2c_sensor));
const struct i2c_dt_spec i2c1_eeprom= I2C_DT_SPEC_GET(DT_NODELABEL(user_i2c_eeprom));

i2c 設(shè)備在讀寫(xiě)操作前無(wú)需調(diào)用 API 來(lái)配置 ,直接調(diào)用下面的寫(xiě)函數(shù)。

err = i2c_write_dt(&i2c1_sensor, buf, 1);

err = i2c_write_dt(&i2c1_eeprom, buf, 1);

通過(guò)邏輯分析儀我們可以看到如下的總線數(shù)據(jù),操作的目標(biāo)地址分別是我們?cè)?devicetree 里設(shè)置的數(shù)值 0x05 和 0x0A 。

wKgZPGilNdqATuRpAABLFQTcgaw05.jpeg

SPI 設(shè)備控制

Nordic 的芯片中 SPI 接口的 master 端通過(guò) SPIM 實(shí)現(xiàn), slave 端通過(guò) SPIS 實(shí)現(xiàn)。這里將演示如何用一個(gè) SPIM 來(lái)連接兩個(gè) SPI slave 設(shè)備。

首先修改 devicetree。

這里我們使用 spi2, 并且關(guān)閉 spi1。在 nordic 的nRF52 系列芯片中,相同數(shù)字編號(hào)的 TWIM, TWIS, SPIM, SPIS 是共用一組硬件模塊的。在上面 i2c 中我們已經(jīng)使用 i2c1, 所以這里我們就不能同時(shí)使用 spi1了。

cs-gpios 定義了 P0.26 和 P0.27 兩 個(gè)CS 信號(hào)。 SPI 用不同的片選信號(hào),區(qū)分不同的 slave 設(shè)備。

devicetree node spi2 下定義了兩個(gè) sub-node 分別是 user_spi_adc 和 user_spi_flash。 sub-node 里定義了三個(gè) propertise。propertise compatible 的取值來(lái)自于我們?cè)诠こ汤镄绿砑拥奈募?dtsbindingsspi-user-define.yaml。 propertise reg 的取值和前面的 propertise cs-gpios 呼應(yīng),reg = <0> 的 sub-node 使用 cs-gpios 里面定義的第一個(gè) CS 引腳。reg = <1> 的 sub-node 使用 cs-gpios 里面定義的第二個(gè) CS 引腳。propertise spi-max-frequency 定義 SPI 的時(shí)鐘頻率。兩個(gè)不同的 SPI 設(shè)備可以使用不同的時(shí)鐘頻率驅(qū)動(dòng)。

&spi1 {
    status = "disabled";
};
&spi2 {
    status = "okay";
    cs-gpios = ,
               ;
    pinctrl-0 = < &spi2_default >;
    pinctrl-1 = < &spi2_sleep >;
    pinctrl-names = "default", "sleep";

    user_spi_adc: user_spi_adc@0 {
        compatible = "spi-user-define";
        reg = ;
        spi-max-frequency = ;
    };
    user_spi_flash: user_spi_flash@0 {
        compatible = "spi-user-define";
        reg = ;
        spi-max-frequency = ;
    };
};

來(lái)看一下我們新添加的 dtsbindingsspi-user-define.yaml 里面的內(nèi)容。如下圖 spi-user-define.yaml 里面包含了 spi-device.yaml 文件,這個(gè)文件的位置在目錄 zephyrdtsbindingsspi 。

compatible: "spi-user-define"

include: [spi-device.yaml]

spi-device.yaml 文件里面定義了 spi 節(jié)點(diǎn)需要的一些 propertise。 比如我們?cè)?sub-node 里定義的 propertise spi-max-frequency。

# Copyright (c) 2018, I-SENSE group of ICCS
# SPDX-License-Identifier: Apache-2.0

# Common fields for SPI devices

include: [base.yaml, power.yaml]

on-bus: spi

properties:
  reg:
    required: true
  spi-max-frequency:
    type: int
    required: true
    description: Maximum clock frequency of device's SPI interface in Hz
  duplex:
    type: int
    default: 0
    description: |
      Duplex mode, full or half. By default it's always full duplex thus 0
      as this is, by far, the most common mode.
      Use the macros not the actual enum value, here is the concordance
      list (see dt-bindings/spi/spi.h)
        0    SPI_FULL_DUPLEX
        2048 SPI_HALF_DUPLEX
    enum:
      - 0
      - 2048
  frame-format:
    type: int
    default: 0
    description: |
      Motorola or TI frame format. By default it's always Motorola's,
      thus 0 as this is, by far, the most common format.
      Use the macros not the actual enum value, here is the concordance
      list (see dt-bindings/spi/spi.h)
        0     SPI_FRAME_FORMAT_MOTOROLA
        32768 SPI_FRAME_FORMAT_TI
    enum:
      - 0
      - 32768
  spi-cpol:

SPI 引腳定義如下 CLK P0.28, MISO P0.29, MOSI P0.30。

spi2_default: spi2_default {
    group1 {
        psels = ,
                ,
                ;
    };
};
spi2_sleep: spi2_sleep {
    group1 {
        psels = ,
                ,
                ;
        low-power-enable;
    };
};

修改 prj.conf 添加 CONFIG_SPI=y CONFIG_SPI_ASYNC=y。

在 main.c 里添加 SPI 的應(yīng)用代碼。下面這段代碼定義了兩個(gè)結(jié)構(gòu)體變量,并通過(guò)宏 SPI_DT_SPEC_GET 用 devicetree 里的參數(shù)初始化了這兩個(gè)結(jié)構(gòu)體變量。

#define SPI_OP     SPI_OP_MODE_MASTER | SPI_MODE_CPOL | SPI_MODE_CPHA 
                   | SPI_WORD_SET(8) | SPI_LINES_SINGLE
static struct spi_dt_spec spim2_adc = SPI_DT_SPEC_GET(DT_NODELABEL(user_spi_adc), SPI_OP, 0);
static struct spi_dt_spec spim2_flash = SPI_DT_SPEC_GET(DT_NODELABEL(user_spi_flash), SPI_OP, 0);

spi 驅(qū)動(dòng)支持多 buffer 所以要定義 buffer 個(gè)數(shù),和每個(gè) buffer 的長(zhǎng)度。同樣 spi 在讀寫(xiě)之前無(wú)需調(diào)用配置函數(shù),直接調(diào)用讀寫(xiě)函數(shù)就行。

struct spi_buf_set tx_bufs;
struct spi_buf spi_tx_buf;

tx_bufs.buffers = &spi_tx_buf;
tx_bufs.count = 1;
spi_tx_buf.buf = buf;
spi_tx_buf.len = 2;

err = spi_write_dt(&spim2_adc, &tx_bufs);
err = spi_write_dt(&spim2_flash, &tx_bufs);

下面是SPI的波形??梢钥吹胶筒煌?spi slave 設(shè)備通訊的時(shí)候, spi master 會(huì)拉低不同的 CS 引腳。

wKgZO2ilNdqAfdkyAAAzjUGgVu089.jpeg

UART 控制

Nordic 的芯片中 UART 接口叫做 UARTE。這里的 E 是指 EasyDMA , UART 可以使用 DMA 來(lái)連續(xù)收發(fā)。

修改 Devicetree。這里使用 uart1。propertise current-speed 設(shè)置 uart 的波特率。

&uart1 {
    status = "okay";
    current-speed = ;
    pinctrl-0 = < &uart1_default >;
    pinctrl-1 = < &uart1_sleep >;
    pinctrl-names = "default", "sleep";
};

TXD pin 為 P1.02, RXD pin 為 P1.01。

 uart1_default: uart1_default {
    group1 {
        psels = ;
        bias-pull-up;
    };
    group2 {
        psels = ;
    };
};

uart1_sleep: uart1_sleep {
    group1 {
        psels = ,
            ;
        low-power-enable;
    };
};

修改 prj.conf 在里面添加 CONFIG_UART_ASYNC_API=y CONFIG_UART_ASYNC_RX_HELPER=y。

修改 main.c 添加 uart 收發(fā)代碼。 uart_callback_set 設(shè)置 callback 函數(shù) uart_cb。因?yàn)檫@里采用的是異步收發(fā)的模式,所以設(shè)置callback 函數(shù)是必備的。uart_rx_enable 使能接收。uart_tx 發(fā)送數(shù)據(jù)。

err = uart_callback_set(uart1, uart_cb, NULL);
//printk("uart_callback_set return %dn", err);

err = uart_rx_enable(uart1, uart_rx_buf, MAX_UART_BUF_LEN, UART_RX_TIMEOUT_MS);
//printk("uart_rx_enable return %dn", err);

err = uart_tx(uart1, uart_tx_buf, 6, SYS_FOREVER_MS);
//printk("uart_tx return %dn", err);

callback 函數(shù) uart_cb 可能由多種事件觸發(fā)。比如當(dāng)接收到數(shù)據(jù)后會(huì)觸發(fā)回調(diào),并在參數(shù) EVT 傳遞 UART_RX_RDY 和接收到的數(shù)據(jù)和長(zhǎng)度。

static void uart_cb(const struct device *dev, struct uart_event *evt, void *user_data)
{
    ARG_UNUSED(dev);

    //LOG_INF("uart_cb evt->type:%d", evt->type);
    switch (evt->type) {
    case UART_TX_DONE:
        printk("UART_TX_DONEn");
        break;

    case UART_RX_RDY:
        printk("UART_RX_RDYn");
        printk("received %d bytesn", evt->data.rx.len);
        break;

    case UART_RX_DISABLED:
        printk("UART_RX_DISABLEDn");
        break;

    case UART_RX_BUF_REQUEST:
        printk("UART_RX_BUF_REQUESTn");
        uart_rx_buf_rsp(uart1, uart_rx_buf2, MAX_UART_BUF_LEN);
        break;

    case UART_RX_BUF_RELEASED:
        printk("UART_RX_BUF_RELEASEDn");
        break;

    case UART_TX_ABORTED:
        printk("UART_TX_ABORTEDn");
        break;

    default:
        break;
    }
}

我們?cè)?DK 上把 TXD 引腳和 RXD 引腳短接來(lái)測(cè)試 UART 的收發(fā),可以看到如下的 log 信息。UART 收到了自己發(fā)送的6字節(jié)的數(shù)據(jù)。

wKgZPGilNduAY7_BAACdqEMlnvU82.jpeg

UART 應(yīng)用代碼的優(yōu)化

上面的 uart 演示代碼中,我們只實(shí)現(xiàn)了簡(jiǎn)單的收發(fā)。下面我們將進(jìn)一步在此基礎(chǔ)上優(yōu)化 UART 的收發(fā)代碼。這一部分的修改都在 main.c 里,主要涉及下面幾個(gè)部分:

Thread 線程

Semaphore 信號(hào)量

線程間通訊 Message queue

線程 下面的代碼中通過(guò) K_THREAD_DEFINE 定義了 一個(gè)獨(dú)立的線程來(lái)處理 uart 相關(guān)的代碼。線程處理函數(shù) uart_thread_task 中:也是先用 uart_callback_set 設(shè)置了回調(diào)函數(shù);再用 uart_rx_enable 使能了接收;然后是一個(gè) for 循環(huán),在里面不斷的接收消息,根據(jù)消息中的指令發(fā)送數(shù)據(jù),或者處理接收到的數(shù)據(jù)。

#define UART_THREAD_STACK_SIZE    512
#define UART_THREAD_PRIORITY      -1

void uart_thread_task(void)
{
    int err;
    struct uart_data_item_type uart_msgq;

    k_sem_take(&uart_thread_start, K_FOREVER);

    printk("uart_thread_taskn");

    err = uart_callback_set(uart1, uart_cb, NULL);

    err = uart_rx_enable(uart1, uart_rx_buf, MAX_UART_BUF_LEN, UART_RX_TIMEOUT_MS);

    for (;;) {
        k_msgq_get(&uart_data_msgq, &uart_msgq, K_FOREVER);
        printk("received uart data itemn");

        switch(uart_msgq.cmd) {
        case UART_CMD_TX:
        memcpy(uart_tx_buf,&uart_msgq.data, sizeof(uint32_t));
        err = uart_tx(uart1, uart_tx_buf, sizeof(uint32_t), SYS_FOREVER_MS);
        break;

        case UART_CMD_DATA_PROCESS:
        break;

        default:
            break;
        }
    }
}

K_THREAD_DEFINE(uart_thread_id, UART_THREAD_STACK_SIZE, uart_thread_task, NULL, NULL,
                NULL, UART_THREAD_PRIORITY, 0, 0);

上面的代碼中用 K_THREAD_DEFINE 定義線程的時(shí)候,需要指定此線程的優(yōu)先級(jí) UART_THREAD_PRIORITY。UART_THREAD_PRIORITY 的數(shù)據(jù)類型是 integer,可以是正數(shù)也可以是負(fù)數(shù)。優(yōu)先級(jí)的數(shù)字越小,優(yōu)先級(jí)越高,負(fù)數(shù)的優(yōu)先級(jí)比正數(shù)高。thread 的優(yōu)先級(jí)取值為負(fù)數(shù)時(shí),此 thread 為協(xié)同線程 cooperative thread 。當(dāng)這種線程正在執(zhí)行的時(shí)候,其它更高優(yōu)先級(jí)的線程不能打斷它,必須等它執(zhí)行完再執(zhí)行下一個(gè)線程。當(dāng) thread 的優(yōu)先級(jí)取值為正數(shù),此 thread 為搶占線程 preemptible thread。當(dāng)這種線程正在執(zhí)行的時(shí)候,其它更高優(yōu)先級(jí)的線程可以打斷它,跳轉(zhuǎn)到高優(yōu)先級(jí)的任務(wù)。等高優(yōu)先級(jí)的線程執(zhí)行完才返回原 thread 繼續(xù)執(zhí)行?;氐嚼檀a,從應(yīng)用的角度出發(fā),我們希望 uart_thread_task 的執(zhí)行優(yōu)先級(jí)大于 main 函數(shù)。通過(guò)查詢文件 buildzephyr.config 我們得知 CONFIG_MAIN_THREAD_PRIORITY 的取值為 0,也就是說(shuō) main thread 當(dāng)前的優(yōu)先級(jí)為 0, 所以我們定義了 UART_THREAD_PRIORITY 為 -1。這樣 uart thread 的優(yōu)先級(jí)就高于 main thread, 而且 uart thread 的執(zhí)行不會(huì)被其它更高優(yōu)先級(jí)的 thread 打斷。需要注意的是這里的不能被打斷只是對(duì) thread 而言,中斷是可以打斷 cooperative thread 的。

信號(hào)量 函數(shù) uart_thread_task 的優(yōu)先級(jí)比 main 函數(shù)高,所以會(huì)先于main 函數(shù)執(zhí)行。如果之前的函數(shù) uart_thread_task 里沒(méi)有 k_sem_take(&uart_thread_start, K_FOREVER),就會(huì)出現(xiàn)如下圖的現(xiàn)象。我們看到 uart thread 的 log 是先于 main thread 被打印出來(lái)的。

wKgZO2ilNdyASkHZAACxi5yzJDg78.jpeg

從應(yīng)用的角度,我們希望 uart_thread_task 在 main 函數(shù)啟動(dòng)完廣播之后再執(zhí)行。這就引入了一個(gè)不同線程之間的同步問(wèn)題。Zephyr RTOS 中可以通過(guò) semaphore 解決不同 thread 間的同步問(wèn)題。下面的代碼中通過(guò) K_SEM_DEFINE 定義了一個(gè)為 uart_thread_start 的 semaphore 。 函數(shù) uart_thread_task 執(zhí)行到函數(shù) k_sem_take 時(shí),如果 uart_thread_start 沒(méi)有被釋放,當(dāng)前 thread 會(huì)被掛起等待,直到 semaphore 被釋放。

static K_SEM_DEFINE(uart_thread_start, 0, 1);

#define UART_THREAD_STACK_SIZE    512
#define UART_THREAD_PRIORITY      -1

void uart_thread_task(void)
{
    int err;
    struct uart_data_item_type uart_msgq;

    k_sem_take(&uart_thread_start, K_FOREVER);

    printk("uart_thread_taskn");

    err = uart_callback_set(uart1, uart_cb, NULL);

    err = uart_rx_enable(uart1, uart_rx_buf, MAX_UART_BUF_LEN, UART_RX_TIMEOUT_MS);

    for (;;) {

在 main 里通過(guò) k_sem_give 釋放 uart_thread_start。uart 線程會(huì)打斷當(dāng)前的 main thread 從 k_sem_take 繼續(xù)執(zhí)行。

err = spi_write_dt(&spim2_adc, &tx_bufs);
err = spi_write_dt(&spim2_flash, &tx_bufs);

k_sem_give(&uart_thread_start);

struct uart_data_item_type main_msgq;

main_msgq.cmd = UART_CMD_TX;
main_msgq.data = 0;

for (;;) {

    while (k_msgq_put(&uart_data_msgq, &main_msgq, K_NO_WAIT) != 0) {
        /* message queue is full: purge old data & try again */
        k_msgq_purge(&uart_data_msgq);
    }
    main_msgq.data++;

    dk_set_led(RUN_STATUS_LED, (++blink_status) % 2);
    k_sleep(K_MSEC(RUN_LED_BLINK_INTERVAL));
}

線程間通訊 演示代碼中 main thread 會(huì)把要發(fā)送的數(shù)據(jù)通過(guò)線程通訊發(fā)送到 uart thread, uart thread 調(diào)用驅(qū)動(dòng)函數(shù)發(fā)送。zephyr 中提供了多種線程間通訊方式,具體如下圖,這里使用的是 message queue。

wKgZPGilNdyADvoPAABtzOcdD7823.jpeg

下面的代碼中 K_MSGQ_DEFINE 定義了一個(gè)名為 uart_data_msgq 的 message queue。uart_data_msgq 的緩沖區(qū)里最多可以容納 8 個(gè)消息。

struct uart_data_item_type {
    uint8_t cmd;
    uint32_t data;
};

K_MSGQ_DEFINE(uart_data_msgq, sizeof(struct uart_data_item_type), 8, 4);

下面這段代碼來(lái)自于 main thread 的 main 函數(shù)。代碼會(huì)定時(shí)循環(huán)把待發(fā)送的數(shù)據(jù)打包成一個(gè) message,然后推送到 message queue 里面。

struct uart_data_item_type main_msgq;

main_msgq.cmd = UART_CMD_TX;
main_msgq.data = 0;

for (;;) {

    while (k_msgq_put(&uart_data_msgq, &main_msgq, K_NO_WAIT) != 0) {
        /* message queue is full: purge old data & try again */
        k_msgq_purge(&uart_data_msgq);
    }
    main_msgq.data++;

    dk_set_led(RUN_STATUS_LED, (++blink_status) % 2);
    k_sleep(K_MSEC(RUN_LED_BLINK_INTERVAL));
}

下面的代碼來(lái)自 uart thread 的 uart_thread_task 函數(shù)。 函數(shù)等待 message queue 里推送來(lái)的 message。得到 message 后,根據(jù)里面的 cmd 字段來(lái)處理發(fā)送或者接收數(shù)據(jù)。

void uart_thread_task(void)
{
    int err;
    struct uart_data_item_type uart_msgq;

    k_sem_take(&uart_thread_start, K_FOREVER);

    printk("uart_thread_taskn");

    err = uart_callback_set(uart1, uart_cb, NULL);

    err = uart_rx_enable(uart1, uart_rx_buf, MAX_UART_BUF_LEN, UART_RX_TIMEOUT_MS);

    for (;;) {
        k_msgq_get(&uart_data_msgq, &uart_msgq, K_FOREVER);
        printk("received uart data itemn");

        switch(uart_msgq.cmd) {
        case UART_CMD_TX:
        memcpy(uart_tx_buf,&uart_msgq.data, sizeof(uint32_t));
        err = uart_tx(uart1, uart_tx_buf, sizeof(uint32_t), SYS_FOREVER_MS);
        break;

        case UART_CMD_DATA_PROCESS:
        break;

        default:
            break;
        }
    }
}

下面是加入線程間通訊的代碼后得到的 log,當(dāng)我們把 TX 和 RX 引腳短接后可以看出 uart thread 不斷的發(fā)送從 main thread 傳輸?shù)臄?shù)據(jù)。

wKgZPGilNb6AbhUUAAJR31FvtbQ998.png

總結(jié)

本文從實(shí)際操作出發(fā),介紹了用戶最常用的一些外設(shè)如 GPIO, I2C, SPI, UART 的配置和使用方法。并介紹了一些簡(jiǎn)單 RTOS 組件的應(yīng)用如 thread, semaphore, message queue。希望能幫助 Nordic 用戶加快 nRF Connect SDK 的開(kāi)發(fā)速度。

審核編輯 黃宇

聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • NRF
    NRF
    +關(guān)注

    關(guān)注

    0

    文章

    50

    瀏覽量

    38512
  • SDK
    SDK
    +關(guān)注

    關(guān)注

    3

    文章

    1091

    瀏覽量

    50772
收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評(píng)論

    相關(guān)推薦
    熱點(diǎn)推薦

    Nordic 推出nRF Connect for Cloud 的無(wú)線物聯(lián)網(wǎng)設(shè)計(jì)方案

    Nordic Semiconductor宣布推出nRF Connect for Cloud,用于免費(fèi)評(píng)估、測(cè)試和驗(yàn)證基于云并且采用Nordic nRF51和nRF52系列多協(xié)議低功耗藍(lán)
    的頭像 發(fā)表于 06-21 15:05 ?9590次閱讀

    nRF Connect SDK(NCS)/Zephyr固件升級(jí)詳解 – 重點(diǎn)講述MCUboot和藍(lán)牙空中升級(jí)

    如何在nRF Connect SDK(NCS)中實(shí)現(xiàn)藍(lán)牙空中升級(jí)?MCUboot和B0兩個(gè)Bootloader有什么區(qū)別?MCUboot升級(jí)使用的image格式是怎么樣的?什么是SMP協(xié)議?CBOR
    的頭像 發(fā)表于 05-09 14:14 ?2613次閱讀
    <b class='flag-5'>nRF</b> <b class='flag-5'>Connect</b> <b class='flag-5'>SDK</b>(NCS)/Zephyr固件升級(jí)詳解 – 重點(diǎn)講述MCUboot和藍(lán)牙空中升級(jí)

    Nordic nRF5 SDK和softdevice介紹

    Connect SDK。一般來(lái)說(shuō),開(kāi)發(fā)nRF51/52產(chǎn)品推薦使用nRF5 SDK,開(kāi)發(fā)nRF
    的頭像 發(fā)表于 08-20 09:54 ?2415次閱讀
    Nordic <b class='flag-5'>nRF</b>5 <b class='flag-5'>SDK</b>和softdevice介紹

    Nordic nRF Connect SDK 官方開(kāi)發(fā)文檔、學(xué)習(xí)資料下載鏈接

    /14174427.html nRF Connect SDK詳解 https://lgl88911.gitee.io/ 其他博客 https://academy.nordicsemi.com/courses
    發(fā)表于 04-23 13:48

    如何調(diào)試nRF5 SDK

    本文將講述Nordic nRF5 SDK的主要調(diào)試手段,以幫助大家快速定位問(wèn)題,并解決問(wèn)題。一般來(lái)說(shuō),你可以通過(guò)打log方式,IDE的debug模式,SDK自帶的app_error_check函數(shù)
    發(fā)表于 04-26 23:13

    nRF52840-DK和nRF21540-EK上FEM的支持事宜

    1:PDN引腳問(wèn)題只在使用 ESB 協(xié)議時(shí)發(fā)生,nRF52840-DK 和 nRF21540-EK 之間的引腳連接。 Nordic Connect SDK 2.8.0、2.9.0 及更
    發(fā)表于 07-31 11:08

    CH582使用nRF Connect這個(gè)軟件根本搜索不到藍(lán)牙設(shè)備怎么解決?

    我參考了你們的例程修改后打印log 顯示開(kāi)啟廣播 但手機(jī)使用nRF Connect這個(gè)軟件根本搜索不到藍(lán)牙設(shè)備 請(qǐng)問(wèn)咋搞
    發(fā)表于 09-06 06:01

    esp32連接nrf-connect報(bào)錯(cuò)是何原因?如何解決?

    nrf-connect連不上,報(bào)錯(cuò) Error 133(0x85): GATT ERROR需要經(jīng)常connect好多次才能成功連上
    發(fā)表于 03-03 07:58

    講述Nordic nRF5 SDK的主要調(diào)試手段,以幫助大家快速定位問(wèn)題

    nRF5 SDK日志打印功能是通過(guò)nRF_Log模塊實(shí)現(xiàn)的(上面展示的日志都是通過(guò)nRF_Log打印出來(lái)的),SDK包含的大部分例子都自帶打
    的頭像 發(fā)表于 04-15 15:38 ?1.4w次閱讀
    講述Nordic <b class='flag-5'>nRF</b>5 <b class='flag-5'>SDK</b>的主要調(diào)試手段,以幫助大家快速定位問(wèn)題

    DFU協(xié)議簡(jiǎn)介 NCS DFU升級(jí)步驟說(shuō)明

    nRF Connect SDK (NCS) / Zephyr 固件升級(jí),主要包括MCUboot和藍(lán)牙空中升級(jí)。
    的頭像 發(fā)表于 05-11 12:51 ?1.1w次閱讀

    Memfault基于云的自助設(shè)備可觀察性平臺(tái)

      入門指南適用于 Arm Cortex-M、nRF Connect SDK、Laird Pinnacle 100、ESP32 ESP-IDF 和 ESP8266 RTOS SDK。
    的頭像 發(fā)表于 06-21 09:12 ?1109次閱讀
    Memfault基于云的自助設(shè)備可觀察性平臺(tái)

    基于XIAO nRF52840的鑰匙尋找器

    BLE nRF52840 Sense × 1 蜂鳴器 × 1 LED × 1 軟件 nRF Connect SDK? ? Seeed Fusion 核心組件及作用 這款智能鑰匙尋
    的頭像 發(fā)表于 01-17 11:03 ?826次閱讀
    基于XIAO <b class='flag-5'>nRF</b>52840的鑰匙尋找器

    nRF5 SDK軟件架構(gòu)及softdevice工作原理

    本文將介紹Nordic nRF5 SDK軟件架構(gòu)以及softdevice工作原理,以加深大家對(duì)Nordic產(chǎn)品開(kāi)發(fā)的理解,這樣開(kāi)發(fā)過(guò)程中碰到問(wèn)題時(shí),大家也知道如何去調(diào)試。 如果你剛開(kāi)始接觸nRF
    的頭像 發(fā)表于 06-23 11:08 ?382次閱讀
    <b class='flag-5'>nRF</b>5 <b class='flag-5'>SDK</b>軟件架構(gòu)及softdevice工作原理

    如何調(diào)試nRF5 SDK

    本文將講述Nordic nRF5 SDK的主要調(diào)試手段,以幫助大家快速定位問(wèn)題,并解決問(wèn)題。一般來(lái)說(shuō),你可以通過(guò)打log方式,IDE的debug模式,SDK自帶的app_error_check函數(shù)
    的頭像 發(fā)表于 06-24 08:59 ?386次閱讀
    如何調(diào)試<b class='flag-5'>nRF</b>5 <b class='flag-5'>SDK</b>

    nRF Connect SDK 使用 nPM2100 評(píng)估套件 (PCA10170) 為 nPM2100 電源管理 IC (PMIC) 的開(kāi)發(fā)

    and libraries nRF Connect SDK 提供了多個(gè) PMIC 示例 ,演示了使用 nPM2100 EK 的 nPM2100 的特性和功能。 nRF
    的頭像 發(fā)表于 07-28 17:48 ?387次閱讀
    <b class='flag-5'>nRF</b> <b class='flag-5'>Connect</b> <b class='flag-5'>SDK</b> 使用 nPM2100 評(píng)估套件 (PCA10170) 為 nPM2100 電源管理 IC (PMIC) 的開(kāi)發(fā)