通过UART实现shell

通过UART实现shell

背景:

有些小型mcu芯片无法移植Linux,所以就不能通过shell指令执行各种操作,所以想通过mcu里面的uart驱动来模拟shell来达到方便调试单片机的效果。

实现:

My_Uart.h

 

#ifndef __MY_UART_H_
#define __MY_UART_H_
/*********************************************************************************************************************/
/*-----------------------------------------------------Includes------------------------------------------------------*/
/*********************************************************************************************************************/
#include "stm32g4xx_hal.h"
#include <inttypes.h>
/*********************************************************************************************************************/
/*------------------------------------------------------Macros-------------------------------------------------------*/
/*********************************************************************************************************************/
#define UART_DEFAULT_STRING                "\r\nroot@MCU:~# "
#define UAER1_NAME                        hlpuart1
#define UAER2_NAME                        huart1

#define UART_HAVE_DATA                    (1U)
#define UART_NO_DATA                    (0U)
#define MY_PRINT_MESSAGE_LENGTH_MAX        (128U)
#define LPUART_CMD_BUFER                (2U)
/*********************************************************************************************************************/
/*-------------------------------------------------Global variables--------------------------------------------------*/
/*********************************************************************************************************************/
extern uint8_t uart_rx_buffer[MY_PRINT_MESSAGE_LENGTH_MAX];
/*********************************************************************************************************************/
/*------------------------------------------------Function Prototypes------------------------------------------------*/
/*********************************************************************************************************************/
extern void My_UART_Init(void);
extern void UART1_Print(const char *p_frm, ...);
extern void UART2_Print(const char *p_frm, ...);
extern void Shell_Process_Special_Char(void);
extern void Shell_Main_Fun(void);

#endif

 

My_Uart.c

 

/*********************************************************************************************************************/
/*-----------------------------------------------------Includes------------------------------------------------------*/
/*********************************************************************************************************************/
#include "My_Uart.h"
#include "stdio.h"
#include "stdarg.h"
#include "string.h"
/*********************************************************************************************************************/
/*------------------------------------------------------Macros-------------------------------------------------------*/
/*********************************************************************************************************************/

/*********************************************************************************************************************/
/*-------------------------------------------------Global variables--------------------------------------------------*/
/*********************************************************************************************************************/
uint8_t uart_rx_byte = 0U;
uint8_t uart_special_rx_byte = 0U;
uint32_t uart_rx_buffer_indx = 0U;
uint8_t uart_rx_byte_buffer[2];
uint8_t uart_rx_buffer_tmp[MY_PRINT_MESSAGE_LENGTH_MAX] = {0U};     // 接收缓冲区
uint8_t uart_rx_buffer[MY_PRINT_MESSAGE_LENGTH_MAX] = {0U};         // 接收数据

uint32_t uart_rx_flag = 0U;
uint32_t uart_cmd_flag = 0U;

/*********************************************************************************************************************/
/*------------------------------------------------Function Prototypes------------------------------------------------*/
/*********************************************************************************************************************/
extern UART_HandleTypeDef UAER1_NAME;
extern UART_HandleTypeDef UAER2_NAME;

/*********************************************************************************************************************/
/*---------------------------------------------Function Implementations----------------------------------------------*/
/*********************************************************************************************************************/
void My_UART_Init_Fun(void)
{
    //启动中断接收
    HAL_UART_Receive_IT(&UAER1_NAME, uart_rx_byte_buffer, 1);
}

void UART_Shell_Init(void)
{
    UART1_Print(UART_DEFAULT_STRING);
}

//中断处理一个字节
void My_UART1_Push_A_Byte(UART_HandleTypeDef *huart)
{
    //读取一个字节数据
    uart_rx_byte = uart_rx_byte_buffer[0];
    if((uart_rx_byte >= 0x20U) && (uart_rx_byte <= 0x7EU))
    {
        if(uart_rx_buffer_indx + 1U < MY_PRINT_MESSAGE_LENGTH_MAX)
        {
            //发送一个字节数据
            huart->Instance->TDR = uart_rx_byte;
            uart_rx_buffer_tmp[uart_rx_buffer_indx] = uart_rx_byte;
            uart_rx_buffer_indx++;
        }
        else
        {}
    }
    else
    {
        uart_special_rx_byte = uart_rx_byte;
        uart_rx_flag = UART_HAVE_DATA;
    }
}

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
    if(huart->Instance == UAER1_NAME.Instance)
    {
        My_UART1_Push_A_Byte(huart);
        HAL_UART_Receive_IT(&UAER1_NAME, uart_rx_byte_buffer, 1);
    }
}

