引言

在嵌入式系统开发中,实时操作系统(RTOS)扮演着至关重要的角色。uC/OS-III作为一款成熟可靠的实时内核,具有以下显著优势:
硬实时性能:确保关键任务在指定时间内完成
可抢占式调度:高优先级任务可立即获得CPU控制权
资源管理:提供信号量、消息队列等机制避免资源冲突
可移植性:高度模块化设计,便于移植到不同硬件平台
商业认证:已通过多种安全认证,适合工业级应用
本文将详细介绍如何将uC/OS-III移植到STM32F103C8T6微控制器,并构建一个包含三个任务的多任务系统。

一、开发环境准备

1.1 硬件要求

STM32F103C8T6最小系统板
USB转TTL串口模块
LED灯 x 2(PA6和PA3)
杜邦线若干

1.2 软件工具

STM32CubeMX
Keil MDK-ARM
uC/OS-III源码
串口调试助手(SSCOM)

二、STM32CubeMX工程配置

2.1 创建新工程

  1. 打开STM32CubeMX,选择STM32F103C8T6
  2. 配置系统核心:
    SYS: Debug → Serial Wire
    在这里插入图片描述
    RCC: HSE → Crystal/Ceramic Resonator
    在这里插入图片描述
  3. 时钟配置
    HSE: 8MHz
    PLL Source: HSE
    PLL Mul: ×9
    System Clock: 72MHz
    AHB Prescaler: /1
    APB1 Prescaler: /2
    APB2 Prescaler: /1
    在这里插入图片描述
  4. GPIO配置
    PA6: GPIO_Output → LED1(1秒周期)
    PA3: GPIO_Output → LED2(3秒周期)
    推挽输出模式,初始电平高
    在这里插入图片描述
  5. 串口配置
    USART1: Asynchronous Mode
    Baud Rate: 115200
    Word Length: 8 Bits
    Parity: None
    Stop Bits: 1
    在这里插入图片描述
  6. 工程配置
    在这里插入图片描述在这里插入图片描述

三、uC/OS-III源码移植

3.1 uC/OS-III源码

链接:https://pan.baidu.com/s/1bg7K34vgNuw2AR8qmb81hQ
提取码:1234

3.2 添加uC/OS-III文件

打开刚刚下载的源码文件
将以下文件复制
在这里插入图片描述
粘贴到工程文件中MDK-ARM下
在这里插入图片描述

3.3 修改工程结构

在Keil中添加文件组:
在这里插入图片描述
在每个分组下添加对应的文件
①CPU
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
②LIB
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
③PORT
在这里插入图片描述
在这里插入图片描述
④SOURCE
在这里插入图片描述
在这里插入图片描述
⑤CONFIG
在这里插入图片描述
在这里插入图片描述
⑥BSP
在这里插入图片描述
在这里插入图片描述
接下来导入头文件路径
在这里插入图片描述
在这里插入图片描述

四、代码修改与添加

4.1 代码修改

①打开启动文件
分别将PendSV_Handler和Systick_Handler改为OS_CPU_PendSVHandler和OS_CPU_SysTickHandler
在这里插入图片描述
在这里插入图片描述
②app_cfg.h
第一处修改:
修改前
#define APP_CFG_SERIAL_EN DEF_ENABLED
修改后
#define APP_CFG_SERIAL_EN DEF_DISABLED
在这里插入图片描述
第二处修改:
修改前
#define APP_TRACE BSP_Ser_Printf
修改后
#define APP_TRACE (void)
在这里插入图片描述
③ includes.h
第一处修改: 添加相关头文件
修改前
#include <bsp.h>
修改后
#include <bsp.h>
#include “gpio.h”
#include “app_cfg.h”
在这里插入图片描述
第二处修改: 添加HAL 库
修改前
#include <stm32f10x_lib.h>
修改后
#include “stm32f1xx_hal.h”
在这里插入图片描述
④lib_cfg.h
该处宏定义设置堆空间的大小,STM32F103C8T6的RAM只有20K,所以要改小一点,这里改为了5。
在这里插入图片描述

4.2 代码添加

①bsp.c

// bsp.c
#include "includes.h"

