本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:51单片机是一种广泛应用的微控制器,常用于嵌入式系统中处理按键输入。本压缩包提供了51单片机源代码,专注于实现按键长按和短按功能。源码包括按键检测、去抖动处理、事件判断和响应处理等关键步骤。开发者可以通过学习和实践这些代码,深入理解硬件交互和实时事件处理,为实现更复杂的按键逻辑打下基础。
单片机

1. 51单片机简介与结构

51单片机是一种经典的微控制器,它在IT领域特别是在嵌入式系统的开发中拥有着悠久的历史和广泛的应用。它基于Intel 8051微处理器架构,因此得名。其核心是一个哈佛结构的微处理器,内置有ROM(用于存储程序代码)、RAM(用于数据存储)以及多种外设接口,非常适合于学习和产品原型开发。

1.1 51单片机的硬件组成

51单片机的硬件组成主要包括以下几个部分:

  • CPU核心 :负责运算和控制。
  • 存储器 :包含程序存储器(ROM)和数据存储器(RAM)。
  • I/O端口 :提供与外部设备的接口,可以配置为输入或输出。
  • 定时器/计数器 :可以用于时间的测量和计数。
  • 串行通信接口 :用于与其他设备的串行数据交换。
  • 中断系统 :支持多种中断源,可以提高程序响应外部事件的效率。

1.2 51单片机的软件结构

在软件层面,51单片机使用的编程语言主要是C语言和汇编语言。开发环境通常包括Keil uVision等集成开发环境。51单片机通过编译器将代码编译成机器码,这些机器码能够直接在单片机上执行。一个标准的软件项目结构包括主函数(main函数)和各种子函数,它们通过函数调用来组织程序逻辑。

51单片机的编程和应用是学习嵌入式系统开发的基石,掌握其原理和使用方法对于初学者和有经验的开发者都是极为有益的。接下来的章节,我们将深入探讨如何在51单片机上实现按键长按短按的功能,这将涉及到硬件设计、软件编程以及实时事件处理等核心概念。

2. 按键长按短按实现原理

2.1 按键长按短按的理论基础

2.1.1 长按与短按的定义和区别

在用户界面交互设计中,按键长按和短按是两种常见的操作模式。短按时,用户通常是为了激活一个功能或执行一个命令,例如短按手机上的屏幕解锁键。而长按时,用户可能想要打开更多选项或进入二级菜单,例如长按音量键调整音量设置。区别这两者的关键在于按下的持续时间:短按通常在几百毫秒内,而长按则超过一秒。

2.1.2 按键状态的识别理论

识别按键状态的理论基础是状态机模型。在最简单的形式中,按键只有两种状态:未按下和按下。当检测到按键状态变化时,系统会相应地转换状态,并根据状态来决定触发何种事件或执行何种操作。更复杂的情况下,可能涉及中间状态,例如“正在按压”,以区分长按和短按。在编程实现中,这通常涉及到轮询检测或外部中断,以及定时器和软件去抖动算法。

2.2 按键检测的硬件与软件技术

2.2.1 硬件电路设计要点

硬件设计要点主要集中在如何准确地将物理按键状态转换为电气信号。电路设计通常包括按键、上拉或下拉电阻、电源和地线。当按键未被按下时,电路通过上拉或下拉电阻维持稳定的逻辑电平(通常是高电平或低电平)。当按键被按下时,它将电路连接到另一个电平,从而触发状态变化。为了避免因接触不良造成的误判,硬件设计中常常包含去抖动电路。

2.2.2 软件逻辑判断方法

软件逻辑判断方法主要包括轮询检测和中断服务程序两种模式。轮询检测是周期性地查询按键状态,并根据状态变化触发相应的事件。这种方法简单但占用CPU时间,适用于不需要高响应速度的场景。中断服务程序则是在按键状态发生改变时,通过中断信号通知CPU,由CPU调用相应的中断服务程序处理按键事件。中断模式响应快,效率高,适用于需要快速响应的场景。

按键电路图和状态机模型

接下来,我们通过一个简单的按键电路图和状态机模型来展示硬件与软件技术的结合:

graph LR
A[按键未按下] -->|按压| B[正在按压]
B -->|松开| A
B -->|持续| C[长按]
C -->|松开| A

