Funpack5-1 - 基于FRDM-MCXA346实现shell控制RGB LED
该项目使用了FRDM-MCXA346开发板,实现了shell控制板载RGB灯的设计,它的主要功能为:串口输入内容处理,PWM控制RGB灯。
标签
Funpack活动
开发板
FuShenxiao
更新2026-03-13
16

活动开发板介绍

本次活动使用的开发板是恩智浦的FRDM-MCXA346开发板,这块开发板搭载了MCX A346 MCU,该MCU基于Arm® Cortex®-M33内核,运行频率高达180MHz,1MB闪存,256KB RAM,带8KB的纠错码(ECC),同时具有双FlexPWM、4组16位ADC、专用MAU数学加速器以及SmartDMA,开发板正反面如下

image.png

屏幕截图 2026-02-25 230550.png

开发板器件框图如下,可以看到开发板有着丰富的外设接口,还有用户按键和RGB LED可以验证GPIO和PWM

image.png

任务分析

本次活动我选择的是任务1:串口通信的进阶题目,使用MCXA346开发板并用AI辅助实现一个带缓冲区的shell,核心是实现一个能读取、解析并执行用户输入命令的简易命令行解释器,并管理好输入缓冲区。基本要求:程序需能显示命令提示符(如 ysh > $),并循环接收用户输入(\n换行符为断句符号)。管理好输入缓冲区,妥善处理字符,并能进行基本的命令解析。例如:实现简单的指令控制板载的LED的颜色和亮度。

该任务可以拆分为两个任务

RGB LED的PWM控制

根据开发板原理图,可以看到RGB LED的RGB分别对应P3_18、P3_19、P3_21三个引脚,为了调整LED亮度,采用的是引脚的CTIMER功能

屏幕截图 2026-02-25 230629.png

串口模拟shell指令输入和分析

串口模拟shell的重点在于串口交互,既需要产生类似于SHELL>>这样提示一行指令开始的内容,又需要分析指令,包括正确读取指令并分析,对不正确的指令有识别纠错的功能

目标实现功能

基于以上这些分析,可以设置芯片引脚如下,其中LPUART2用于串口接收和发送,CTIMER2用于时间比较,从而用于产生对应占空比的PWM

image.png

本次任务我将创建两条shell指令,分别用于控制RGB LED亮度和RGB LED呼吸灯速率

  1. RGB LED亮度调节,ledset <R> <G> <B>,每个参数输入0-100的整数作为占空比,调节输出到RGB三盏LED灯的PWM占空比从而调整亮度
  2. RGB LED呼吸灯速率调节,ledbreath <R> <G> <B>,每个参数输入0-5的整数作为呼吸速度等级,调节输出到RGB三盏LED灯的PWM占空比变化速率从而调整呼吸灯速率

代码功能实现

PWM波形的产生

由于P3_18、P3_19、P3_21三个引脚并不能够使用FlexPWM,因此需要借助ctimer功能实现

在头文件中加入fsl_ctimer.h用于导入ctimer

#include "fsl_ctimer.h"

接着宏定义一些ctimer相关的参数,并设定PWM的默认频率为200Hz

#define RED_LED_CTIMER			CTIMER2
#define GREEN_LED_CTIMER CTIMER2
#define BLUE_LED_CTIMER CTIMER2
#define LED_PWM_PERIOD_CH kCTIMER_Match_2
#define RED_LED_PWM_DUTY_CH kCTIMER_Match_0
#define GREEN_LED_PWM_DUTY_CH kCTIMER_Match_1
#define BLUE_LED_PWM_DUTY_CH kCTIMER_Match_3
#define DEFAULT_PWM_FREQ (200U)

设置ctimer时钟初始化函数

static void Clocks_InitForCtimer2(void)
{
CLOCK_SetClockDiv(kCLOCK_DivCTIMER2, 1U);
CLOCK_AttachClk(kFRO_HF_to_CTIMER2);
RESET_ReleasePeripheralReset(kCTIMER2_RST_SHIFT_RSTn);
}

设置RGB三盏LED灯引脚的初始化函数