// 发送字符串
void UART1_Print(const char *p_frm, ...)
{
    char ubOutputBuf[MY_PRINT_MESSAGE_LENGTH_MAX] = {0};
    uint16_t PrintLength = 0;

    /* Print the format string to the buffer. */
    va_list p_arg;
    va_start(p_arg, p_frm);
    vsnprintf(ubOutputBuf, sizeof(ubOutputBuf), p_frm, p_arg);
    va_end(p_arg);

    /* Calculate the length of the string. */
    PrintLength = (uint16_t)strlen(ubOutputBuf);
    if(PrintLength > MY_PRINT_MESSAGE_LENGTH_MAX)
    {
        PrintLength = MY_PRINT_MESSAGE_LENGTH_MAX;
    }
    HAL_UART_Transmit(&UAER1_NAME, (uint8_t *)ubOutputBuf, PrintLength, HAL_MAX_DELAY);
}

// 发送字符串
void UART2_Print(const char *p_frm, ...)
{
    char ubOutputBuf[MY_PRINT_MESSAGE_LENGTH_MAX] = {0};
    uint16_t PrintLength = 0;

    /* Print the format string to the buffer. */
    va_list p_arg;
    va_start(p_arg, p_frm);
    vsnprintf(ubOutputBuf, sizeof(ubOutputBuf), p_frm, p_arg);
    va_end(p_arg);

    /* Calculate the length of the string. */
    PrintLength = (uint16_t)strlen(ubOutputBuf);
    if(PrintLength > MY_PRINT_MESSAGE_LENGTH_MAX)
    {
        PrintLength = MY_PRINT_MESSAGE_LENGTH_MAX;
    }
    HAL_UART_Transmit(&UAER2_NAME, (uint8_t *)ubOutputBuf, PrintLength, HAL_MAX_DELAY);
}

//5ms周期调用处理一些特殊字符和合成最终指令
void Shell_Process_Special_Char(void)
{
    if(UART_HAVE_DATA == uart_rx_flag)
    {
        switch(uart_special_rx_byte)
        {
            /* Back */
            case 0x08U:
            case 0x7fU:
            {
                if(0U != uart_rx_buffer_indx)
                {
                    UART1_Print("\b \b");    // 光标左移 用空格覆盖原字符 再次光标左移
                    uart_rx_buffer_indx--;
                    uart_rx_buffer_tmp[uart_rx_buffer_indx] = '\0';
                    uart_special_rx_byte = 0U;
                }
                else
                {
                    uart_special_rx_byte = 0U;
                    uart_rx_flag = UART_NO_DATA;
                }
                break;
            }
            /* Enter */
            case 0x0dU:
            {
                if(uart_rx_buffer_indx > 0U)
                {
                    memcpy(uart_rx_buffer, uart_rx_buffer_tmp, uart_rx_buffer_indx);
                    memset(uart_rx_buffer_tmp,0,uart_rx_buffer_indx);
                    uart_rx_buffer_indx = 0U;
                    uart_cmd_flag = 1U;
                }
                else
                {
                    UART1_Print(UART_DEFAULT_STRING);
                }
                uart_special_rx_byte = 0U;
                uart_rx_flag = UART_NO_DATA;
                break;
            }
            default:
            {
                break;
            }
        }
    }
}

//20ms调用 按照命令进行对应操作
void Shell_Main_Fun(void)
{
     if(1 == uart_cmd_flag)
     {
        if(strcmp((const char *)uart_rx_buffer, "led1 open") == 0)
        {
            HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,GPIO_PIN_RESET);
            UART1_Print("\r\nSuccess!!!"UART_DEFAULT_STRING);
            UART2_Print("Led1 is open!\r\n");
        }
        else if(strcmp((const char *)uart_rx_buffer, "led1 close") == 0)
        {
            HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,GPIO_PIN_SET);
            UART1_Print("\r\nSuccess!!!"UART_DEFAULT_STRING);
            UART2_Print("Led1 is close!\r\n");
        }
        else
        {
            UART1_Print("\r\nUnknown command: %s"UART_DEFAULT_STRING, uart_rx_buffer);
        }
        memset(uart_rx_buffer,0,sizeof(uart_rx_buffer));
        uart_cmd_flag = 0;
     }
}

void My_UART_Init(void)
{
    My_UART_Init_Fun();
    UART_Shell_Init();
}

 

!!!注意想要使用中断接收,必须在最开始打开全局中断!!!

 

 

测试:

image

 

posted @ 2025-07-17 12:44  西北小蚂蚁  阅读(40)  评论(0)    收藏  举报