本次移植一个串口shell,用于交互命令。串口shell目前有好几个开源的,像nr_micro_shell和letter_shell。本次选择nr_micro_shell移植。
下面首先下载nr_micro_shell源码,然后加入到工程内。
下面修改串口使用中断发送和接收。
生成工程后修改串口发送接收接口。使用fifo缓存方式发送接收数据。
代码如下:
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __DRV_UART_H
#define __DRV_UART_H
#ifdef __cplusplus
extern "C"
{
#endif
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "nr_micro_shell.h"
/* Private includes ----------------------------------------------------------*/
/* Exported types ------------------------------------------------------------*/
/* USER CODE BEGIN ET */
typedef struct fifo_buffer_t
{
volatile uint32_t read_i;
volatile uint32_t write_i;
uint8_t buff[512];
}fifo_buffer_t;
typedef struct shell_uart_buffer_t
{
fifo_buffer_t tx;
fifo_buffer_t rx;
volatile uint32_t tx_cpl : 1;
}shell_uart_buffer_t;
extern shell_uart_buffer_t g_shell_uart;
/* USER CODE END ET */
/* Exported constants --------------------------------------------------------*/
/* USER CODE BEGIN EC */
/* USER CODE END EC */
/* Exported macro ------------------------------------------------------------*/
/* USER CODE BEGIN EM */
/* USER CODE END EM */
/* Exported functions prototypes ---------------------------------------------*/
/* USER CODE BEGIN EFP */
void shell_usart_init(void);
int stdout_putchar (int ch);
void shell_usart_loop(void);
/* USER CODE END EFP */
/* Private defines -----------------------------------------------------------*/
/* USER CODE BEGIN Private defines */
/* USER CODE END Private defines */
#ifdef __cplusplus
}
#endif
#endif /* __DRV_UART_H */
/******************************************************************************
* Include files
******************************************************************************/
#include "main.h"
#include "drv_uart.h"
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,
};
//缓存发送
//发送FIFO缓存还有数据就继续发送
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();
}
}
int stdout_putchar (int ch)
{
uart_send_char(ch & 0xff);
return ch;
}
int fputc(int ch,FILE *f)
{
return stdout_putchar(ch);
}
void shell_usart_init(void)
{
shell_init(); //shell初始化
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)
{
shell(g_shell_uart.rx.buff[g_shell_uart.rx.read_i++]);
g_shell_uart.rx.read_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);//开始接收回应数据
}
}
然后在main中调用初始化和循环接收串口数据,然后解析命令。
添加头文件路径。
编译下载之后就可以实现串口命令解析执行了。
下面就是串口测试效果。
|