static void LedPwm_Init(void)
{
ctimer_config_t cfg;
Clocks_InitForCtimer2();
CTIMER_GetDefaultConfig(&cfg);
CTIMER_Init(RED_LED_CTIMER, &cfg);

uint8_t duty = 0U;
status_t status;

status = CTIMER_SetupPwmPeriod(
RED_LED_CTIMER,
LED_PWM_PERIOD_CH,
RED_LED_PWM_DUTY_CH,
DEFAULT_PWM_FREQ,
duty,
false
);
if(status != kStatus_Success) {
PRINTF("Red LED SetupPwmPeriod failed: %d\r\n", status);
while(1) {
__NOP();
}
}
status = CTIMER_SetupPwmPeriod(
GREEN_LED_CTIMER,
LED_PWM_PERIOD_CH,
GREEN_LED_PWM_DUTY_CH,
DEFAULT_PWM_FREQ,
duty,
false
);
if(status != kStatus_Success) {
PRINTF("Green LED SetupPwmPeriod failed: %d\r\n", status);
while(1) {
__NOP();
}
}
status = CTIMER_SetupPwmPeriod(
BLUE_LED_CTIMER,
LED_PWM_PERIOD_CH,
BLUE_LED_PWM_DUTY_CH,
DEFAULT_PWM_FREQ,
duty,
false
);
if(status != kStatus_Success) {
PRINTF("Blue LED SetupPwmPeriod failed: %d\r\n", status);
while(1) {
__NOP();
}
}
CTIMER_StartTimer(RED_LED_CTIMER);
CTIMER_StartTimer(GREEN_LED_CTIMER);
CTIMER_StartTimer(BLUE_LED_CTIMER);
}

设置亮度调节函数,传参为RGB三盏LED灯的PWM占空比

void Led_SetBrightness(uint8_t brightnessPercent_r, uint8_t brightnessPercent_g, uint8_t brightnessPercent_b)
{
if (brightnessPercent_r > 100U) {
brightnessPercent_r = 100U;
}
if (brightnessPercent_g > 100U) {
brightnessPercent_g = 100U;
}
if (brightnessPercent_b > 100U) {
brightnessPercent_b = 100U;
}

CTIMER_SetupPwmPeriod(
RED_LED_CTIMER,
LED_PWM_PERIOD_CH,
RED_LED_PWM_DUTY_CH,
DEFAULT_PWM_FREQ,
brightnessPercent_r,
false
);
CTIMER_SetupPwmPeriod(
GREEN_LED_CTIMER,
LED_PWM_PERIOD_CH,
GREEN_LED_PWM_DUTY_CH,
DEFAULT_PWM_FREQ,
brightnessPercent_g,
false
);
CTIMER_SetupPwmPeriod(
BLUE_LED_CTIMER,
LED_PWM_PERIOD_CH,
BLUE_LED_PWM_DUTY_CH,
DEFAULT_PWM_FREQ,
brightnessPercent_b,
false
);
}

shell内容的创建

为了使用shell功能需要引入fsl_shell.h头文件

#include "fsl_shell.h"

定义需要创建的shell功能的句柄(功能后续介绍),并设置shell功能的帮助信息,同时引入shell_handle_t和serial_handle_t两个变量用于shell指令的操作

/*******************************************************************************
* Prototypes
******************************************************************************/

/* SHELL command handlers */
static shell_status_t ledset_handler(shell_handle_t shellHandle, int32_t argc, char **argv);
static shell_status_t ledbreath_handler(shell_handle_t shellHandle, int32_t argc, char **argv);

/*******************************************************************************
* Variables
******************************************************************************/

SHELL_COMMAND_DEFINE(ledset, "\r\n\"ledset <R> <G> <B>\": Set RGB-LED brightness\r\n", ledset_handler, 3);
SHELL_COMMAND_DEFINE(ledbreath, "\r\n\"ledbreath <R> <G> <B>\": Set RGB-LED breath speed\r\n", ledbreath_handler, 3);
SDK_ALIGN(static uint8_t s_shellHandleBuffer[SHELL_HANDLE_SIZE], 4);
static shell_handle_t s_shellHandle;

extern serial_handle_t g_serialHandle;

在主函数中初始化shell并创建ledset和ledbreath两个shell功能

    /* Init SHELL */
s_shellHandle = &s_shellHandleBuffer[0];
SHELL_Init(s_shellHandle, g_serialHandle, "SHELL>> ");

SHELL_RegisterCommand(s_shellHandle, SHELL_COMMAND(ledset));
SHELL_RegisterCommand(s_shellHandle, SHELL_COMMAND(ledbreath));

