【Nordic博文分享系列】nRFConnectSDKBasic

Nordic半导体 2025-01-15 17:00




转载自:博客园 |作者:zhengyi_hot

用户在使用 nRF connect SDK(NCS) 的时候经常会操作的外设有GPIO,I2C,SPI,UART。

我们就以 NCS 2.7.0 中的例程代码 nrf\samples\bluetooth\peripheral_lbs 为基础,来演示上述外设的简单使用。

使用的硬件是开发板 nRF52840 DK





具体操作

1

准备工作

  • 首先我们在原本的工程目录的 boards 文件夹里,添加文件 nrf52840dk_nrf52840.overlay。通过这个文件我们可以修改 devicetree。 编译完成后,我们可以查看 build\zephyr\zephyr.dts,以确认devicetree 的更改是否生效。

  • 我们还可以通过修改 prj.conf 来修改 Kconfig。编译完成后,我们可以查看 build\zephyr\.config 以确认 Kconfig 的更改是否生效。




2

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 = <&gpio0 4 GPIO_ACTIVE_LOW>;};
  • 最后我们添加一个用户 GPIO 。这里添加了一个名为 user_gpios 的 node。然后又定义了 user_io0,它是 user_gpios 的 subnode。

/ {    user_gpios {        compatible = "gpio-leds";        user_io0: user_io0 {            gpios = <&gpio0 16 GPIO_ACTIVE_LOW>;            label = "user gpio 0";        };    };};

我们不仅在 devicetree 里添加这个 GPIO ,还要在 main.c 里添加代码使用这个GPIO。下面这句代码中,我们声明了结构体变量  user_gpio0,并用宏 GPIO_DT_SPEC_GET 根据 devicetree 里的定义初始化它。

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

下面这段代码中  gpio_is_ready_dt 是用来检查 GPIO 的状态是否是就绪。用函数 gpio_pin_configure_dt 把 user_gpio_0 配置成输出。gpio_pin_toggle_dt 用来翻转 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));}

从下面的代码可以看出翻转 GPIO 这个操作有两种 API 可以调用。二者的主要区别是 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);}



3

I2C 设备控制

Nordic 的芯片中 I2C 接口是由外设 TWI 来实现的,I2C master 由 TWIM 实现, I2C master 由 TWIS 实现。这里将演示如何用一个 TWIM 来连接两个 I2C slave 设备。

  • 首先我们还是先修改 devicetree我们使用 i2c1 这个 node。 一方面按照应用的要求修改这个 node 的 propertise,另一方面在这个 node 里创建两个 sub-node。

1. i2c 的时钟频率通过 clock-frequency 来定义。

2. i2c 的引脚通过 pinctrl-0 和 pinctrl-1 定义。我们将在后面分析 i2c1_default 和 i2c1_sleep 的定义。

3. 这两个 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 = <0xA>;    };    user_i2c_eeprom: user_i2c_eeprom@0 {        compatible = "i2c-user-define";        reg = <0x5>;    };      };     

4. i2c1_default 和 i2c1_sleep的定义如下。TWIM_SDA 信号使用的是引脚 P0.04,TWIM_SCL 信号使用的是引脚 P0.03。

&pinctrl {    i2c1_default: i2c1_default {        group1 {            psels = 0, 4)>,                0, 3)>;        };    };     i2c1_sleep: i2c1_sleep {        group1 {            psels = 0, 4)>,                0, 3)>;            low-power-enable;        };    }; };
  • 修改 prj.conf 添加 CONFIG_I2C=y

  • 修改完 devicetree 我们在来添加操作 i2c 的代码。分别定义 i2c1_sensor 和 i2c1_eeprom,它们对应刚才 i2c1 的两个子节点。

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 设备在读写操作前无需调用 API 来配置 ,直接调用下面的写函数。

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

通过逻辑分析仪我们可以看到如下的总线数据,操作的目标地址分别是我们在 devicetree 里设置的数值 0x05 和 0x0A 。



4

SPI 设备控制

Nordic 的芯片中 SPI 接口的 master 端通过 SPIM 实现, slave 端通过 SPIS 实现。这里将演示如何用一个 SPIM 来连接两个 SPI slave 设备。

  • 首先修改 devicetree。

1. 这里我们使用 spi2, 并且关闭 spi1。在 nordic 的nRF52 系列芯片中,相同数字编号的 TWIM, TWIS, SPIM, SPIS 是共用一组硬件模块的。在上面 i2c 中我们已经使用 i2c1, 所以这里我们就不能同时使用 spi1了。