在软件逻辑中,状态转换可以这样设计:

  • 未按下(No Press)
  • 正在按压(Pressing)
  • 长按(Long Press)

每次状态转换时,都可能会触发相应的处理函数。代码实现可能会包含一个变量来存储当前状态,并在检测到按键状态变化时更新此变量。

代码块示例

以下是一个简单的状态机代码块示例,用于处理按键状态的转换:

// 定义状态枚举
typedef enum {
    NO_PRESS,
    PRESSING,
    LONG_PRESS
} ButtonState;

// 当前状态
ButtonState currentState = NO_PRESS;

// 按键状态更新函数
void updateButtonState() {
    static uint32_t startTime = 0;
    static bool isPressed = false;
    uint32_t currentTime = millis(); // 获取当前时间

    if (digitalRead(BUTTON_PIN) == LOW) { // 检测到按键按下
        if (!isPressed) { // 如果是第一次检测到按下
            isPressed = true;
            startTime = currentTime;
            currentState = PRESSING;
        } else if ((currentTime - startTime) >= LONG_PRESS_TIME) { // 持续时间超过设定的长按时间
            currentState = LONG_PRESS;
        }
    } else { // 按键释放
        if (isPressed) { // 如果之前是按下状态
            if ((currentTime - startTime) < LONG_PRESS_TIME) {
                currentState = NO_PRESS; // 未达到长按,视为短按
            } else {
                currentState = LONG_PRESS;
            }
            isPressed = false;
        }
    }
}

// 状态机处理函数
void processButtonState() {
    switch (currentState) {
        case PRESSING:
            // 处理正在按压的事件
            break;
        case LONG_PRESS:
            // 处理长按事件
            break;
        case NO_PRESS:
        default:
            // 处理其他情况
            break;
    }
}

在上述代码中, updateButtonState() 函数负责检测按键状态并更新状态机的当前状态。 processButtonState() 函数根据当前状态执行不同的处理逻辑。这只是一个非常基础的示例,实际应用中可能需要加入去抖动处理等更复杂的逻辑。

3. 初始化外设I/O口

3.1 I/O口的工作模式设置

3.1.1 输入输出模式的配置

51单片机的I/O口具有灵活的配置特性,可以被设置为输入或输出模式,这取决于连接到I/O口的外部设备类型和功能需求。例如,当连接一个LED灯时,该I/O口通常被配置为输出模式以控制LED灯的开关状态;而在连接一个按键时,则需要将I/O口配置为输入模式,以便读取按键的状态。

要配置I/O口,必须向相应的SFR(特殊功能寄存器)写入特定的值。例如,在51单片机中,P1口的配置可以通过修改P1寄存器来完成。如果将P1.0设置为高电平(1),那么P1.0就被配置为输入模式;如果将P1.0设置为低电平(0),则为输出模式。配置I/O口的工作模式通常在程序的初始化部分进行。

3.1.2 I/O口初始化的代码实现

以下是一个简单的示例,用于初始化51单片机的P1口作为输入口。

#include <REGX51.H> // 包含51单片机寄存器定义

// 初始化P1口为输入口
void P1_Init() {
    P1 = 0xFF; // 将P1口所有位设置为高电平,即输入模式
}

void main() {
    P1_Init(); // 调用函数初始化P1口
    // ... 其他代码
}

在上面的代码中,我们首先包含了 REGX51.H 头文件,它包含了51单片机特定的SFR定义。 P1_Init 函数将P1口的所有引脚设置为高电平,即输入模式。然后在主函数 main 中调用 P1_Init 函数来完成初始化。

3.2 I/O口的扩展应用

3.2.1 外设接口的扩展原理

在许多实际应用中,单片机的I/O口数量可能不足以满足需求,这就需要进行I/O口扩展。扩展可以通过使用I/O扩展器如I2C或SPI接口的IO扩展芯片来实现,也可以通过外部逻辑电路如译码器等来完成。

扩展I/O口时,需要考虑几个关键因素:首先,扩展设备应与51单片机的通信协议兼容;其次,必须正确地分配地址和控制信号,以确保单片机能够准确无误地识别和访问扩展的I/O口;最后,扩展后的I/O口应能够保持单片机的性能,例如避免引入额外的延迟。

3.2.2 具体扩展案例分析

下面以使用I2C接口的IO扩展芯片PCF8574为例,展示如何进行I/O口的扩展。