while (1)
{
#if !(defined(SHELL_NON_BLOCKING_MODE) && (SHELL_NON_BLOCKING_MODE > 0U))
SHELL_Task(s_shellHandle);
#endif
}

shell功能的创建

我们目标创建两条指令:ledset用于调整RGB三盏LED灯的亮度,ledbreath用于调整三盏LED灯的呼吸速率

ledset的实现

首先进行传参分析,参数不符合(数目不对以及不符合0-100的整数的)产生报警并返回,接着分析三个传参,将它们作为RGB三盏LED灯的占空比,调用函数Led_SetBrightness实现LED灯亮度的调节

static shell_status_t ledset_handler(shell_handle_t shellHandle, int32_t argc, char **argv)
{
uint8_t rgb[3] = {0};

breathFlag = false;

// 入参判断
if (argc != 4)
{
SHELL_Printf("Usage: ledset <R> <G> <B>\r\n");
return kStatus_SHELL_Success;
}

for(int i = 0; i < 3; i++) {
char *endp = NULL;
unsigned long v = strtoul(argv[i + 1], &endp, 0);

// 判断参数是否合规
if (argv[i + 1][0] == '\0' || *endp != '\0' || v > 100UL)
{
SHELL_Printf("Invalid %c value: %s (expect 0..100 integer)\r\n", "RGB"[i], argv[i + 1]);
return kStatus_SHELL_Success;
}
rgb[i] = (uint8_t)v;
}

Led_SetBrightness(rgb[0], rgb[1], rgb[2]);
return kStatus_SHELL_Success;
}

ledbreath的实现

为了实现呼吸灯,最简单的方案是写一个死循环,让占空比往复加减即可,然而为了能不断向shell输入内容,我们并不希望产生死循环。

在学习STM32的时候,我们知道有个概念叫做滴答定时器,这是说系统每个毫秒会进入一次中断。同理的,在FRDM-MCXA346上也可以使用这个思路,利用滴答定时器的中断进行计数,利用计数来实现周期的循环。

在主函数中初始化滴答定时器,设置其中断时间为每个毫秒

    SystemCoreClockUpdate();
SysTick_Config(SystemCoreClock / 1000U);

定义一些全局变量,其中ms用于毫秒计数,breathFlag用于判断当前指令是否为ledbreath,rgb_speed用于存储当前RGB三盏LED灯呼吸灯速率等级

uint32_t ms = 0;
bool breathFlag = false;
uint8_t rgb_speed[3] = {0};

滴答定时器中断回调函数的实现需要在board.c中书写,在board.c中添加以下内容

将上述的全局变量作为这个c文件的外部变量,并设置PWM的相关参数

extern uint32_t ms;
extern bool breathFlag;
extern uint8_t rgb_speed[3];
uint8_t step_r = 0;
uint8_t step_g = 0;
uint8_t step_b = 0;
uint8_t duty_r = 0;
uint8_t duty_g = 0;
uint8_t duty_b = 0;
bool flag_r = true;
bool flag_g = true;
bool flag_b = true;

在board.c中设置一个函数,用于实现呼吸灯速率等级到真实步进值的映射

static uint8_t Speed2Step(uint8_t Speed)
{
switch(Speed) {
case 0:
return 0;
case 1:
return 1;
case 2:
return 2;
case 3:
return 4;
case 4:
return 5;
case 5:
return 10;
}
}

定义滴答定时器的中断回调函数,每50ms进行一次PWM占空比的更新,SysTick_Handler在工程文件最初的源代码中是一个弱定义的函数,在board.c中对其进行了重写

void SysTick_Handler(void)
{
if(!breathFlag) {
return;
}
if(ms++ < 50) {
return;
}
ms = 0;
step_r = Speed2Step(rgb_speed[0]);
step_g = Speed2Step(rgb_speed[1]);
step_b = Speed2Step(rgb_speed[2]);

if(flag_r) {
if(duty_r < 100U) {
duty_r += step_r;
} else {
flag_r = false;
}
} else {
if(duty_r > 0U) {
duty_r -= step_r;
} else {
flag_r = true;
}
}
if(flag_g) {
if(duty_g < 100U) {
duty_g += step_g;
} else {
flag_g = false;
}
} else {
if(duty_g > 0U) {
duty_g -= step_g;
} else {
flag_g = true;
}
}
if(flag_b) {
if(duty_b < 100U) {
duty_b += step_b;
} else {
flag_b = false;
}
} else {
if(duty_b > 0U) {
duty_b -= step_b;
} else {
flag_b = true;
}
}
Led_SetBrightness(duty_r, duty_g, duty_b);
}