2. cs-gpios 定义了 P0.26 和 P0.27 两 个CS 信号。 SPI 用不同的片选信号,区分不同的 slave 设备。

3. devicetree node spi2 下定义了两个 sub-node 分别是 user_spi_adc 和 user_spi_flash。 sub-node 里定义了三个 propertise。propertise compatible 的取值来自于我们在工程里新添加的文件 dts\bindings\spi-user-define.yaml。 propertise reg 的取值和前面的 propertise cs-gpios 呼应,reg = <0> 的 sub-node 使用 cs-gpios 里面定义的第一个 CS 引脚。reg = <1> 的 sub-node 使用 cs-gpios 里面定义的第二个 CS 引脚。propertise spi-max-frequency 定义 SPI 的时钟频率。两个不同的 SPI 设备可以使用不同的时钟频率驱动。                       

&spi1 {    status = "disabled";}; &spi2 {    status = "okay";    cs-gpios = <&gpio0 26 GPIO_ACTIVE_LOW>,               <&gpio0 27 GPIO_ACTIVE_LOW>;    pinctrl-0 = < &spi2_default >;    pinctrl-1 = < &spi2_sleep >;    pinctrl-names = "default", "sleep";     user_spi_adc: user_spi_adc@0 {        compatible = "spi-user-define";        reg = <0>;        spi-max-frequency = 8)>;    };    user_spi_flash: user_spi_flash@0 {        compatible = "spi-user-define";        reg = <1>;        spi-max-frequency = 8)>;    };       };      

4. 来看一下我们新添加的 dts\bindings\spi-user-define.yaml 里面的内容。如下图 spi-user-define.yaml 里面包含了 spi-device.yaml 文件,这个文件的位置在目录 zephyr\dts\bindings\spi 。

compatible: "spi-user-define" include: [spi-device.yaml]

spi-device.yaml 文件里面定义了 spi 节点需要的一些 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:

5. SPI 引脚定义如下 CLK P0.28, MISO P0.29, MOSI P0.30。

spi2_default: spi2_default {    group1 {        psels = 0, 28)>,                0, 29)>,                0, 30)>;    };};spi2_sleep: spi2_sleep {    group1 {        psels = 0, 28)>,                0, 29)>,                0, 30)>;        low-power-enable;    };}; 
  • 修改 prj.conf 添加 CONFIG_SPI=y   CONFIG_SPI_ASYNC=y。

  • 在 main.c 里添加 SPI 的应用代码下面这段代码定义了两个结构体变量,并通过宏 SPI_DT_SPEC_GET 用 devicetree 里的参数初始化了这两个结构体变量。

#define SPI_OP     SPI_OP_MODE_MASTER | SPI_MODE_CPOL | SPI_MODE_CPHA \                   | SPI_WORD_SET(8) | SPI_LINES_SINGLEstatic 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 驱动支持多 buffer 所以要定义 buffer 个数,和每个 buffer 的长度。同样 spi 在读写之前无需调用配置函数,直接调用读写函数就行。

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 设备通讯的时候, spi master 会拉低不同的 CS 引脚。



5

UART 控制

Nordic 的芯片中 UART 接口叫做 UARTE。这里的 E 是指 EasyDMA , UART 可以使用 DMA 来连续收发。

  • 修改 Devicetree。这里使用 uart1。propertise current-speed 设置 uart 的波特率。

&uart1 {    status = "okay";    current-speed = <115200>;    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 = 1, 1)>;        bias-pull-up;    };    group2 {        psels = 1, 2)>;    };}; uart1_sleep: uart1_sleep {    group1 {        psels = 1, 1)>,            1, 2)>;        low-power-enable;    };};
  • 修改 prj.conf 在里面添加 CONFIG_UART_ASYNC_API=y    CONFIG_UART_ASYNC_RX_HELPER=y。

  • 修改 main.c 添加 uart 收发代码。 uart_callback_set 设置 callback 函数 uart_cb。因为这里采用的是异步收发的模式,所以设置callback 函数是必备的。uart_rx_enable 使能接收。uart_tx 发送数据。

err = uart_callback_set(uart1, uart_cb, NULL);//printk("uart_callback_set return %d\n", err); err = uart_rx_enable(uart1, uart_rx_buf, MAX_UART_BUF_LEN, UART_RX_TIMEOUT_MS);//printk("uart_rx_enable return %d\n", err); err = uart_tx(uart1, uart_tx_buf, 6, SYS_FOREVER_MS);//printk("uart_tx return %d\n", err);

