Funpack5-1 用 FRDM-MCXA346 完成zephyr完成shell控制RGB灯
该项目使用了zephyr开发FRDM_MCXA346,实现了串口输出的设计,它的主要功能为:配置串口输出,输出字符串:Hello, DigiKey Funpack 5-1。 该项目使用了zephyr开FRDM_MCXA346,实现了控制开发板上的LED灯的设计,它的主要功能为:使用shell控制台来控制RGB灯的亮与灭,通过软件模拟pwm实现RGB的亮度控制。
标签
Funpack活动
开发板
lugl
更新2026-03-13
10

项目概述

本项目使用 Zephyr RTOS 在 NXP FRDM-MCXA346 开发板上完成 DigiKey Funpack 5-1 的两个任务要求。

硬件平台

  • 开发板: NXP FRDM-MCXA346
  • 处理器: MCXA346 (ARM Cortex-M33, 180MHz)
  • 内存: 240KB SRAM, 1MB Flash
  • 串口: LPUART2 (115200 baud)

软件平台

  • RTOS: Zephyr Project
  • 工具链: Zephyr SDK / GCC ARM Embedded


任务1:基础任务 - UART 串口输出


任务要求

使用 MCXA346 开发板的 UART 串口输出 "Hello, DigiKey Funpack 5-1"

实现方案


1. 项目结构

digikey_funpack/

└── hello/

├── CMakeLists.txt

├── prj.conf

└── src/

└── main.c

2. 配置文件 (prj.conf)

CONFIG_CONSOLE=y
CONFIG_UART_CONSOLE=y
CONFIG_SERIAL=y
CONFIG_PRINTK=y

3. 源代码 (main.c)

#include <zephyr/kernel.h>
#include <zephyr/sys/printk.h>

int main(void)
{
printk("Hello, DigiKey Funpack 5-1\n");
return 0;
}

运行方法

# 进入 Zephyr 环境
cd zephyrproject

# 设置环境变量
source zephyr/zephyr-env.sh

# 构建项目
cd digikey_funpack/hello
west build -b frdm_mcxa346


烧录并运行

使用LinkFlash进行下载:

image.png

预期输出

image.png

任务2:进阶任务 - 带缓冲区的 Shell


任务要求

实现一个带缓冲区的 shell,核心功能包括:

1. 命令提示符显示 (`ysh > $`)

2. 循环接收用户输入

3. 输入缓冲区管理

4. 命令解析与执行

5. 控制板载 LED 的颜色和亮度


实现方案

1. 项目结构

digikey_funpack/
└── shell/
    ├── CMakeLists.txt
    ├── prj.conf
    └── src/
        └── main.c


2. 核心功能实现

2.1 代码实现
#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/sys/printk.h>
#include <zephyr/sys/util.h>
#include <zephyr/console/console.h>
#include <string.h>
#include <stdlib.h>


/* Input buffer configuration */
#define INPUT_BUFFER_SIZE  128
#define MAX_ARGS          16


/* Shell prompt */
#define SHELL_PROMPT      "ysh > $ "


/* LED GPIO specifications */
#define LED_RED_NODE    DT_ALIAS(led0)
#define LED_GREEN_NODE  DT_ALIAS(led1)
#define LED_BLUE_NODE   DT_ALIAS(led2)


static const struct gpio_dt_spec led_red   = GPIO_DT_SPEC_GET(LED_RED_NODE, gpios);
static const struct gpio_dt_spec led_green = GPIO_DT_SPEC_GET(LED_GREEN_NODE, gpios);
static const struct gpio_dt_spec led_blue  = GPIO_DT_SPEC_GET(LED_BLUE_NODE, gpios);


/* Input buffer */
static char input_buffer[INPUT_BUFFER_SIZE];
static int buffer_pos = 0;


/* LED state - brightness 0-100 */
static uint8_t red_brightness = 0;
static uint8_t green_brightness = 0;
static uint8_t blue_brightness = 0;


/* Software PWM state */
static struct k_timer pwm_timer;
static uint8_t pwm_counter = 0;
static volatile uint8_t pwm_period = 100;  /* PWM period */