在主文件中,ledbreath的句柄函数判断了入参合法性,并将入参传入了全局变量rgb_speed,同时将呼吸灯在滴答定时器内启用其逻辑的标志位breathFlag标记为true。如果使用ledset,那么breathFlag这个标志位就会变为false

static shell_status_t ledbreath_handler(shell_handle_t shellHandle, int32_t argc, char **argv)
{
// 入参判断
if (argc != 4)
{
SHELL_Printf("Usage: ledbreath <R> <G> <B>\r\n");
return kStatus_SHELL_Success;
}

for(int i = 0; i < 3; i++) {
char *endp = NULL;
unsigned long v = strtoul(argv[i + 1], &endp, 0);

// 判断参数是否合规
if (argv[i + 1][0] == '\0' || *endp != '\0' || v > 5UL)
{
SHELL_Printf("Invalid %c value: %s (expect 0, 1, 2, 3, 4, 5)\r\n", "RGB"[i], argv[i + 1]);
return kStatus_SHELL_Success;
}
rgb_speed[i] = (uint8_t)v;
}
breathFlag = true;
return kStatus_SHELL_Success;
}

代码汇总

主要的代码汇总如下

主文件RGBShell.c代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "app.h"
#include "board.h"
#include "pin_mux.h"
#include "clock_config.h"
#include "fsl_debug_console.h"
#include "fsl_ctimer.h"
#include "fsl_clock.h"
#include "fsl_reset.h"
#include "fsl_component_serial_manager.h"
#include "fsl_shell.h"
#include "RGBShell.h"

/*******************************************************************************
* Definitions
******************************************************************************/

#define RED_LED_CTIMER CTIMER2
#define GREEN_LED_CTIMER CTIMER2
#define BLUE_LED_CTIMER CTIMER2
#define LED_PWM_PERIOD_CH kCTIMER_Match_2
#define RED_LED_PWM_DUTY_CH kCTIMER_Match_0
#define GREEN_LED_PWM_DUTY_CH kCTIMER_Match_1
#define BLUE_LED_PWM_DUTY_CH kCTIMER_Match_3
#define DEFAULT_PWM_FREQ (200U)

#define SHELL_Printf PRINTF

/*******************************************************************************
* Prototypes
******************************************************************************/

/* SHELL command handlers */
static shell_status_t ledset_handler(shell_handle_t shellHandle, int32_t argc, char **argv);
static shell_status_t ledbreath_handler(shell_handle_t shellHandle, int32_t argc, char **argv);

/*******************************************************************************
* Variables
******************************************************************************/

SHELL_COMMAND_DEFINE(ledset, "\r\n\"ledset <R> <G> <B>\": Set RGB-LED brightness\r\n", ledset_handler, 3);
SHELL_COMMAND_DEFINE(ledbreath, "\r\n\"ledbreath <R> <G> <B>\": Set RGB-LED breath speed\r\n", ledbreath_handler, 3);
SDK_ALIGN(static uint8_t s_shellHandleBuffer[SHELL_HANDLE_SIZE], 4);
static shell_handle_t s_shellHandle;

extern serial_handle_t g_serialHandle;

uint32_t ms = 0;
bool breathFlag = false;
uint8_t rgb_speed[3] = {0};

/*******************************************************************************
* Code
******************************************************************************/
static void Clocks_InitForCtimer2(void)
{
CLOCK_SetClockDiv(kCLOCK_DivCTIMER2, 1U);
CLOCK_AttachClk(kFRO_HF_to_CTIMER2);
RESET_ReleasePeripheralReset(kCTIMER2_RST_SHIFT_RSTn);
}