首先,需要初始化PCF8574芯片的地址和工作模式。PCF8574可以连接到单片机的I2C总线上,其地址通过硬件地址引脚和软件地址字节共同决定。初始化代码如下:

#include <REGX51.H>

// I2C总线写入函数
void I2C_Write(unsigned char deviceAddress, unsigned char data) {
    // ... I2C通信的具体实现代码
}

// 初始化PCF8574
void PCF8574_Init() {
    unsigned char address = 0x20; // 假设PCF8574的硬件地址设置为0010000
    unsigned char mode = 0x00;    // 初始化模式,例如将所有输出置为低电平
    I2C_Write(address, mode);
}

void main() {
    PCF8574_Init(); // 初始化PCF8574扩展的I/O口
    // ... 其他代码
}

在这个例子中, I2C_Write 函数需要根据实际使用的I2C通信协议来完成具体实现。 PCF8574_Init 函数配置了PCF8574扩展芯片,将其所有输出引脚初始化为低电平,这样外部连接的设备就可以按照预期工作了。

通过以上方法,我们就可以根据实际项目需求,灵活地扩展51单片机的I/O口,以满足不同场景下的功能需求。

4. 检测按键状态

4.1 按键状态检测的原理

4.1.1 按键电路的工作状态分析

在硬件层面,按键通过其物理属性改变电路状态来传递信号。当按键未被按下时,电路是断开的,形成开路状态;而当按键被按下时,电路闭合,形成短路状态。这些变化可以被单片机的输入/输出(I/O)口检测到,从而实现按键状态的监控。

在检测过程中,通常会将按键连接到单片机的一个I/O口,并通过电阻拉高或拉低该I/O口的电平,形成一个稳定的信号。当按键未被按下时,由于电阻的作用,I/O口会保持在一个稳定的电平状态;按下时,由于按键形成的临时短路,I/O口的电平会变化。

4.1.2 按键状态检测的基本流程

按键状态检测的基本流程包括初始化I/O口为输入状态、周期性读取I/O口电平、判断电平变化并确定按键状态。通常情况下,为了避免因为按键的机械反弹造成的多次检测,需要对检测到的电平变化进行去抖处理。

这个过程可以通过软件轮询、外部中断或定时器中断等方式来实现。轮询是不断检查按键状态的简单方法;外部中断可以实时响应按键动作;而定时器中断则可以在固定的时间间隔内检查按键状态,为去抖动提供时间窗口。

4.2 按键状态检测的实践操作

4.2.1 读取I/O口状态的代码示例

// 定义一个变量来存储按键状态
uint8_t button_state = 0;

// 读取按键状态的函数
void read_button_state() {
    // 假设 P1_0 是连接按键的I/O口
    if (P1_0 == 0) { // 假设按下按键时,电平为0
        button_state = 1; // 设置按键状态为按下
        // 可以在这里加入去抖动和长按检测的逻辑
    } else {
        button_state = 0; // 设置按键状态为未按下
    }
}

在上述代码中,我们定义了一个 button_state 变量来表示按键的状态。 read_button_state 函数读取了连接到P1.0的按键状态,并根据电平高低来判断按键是否被按下。

4.2.2 按键状态的实时监控方法

要实现按键状态的实时监控,我们可以使用外部中断,它允许单片机在检测到按键状态变化时立即执行中断服务程序。下面的代码展示了如何配置外部中断以及中断服务程序。

#include <REGX51.H>

// 中断服务程序,响应外部中断0
void ext0_isr() interrupt 0 {
    if (P1_0 == 0) {
        // 按键状态处理逻辑
    }
}

void main() {
    // 配置外部中断0为下降沿触发
    IT0 = 1; // 设置为下降沿触发
    EX0 = 1; // 允许外部中断0
    EA = 1;  // 允许全局中断

    // 主循环
    while (1) {
        // 主程序可以在这里继续执行其他任务
    }
}

在这个例子中,我们配置了外部中断0来响应P1.0引脚的下降沿(即按键被按下时)。当中断触发时,执行 ext0_isr 中断服务程序。此程序会检测P1.0的状态,并根据实际情况进行相应处理。

为了实现按键状态的实时监控,你还可以使用定时器中断周期性地检查按键状态。定时器中断允许你在固定时间间隔内检查按键状态,从而进行连续监控。

