chinese直男口爆体育生外卖, 99久久er热在这里只有精品99, 又色又爽又黄18禁美女裸身无遮挡, gogogo高清免费观看日本电视,私密按摩师高清版在线,人妻视频毛茸茸,91论坛 兴趣闲谈,欧美 亚洲 精品 8区,国产精品久久久久精品免费

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

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

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

nRF Connect SDK Basic

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

掃碼添加小助手

加入工程師交流群

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

準備工作

首先我們在原本的工程目錄的 boards 文件夾里,添加文件 nrf52840dk_nrf52840.overlay。通過這個文件我們可以修改 devicetree。 編譯完成后,我們可以查看 buildzephyrzephyr.dts,以確認devicetree 的更改是否生效。

我們還可以通過修改 prj.conf 來修改 Kconfig。編譯完成后,我們可以查看 buildzephyr.config 以確認 Kconfig 的更改是否生效。

wKgZPGilNdmACeSdAABK1LsANgo21.jpeg

GPIO 控制

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

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


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

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

&led2 {
    gpios = ;
};

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

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

我們不僅在 devicetree 里添加這個 GPIO ,還要在 main.c 里添加代碼使用這個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 是用來檢查 GPIO 的狀態(tài)是否是就緒。用函數(shù) gpio_pin_configure_dt 把 user_gpio_0 配置成輸出。gpio_pin_toggle_dt 用來翻轉(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 這個操作有兩種 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 來實現(xiàn)的,I2C master 由 TWIM 實現(xiàn), I2C master 由 TWIS 實現(xiàn)。這里將演示如何用一個 TWIM 來連接兩個 I2C slave 設(shè)備。

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

i2c 的時鐘頻率通過 clock-frequency 來定義。

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

這兩個 sub-node 一個是 user_i2c_sensor,另一個是 user_i2c_eeprom。這兩個 sub-node 通過 propertise reg 來定義各自的 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 信號使用的是引腳 P0.04,TWIM_SCL 信號使用的是引腳 P0.03。

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

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

};

修改 prj.conf 添加 CONFIG_I2C=y

修改完 devicetree 我們在來添加操作 i2c 的代碼。分別定義 i2c1_sensor 和 i2c1_eeprom,它們對應(yīng)剛才 i2c1 的兩個子節(jié)點。

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è)備在讀寫操作前無需調(diào)用 API 來配置 ,直接調(diào)用下面的寫函數(shù)。

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

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

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

wKgZPGilNdqATuRpAABLFQTcgaw05.jpeg

SPI 設(shè)備控制

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

首先修改 devicetree。

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

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

devicetree node spi2 下定義了兩個 sub-node 分別是 user_spi_adc 和 user_spi_flash。 sub-node 里定義了三個 propertise。propertise compatible 的取值來自于我們在工程里新添加的文件 dtsbindingsspi-user-define.yaml。 propertise reg 的取值和前面的 propertise cs-gpios 呼應(yīng),reg = <0> 的 sub-node 使用 cs-gpios 里面定義的第一個 CS 引腳。reg = <1> 的 sub-node 使用 cs-gpios 里面定義的第二個 CS 引腳。propertise spi-max-frequency 定義 SPI 的時鐘頻率。兩個不同的 SPI 設(shè)備可以使用不同的時鐘頻率驅(qū)動。

&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 = ;
    };
};

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

compatible: "spi-user-define"

include: [spi-device.yaml]

spi-device.yaml 文件里面定義了 spi 節(jié)點需要的一些 propertise。 比如我們在 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)用代碼。下面這段代碼定義了兩個結(jié)構(gòu)體變量,并通過宏 SPI_DT_SPEC_GET 用 devicetree 里的參數(shù)初始化了這兩個結(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ū)動支持多 buffer 所以要定義 buffer 個數(shù),和每個 buffer 的長度。同樣 spi 在讀寫之前無需調(diào)用配置函數(shù),直接調(diào)用讀寫函數(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è)備通訊的時候, spi master 會拉低不同的 CS 引腳。

wKgZO2ilNdqAfdkyAAAzjUGgVu089.jpeg

UART 控制