/* Software PWM callback - runs every 0.1ms (10kHz PWM frequency) */
static void pwm_callback(struct k_timer *timer)
{
    ARG_UNUSED(timer);


    pwm_counter++;
    if (pwm_counter >= pwm_period) {
        pwm_counter = 0;
    }


    /* 根据测试结果修正:brightness=0 全亮,brightness=100 全灭 */
    /* 所以 GPIO 逻辑需要反过来 */


    /* Red LED */
    if (red_brightness == 0) {
        gpio_pin_set_dt(&led_red, 0);  /* On (全亮) */
    } else if (red_brightness >= 100) {
        gpio_pin_set_dt(&led_red, 1);  /* Off (全灭) */
    } else {
        gpio_pin_set_dt(&led_red, pwm_counter < red_brightness ? 1 : 0);
    }


    /* Green LED */
    if (green_brightness == 0) {
        gpio_pin_set_dt(&led_green, 0);  /* On */
    } else if (green_brightness >= 100) {
        gpio_pin_set_dt(&led_green, 1);  /* Off */
    } else {
        gpio_pin_set_dt(&led_green, pwm_counter < green_brightness ? 1 : 0);
    }


    /* Blue LED */
    if (blue_brightness == 0) {
        gpio_pin_set_dt(&led_blue, 0);  /* On */
    } else if (blue_brightness >= 100) {
        gpio_pin_set_dt(&led_blue, 1);  /* Off */
    } else {
        gpio_pin_set_dt(&led_blue, pwm_counter < blue_brightness ? 1 : 0);
    }
}


/* LED control command */
static void cmd_led(int argc, char **argv);


/* Forward declaration */
static void print_prompt(void);


/* Available commands for tab completion */
static const char *commands[] = {
    "help",
    "led",
    "rgb",
    "clear",
    "info",
    "reboot"
};
#define NUM_COMMANDS (sizeof(commands) / sizeof(commands[0]))


/* Tab completion function */
static void tab_complete(void)
{
    int matches = 0;
    int i;
    const char *match = NULL;


    /* Find matches */
    for (i = 0; i < NUM_COMMANDS; i++) {
        if (strncmp(input_buffer, commands[i], buffer_pos) == 0) {
            match = commands[i];
            matches++;
        }
    }


    if (matches == 1 && match != NULL) {
        /* Complete the command */
        printk("\n%s", match);
        strcpy(input_buffer, match);
        buffer_pos = strlen(match);
    } else if (matches > 1) {
        /* Show all matches */
        printk("\n");
        for (i = 0; i < NUM_COMMANDS; i++) {
            if (strncmp(input_buffer, commands[i], buffer_pos) == 0) {
                printk("%s ", commands[i]);
            }
        }
        printk("\n");
        print_prompt();
        printk("%s", input_buffer);
    }
}


/* Simple token parser - compatible with Zephyr */
static char *my_strtok(char *str, const char *delim)
{
    static char *next_token = NULL;
    char *token;


    if (str != NULL) {
        next_token = str;
    }


    if (next_token == NULL) {
        return NULL;
    }


    /* Skip leading delimiters */
    while (*next_token != '\0') {
        const char *d = delim;
        while (*d != '\0') {
            if (*next_token == *d) {
                next_token++;
                break;
            }
            d++;
        }
        if (*d == '\0') {
            break;  /* Not a delimiter */
        }
    }


    if (*next_token == '\0') {
        next_token = NULL;
        return NULL;
    }


    token = next_token;


    /* Find end of token */
    while (*next_token != '\0') {
        const char *d = delim;
        while (*d != '\0') {
            if (*next_token == *d) {
                *next_token = '\0';
                next_token++;
                return token;
            }
            d++;
        }
        next_token++;
    }


    next_token = NULL;
    return token;
}


/* Parse input buffer into arguments */
static int parse_command(char *buffer, char **argv, int max_args)
{
    int argc = 0;
    char *token;


    /* Skip leading spaces */
    while (*buffer == ' ') {
        buffer++;
    }


    /* Parse tokens */
    token = my_strtok(buffer, " \t\r\n");
    while (token != NULL && argc < max_args) {
        argv[argc++] = token;
        token = my_strtok(NULL, " \t\r\n");
    }


    return argc;
}


/* Print help message */
static void print_help(void)
{
    printk("Available commands:\n");
    printk("  help           - Show this help message\n");
    printk("  led <color>   - Turn LED on/off (red, green, blue, all)\n");
    printk("  led <color> <0-100> - Set LED brightness (0-100)\n");
    printk("  rgb <r> <g> <b> - Set RGB LED values (0-100 each)\n");
    printk("  clear          - Clear screen\n");
    printk("  info           - Show board information\n");
    printk("  reboot         - Reboot the board\n");
}