#define  DWT_CR      *(CPU_REG32 *)0xE0001000
#define  DWT_CYCCNT  *(CPU_REG32 *)0xE0001004
#define  DEM_CR      *(CPU_REG32 *)0xE000EDFC
#define  DBGMCU_CR   *(CPU_REG32 *)0xE0042004

#define  DEM_CR_TRCENA                   (1 << 24)
#define  DWT_CR_CYCCNTENA                (1 <<  0)

CPU_INT32U  BSP_CPU_ClkFreq (void)
{
    return HAL_RCC_GetHCLKFreq();
}

void BSP_Tick_Init(void)
{
	CPU_INT32U cpu_clk_freq;
	CPU_INT32U cnts;
	cpu_clk_freq = BSP_CPU_ClkFreq();
	
	#if(OS_VERSION>=3000u)
		cnts = cpu_clk_freq/(CPU_INT32U)OSCfg_TickRate_Hz;
	#else
		cnts = cpu_clk_freq/(CPU_INT32U)OS_TICKS_PER_SEC;
	#endif
	OS_CPU_SysTickInit(cnts);
}



void BSP_Init(void)
{
	BSP_Tick_Init();
	MX_GPIO_Init();
}


#if (CPU_CFG_TS_TMR_EN == DEF_ENABLED)
void  CPU_TS_TmrInit (void)
{
    CPU_INT32U  cpu_clk_freq_hz;


    DEM_CR         |= (CPU_INT32U)DEM_CR_TRCENA;                /* Enable Cortex-M3's DWT CYCCNT reg.                   */
    DWT_CYCCNT      = (CPU_INT32U)0u;
    DWT_CR         |= (CPU_INT32U)DWT_CR_CYCCNTENA;

    cpu_clk_freq_hz = BSP_CPU_ClkFreq();
    CPU_TS_TmrFreqSet(cpu_clk_freq_hz);
}
#endif


#if (CPU_CFG_TS_TMR_EN == DEF_ENABLED)
CPU_TS_TMR  CPU_TS_TmrRd (void)
{
    return ((CPU_TS_TMR)DWT_CYCCNT);
}
#endif


#if (CPU_CFG_TS_32_EN == DEF_ENABLED)
CPU_INT64U  CPU_TS32_to_uSec (CPU_TS32  ts_cnts)
{
	CPU_INT64U  ts_us;
  CPU_INT64U  fclk_freq;

 
  fclk_freq = BSP_CPU_ClkFreq();
  ts_us     = ts_cnts / (fclk_freq / DEF_TIME_NBR_uS_PER_SEC);

  return (ts_us);
}
#endif
 
 
#if (CPU_CFG_TS_64_EN == DEF_ENABLED)
CPU_INT64U  CPU_TS64_to_uSec (CPU_TS64  ts_cnts)
{
	CPU_INT64U  ts_us;
	CPU_INT64U  fclk_freq;


  fclk_freq = BSP_CPU_ClkFreq();
  ts_us     = ts_cnts / (fclk_freq / DEF_TIME_NBR_uS_PER_SEC);
	
  return (ts_us);
}
#endif


②bsp.h

// bsp.h
#ifndef  __BSP_H__
#define  __BSP_H__

#include "stm32f1xx_hal.h"

void BSP_Init(void);

#endif

五、多任务代码实现

5.1 主函数(main.c)

其中两个task分别以1s和3s周期对LED等进行点亮-熄灭的控制;另外一个task以2s周期通过串口发送“hello uc/OS! 欢迎来到RTOS多任务环境!”。

#include "main.h"
#include "gpio.h"
#include "usart.h"
#include <includes.h>
#include <stdio.h>

/* 任务优先级定义 */
#define START_TASK_PRIO     3
#define LED1_TASK_PRIO      4  
#define MSG_TASK_PRIO       5
#define LED2_TASK_PRIO      6

/* 任务堆栈定义 */
CPU_STK START_TASK_STK[256];
CPU_STK LED1_TASK_STK[128];
CPU_STK LED2_TASK_STK[128]; 
CPU_STK MSG_TASK_STK[128];

/* 任务控制块 */
OS_TCB StartTaskTCB, Led1TaskTCB, Led2TaskTCB, MsgTaskTCB;

