本帖最后由 WoodData 于 2024-5-22 15:00 编辑
上期已经搞定了APM32F411的串口通信,本期就移植一下串口shell,方便命令控制。目前shell比较好的有nr_micao_shell和letter shell这2种。其中nr_micro_shell比较简单,只是基本的shell命令。
而letter shell相对复杂一些,但是功能也更多。有用户权限控制和密码控制。
下面就开始我的移植过程。由于之前也移植到其他平台MCU,所以本次移植也非常简单了。
首先下载nr_micao_shell和letter shell的代码,添加到keil工程中。加入头文件路径。
然后就是实现串口发送接收。接收要使用中断模式,使用FIFO缓存接收,防止数据丢失。
串口初始化和发送接收:
void APM_TINY_COMInit(USART_T * com, uint32_t baud)
{
GPIO_Config_T GPIO_configStruct;
USART_Config_T usartConfigStruct;
GPIO_ConfigStructInit(&GPIO_configStruct);
if (USART1 == com)
{
/* Enable GPIO clock */
RCM_EnableAHB1PeriphClock(RCM_AHB1_PERIPH_GPIOA);
RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_USART1);
/* Connect PXx to USARTx_Tx */
GPIO_ConfigPinAF(GPIOA, GPIO_PIN_SOURCE_9, GPIO_AF_USART1);
/* Connect PXx to USARTx_Rx */
GPIO_ConfigPinAF(GPIOA, GPIO_PIN_SOURCE_10, GPIO_AF_USART1);
/* Configure USART Tx as alternate function push-pull */
GPIO_configStruct.mode = GPIO_MODE_AF;
GPIO_configStruct.pin = GPIO_PIN_9;
GPIO_configStruct.speed = GPIO_SPEED_50MHz;
GPIO_Config(GPIOA, &GPIO_configStruct);
/* Configure USART Rx as input floating */
GPIO_configStruct.mode = GPIO_MODE_AF;
GPIO_configStruct.pin = GPIO_PIN_10;
GPIO_Config(GPIOA, &GPIO_configStruct);
}
else if (USART2 == com)
{
RCM_EnableAHB1PeriphClock(RCM_AHB1_PERIPH_GPIOA);
RCM_EnableAPB1PeriphClock(RCM_APB1_PERIPH_USART2);
/* Connect PXx to USARTx_Tx */
GPIO_ConfigPinAF(GPIOA, GPIO_PIN_SOURCE_2, GPIO_AF_USART2);
/* Connect PXx to USARTx_Rx */
GPIO_ConfigPinAF(GPIOA, GPIO_PIN_SOURCE_3, GPIO_AF_USART2);
/* Configure USART Tx as alternate function push-pull */
GPIO_configStruct.mode = GPIO_MODE_AF;
GPIO_configStruct.pin = GPIO_PIN_2;
GPIO_configStruct.speed = GPIO_SPEED_50MHz;
GPIO_Config(GPIOA, &GPIO_configStruct);
/* Configure USART Rx as input floating */
GPIO_configStruct.mode = GPIO_MODE_AF;
GPIO_configStruct.pin = GPIO_PIN_3;
GPIO_Config(GPIOA, &GPIO_configStruct);
}
/* USART1 configuration */
usartConfigStruct.baudRate = baud;
usartConfigStruct.hardwareFlow = USART_HARDWARE_FLOW_NONE;
usartConfigStruct.mode = USART_MODE_TX_RX;
usartConfigStruct.parity = USART_PARITY_NONE;
usartConfigStruct.stopBits = USART_STOP_BIT_1;
usartConfigStruct.wordLength = USART_WORD_LEN_8B;
/* USART configuration */
USART_Config(com, &usartConfigStruct);
/* Enable USART1 RXBNEinterrput */
USART_EnableInterrupt(com,USART_INT_RXBNE);
USART_ClearStatusFlag(com,USART_FLAG_RXBNE);
NVIC_EnableIRQRequest(USART1_IRQn,1,0);
/* Enable USART */
USART_Enable(com);
}
void shell_usart_init(void)
{
APM_TINY_COMInit(USART1,115200);
#ifdef UART_SHELL
#if UART_SHELL == 1
userShellInit(); //LETTER_SHELL
#elif UART_SHELL == 2
shell_init(); //NR_MICRO_SHELL
#endif
#endif
}
fifo结构体定义
typedef struct fifo_buffer
{
volatile uint32_t read_i;
volatile uint32_t write_i;
uint8_t buff[128];
}fifo_buffer;
extern fifo_buffer shell_uart_rx;
接收数据处理:
void shell_usart_loop(void)
{
if(shell_uart_rx.read_i != shell_uart_rx.write_i)
{
#ifdef UART_SHELL
#if UART_SHELL == 1
shellHandler(&shell, shell_uart_rx.buff[shell_uart_rx.read_i++]); //letter shell
#elif UART_SHELL == 2
shell(shell_uart_rx.buff[shell_uart_rx.read_i++]);
#endif
#endif
shell_uart_rx.read_i &= 0x7f;
}
}
void USART1_IRQHandler(void)
{
uint32_t ch;
if(USART_ReadStatusFlag(USART1, USART_FLAG_RXBNE) == SET)
{
ch = USART_RxData(USART1);
if(((shell_uart_rx.write_i+1)&0x7f) != shell_uart_rx.read_i)
{
shell_uart_rx.buff[shell_uart_rx.write_i++] = ch & 0xff;
shell_uart_rx.write_i &= 0x7f;
}
USART_ClearStatusFlag(USART1,USART_FLAG_RXBNE);
}
}
在main中调用,2个shell是通过宏定义选择编译。
接下来是修改nr_micro_shell配置移植,主要修改nr_micro_shell_config.h配置。
关键的串口部分:
letter shell的修改主要在port部分,shell_port.c文件内
#include "shell_cfg_user.h"
#include "shell_uart.h"
#include "shell.h"
Shell shell;
char shellBuffer[512];
/**
* [url=home.php?mod=space&uid=247401]@brief[/url] 用户shell写
*
* @param data 数据
* @param len 数据长度
*
* [url=home.php?mod=space&uid=266161]@return[/url] short 实际写入的数据长度
*/
short userShellWrite(char *data, unsigned short len)
{
for(uint32_t i=0;i<len;i++)
USART_PutChar(data[i]);
return len;
}
/**
* [url=home.php?mod=space&uid=247401]@brief[/url] 用户shell读
*
* @param data 数据
* @param len 数据长度
*
* [url=home.php?mod=space&uid=266161]@return[/url] short 实际读取到
*/
short userShellRead(char *data, unsigned short len)
{
uint32_t rlen = 0;
for(uint32_t i=0;i<len;i++)
{
if(shell_uart_rx.read_i != shell_uart_rx.write_i)
{
data[rlen++] = shell_uart_rx.buff[shell_uart_rx.read_i++];
shell_uart_rx.read_i &= 0x7f;
}
}
return rlen;
}
/**
* @brief 用户shell上锁
*
* @param shell shell
*
* @return int 0
*/
int userShellLock(Shell *shell)
{
return 0;
}
/**
* @brief 用户shell解锁
*
* @param shell shell
*
* @return int 0
*/
int userShellUnlock(Shell *shell)
{
return 0;
}
/**
* @brief 用户shell初始化
*
*/
void userShellInit(void)
{
shell.write = userShellWrite;
shell.read = userShellRead;
// shell.lock = userShellLock;
// shell.unlock = userShellUnlock;
shellInit(&shell, shellBuffer, 512);
}
配置在shell_cfg_user.h文件内。
下面来编译烧录测试一下。首先选择nr_micro_shell。定义#define UART_SHELL 2
再来测试一下letter shell。定义#define UART_SHELL 1。然后编译下载测试。
代码工程:
|