/* LED control command */
static void cmd_led(int argc, char **argv)
{
    if (argc < 2) {
        printk("Usage: led <color> [0-100]\n");
        printk("  colors: red, green, blue, all\n");
        return;
    }


    const char *color = argv[1];


    if (argc == 2) {
        /* Toggle LED */
        if (strcmp(color, "red") == 0) {
            red_brightness = red_brightness ? 0 : 100;
        } else if (strcmp(color, "green") == 0) {
            green_brightness = green_brightness ? 0 : 100;
        } else if (strcmp(color, "blue") == 0) {
            blue_brightness = blue_brightness ? 0 : 100;
        } else if (strcmp(color, "all") == 0) {
            red_brightness = red_brightness ? 0 : 100;
            green_brightness = green_brightness ? 0 : 100;
            blue_brightness = blue_brightness ? 0 : 100;
        } else {
            printk("Unknown color. Use: red, green, blue, all\n");
            return;
        }
    } else {
        /* Set brightness */
        int value = atoi(argv[2]);
        if (value < 0 || value > 100) {
            printk("Brightness must be 0-100\n");
            return;
        }


        if (strcmp(color, "red") == 0) {
            red_brightness = value;
        } else if (strcmp(color, "green") == 0) {
            green_brightness = value;
        } else if (strcmp(color, "blue") == 0) {
            blue_brightness = value;
        } else if (strcmp(color, "all") == 0) {
            red_brightness = value;
            green_brightness = value;
            blue_brightness = value;
        } else {
            printk("Unknown color. Use: red, green, blue, all\n");
            return;
        }
    }


    /* LED is active low, so setting GPIO to 0 turns LED on */
    gpio_pin_set_dt(&led_red, red_brightness > 0 ? 1 : 0);
    gpio_pin_set_dt(&led_green, green_brightness > 0 ? 1 : 0);
    gpio_pin_set_dt(&led_blue, blue_brightness > 0 ? 1 : 0);


    printk("LED: R=%d%% G=%d%% B=%d%%\n", red_brightness, green_brightness, blue_brightness);
}


/* RGB command - set all three LEDs at once */
static void cmd_rgb(int argc, char **argv)
{
    if (argc < 4) {
        printk("Usage: rgb <red> <green> <blue>\n");
        printk("  Each value: 0-100\n");
        return;
    }


    int r = atoi(argv[1]);
    int g = atoi(argv[2]);
    int b = atoi(argv[3]);


    if (r < 0 || r > 100 || g < 0 || g > 100 || b < 0 || b > 100) {
        printk("All values must be 0-100\n");
        return;
    }


    red_brightness = r;
    green_brightness = g;
    blue_brightness = b;


    /* LED is active low, so setting GPIO to 0 turns LED on */
    gpio_pin_set_dt(&led_red, red_brightness > 0 ? 1 : 0);
    gpio_pin_set_dt(&led_green, green_brightness > 0 ? 1 : 0);
    gpio_pin_set_dt(&led_blue, blue_brightness > 0 ? 1 : 0);


    printk("RGB: R=%d%% G=%d%% B=%d%%\n", r, g, b);
}


/* Info command */
static void cmd_info(void)
{
    printk("========================================\n");
    printk("  DigiKey Funpack 5-1 - Shell Demo\n");
    printk("  Board: NXP FRDM-MCXA346\n");
    printk("  Zephyr RTOS\n");
    printk("========================================\n");
    printk("LED Status: R=%d%% G=%d%% B=%d%%\n",
           red_brightness, green_brightness, blue_brightness);
}


/* Clear screen command */
static void cmd_clear(void)
{
    /* ANSI escape code to clear screen */
    printk("\033[2J\033[H");
}


/* Process command */
static void process_command(char *buffer)
{
    char *argv[MAX_ARGS];
    int argc;


    /* Skip empty lines */
    if (buffer[0] == '\0' || buffer[0] == '\n') {
        return;
    }


    /* Parse command */
    argc = parse_command(buffer, argv, MAX_ARGS);


    if (argc == 0) {
        return;
    }


    /* Execute command */
    if (strcmp(argv[0], "help") == 0) {
        print_help();
    } else if (strcmp(argv[0], "led") == 0) {
        cmd_led(argc, argv);
    } else if (strcmp(argv[0], "rgb") == 0) {
        cmd_rgb(argc, argv);
    } else if (strcmp(argv[0], "clear") == 0) {
        cmd_clear();
    } else if (strcmp(argv[0], "info") == 0) {
        cmd_info();
    } else if (strcmp(argv[0], "reboot") == 0) {
        printk("Reboot command not available\n");
    } else {
        printk("Unknown command: %s\n", argv[0]);
        printk("Type 'help' for available commands.\n");
    }
}


/* Print prompt */
static void print_prompt(void)
{
    printk("%s", SHELL_PROMPT);
}