总结而言,按键状态的检测依赖于硬件电路设计和软件逻辑判断的结合。硬件方面需要注意电平状态和去抖动处理,而软件方面则需要合理设计轮询、外部中断和定时器中断来实现按键状态的实时监控。在下一章节中,我们会深入讨论去抖动技术,以进一步完善按键状态检测机制。

5. 去抖动处理方法

去抖动技术是电子工程中为了确保输入设备如按键的信号稳定而设计的一种常用技术。在机械开关中,由于接触不良、机械振动等原因,会产生多次快速的闭合与断开,这种现象称为抖动。为了防止这种抖动造成的误判,我们通常会在软件层面上对信号进行处理,确保信号的稳定性。

5.1 去抖动技术的理论分析

5.1.1 去抖动的必要性

在数字电路设计中,开关设备的接触不稳定往往会产生抖动,抖动会产生一系列的高频信号波动,这不仅可能导致错误的信号读取,还可能对电路的稳定性和设备寿命造成不良影响。因此,为了确保信号的稳定性和正确性,去抖动处理成为了电子设备设计中不可或缺的一步。

5.1.2 去抖动算法的基本原理

去抖动算法的基本原理是通过设置一个短暂的时间窗口,在这个时间窗口内忽略掉那些高频的抖动信号,只识别并记录下稳定的信号状态。这通常涉及到了一个简单的延时逻辑,通过软件延时或者基于时钟周期的计数来实现。

5.2 去抖动处理的代码实现

5.2.1 常用去抖动算法的编程技巧

在编程中,实现去抖动算法有多种方法,最简单的是软件延时去抖动。下面是一个简单的延时去抖动的伪代码示例:

#define DEBOUNCE_TIME 50 // 去抖动延时时间,单位为毫秒

int read_key() {
    if (button_state == PRESSED) {
        delay(DEBOUNCE_TIME); // 延时去抖动
        if (button_state == PRESSED) { // 再次检测按键状态
            return PRESSED; // 确认按键按下
        }
    }
    return RELEASED; // 返回未按下状态
}

5.2.2 去抖动代码的优化与调试

去抖动的代码实现虽然简单,但在实际的应用中需要根据具体的硬件特性和应用场景进行优化。例如,对于高速按键操作,可以将去抖动的时间窗口设置得更短一些;对于低速操作,则可以相对长一些。

int key_state = RELEASED;

void setup() {
    // 初始化代码
}

void loop() {
    int current_state = read_key(); // 读取按键状态

    if (current_state == PRESSED && key_state == RELEASED) {
        // 按键从未按下状态变为按下状态
        // 这里可以触发一些操作,比如点亮LED灯
    }

    key_state = current_state; // 更新按键状态
    delay(10); // 简单的防抖动延时
}

int read_key() {
    // 模拟的按键读取函数
}

在实际的项目中,去抖动的实现也可能采用中断服务程序来提高效率,或者使用定时器来优化时间控制精度。调试过程中,可以通过示波器观察信号波形,确保去抖动算法可以正确地过滤掉抖动信号。需要注意的是,去抖动的时间设置需要根据实际情况进行调整,时间过短可能无法有效去除抖动,时间过长则会影响按键响应速度。

// 中断服务程序实现去抖动
ISR(EXT_INT0_vect) {
    static unsigned long last_interrupt_time = 0;
    unsigned long interrupt_time = millis();
    if (interrupt_time - last_interrupt_time > DEBOUNCE_TIME) {
        // 按键去抖动后的处理逻辑
    }
    last_interrupt_time = interrupt_time;
}

以上代码块展示了基于中断的去抖动实现方法,这种方法可以很好地处理在中断服务程序中对信号的即时处理,保证了响应的及时性和准确性。去抖动处理是确保按键输入稳定性的关键步骤,对于提高人机交互体验具有重要意义。

6. 计时器用于按键事件判断

6.1 计时器的配置与应用

6.1.1 计时器工作模式的选择

