单片机 串口控制台 ,类似shell cmd命令解析实现

基于串口的 调试方法  , 调试非常方便

功能:

1. 串口调试输入

2.命令解析, 空格区分参数

3.支持del

 

使用方法

一、如果使用工程中的Init.d框架,直接使用.c .h文件即可。 调试文件
 

//cmdtp 当前命令句柄

//flag  run_command中传入

//argc  参数数量

//*argv[] 参数

int do_ls(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])

{

...

}

//name  名称, 也是串口输入的第一个参数, 命令名称
//maxargs 允许输入的最大参数数量
//rep 是否允许自动重放
//cmd 命令执行的函数
//usage 使用说明- 简单描述
//help 命令对应的帮助说明
SHELL_CMD_REG(name, maxargs, rep, cmd, usage, help)

 

 

IAR编译器需要在.icf文件中添加

place in  ROM_region{ readonly section _shell_cmd };

GCC为ld文件, KEIL 好久没用,忘记 了。

示例

#include "shell_cmd.h"
#include "log.h"
#include "stm32l4xx.h"

#define TAG "SHELL"

int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{

    if ((strlen(argv[1]) > 0) && (argc == 2))
    {
        if (strncmp(argv[1], "soft", strlen("soft")) == 0)
        {
            NVIC_SystemReset();
        }
    }

    return 0;
}

SHELL_CMD_REG(
    reset, 4, 1, do_reset,
    "reset\t-reset system\n",
    "\treset system\n\n\
reset soft\treset system use soft\n\
reset wwdg\treset system use wdg , stop feed wwdg\n");

源码

shell_cmd.c

#include <stdio.h>
#include <string.h>
#include <shell_cmd.h>

#define TAG "SHELL"

static cmd_tbl_t *__shell_cmd_start = __section_begin("_shell_cmd");
static cmd_tbl_t *__shell_cmd_end = __section_end("_shell_cmd");

static char *delete_char(char *buffer, char *p, int *colp, int *np, int plen);

static char console_buffer[CFG_CBSIZE];
static char erase_seq[] = "\b \b";
static char tab_seq[] = "        ";
static int ctrlc_was_pressed = 0;

static xTaskHandle shellcmd_handle;
static DEV_HAND fd;

/*
* Prompt for input and read a line.
* If CONFIG_BOOT_RETRY_TIME is defined and retry_time >= 0,
* time out when time goes past endtime (timebase time in ticks).
* Return: number of read characters
* -1 if break
* -2 if timed out
*/
static int read_line(const char *const prompt)
{
    char *p = console_buffer;
    int n = 0;    /* buffer index */
    int plen = 0; /* prompt length */
    int col;      /* output column cnt */
    char c;

    /* print prompt */
    if (prompt)
    {
        plen = strlen(prompt);
        LOG("%s", prompt);
    }
    col = plen;

    for (;;)
    {
        dev_read(fd, (uint8_t *)&c, 1);
        //sysclock_resurm();
        /*
        * Special character handling
        */
        switch (c)
        {
        case '\r': /* Enter */
        case '\n':
            *p = '\0';
            LOG("\r\n");
            return (p - console_buffer);

        case '\0': /* nul */
            continue;

        case 0x03:                    /* ^C - break */
            console_buffer[0] = '\0'; /* discard input */
            return (-1);

        case 0x15: /* ^U - erase line */
            while (col > plen)
            {
                LOG("%s", erase_seq);
                --col;
            }
            p = console_buffer;
            n = 0;
            continue;

        case 0x17: /* ^W - erase word */
            p = delete_char(console_buffer, p, &col, &n, plen);
            while ((n > 0) && (*p != ' '))
            {
                p = delete_char(console_buffer, p, &col, &n, plen);
            }
            continue;

        case 0x08: /* ^H - backspace */
        case 0x7F: /* DEL - backspace */
            p = delete_char(console_buffer, p, &col, &n, plen);
            continue;

        default:
            /*
            * Must be a normal character then
            */
            if (n < CFG_CBSIZE - 2)
            {
                if (c == '\t')
                { /* expand TABs */
                    LOG("%s", tab_seq + (col & 07));
                    col += 8 - (col & 07);
                }
                else
                {
                    ++col; /* echo input */
                    putchar(c);
                }
                *p++ = c;
                ++n;
            }
            else
            { /* Buffer full */
                putchar('\a');
            }
        }
    }
}