static void LedPwm_Init(void)
{
ctimer_config_t cfg;
Clocks_InitForCtimer2();
CTIMER_GetDefaultConfig(&cfg);
CTIMER_Init(RED_LED_CTIMER, &cfg);

uint8_t duty = 0U;
status_t status;

status = CTIMER_SetupPwmPeriod(
RED_LED_CTIMER,
LED_PWM_PERIOD_CH,
RED_LED_PWM_DUTY_CH,
DEFAULT_PWM_FREQ,
duty,
false
);
if(status != kStatus_Success) {
PRINTF("Red LED SetupPwmPeriod failed: %d\r\n", status);
while(1) {
__NOP();
}
}
status = CTIMER_SetupPwmPeriod(
GREEN_LED_CTIMER,
LED_PWM_PERIOD_CH,
GREEN_LED_PWM_DUTY_CH,
DEFAULT_PWM_FREQ,
duty,
false
);
if(status != kStatus_Success) {
PRINTF("Green LED SetupPwmPeriod failed: %d\r\n", status);
while(1) {
__NOP();
}
}
status = CTIMER_SetupPwmPeriod(
BLUE_LED_CTIMER,
LED_PWM_PERIOD_CH,
BLUE_LED_PWM_DUTY_CH,
DEFAULT_PWM_FREQ,
duty,
false
);
if(status != kStatus_Success) {
PRINTF("Blue LED SetupPwmPeriod failed: %d\r\n", status);
while(1) {
__NOP();
}
}
CTIMER_StartTimer(RED_LED_CTIMER);
CTIMER_StartTimer(GREEN_LED_CTIMER);
CTIMER_StartTimer(BLUE_LED_CTIMER);
}

void Led_SetBrightness(uint8_t brightnessPercent_r, uint8_t brightnessPercent_g, uint8_t brightnessPercent_b)
{
if (brightnessPercent_r > 100U) {
brightnessPercent_r = 100U;
}
if (brightnessPercent_g > 100U) {
brightnessPercent_g = 100U;
}
if (brightnessPercent_b > 100U) {
brightnessPercent_b = 100U;
}

CTIMER_SetupPwmPeriod(
RED_LED_CTIMER,
LED_PWM_PERIOD_CH,
RED_LED_PWM_DUTY_CH,
DEFAULT_PWM_FREQ,
brightnessPercent_r,
false
);
CTIMER_SetupPwmPeriod(
GREEN_LED_CTIMER,
LED_PWM_PERIOD_CH,
GREEN_LED_PWM_DUTY_CH,
DEFAULT_PWM_FREQ,
brightnessPercent_g,
false
);
CTIMER_SetupPwmPeriod(
BLUE_LED_CTIMER,
LED_PWM_PERIOD_CH,
BLUE_LED_PWM_DUTY_CH,
DEFAULT_PWM_FREQ,
brightnessPercent_b,
false
);
}

static shell_status_t ledset_handler(shell_handle_t shellHandle, int32_t argc, char **argv)
{
uint8_t rgb[3] = {0};

breathFlag = false;

// 入参判断
if (argc != 4)
{
SHELL_Printf("Usage: ledset <R> <G> <B>\r\n");
return kStatus_SHELL_Success;
}

for(int i = 0; i < 3; i++) {
char *endp = NULL;
unsigned long v = strtoul(argv[i + 1], &endp, 0);

// 判断参数是否合规
if (argv[i + 1][0] == '\0' || *endp != '\0' || v > 100UL)
{
SHELL_Printf("Invalid %c value: %s (expect 0..100 integer)\r\n", "RGB"[i], argv[i + 1]);
return kStatus_SHELL_Success;
}
rgb[i] = (uint8_t)v;
}

Led_SetBrightness(rgb[0], rgb[1], rgb[2]);
return kStatus_SHELL_Success;
}

static shell_status_t ledbreath_handler(shell_handle_t shellHandle, int32_t argc, char **argv)
{
// 入参判断
if (argc != 4)
{
SHELL_Printf("Usage: ledbreath <R> <G> <B>\r\n");
return kStatus_SHELL_Success;
}

for(int i = 0; i < 3; i++) {
char *endp = NULL;
unsigned long v = strtoul(argv[i + 1], &endp, 0);

// 判断参数是否合规
if (argv[i + 1][0] == '\0' || *endp != '\0' || v > 5UL)
{
SHELL_Printf("Invalid %c value: %s (expect 0, 1, 2, 3, 4, 5)\r\n", "RGB"[i], argv[i + 1]);
return kStatus_SHELL_Success;
}
rgb_speed[i] = (uint8_t)v;
}
breathFlag = true;
return kStatus_SHELL_Success;
}