int main(void)
{
    OS_ERR err;
    
    HAL_Init();
    SystemClock_Config();
    MX_GPIO_Init();
    MX_USART1_UART_Init();
    
    /* 初始化LED状态 */
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, GPIO_PIN_SET);
    
    OSInit(&err);
    
    /* 创建启动任务 */
    OSTaskCreate(&StartTaskTCB, "start task", start_task, 0,
                 START_TASK_PRIO, START_TASK_STK, 256/10, 256,
                 5, 0, 0, OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR, &err);
    
    OSStart(&err);
}

5.2 启动任务

void start_task(void *p_arg)
{
    OS_ERR err;
    (void)p_arg;
    
    /* 创建LED1任务 - PA6, 1秒周期 */
    OSTaskCreate(&Led1TaskTCB, "led_pa6", led_pa6, 0,
                 LED1_TASK_PRIO, LED1_TASK_STK, 128/10, 128,
                 5, 0, 0, OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR, &err);
    
    /* 创建LED2任务 - PA3, 3秒周期 */  
    OSTaskCreate(&Led2TaskTCB, "led_pa3", led_pa3, 0,
                 LED2_TASK_PRIO, LED2_TASK_STK, 128/10, 128, 
                 5, 0, 0, OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR, &err);
    
    /* 创建消息任务 - 2秒周期 */
    OSTaskCreate(&MsgTaskTCB, "send_msg", send_msg, 0,
                 MSG_TASK_PRIO, MSG_TASK_STK, 128/10, 128,
                 5, 0, 0, OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR, &err);
    
    OSTaskDel((OS_TCB*)0, &err);
}

5.3 LED控制任务

/* PA6 LED任务 - 1秒周期 */
static void led_pa6(void *p_arg)
{
    OS_ERR err;
    (void)p_arg;
    
    while (DEF_TRUE) {
        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, GPIO_PIN_RESET);  // 亮
        OSTimeDlyHMSM(0, 0, 0, 500, OS_OPT_TIME_HMSM_STRICT, &err);
        
        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, GPIO_PIN_SET);    // 灭  
        OSTimeDlyHMSM(0, 0, 0, 500, OS_OPT_TIME_HMSM_STRICT, &err);
    }
}

/* PA3 LED任务 - 3秒周期 */
static void led_pa3(void *p_arg)  
{
    OS_ERR err;
    (void)p_arg;
    
    while (DEF_TRUE) {
        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, GPIO_PIN_RESET);  // 亮
        OSTimeDlyHMSM(0, 0, 1, 500, OS_OPT_TIME_HMSM_STRICT, &err);
        
        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, GPIO_PIN_SET);    // 灭
        OSTimeDlyHMSM(0, 0, 1, 500, OS_OPT_TIME_HMSM_STRICT, &err);
    }
}

5.4 串口消息任务

/* 串口输出重定向 */
int fputc(int ch, FILE *f)
{
    HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, HAL_MAX_DELAY);
    return ch;
}

/* 消息发送任务 - 2秒周期 */
static void send_msg(void *p_arg)
{
    OS_ERR err;
    (void)p_arg;
    
    while (DEF_TRUE) {
        printf("hello uc/OS! 欢迎来到RTOS多任务环境!\r\n");
        OSTimeDlyHMSM(0, 0, 2, 0, OS_OPT_TIME_HMSM_STRICT, &err);
    }
}

5.5 完整代码

/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "gpio.h"
#include "usart.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <includes.h>
#include <stdio.h>

/* USER CODE END Includes */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* 任务优先级 */
#define START_TASK_PRIO		3
#define LED0_TASK_PRIO		4
#define LED1_TASK_PRIO		5
#define MSG_TASK_PRIO		6

/* 任务堆栈大小	*/
#define START_STK_SIZE 		256
#define LED0_STK_SIZE 		128
#define LED1_STK_SIZE 		128
#define MSG_STK_SIZE		128

/* 任务栈 */	
CPU_STK START_TASK_STK[START_STK_SIZE];
CPU_STK LED0_TASK_STK[LED0_STK_SIZE];
CPU_STK LED1_TASK_STK[LED1_STK_SIZE];
CPU_STK MSG_TASK_STK[MSG_STK_SIZE];