计时器是微控制器中不可或缺的资源,用于在特定时间段内产生中断,从而允许执行定时任务。选择合适的计时器工作模式对于实现高效且准确的按键事件判断至关重要。在51单片机中,计时器主要有以下几种工作模式:

  • 模式0:13位计时器模式 - 最低位始终为0,可以计数0-8191,但不常用,因为其分辨力较低。
  • 模式1:16位计时器模式 - 最通用的模式,可以计数0-65535,适合大多数需要定时或计数的场合。
  • 模式2:8位自动重装载计时器模式 - 这个模式下计时器计数至255后自动重置为初始值,适用于需要周期性重复定时任务的场景。
  • 模式3:分裂计时器模式 - 将一个16位计时器拆分成两个独立的8位计时器,但51单片机中只有定时器T0能用此模式。

在实现按键事件判断时,模式1和模式2是最常被选择的模式。例如,若需要实现长按超过3秒触发特定动作的功能,则可以使用模式1的计时器进行精确计时。

6.1.2 计时器的初始化与配置

以下是使用51单片机计时器0实现模式1,并初始化配置的代码示例:

#include <reg51.h>

void Timer0_Init() {
    TMOD &= 0xF0; // 清除定时器0模式位
    TMOD |= 0x01; // 设置定时器0为模式1(16位计时器模式)
    TH0 = 0x00;   // 装载定时器高位初值
    TL0 = 0x00;   // 装载定时器低位初值
    ET0 = 1;      // 开启定时器0中断
    TR0 = 1;      // 启动定时器0
}

void main() {
    Timer0_Init(); // 初始化定时器
    EA = 1;        // 开启全局中断
    while(1) {
        // 主循环,执行其他任务
    }
}

void Timer0_ISR(void) interrupt 1 using 1 {
    // 定时器中断服务程序
    TH0 = 0x00;   // 重新装载定时器高位初值
    TL0 = 0x00;   // 重新装载定时器低位初值
    // 在这里添加按键事件处理代码
}

在此代码中,计时器0被初始化为模式1,并通过中断服务程序(ISR)来处理定时事件。定时器溢出后需要重新装载初值以继续计时。

6.2 计时器在按键事件中的应用

6.2.1 计时器实现按键长按检测

使用计时器实现按键长按检测是一种常见应用。通过计时器记录按键持续按下的时间,当时间超过预设的阈值时,判定为长按事件发生。

下面给出一个具体的按键长按检测的实现:

#include <reg51.h>

#define LONG_PRESS_TIME 300 // 长按时间阈值,单位为计时器中断周期

unsigned int long_press_counter = 0; // 长按计时器

void Timer0_ISR(void) interrupt 1 {
    TH0 = (65536 - 50000) / 256; // 重新装载初值,假设中断周期为50ms
    TL0 = (65536 - 50000) % 256;
    if(long_press_counter < LONG_PRESS_TIME) {
        long_press_counter++;
        if(long_press_counter == LONG_PRESS_TIME) {
            // 长按事件发生
            // 在这里添加长按事件处理代码
        }
    }
}

void main() {
    Timer0_Init(); // 初始化定时器
    EA = 1;        // 开启全局中断
    while(1) {
        // 检测按键状态
        if (P1 & 0x01) { // 假设按键连接在P1.0
            long_press_counter = 0; // 重置长按计数器
        }
    }
}

在上述代码中,当按键被按下时,计时器开始计数,每当计时器中断触发时,计数器加1。当计数器达到预设值 LONG_PRESS_TIME 时,触发长按事件。

6.2.2 计时器优化按键响应的策略

为了提高系统的响应效率并减少误操作,计时器还可以用于优化按键响应。例如,在一个有弹性的按键设计中,用户按下后需要一定的时间来稳定按键状态。在此期间,计时器可以延迟响应,避免因短暂的抖动或误按产生错误的操作。

unsigned int debounce_counter = 0;
#define DEBOUNCE_TIME 100 // 弹性响应时间阈值

void main() {
    Timer0_Init(); // 初始化定时器
    EA = 1;        // 开启全局中断
    while(1) {
        // 检测按键状态
        if ((P1 & 0x01) == 0) { // 假设按键未按下
            debounce_counter = 0; // 重置抖动计数器
        } else {
            debounce_counter++;
            if(debounce_counter >= DEBOUNCE_TIME) {
                // 确认按键稳定按下
                // 在这里添加按键稳定按下后的处理代码
            }
        }
    }
}

在以上实现中,当检测到按键按下后,延迟 DEBOUNCE_TIME 时间,如果此时确认按键依然被按下,则认为这是一个稳定的按键事件,从而避免了因为短暂抖动或误按而错误地处理按键事件。