static char *delete_char(char *buffer, char *p, int *colp, int *np, int plen)
{
    char *s;

    if (*np == 0)
    {
        return (p);
    }

    if (*(--p) == '\t')
    { /* will retype the whole line	*/
        while (*colp > plen)
        {
            LOG("%s", erase_seq);
            (*colp)--;
        }
        for (s = buffer; s < p; ++s)
        {
            if (*s == '\t')
            {
                LOG("%s", tab_seq + ((*colp) & 07));
                *colp += 8 - ((*colp) & 07);
            }
            else
            {
                ++(*colp);
                putchar(*s);
            }
        }
    }
    else
    {
        LOG("%s", erase_seq);
        (*colp)--;
    }
    (*np)--;
    return (p);
}

static int had_ctrlc(void)
{
    return ctrlc_was_pressed;
}

static void clear_ctrlc(void)
{
    ctrlc_was_pressed = 0;
}

/****************************************************************************/
static void process_macros(const char *input, char *output)
{
    char c, prev;

    int inputcnt = strlen(input);
    int outputcnt = CFG_CBSIZE;
    int state = 0; /* 0 = waiting for '$'  */

    /* 1 = waiting for '(' or '{' */
    /* 2 = waiting for ')' or '}' */
    /* 3 = waiting for '''  */

    prev = '\0'; /* previous character   */

    while (inputcnt && outputcnt)
    {
        c = *input++;
        inputcnt--;

        if (state != 3)
        {
            /* remove one level of escape characters */
            if ((c == '\\') && (prev != '\\'))
            {
                if (inputcnt-- == 0)
                    break;
                prev = c;
                c = *input++;
            }
        }

        switch (state)
        {
        case 0: /* Waiting for (unescaped) $    */
            if ((c == '\'') && (prev != '\\'))
            {
                state = 3;
                break;
            }
            if ((c == '$') && (prev != '\\'))
            {
                state++;
            }
            else
            {
                *(output++) = c;
                outputcnt--;
            }
            break;
        case 1: /* Waiting for (        */
            if (c == '(' || c == '{')
            {
                state++;
            }
            else
            {
                state = 0;
                *(output++) = '$';
                outputcnt--;

                if (outputcnt)
                {
                    *(output++) = c;
                    outputcnt--;
                }
            }
            break;
        case 2: /* Waiting for )        */
            if (c == ')' || c == '}')
            {

                char *envval;

                envval = NULL;

                /* Copy into the line if it exists */
                if (envval != NULL)
                    while ((*envval) && outputcnt)
                    {
                        *(output++) = *(envval++);
                        outputcnt--;
                    }
                /* Look for another '$' */
                state = 0;
            }
            break;
        case 3: /* Waiting for '        */
            if ((c == '\'') && (prev != '\\'))
            {
                state = 0;
            }
            else
            {
                *(output++) = c;
                outputcnt--;
            }
            break;
        }
        prev = c;
    }

    if (outputcnt)
        *output = 0;
}
/****************************************************************************/

static int parse_line(char *line, char **argv)
{
    int nargs = 0;

    while (nargs < CFG_MAXARGS)
    {

        /* skip any white space */
        while ((*line == ' ') || (*line == '\t'))
        {
            ++line;
        }

        if (*line == '\0')
        { /* end of line, no more args	*/
            argv[nargs] = NULL;
            return (nargs);
        }

        argv[nargs++] = line; /* begin of argument string	*/

        /* find end of string */
        while (*line && (*line != ' ') && (*line != '\t'))
        {
            ++line;
        }

        if (*line == '\0')
        { /* end of line, no more args	*/
            argv[nargs] = NULL;
            return (nargs);
        }

        *line++ = '\0'; /* terminate current arg	 */
    }

    LOGD(TAG, "** Too many args (max. %d) **\n", CFG_MAXARGS);
    return (nargs);
}

/***************************************************************************
 * find command table entry for a command
 */