/* 任务控制块 */
OS_TCB StartTaskTCB;
OS_TCB Led0TaskTCB;
OS_TCB Led1TaskTCB;
OS_TCB MsgTaskTCB;

/* USER CODE END PD */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */

/* 重定向printf到串口 */
#ifdef __GNUC__
  #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
  #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif

PUTCHAR_PROTOTYPE
{
  HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, HAL_MAX_DELAY);
  return ch;
}

/* 任务函数定义 */
void start_task(void *p_arg);
static void led_pa6(void *p_arg);    
static void led_pa3(void *p_arg);  
static void send_msg(void *p_arg);

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
  
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
  
  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  {
    Error_Handler();
  }
}

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
    OS_ERR err;
    
    HAL_Init();
    SystemClock_Config();
    
    /* 初始化外设 */
    MX_GPIO_Init();
    MX_USART1_UART_Init();
    
    /* 初始化LED为默认状态(灭) */
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, GPIO_PIN_SET);   // PA6灭
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, GPIO_PIN_SET);   // PA3灭
    
    /* 初始化uC/OS-III */
    OSInit(&err);
    if (err != OS_ERR_NONE) {
        Error_Handler();
    }
    
    /* 创建启动任务 */
    OSTaskCreate((OS_TCB     *)&StartTaskTCB,
                 (CPU_CHAR   *)"start task",
                 (OS_TASK_PTR )start_task,
                 (void       *)0,
                 (OS_PRIO     )START_TASK_PRIO,
                 (CPU_STK    *)&START_TASK_STK[0],
                 (CPU_STK_SIZE)START_STK_SIZE/10,
                 (CPU_STK_SIZE)START_STK_SIZE,
                 (OS_MSG_QTY  )5,
                 (OS_TICK     )0,
                 (void       *)0,
                 (OS_OPT      )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR),
                 (OS_ERR     *)&err);
    
    if (err != OS_ERR_NONE) {
        Error_Handler();
    }
    
    /* 启动多任务系统 */
    OSStart(&err);
}

/**
  * @brief 启动任务
  */
void start_task(void *p_arg)
{
    OS_ERR err;
    (void)p_arg;
    
    /* 创建LED0任务 - PA6, 1s周期 */
    OSTaskCreate((OS_TCB *)&Led0TaskTCB,
                 (CPU_CHAR *)"led_pa6",        
                 (OS_TASK_PTR)led_pa6,        
                 (void *)0,
                 (OS_PRIO)LED0_TASK_PRIO,
                 (CPU_STK *)&LED0_TASK_STK[0],
                 (CPU_STK_SIZE)LED0_STK_SIZE/10,
                 (CPU_STK_SIZE)LED0_STK_SIZE,
                 (OS_MSG_QTY)5,
                 (OS_TICK)0,
                 (void *)0,
                 (OS_OPT)OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR,
                 (OS_ERR *)&err);
    
    /* 创建LED1任务 - PA3, 3s周期 */
    OSTaskCreate((OS_TCB *)&Led1TaskTCB,
                 (CPU_CHAR *)"led_pa3",
                 (OS_TASK_PTR)led_pa3,
                 (void *)0,
                 (OS_PRIO)LED1_TASK_PRIO,
                 (CPU_STK *)&LED1_TASK_STK[0],
                 (CPU_STK_SIZE)LED1_STK_SIZE/10,
                 (CPU_STK_SIZE)LED1_STK_SIZE,
                 (OS_MSG_QTY)5,
                 (OS_TICK)0,
                 (void *)0,
                 (OS_OPT)OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR,
                 (OS_ERR *)&err);
    
    /* 创建消息发送任务 - 2s周期 */
    OSTaskCreate((OS_TCB *)&MsgTaskTCB,
                 (CPU_CHAR *)"send_msg",
                 (OS_TASK_PTR)send_msg,
                 (void *)0,
                 (OS_PRIO)MSG_TASK_PRIO,
                 (CPU_STK *)&MSG_TASK_STK[0],
                 (CPU_STK_SIZE)MSG_STK_SIZE/10,
                 (CPU_STK_SIZE)MSG_STK_SIZE,
                 (OS_MSG_QTY)5,
                 (OS_TICK)0,
                 (void *)0,
                 (OS_OPT)OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR,
                 (OS_ERR *)&err);
    
    /* 删除启动任务 */
    OSTaskDel((OS_TCB *)0, &err);
}