7. 按键长按与短按的响应处理

按键作为用户交互的最直接手段,其响应处理对于产品易用性和用户体验有着至关重要的影响。本章节将详细介绍长按与短按响应机制的原理,并提供相应的代码实现和调试策略。

7.1 长按与短按的响应机制

长按与短按的区别主要在于按键持续的时间不同。在51单片机系统中,我们需要通过程序来区分这两种不同的操作。

7.1.1 长按事件的响应逻辑

长按事件通常意味着用户希望执行一个较为复杂或不常执行的操作。当检测到按键被持续按下超过预设的时间阈值时,系统将触发长按事件,并执行相应的响应逻辑。

7.1.2 短按事件的响应逻辑

短按事件则通常用于频繁执行的操作。短按意味着用户希望立即得到反馈,因此当检测到按键被按下并迅速释放时,系统将触发短按事件,并执行快速响应。

7.2 响应处理的代码编写与调试

在实际编程中,我们需要将长按与短按的逻辑转化为代码,这里我们将给出一个基础的实现。

7.2.1 编写响应处理的源码

假设我们有一个简单的按键检测函数 DetectButton() ,以及用于处理长按和短按的函数 HandleLongPress() HandleShortPress() 。以下是一个示例代码实现:

#include <REG52.H>

#define LONG_PRESS_TIME 2000 // 长按时间阈值,单位毫秒

// 声明按键处理函数
void HandleLongPress();
void HandleShortPress();

// 全局变量记录按键状态和时间戳
bit buttonState = 0;
unsigned int buttonPressTime = 0;

void main() {
    // 初始化代码...
    while (1) {
        buttonState = DetectButton(); // 检测按键状态
        if (buttonState) {
            if (buttonPressTime == 0) {
                // 记录按键按下的开始时间
                buttonPressTime = GetSystemTime();
            } else if (GetSystemTime() - buttonPressTime >= LONG_PRESS_TIME) {
                // 超过长按阈值,处理长按事件
                HandleLongPress();
                // 重置时间戳
                buttonPressTime = 0;
            }
        } else if (buttonPressTime != 0) {
            // 按键释放,处理短按事件
            HandleShortPress();
            // 重置时间戳
            buttonPressTime = 0;
        }
    }
}

// 检测按键是否按下的函数示例
bit DetectButton() {
    // 检测代码...
    return /* 按键按下的状态 */;
}

// 获取系统时间的函数示例
unsigned int GetSystemTime() {
    // 获取系统时间代码...
    return /* 当前系统时间 */;
}

// 处理长按事件的函数示例
void HandleLongPress() {
    // 长按事件处理代码...
}

// 处理短按事件的函数示例
void HandleShortPress() {
    // 短按事件处理代码...
}

7.2.2 调试与优化响应处理的策略

在上述代码编写完毕后,需要对程序进行调试,确保长按和短按事件能够准确识别和响应。调试过程中可能需要调整长按时间阈值 LONG_PRESS_TIME 以匹配用户的实际使用习惯。

在实际部署后,根据用户的反馈和产品使用情况,可能还需要进一步优化按键响应的灵敏度、准确性以及防抖动算法等。此外,对于复杂的系统,还可以考虑使用外部中断来提高按键处理的效率。

以上便是本章节关于按键长按与短按响应处理的全部内容。在下一章节中,我们将进一步探讨外部中断处理按键事件的原理和应用。

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:51单片机是一种广泛应用的微控制器,常用于嵌入式系统中处理按键输入。本压缩包提供了51单片机源代码,专注于实现按键长按和短按功能。源码包括按键检测、去抖动处理、事件判断和响应处理等关键步骤。开发者可以通过学习和实践这些代码,深入理解硬件交互和实时事件处理,为实现更复杂的按键逻辑打下基础。


本文还有配套的精品资源,点击获取
menu-r.4af5f7ec.gif

Logo

openvela 操作系统专为 AIoT 领域量身定制,以轻量化、标准兼容、安全性和高度可扩展性为核心特点。openvela 以其卓越的技术优势,已成为众多物联网设备和 AI 硬件的技术首选,涵盖了智能手表、运动手环、智能音箱、耳机、智能家居设备以及机器人等多个领域。

更多推荐