/* UART device */
int main(void)
{
    uint8_t c;


    printk("Initializing DigiKey Funpack 5-1 Shell...\n");


    /* Initialize console */
    console_init();
    printk("Console initialized\n");


    /* Initialize LEDs */
    if (device_is_ready(led_red.port)) {
        gpio_pin_configure_dt(&led_red, GPIO_OUTPUT);
        gpio_pin_set_dt(&led_red, 1);  /* Off (active low) */
        printk("Red LED initialized\n");
    }


    if (device_is_ready(led_green.port)) {
        gpio_pin_configure_dt(&led_green, GPIO_OUTPUT);
        gpio_pin_set_dt(&led_green, 1);  /* Off (active low) */
        printk("Green LED initialized\n");
    }


    if (device_is_ready(led_blue.port)) {
        gpio_pin_configure_dt(&led_blue, GPIO_OUTPUT);
        gpio_pin_set_dt(&led_blue, 1);  /* Off (active low) */
        printk("Blue LED initialized\n");
    }


    /* Initialize and start software PWM timer - 0.1ms period (10kHz) */
    k_timer_init(&pwm_timer, pwm_callback, NULL);
    k_timer_start(&pwm_timer, K_USEC(100), K_USEC(100));
    printk("Software PWM started (10kHz)\n");


    /* Initialize buffer */
    buffer_pos = 0;
    memset(input_buffer, 0, sizeof(input_buffer));


    /* Welcome message */
    printk("\n");
    printk("========================================\n");
    printk("  DigiKey Funpack 5-1 - Shell Demo\n");
    printk("  Board: NXP FRDM-MCXA346\n");
    printk("  Zephyr RTOS\n");
    printk("========================================\n");
    printk("Type 'help' for available commands.\n");
    printk("\n");


    /* Print prompt */
    print_prompt();


    /* Main loop - read characters from console */
    while (1) {
        /* Read character from console (blocking) */
        /* Read character from UART (polling) */
        /* Read character from console (blocking) */
        c = console_getchar();
        if (c < 0) {
            k_yield();
            continue;
        }


        /* Handle character */
        switch (c) {
            case '\r':
            case '\n':
                /* Enter key - process command */
                printk("\r\n");
                if (buffer_pos > 0) {
                    input_buffer[buffer_pos] = '\0';
                    process_command(input_buffer);
                    buffer_pos = 0;
                    memset(input_buffer, 0, sizeof(input_buffer));
                }
                print_prompt();
                break;


            case '\b':
            case 0x7F:
                /* Backspace / Delete - delete character */
                if (buffer_pos > 0) {
                    buffer_pos--;
                    printk("\b \b");  /* Erase character */
                }
                break;


            case '\t':
                /* Tab - auto-complete */
                tab_complete();
                break;


            default:
                /* Regular character - add to buffer */
                if (buffer_pos < (INPUT_BUFFER_SIZE - 1) && c >= 0x20 && c <= 0x7E) {
                    input_buffer[buffer_pos++] = c;
                    printk("%c", c);  /* Echo */
                }
                break;
        }


        k_yield();
    }


    return 0;
}

缓冲区管理包括:

  • 字符接收与存储
  • 退格键处理 (删除字符)
  • 回车键处理 (执行命令)
  • 特殊字符过滤 (仅接受可打印 ASCII 字符)
2.2 命令解析

使用自定义的 `my_strtok` 函数进行命令行解析,支持:

  • 空格和tab 作为分隔符
  • 最多16个参数
2.3 LED控制

板载RGB LED GPIO 定义:

  • 红色 LED:GPIO3_18
  • 绿色 LED:GPIO3_19
  • 绿色 LED:GPIO3_21
2.4 支持的命令

image.png

3. 源代码 (main.c)

主要函数:

  • my_strtok() - 命令行解析
  • parse_command() - 参数解析
  • process_command() - 命令处理分发
  • cmd_led() - LED 控制命令
  • cmd_rgb() - RGB 同时控制
  • cmd_info() - 显示信息
  • cmd_clear() - 清屏
  • print_help() - 帮助信息

运行方法

# 构建项目
cd digikey_funpack/shell
west build -b frdm_mcxa346


烧录

image.png


交互示例:

ysh > $ rgb 50 50 50
RGB: R=50% G=50% B=50% led灯50%的亮度
ysh > $ rgb 100 100 100
RGB: R=100% G=100% B=100% led灯1000%的亮度
ysh > $ rgb 0 0 0
RGB: R=0% G=0% B=0% led灯全灭
ysh > $ led blue
LED: R=0% G=0% B=100% 打开蓝灯
ysh > $ led blue
LED: R=0% G=0% B=0% 关闭蓝灯
ysh > $ led red
LED: R=100% G=0% B=0% 打开红灯
ysh > $


附件下载
hello.zip
输出Hello, DigiKey Funpack 5-1
shell.zip
shell控制台使用命令控件帽LED
团队介绍
本人为个人创客爱好者
评论
0 / 100
查看更多
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2024 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号