/**
  * @brief LED PA6任务 - 1s周期闪烁 (亮0.5s + 灭0.5s)
  */
static void led_pa6(void *p_arg)  
{
    OS_ERR err;
    (void)p_arg;
    
    while (DEF_TRUE)
    {
        /* LED亮 - 0.5秒 */
        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, GPIO_PIN_RESET);  
        OSTimeDlyHMSM(0, 0, 0, 500, OS_OPT_TIME_HMSM_STRICT, &err);
        
        /* LED灭 - 0.5秒 */
        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, GPIO_PIN_SET);    
        OSTimeDlyHMSM(0, 0, 0, 500, OS_OPT_TIME_HMSM_STRICT, &err);
    }
}

/**
  * @brief LED PA3任务 - 3s周期闪烁 (亮1.5s + 灭1.5s)
  */
static void led_pa3(void *p_arg)
{
    OS_ERR err;
    (void)p_arg;
    
    while (DEF_TRUE)
    {
        /* LED亮 - 1.5秒 */
        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, GPIO_PIN_RESET);
        OSTimeDlyHMSM(0, 0, 1, 500, OS_OPT_TIME_HMSM_STRICT, &err);
        
        /* LED灭 - 1.5秒 */
        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, GPIO_PIN_SET);
        OSTimeDlyHMSM(0, 0, 1, 500, OS_OPT_TIME_HMSM_STRICT, &err);
    }
}

/**
  * @brief 消息发送任务 - 2s周期发送消息
  */
static void send_msg(void *p_arg)
{
    OS_ERR err;
    (void)p_arg;
    
    while (DEF_TRUE)
    {
        printf("hello uc/OS!欢迎来到RTOS多任务环境!\r\n");  
        OSTimeDlyHMSM(0, 0, 2, 0, OS_OPT_TIME_HMSM_STRICT, &err);
    }
}

/* USER CODE BEGIN 4 */
// 这里可以添加其他应用代码
/* USER CODE END 4 */

/**
  * @brief 错误处理函数
  */
void Error_Handler(void)
{
    /* 错误指示:使用PA6快速闪烁 */
    while (1)
    {
        HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_6);
        HAL_Delay(100);
    }
}

#ifdef USE_FULL_ASSERT
void assert_failed(uint8_t *file, uint32_t line)
{
    printf("Wrong parameters value: file %s on line %ld\r\n", file, line);
}
#endif

六、实验结果与分析

  1. 实验现象
    PA6 LED:以精确的1秒周期闪烁(亮0.5s + 灭0.5s)
    PA3 LED:以精确的3秒周期闪烁(亮1.5s + 灭1.5s)
    串口输出:每2秒接收到"hello uc/OS! 欢迎来到RTOS多任务环境!"
  2. 系统性能分析
    通过uC/OS-III的内置统计功能,可以观察到:
    CPU利用率稳定在5%以下
    各任务按时序精确执行
    无任务阻塞或优先级反转现象
  3. 实验视频展示

uCOS

视频内容展示:
两个LED不同频率的同步闪烁
串口调试助手实时显示消息
系统稳定运行状态

本视频中用到了野火的串口调试助手
因为sscom显示我的中文是乱码,但是sscom可以看到接收信息时间及间隔
这里放图:
在这里插入图片描述

七、应用拓展建议

基于此基础框架,可进一步实现:
① 添加传感器数据采集任务
② 实现任务间通信(消息队列)
③ 加入看门狗任务提高系统可靠性
④ 移植文件系统实现数据存储

通过本次实践,我们成功验证了uC/OS-III在STM32平台上的稳定性和实用性,为更复杂的嵌入式应用开发奠定了坚实基础。
本次的分享就到这里啦!

参考:
超详细教程:
https://blog.csdn.net/weixin_43116606/article/details/105532222

Logo

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

更多推荐