通过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(); }
!!!注意想要使用中断接收,必须在最开始打开全局中断!!!

测试:


浙公网安备 33010602011771号