callback 函数 uart_cb 可能由多种事件触发。比如当接收到数据后会触发回调,并在参数 EVT 传递 UART_RX_RDY 和接收到的数据和长度。

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_DONE\n");        break;     case UART_RX_RDY:        printk("UART_RX_RDY\n");        printk("received %d bytes\n", evt->data.rx.len);        break;     case UART_RX_DISABLED:        printk("UART_RX_DISABLED\n");        break;     case UART_RX_BUF_REQUEST:        printk("UART_RX_BUF_REQUEST\n");        uart_rx_buf_rsp(uart1, uart_rx_buf2, MAX_UART_BUF_LEN);        break;     case UART_RX_BUF_RELEASED:        printk("UART_RX_BUF_RELEASED\n");        break;     case UART_TX_ABORTED:        printk("UART_TX_ABORTED\n");        break;     default:        break;    }}
  • 我们在 DK 上把 TXD 引脚和 RXD 引脚短接来测试 UART 的收发,可以看到如下的 log 信息。UART 收到了自己发送的6字节的数据。 



6

UART 应用代码的优化

上面的 uart 演示代码中,我们只实现了简单的收发。下面我们将进一步在此基础上优化 UART 的收发代码。这一部分的修改都在 main.c 里,主要涉及下面几个部分:

  1. Thread 线程

  2. Semaphore 信号量

  3. 线程间通讯 Message queue

  • 线程 下面的代码中通过 K_THREAD_DEFINE 定义了 一个独立的线程来处理 uart 相关的代码。线程处理函数 uart_thread_task 中:也是先用 uart_callback_set 设置了回调函数;再用 uart_rx_enable 使能了接收;然后是一个 for 循环,在里面不断的接收消息,根据消息中的指令发送数据,或者处理接收到的数据。     

#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_task\n");     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 item\n");                 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 定义线程的时候,需要指定此线程的优先级 UART_THREAD_PRIORITY。

UART_THREAD_PRIORITY 的数据类型是 integer,可以是正数也可以是负数。优先级的数字越小,优先级越高,负数的优先级比正数高。

thread 的优先级取值为负数时,此 thread 为协同线程 cooperative thread 。当这种线程正在执行的时候,其它更高优先级的线程不能打断它,必须等它执行完再执行下一个线程。

当 thread 的优先级取值为正数,此 thread 为抢占线程 preemptible thread。当这种线程正在执行的时候,其它更高优先级的线程可以打断它,跳转到高优先级的任务。等高优先级的线程执行完才返回原 thread 继续执行。

回到例程代码,从应用的角度出发,我们希望 uart_thread_task 的执行优先级大于 main 函数。通过查询文件 build\zephyr\.config 我们得知 CONFIG_MAIN_THREAD_PRIORITY 的取值为 0,也就是说 main thread 当前的优先级为 0, 所以我们定义了 UART_THREAD_PRIORITY 为 -1。这样 uart thread 的优先级就高于 main thread, 而且 uart thread 的执行不会被其它更高优先级的 thread 打断。

需要注意的是这里的不能被打断只是对 thread 而言,中断是可以打断 cooperative thread 的。

  • 信号量 函数 uart_thread_task 的优先级比 main 函数高,所以会先于main 函数执行。如果之前的函数 uart_thread_task 里没有 k_sem_take(&uart_thread_start, K_FOREVER),就会出现如下图的现象。我们看到 uart thread 的 log 是先于 main thread 被打印出来的。 


从应用的角度,我们希望 uart_thread_task  在 main 函数启动完广播之后再执行。这就引入了一个不同线程之间的同步问题。

Zephyr RTOS 中可以通过 semaphore 解决不同 thread 间的同步问题。下面的代码中通过 K_SEM_DEFINE 定义了一个为 uart_thread_start 的 semaphore 。 

函数 uart_thread_task 执行到函数 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_task\n");     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 继续执行。

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 会把要发送的数据通过线程通讯发送到  uart thread, uart thread 调用驱动函数发送。zephyr 中提供了多种线程间通讯方式,具体如下图,这里使用的是 message queue。

下面的代码中 K_MSGQ_DEFINE 定义了一个名为 uart_data_msgq 的 message queue。uart_data_msgq 的缓冲区里最多可以容纳 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 函数。代码会定时循环把待发送的数据打包成一个 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 函数。 函数等待 message queue 里推送来的 message。得到 message 后,根据里面的 cmd 字段来处理发送或者接收数据。

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_task\n");     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 item\n");                 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 不断的发送从 main thread 传输的数据。   






总结