int main(void)
{
BOARD_InitHardware();
LedPwm_Init();
SystemCoreClockUpdate();
SysTick_Config(SystemCoreClock / 1000U);

/* Init SHELL */
s_shellHandle = &s_shellHandleBuffer[0];
SHELL_Init(s_shellHandle, g_serialHandle, "SHELL>> ");

SHELL_RegisterCommand(s_shellHandle, SHELL_COMMAND(ledset));
SHELL_RegisterCommand(s_shellHandle, SHELL_COMMAND(ledbreath));

while (1)
{
#if !(defined(SHELL_NON_BLOCKING_MODE) && (SHELL_NON_BLOCKING_MODE > 0U))
SHELL_Task(s_shellHandle);
#endif
}
}

board.c中与中断回调实现呼吸灯效果的代码

/*******************************************************************************
* Variables
******************************************************************************/
extern uint32_t ms;
extern bool breathFlag;
extern uint8_t rgb_speed[3];
uint8_t step_r = 0;
uint8_t step_g = 0;
uint8_t step_b = 0;
uint8_t duty_r = 0;
uint8_t duty_g = 0;
uint8_t duty_b = 0;
bool flag_r = true;
bool flag_g = true;
bool flag_b = true;
/*******************************************************************************
* Code
******************************************************************************/

static uint8_t Speed2Step(uint8_t Speed)
{
switch(Speed) {
case 0:
return 0;
case 1:
return 1;
case 2:
return 2;
case 3:
return 4;
case 4:
return 5;
case 5:
return 10;
}
}

void SysTick_Handler(void)
{
if(!breathFlag) {
return;
}
if(ms++ < 50) {
return;
}
ms = 0;
step_r = Speed2Step(rgb_speed[0]);
step_g = Speed2Step(rgb_speed[1]);
step_b = Speed2Step(rgb_speed[2]);

if(flag_r) {
if(duty_r < 100U) {
duty_r += step_r;
} else {
flag_r = false;
}
} else {
if(duty_r > 0U) {
duty_r -= step_r;
} else {
flag_r = true;
}
}
if(flag_g) {
if(duty_g < 100U) {
duty_g += step_g;
} else {
flag_g = false;
}
} else {
if(duty_g > 0U) {
duty_g -= step_g;
} else {
flag_g = true;
}
}
if(flag_b) {
if(duty_b < 100U) {
duty_b += step_b;
} else {
flag_b = false;
}
} else {
if(duty_b > 0U) {
duty_b -= step_b;
} else {
flag_b = true;
}
}
Led_SetBrightness(duty_r, duty_g, duty_b);
}

完整代码可以参见附件代码文件RGBShell

演示效果

将代码烧录进入芯片,使用ledset调整输入到每盏灯的PWM的占空比,如果占空比超过了100,那么就会产生告警

image.png

SHELL>> ledset 10 0 0的实现效果

2.jpg

SHELL>> ledset 50 0 0的实现效果

3.jpg

SHELL>> ledset 10 20 30的实现效果

4.jpg

使用ledbreath调整输入到每盏灯的PWM占空比的变化速率,如果速率等级不为0-5,那么就会产生告警

image.png

SHELL>> ledbreath 2 0 0的实现效果

a0b6f0f6d80dae2581832a17a754af09.gif

SHELL>> ledbreath 4 0 0的实现效果

ec5ec864e820ad84c894e38032f3818d.gif

SHELL>> ledbreath 1 2 3的实现效果

a8f7074d8ccceb47f49816fe1fe7611d.gif

更加具体的实现效果可以参见我的b站视频

心得总结

再次感谢得捷电子和硬禾科技对本次活动的支持。恩智浦的产品并不是我所常用的,其开发思路也与我目前掌握的一些MCU的开发方式有些差异,但是通过本次活动,我对恩智浦的MCU的相关开发流程有了一定的理解,尤其是其PWM的ctimer生成方案以及shell功能的实现。并且在这个过程中,我作为一名恩智浦产品的初学者,使用GitHub copilot这个AI工具解答了不少我在基本配置代码书写过程中产生的一系列疑问,这使得我对一款全新产品的认识速度在AI的帮助下相较之前有所提升。

附件下载
FRDM-MCXA346原理图.pdf
FRDM-MCXA346原理图
FRDM-MCXA346用户手册.pdf
FRDM-MCXA346用户手册
RGBShell.zip
项目源代码
团队介绍
傅沈骁是一名UEFI开发工程师
评论
0 / 100
查看更多
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2024 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号