static cmd_tbl_t *find_cmd(const char *cmd)
{
    cmd_tbl_t *cmdtp;
    cmd_tbl_t *cmdtp_temp = __shell_cmd_start;
    const char *p;
    int len;
    int n_found = 0;

    /*
     * Some commands allow length modifiers (like "cp.b");
     * compare command name only until first dot.
     */
    len = ((p = strchr(cmd, '.')) == NULL) ? strlen(cmd) : (p - cmd);

    for (cmdtp = __shell_cmd_start;
         cmdtp != __shell_cmd_end;
         cmdtp++)
    {
        if (strncmp(cmd, cmdtp->name, len) == 0)
        {
            if (len == strlen(cmdtp->name))
                return cmdtp; /* full match */

            cmdtp_temp = cmdtp; /* abbreviated command ? */
            n_found++;
        }
    }
    if (n_found == 1)
    { /* exactly one match */
        return cmdtp_temp;
    }

    return NULL; /* not found or ambiguous command */
}

/****************************************************************************
 * returns:
 *	1  - command executed, repeatable
 *	0  - command executed but not repeatable, interrupted commands are
 *	     always considered not repeatable
 *	-1 - not executed (unrecognized, bootd recursion or too many args)
 *           (If cmd is NULL or "" or longer than CFG_CBSIZE-1 it is
 *           considered unrecognized)
 *
 * WARNING:
 *
 * We must create a temporary copy of the command since the command we get
 * may be the result from getenv(), which returns a pointer directly to
 * the environment data, which may change magicly when the command we run
 * creates or modifies environment variables (like "bootp" does).
 */
//char *argv[CFG_MAXARGS + 1];

int run_command(const char *cmd, int flag)
{
    cmd_tbl_t *cmdtp;
    char *token; /* start of token in cmdbuf	*/
    char *sep;   /* end of token (separator) in cmdbuf */
    char *str = NULL;
    char **argv;
    int argc, inquotes;
    int repeatable = 1;
    int rc = 0;

    char *cmdbuf = NULL;
    char *finaltoken = NULL;

    if ((cmdbuf = (char *)malloc(CFG_CBSIZE)) == NULL)
    {
        return -1;
    }

    if ((finaltoken = (char *)malloc(CFG_CBSIZE)) == NULL)
    {
        free(cmdbuf);
        return -1;
    }

    if ((argv = (char **)malloc(sizeof(char *) * (CFG_MAXARGS + 1))) == NULL)
    {

        LOGE(TAG, "%s:%d malloc err\n", __func__, __LINE__);
        free(cmdbuf);
        free(finaltoken);
        return -1;
    }

    //LOGD(TAG, "argv address = %x\n", (uint32_t)argv);
    //LOGD(TAG, "cmdbuf address = %x\n", (uint32_t)cmdbuf);
    //LOGD(TAG, "finaltoken address = %x\n", (uint32_t)finaltoken);

    memset(cmdbuf, 0, CFG_CBSIZE);
    memset(finaltoken, 0, CFG_CBSIZE);

    str = cmdbuf;

    clear_ctrlc(); /* forget any previous Control C */

    if (!cmd || !*cmd)
    {
        goto err_run; /* empty command */
    }

    if (strlen(cmd) >= CFG_CBSIZE)
    {
        LOG("## Command too long!\n");
        goto err_run;
    }

    strcpy(cmdbuf, cmd);

    /* Process separators and check for invalid
     * repeatable commands
     */
    while (*str)
    {

        /*
         * Find separator, or string end
         * Allow simple escape of ';' by writing "\;"
         */
        for (inquotes = 0, sep = str; *sep; sep++)
        {
            if ((*sep == '\'') &&
                (*(sep - 1) != '\\'))
                inquotes = !inquotes;

            if (!inquotes &&
                (*sep == ';') &&      /* separator		*/
                (sep != str) &&       /* past string start	*/
                (*(sep - 1) != '\\')) /* and NOT escaped	*/
                break;
        }

        /*
         * Limit the token to data between separators
         */
        token = str;
        if (*sep)
        {
            str = sep + 1; /* start of command for next pass */
            *sep = '\0';
        }
        else
            str = sep; /* no more commands for next pass */

        /* find macros in this token and replace them */
        process_macros(token, finaltoken);

        /* Extract arguments */
        if ((argc = parse_line(finaltoken, argv)) == 0)
        {
            rc = -1; /* no command at all */
            continue;
        }

        /* Look up command in command table */
        if ((cmdtp = find_cmd(argv[0])) == NULL)
        {
            LOGD(TAG, "Unknown command '%s' - try 'help'\n", argv[0]);
            rc = -1; /* give up after bad command */
            continue;
        }

        /* found - check max args */
        if (argc > cmdtp->maxargs)
        {
            LOGD(TAG, "Usage:\n%s\n", cmdtp->usage);
            rc = -1;
            continue;
        }

        /* OK - call function to do the command */
        if ((cmdtp->cmd)(cmdtp, flag, argc, argv) != 0)
        {
            rc = -1;
        }

        repeatable &= cmdtp->repeatable;

        /* Did the user stop this? */
        if (had_ctrlc())
            goto err_run; /* if stopped then not repeatable */
    }

err_run:
    free(cmdbuf);
    free(finaltoken);
    free(argv);

    return rc ? rc : repeatable;
}