本文从实际操作出发,介绍了用户最常用的一些外设如 GPIO, I2C, SPI, UART 的配置和使用方法。并介绍了一些简单 RTOS 组件的应用如 thread, semaphore, message queue。希望能帮助 Nordic 用户加快 nRF Connect SDK 的开发速度。          


【联系我们】

中文官网:www.nordicsemi.cn

英文官网:www.nordicsemi.com

微信公众号:nordicsemi


【Nordic 开发者论坛】

https://devzone.nordicsemi.com


【销售接洽】

北京分公司: +86 010 8438 2767

上海分公司: +86 21 6330 0620

深圳分公司: +86 755 8322 0147

sales.cn@nordicsemi.no

 点击“阅读原文” 探索更多Nordic资讯

Nordic半导体 Nordic 半导体开发支持蓝牙智能、ANT+和2.4GHz应用的超低功耗短距无线通信技术,用于物联网 、可穿戴产品、智能家居、玩具等应用。Nordic 提供现成可用的设计框架、世界级文档资料和支持,以加快专业工程师和业余爱好者的开发速度。
评论 (0)
  • 文/陈昊编辑/cc孙聪颖‍2025 年,作为中国实施制造强国战略第一个十年计划的关键里程碑,被赋予了极为重大的意义。两会政府工作报告清晰且坚定地指出,要全力加速新质生产力的发展进程,推动传统产业全方位向高端化、智能化与绿色化转型。基于此,有代表敏锐提议,中国制造应从前沿技术的应用切入,逐步拓展至产业生态的构建,最终延伸到提升用户体验的维度,打出独树一帜、具有鲜明特色的发展牌。正是在这样至关重要的时代背景之下,于 AWE 2025(中国家电及消费电子博览会)这一备受瞩目的舞台上,高端厨房的中国方案
    华尔街科技眼 2025-03-25 16:10 85浏览
  • 在嵌入式语音系统的开发过程中,广州唯创电子推出的WT588系列语音芯片凭借其优异的音质表现和灵活的编程特性,广泛应用于智能终端、工业控制、消费电子等领域。作为该系列芯片的关键状态指示信号,BUSY引脚的设计处理直接影响着系统交互的可靠性和功能拓展性。本文将从电路原理、应用场景、设计策略三个维度,深入解析BUSY引脚的技术特性及其工程实践要点。一、BUSY引脚工作原理与信号特性1.1 电气参数电平标准:输出3.3V TTL电平(与VDD同源)驱动能力:典型值±8mA(可直接驱动LED)响应延迟:语
    广州唯创电子 2025-03-26 09:26 206浏览
  • ​2025年3月27日​,贞光科技授权代理品牌紫光同芯正式发布新一代汽车安全芯片T97-415E。作为T97-315E的迭代升级产品,该芯片以大容量存储、全球化合规认证、双SPI接口协同为核心突破,直击智能网联汽车"多场景安全并行"与"出口合规"两大行业痛点,助力车企抢占智能驾驶与全球化市场双赛道。行业趋势锚定:三大升级回应智能化浪潮1. 大容量存储:破解车联网多任务瓶颈随着​车机功能泛在化​(数字钥匙、OTA、T-BOX等安全服务集成),传统安全芯片面临存储资源挤占难题。T97-415E创新性
    贞光科技 2025-03-27 13:50 148浏览
  • 在当今竞争激烈的工业环境中,效率和响应速度已成为企业制胜的关键。为了满足这一需求,我们隆重推出宏集Panorama COOX,这是Panorama Suite中首款集成的制造执行系统(MES)产品。这一创新产品将Panorama平台升级为全面的工业4.0解决方案,融合了工业SCADA和MES技术的双重优势,帮助企业实现生产效率和运营能力的全面提升。深度融合SCADA与MES,开启工业新纪元宏集Panorama COOX的诞生,源于我们对创新和卓越运营的不懈追求。通过战略性收购法国知名MES领域专
    宏集科技 2025-03-27 13:22 191浏览
  • 汽车导航系统市场及应用环境参照调研机构GII的研究报告中的市场预测,全球汽车导航系统市场预计将于 2030年达到472亿美元的市场规模,而2024年至2030年的年复合成长率则为可观的6.7%。汽车导航系统无疑已成为智能汽车不可或缺的重要功能之一。随着人们在日常生活中对汽车导航功能的日渐依赖,一旦出现定位不准确或地图错误等问题,就可能导致车主开错路线,平白浪费更多行车时间,不仅造成行车不便,甚或可能引发交通事故的发生。有鉴于此,如果想要提供消费者完善的使用者体验,在车辆开发阶段便针对汽车导航功能
    百佳泰测试实验室 2025-03-27 14:51 188浏览
  • 六西格玛首先是作为一个量度质量水平的指标,它代表了近乎完美的质量的水平。如果你每天都吃一个苹果,有一间水果店的老板跟你说,他们所卖的苹果,质量达到六西格玛水平,换言之,他们每卖一百万个苹果,只会有3.4个是坏的。你算了一下,发现你如果要从这个店里买到一个坏苹果,需要805年。你会还会选择其他店吗?首先发明六西格玛这个词的人——比尔·史密斯(Bill Smith)他是摩托罗拉(Motorloa)的工程师,在追求这个近乎完美的质量水平的时候,发明了一套方法模型,开始时是MAIC,后来慢慢演变成DMA
    优思学院 2025-03-27 11:47 151浏览
  • 长期以来,智能家居对于大众家庭而言就像空中楼阁一般,华而不实,更有甚者,还将智能家居认定为资本家的营销游戏。商家们举着“智慧家居、智慧办公”的口号,将原本价格亲民、能用几十年的家电器具包装成为了高档商品,而消费者们最终得到的却是家居设备之间缺乏互操作性、不同品牌生态之间互不兼容的碎片化体验。这种早期的生态割裂现象致使消费者们对智能家居兴趣缺失,也造就了“智能家居无用论”的刻板印象。然而,自Matter协议发布之后,“命运的齿轮”开始转动,智能家居中的生态割裂现象与品牌生态之间的隔阂正被基于IP架
    华普微HOPERF 2025-03-27 09:46 109浏览
  • WT588F02B是广州唯创电子推出的一款高性能语音芯片,广泛应用于智能家电、安防设备、玩具等领域。然而,在实际开发中,用户可能会遇到烧录失败的问题,导致项目进度受阻。本文将从下载连线、文件容量、线路长度三大核心因素出发,深入分析烧录失败的原因并提供系统化的解决方案。一、检查下载器与芯片的物理连接问题表现烧录时提示"连接超时"或"设备未响应",或烧录进度条卡顿后报错。原因解析接口错位:WT588F02B采用SPI/UART双模通信,若下载器引脚定义与芯片引脚未严格对应(如TXD/RXD交叉错误)
    广州唯创电子 2025-03-26 09:05 146浏览
  • 案例概况在丹麦哥本哈根,西门子工程师们成功完成了一项高安全设施的数据集成项目。他们利用宏集Cogent DataHub软件,将高安全设施内的设备和仪器与远程监控位置连接起来,让技术人员能够在不违反安全规定、不引入未经授权人员的情况下,远程操作所需设备。突破OPC 服务器的远程连接难题该项目最初看似是一个常规的 OPC 应用:目标是将高安全性设施中的冷水机(chiller)设备及其 OPC DA 服务器,与远程监控站的两套 SCADA 系统(作为 OPC DA 客户端)连接起来。然而,在实际实施过
    宏集科技 2025-03-27 13:20 109浏览
  • 在电子设计中,电磁兼容性(EMC)是确保设备既能抵御外部电磁干扰(EMI),又不会对自身或周围环境产生过量电磁辐射的关键。电容器、电感和磁珠作为三大核心元件,通过不同的机制协同作用,有效抑制电磁干扰。以下是其原理和应用场景的详细解析:1. 电容器:高频噪声的“吸尘器”作用原理:电容器通过“通高频、阻低频”的特性,为高频噪声提供低阻抗路径到地,形成滤波效果。例如,在电源和地之间并联电容,可吸收电源中的高频纹波和瞬态干扰。关键应用场景:电源去耦:在IC电源引脚附近放置0.1μF陶瓷电容,滤除数字电路
    时源芯微 2025-03-27 11:19 163浏览
  • 在智能语音产品的开发过程中,麦克风阵列的选型直接决定了用户体验的优劣。广州唯创电子提供的单麦克风与双麦克风解决方案,为不同场景下的语音交互需求提供了灵活选择。本文将深入解析两种方案的性能差异、适用场景及工程实现要点,为开发者提供系统化的设计决策依据。一、基础参数对比分析维度单麦克风方案双麦克风方案BOM成本¥1.2-2.5元¥4.8-6.5元信噪比(1m)58-62dB65-68dB拾音角度全向360°波束成形±30°功耗8mW@3.3V15mW@3.3V典型响应延迟120ms80ms二、技术原
    广州唯创电子 2025-03-27 09:23 165浏览
我要评论
0
0
点击右上角,分享到朋友圈 我知道啦
请使用浏览器分享功能 我知道啦