Nordic 的芯片中 UART 接口叫做 UARTE。這里的 E 是指 EasyDMA , UART 可以使用 DMA 來連續(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。因為這里采用的是異步收發(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ā)。比如當接收到數(shù)據(jù)后會觸發(fā)回調(diào),并在參數(shù) EVT 傳遞 UART_RX_RDY 和接收到的數(shù)據(jù)和長度。

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;
    }
}

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

wKgZPGilNduAY7_BAACdqEMlnvU82.jpeg

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

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

Thread 線程

Semaphore 信號量

線程間通訊 Message queue

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

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

wKgZO2ilNdyASkHZAACxi5yzJDg78.jpeg

從應(yīng)用的角度,我們希望 uart_thread_task 在 main 函數(shù)啟動完廣播之后再執(zhí)行。這就引入了一個不同線程之間的同步問題。Zephyr RTOS 中可以通過 semaphore 解決不同 thread 間的同步問題。下面的代碼中通過 K_SEM_DEFINE 定義了一個為 uart_thread_start 的 semaphore 。 函數(shù) uart_thread_task 執(zhí)行到函數(shù) k_sem_take 時,如果 uart_thread_start 沒有被釋放,當前 thread 會被掛起等待,直到 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 里通過 k_sem_give 釋放 uart_thread_start。uart 線程會打斷當前的 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 會把要發(fā)送的數(shù)據(jù)通過線程通訊發(fā)送到 uart thread, uart thread 調(diào)用驅(qū)動函數(shù)發(fā)送。zephyr 中提供了多種線程間通訊方式,具體如下圖,這里使用的是 message queue。

wKgZPGilNdyADvoPAABtzOcdD7823.jpeg

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

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);

下面這段代碼來自于 main thread 的 main 函數(shù)。代碼會定時循環(huán)把待發(fā)送的數(shù)據(jù)打包成一個 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));
}

下面的代碼來自 uart thread 的 uart_thread_task 函數(shù)。 函數(shù)等待 message queue 里推送來的 message。得到 message 后,根據(jù)里面的 cmd 字段來處理發(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,當我們把 TX 和 RX 引腳短接后可以看出 uart thread 不斷的發(fā)送從 main thread 傳輸?shù)臄?shù)據(jù)。

wKgZPGilNb6AbhUUAAJR31FvtbQ998.png

總結(jié)

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

審核編輯 黃宇

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

    關(guān)注

    0

    文章

    50

    瀏覽量

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

    關(guān)注

    3

    文章

    1091

    瀏覽量

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

掃碼添加小助手

加入工程師交流群

    評論

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

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

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

    nRF Connect SDK(NCS)/Zephyr固件升級詳解 – 重點講述MCUboot和藍牙空中升級

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

    Nordic nRF5 SDK和softdevice介紹

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

    Nordic nRF Connect SDK 官方開發(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)試手段,以幫助大家快速定位問題,并解決問題。一般來說,你可以通過打log方式,IDE的debug模式,SDK自帶的app_error_check函數(shù)
    發(fā)表于 04-26 23:13

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

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

    esp32連接nrf-connect報錯是何原因?如何解決?

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

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

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

    nRF52開發(fā)工具包用戶指南免費下載

    nRF5 SDK v14.1.0開始,SDK支持為nRF52810開發(fā),包括一個模擬nRF52810的示例項目。此項目位于PCA1004E子
    發(fā)表于 12-02 08:00 ?34次下載
    <b class='flag-5'>nRF</b>52開發(fā)工具包用戶指南免費下載

    DFU協(xié)議簡介 NCS DFU升級步驟說明

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

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

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

    基于XIAO nRF52840的鑰匙尋找器

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

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

    本文將介紹Nordic nRF5 SDK軟件架構(gòu)以及softdevice工作原理,以加深大家對Nordic產(chǎn)品開發(fā)的理解,這樣開發(fā)過程中碰到問題時,大家也知道如何去調(diào)試。 如果你剛開始接觸nRF
    的頭像 發(fā)表于 06-23 11:08 ?364次閱讀
    <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)試手段,以幫助大家快速定位問題,并解決問題。一般來說,你可以通過打log方式,IDE的debug模式,SDK自帶的app_error_check函數(shù)
    的頭像 發(fā)表于 06-24 08:59 ?362次閱讀
    如何調(diào)試<b class='flag-5'>nRF</b>5 <b class='flag-5'>SDK</b>

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

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