/*
 * Use LOG() instead of LOG() to avoid LOG buffer overflow
 * for long help messages
 */
//cmd_tbl_t *cmd_array[30];

int do_help(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
    int i;
    int rcode = 0;

    if (argc == 1)
    { /*show list of commands */

        cmd_tbl_t **cmd_array = NULL;
        int cmd_items = __shell_cmd_end -
                        __shell_cmd_start; /* pointer arith! */
        int i, j, swaps;

        if ((cmd_array = (cmd_tbl_t **)malloc(sizeof(cmd_tbl_t *) * cmd_items)) == NULL)
        {
            LOGE(TAG, "%s:%d malloc err\n", __func__, __LINE__);
            return -1;
        }

        if (cmd_items > CFG_MAXCMDS)
        {
            LOGE(TAG, "cmd_array define less , cmd_items=%d.\n", cmd_items);
        }
        /* Make array of commands from .uboot_cmd section */
        cmdtp = __shell_cmd_start;
        for (i = 0; i < cmd_items; i++)
        {
            cmd_array[i] = cmdtp++;
        }

        /* Sort command list (trivial bubble sort) */
        for (i = cmd_items - 1; i > 0; --i)
        {
            swaps = 0;
            for (j = 0; j < i; ++j)
            {
                if (strcmp(cmd_array[j]->name,
                           cmd_array[j + 1]->name) > 0)
                {
                    cmd_tbl_t *tmp;
                    tmp = cmd_array[j];
                    cmd_array[j] = cmd_array[j + 1];
                    cmd_array[j + 1] = tmp;
                    ++swaps;
                }
            }
            if (!swaps)
                break;
        }

        /* print short help (usage) */
        for (i = 0; i < cmd_items; i++)
        {
            const char *usage = cmd_array[i]->usage;

#if 0
            /* allow user abort */
            if (ctrlc ())
                return 1;
#endif
            if (usage == NULL)
                continue;
            LOG("%s", usage);
        }
        //free(*cmd_array);
        free(cmd_array);
        return 0;
    }
    /*
     * command help (long version)
     */
    for (i = 1; i < argc; ++i)
    {
        if ((cmdtp = find_cmd(argv[i])) != NULL)
        {
            /* found - print (long) help info */
            LOG("%s", cmdtp->name);
            putchar(' ');
            if (cmdtp->help)
            {
                LOG("%s", cmdtp->help);
            }
            else
            {
                LOG("- No help available.\n");
                rcode = 1;
            }
            putchar('\n');
        }
        else
        {
            LOGD(TAG, "Unknown command '%s' - try 'help'"
                      " without arguments for list of all"
                      " known commands\n\n",
                 argv[i]);
            rcode = 1;
        }
    }
    return rcode;
}

SHELL_CMD_REG(
    help, CFG_MAXARGS, 1, do_help,
    "help    - print online help\n",
    "[command ...]\n"
    "    - show help information (for 'command')\n"
    "'help' prints online help for the monitor commands.\n\n"
    "Without arguments, it prints a short usage message for all commands.\n\n"
    "To get detailed help information for specific commands you can type\n"
    "'help' with one or more command names as arguments.\n");

int do_clear(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
    LOG(SELL_CLEAR);
    return 0;
}
SHELL_CMD_REG(
    clear, 1, 1, do_clear,
    "clear\tClear screen\n",
    "Clear screen\n");

unsigned portBASE_TYPE uxHighWaterMark;

//286
//359 TASK while 1 no things

