本期主要分享一下如何移植串口shell,方便用于命令控制。目前shell比较好的有nr_micao_shell和letter shell这2种。其中nr_micro_shell比较简单,只是基本的shell命令。而letter shell相对复杂一些,但是功能也更多。有用户权限控制和密码控制。一般我们简单点用nr_micro_shell足够了。
下面就开始我的移植过程。由于之前也移植到其他平台MCU,所以本次移植非常快速就成功了。
首先下载nr_micao_shell和letter shell的代码,添加到keil工程中。加入头文件路径。
nr_micro_shell移植:
然后设置头文件路径:
下面是串口通信设置,这里为了使用串口数据不丢失,使用了中断模式发送和接收数据。
先定义一个FIFO结构用于发送和接收数据缓存。
接着是发送和中断接收处理接口:
static uint8_t uart_recv_buff[4];
static uint8_t uart_send_buff[128];
shell_uart_buffer_t g_shell_uart=
{
.tx.read_i = 0,
.tx.write_i = 0,
.rx.read_i = 0,
.rx.write_i = 0,
.tx_cpl = 0,
};
//
static void uart_get_data_send(void)
{
uint32_t i;
//
for(i=0;i<128;i++)
{
if(g_shell_uart.tx.read_i != g_shell_uart.tx.write_i)
{
uart_send_buff[i] = g_shell_uart.tx.buff[g_shell_uart.tx.read_i++];
g_shell_uart.tx.read_i &= 0x1ff; //256Byte
}else break;
}
if(i)
{
g_shell_uart.tx_cpl = 1;
HAL_UART_Transmit_IT(&huart2,uart_send_buff,i);
}
}
static void uart_send_char(uint8_t ch)
{
//
if(((g_shell_uart.tx.write_i+1)&0x1ff) != g_shell_uart.tx.read_i)
{
g_shell_uart.tx.buff[g_shell_uart.tx.write_i++] = ch;
g_shell_uart.tx.write_i &= 0x1ff;//256Byte
}
if((g_shell_uart.tx_cpl == 0))
{
uart_get_data_send();
}
}
//////////////////////////////////////////////////////////////////////////////
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance == USART2) //shell
{
//
if(((g_shell_uart.rx.write_i+1)&0x1ff) != g_shell_uart.rx.read_i)
{
g_shell_uart.rx.buff[g_shell_uart.rx.write_i++] = uart_recv_buff[0] & 0xff;
g_shell_uart.rx.write_i &= 0x1ff;//256Byte
}
HAL_UART_Receive_IT(huart,uart_recv_buff,1);//
}
}
//
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance == USART2) //shell
{
g_shell_uart.tx_cpl = 0;
uart_get_data_send();
}
}
//
void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance == USART2) //shell
{
HAL_UART_Receive_IT(huart,uart_recv_buff,1);//
}
}
接着是发送接收字节接口:
int stdout_putchar (int ch)
{
uart_send_char(ch & 0xff);
return ch;
}
int fputc(int ch,FILE *f)
{
return stdout_putchar(ch);
}
void USART_PutChar(uint8_t ch)
{
stdout_putchar(ch);
}
uint8_t USART_GetChar(void)
{
uint8_t ch;
while(g_shell_uart.rx.read_i == g_shell_uart.rx.write_i);
ch = g_shell_uart.rx.buff[g_shell_uart.rx.read_i++];
g_shell_uart.rx.read_i &= 0x1ff; //256Byte
return ch;
}
下面是初始化和循环调用接口。包含了shell初始化和shell处理数据循环。
void shell_usart_init(void)
{
#ifdef UART_SHELL
#if UART_SHELL == 1
userShellInit(); //LETTER_SHELL
#elif UART_SHELL == 2
shell_init(); //NR_MICRO_SHELL
#endif
#endif
HAL_UART_Receive_IT(&huart2,uart_recv_buff,1);//
}
void shell_usart_loop(void)
{
//
if(g_shell_uart.rx.read_i != g_shell_uart.rx.write_i)
{
#ifdef UART_SHELL
#if UART_SHELL == 1
shellHandler(&shell, g_shell_uart.rx.buff[g_shell_uart.rx.read_i++]); //letter shell
#elif UART_SHELL == 2
shell(g_shell_uart.rx.buff[g_shell_uart.rx.read_i++]);
#endif
#endif
g_shell_uart.rx.read_i &= 0x1ff; //256Byte
}
if(g_shell_uart.tx_cpl == 0)
{
uart_get_data_send();
}
}
nr_micro_shell的移植配置关键在如下地方:
然后就是初始化和循环处理输入数据:
shell定义命令的方式如下:
编译下载之后,测试效果如下:
letter_shell移植:
移植接口在如下框起来几个文件。其中shell_port.c是读写串口数据接口,shell_cfg_user.h是功能配置接口。
然后也是shell初始化调用和数据处理循环:
shell命令格式配置和用户添加配置例子如下。
下面编译下载测试效果:
切换用户后可以看到不同用户有权限可执行的命令不同。
# V1 P9 O) R. q* s" s. f2 N! G
阅读权限: 10