static void shell_cmd_task(void const *pvParameters)
{
    char len;

    configASSERT(((unsigned long)pvParameters) == 0);

    fd = dev_open("serial1", 0);

    if (fd == NULL)
    {
        LOGE(TAG, "open serial1 fail ,delet task.\n");
        osThreadTerminate(shellcmd_handle);
    }

    while (1)
    {

        len = read_line(CFG_PROMPT);
        if (len > 0)
        {
            run_command(console_buffer, 0);
        }
        uxHighWaterMark = uxTaskGetStackHighWaterMark(shellcmd_handle);
    }
}

int shell_cmd(void)
{
    LOG_ADD(TAG, _LOG_DEBUG);
    osThreadDef(shell, shell_cmd_task, osPriorityLow, 0, configMINIMAL_STACK_SIZE * 6);
    shellcmd_handle = osThreadCreate(osThread(shell), NULL);
    configASSERT(shellcmd_handle);

    return 0;
}

int shell_cmd_resume(void)
{
    dev_ioctl(fd, NULL, 0, IOCTL_FLAG_RESUME);

    return 0;
}

int shell_cmd_suspend(void)
{

    dev_ioctl(fd, NULL, 0, IOCTL_FLAG_SUSPEND);

    return 0;
}

task_init(shell_cmd);
resume_register(shell_cmd_resume);
suspend_register(shell_cmd_suspend);

shell_cmd.h

#ifndef __SHELL_CMD_H
#define __SHELL_CMD_H

#ifdef __cplusplus
extern "C"
{
#endif

#include "cmsis_os.h"
#include "log.h"
#include "miscdevice.h"
#include "init_d.h"

#define CFG_PROMPT "> " /* Monitor Command Prompt	*/
#define CFG_CBSIZE 64   /* Console I/O Buffer Size	*/
#define CFG_MAXCMDS 30  /* max command */
#define CFG_MAXARGS 16  /* max number of command args	*/

#define SELL_CLEAR "\033[2J\033[H"

#pragma section = "_shell_cmd"

#define SHELL @ "_shell_cmd"

    struct cmd_tbl_s
    {
        char *name;     /* Command Name			*/
        int maxargs;    /* maximum number of arguments	*/
        int repeatable; /* autorepeat allowed?		*/
        /* Implementation function	*/
        int (*cmd)(struct cmd_tbl_s *, int, int, char *[]);
        char *usage; /* Usage message	(short)	*/
        char *help;  /* Help  message	(long)	*/
    };

    typedef struct cmd_tbl_s cmd_tbl_t;

#define SHELL_CMD_REG(name, maxargs, rep, cmd, usage, help) \
    __root cmd_tbl_t __shell_cmd_##name SHELL = {#name, maxargs, rep, cmd, usage, help}

#ifdef __cplusplus
}
#endif

#endif /* __SHELL_CMD_H */

 

工程地址, github:https://github.com/KarmaStone/stp_coms.git

  • 3
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
串口命令解析 CLI(Command Line Interface),是一种用于与单片机进行交互的方式。在单片机中,我们可以通过串口通信模块(例如UART)与外部设备(如计算机、手机等)进行通信。通过串口命令解析 CLI,我们可以实现在外部设备上向单片机发送命令并获取相应的结果。 串口命令解析 CLI 的工作流程通常包括以下几个步骤: 1. 初始化串口:首先需要配置单片机串口通信模块,包括波特率、数据位、停止位等参数。 2. 监听串口接收:接下来开始监听串口接收,等待外部设备发送指令。 3. 解析命令:当单片机接收到数据后,需要进行数据解析解析方式可以根据需求而定,常见的解析方式包括按照固定长度截取指令、通过特定标识符(如换行符)来分割指令等。 4. 执行命令解析出指令后,单片机需要执行相应的命令。这可能涉及到一系列的操作,如读取传感器数据、控制外设等。 5. 返回结果:执行完命令后,单片机需要将执行结果返回给外部设备。可以通过串口将结果发送回去。 需要注意的是,在开发串口命令解析 CLI 时,还需要考虑错误处理和异常情况。例如,如果接收到的命令无法解析或执行出错,单片机应该发送相应的错误信息给外部设备。 总之,串口命令解析 CLI 是一种实现单片机与外部设备交互的方式,将命令发送给单片机并获取执行结果。通过合理设计解析和执行流程,可以实现功能丰富、稳定可靠的交互系统。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值