软件资源如下:
以下为函数初始化配置及相关全局变量定义内容,代码如下:typedef struct
{
char *command; // shell命令提示符
char buffer[SHELL_COMMAND_MAX_LENGTH]; // shell命令缓冲buffer
unsigned short length; // shell命令长度大小
unsigned short cursor; // shell光标位置偏移
char *param[SHELL_PARAMETER_MAX_NUMBER]; // shell参数变量
char history[SHELL_HISTORY_MAX_NUMBER][SHELL_COMMAND_MAX_LENGTH]; // 历史记录区域
unsigned short historyCount; // 历史记录数量
short historyFlag; // 当前记录偏移位置
short historyOffset; // 历史记录偏移大小
SHELL_CommandTypeDef *commandBase; // 命令表基地址
unsigned short commandNumber; // 命令数量
int keyFuncBase; // 按键响应表基地址
unsigned short keyFuncNumber; // 按键响应数量
SHELL_InputMode status; // shell输入状态
unsigned char isActive; //是不是当前激活的shell
shellRead read; // shell读函数接口
shellWrite write; // shell写函数接口
}SHELL_TypeDef;
如上所示,为对象的定义接口,具体说明看注释,我们需要关注的是shell的读写接口。void shellInit(SHELL_TypeDef *shell)
{
shellDisplay(shell, "\r\n\r\n");
shellDisplay(shell, "+=========================================================+\r\n");
shellDisplay(shell, "| (C) COPYRIGHT 2019 MindMotion |\r\n");
shellDisplay(shell, "| shell v"SHELL_VERSION" |\r\n");
shellDisplay(shell, "| Build: "__DATE__" "__TIME__" |\r\n");
shellDisplay(shell, "+=========================================================+\r\n");
shell->length = 0;
shell->cursor = 0;
shell->historyCount = 0;
shell->historyFlag = 0;
shell->historyOffset = 0;
shell->status = SHELL_IN_NORMAL;
shell->command = SHELL_DEFAULT_COMMAND;
shell->isActive = 0;
shellAdd(shell);
shellDisplay(shell, shell->command);
#if defined(__CC_ARM) || (defined(__ARMCC_VERSION) && __ARMCC_VERSION >= 6000000)
extern const unsigned int shellCommand$$Base;
extern const unsigned int shellCommand$$Limit;
extern const unsigned int shellVariable$$Base;
extern const unsigned int shellVariable$$Limit;
shell->commandBase = (SHELL_CommandTypeDef *)(&shellCommand$$Base);
shell->commandNumber = ((unsigned int)(&shellCommand$$Limit)
- (unsigned int)(&shellCommand$$Base))
/ sizeof(SHELL_CommandTypeDef);
#endif
}
上述代码void shellInit(SHELL_TypeDef *shell)用来初始化shell对象,首先打印shell界面,然后对shell对象进行初始化为默认状态,然后给shell命令表指定区域和数量。 对于shell输入处理,需要分两种类型判断,一个是正常的字母按键,如A、B、C、D等,一个是功能按键,如方向键等。下面给出两种类型处理代码。// shell ansi按键处理函数
void shellAnsi(SHELL_TypeDef *shell, char data)
{
switch ((unsigned char)(shell->status))
{
case SHELL_ANSI_CSI:
switch (data)
{
case 0x41: // 键盘方向键向上键
shellHistory(shell, 0);
break;
case 0x42: // 键盘方向键向下键
shellHistory(shell, 1);
break;
case 0x43: // 键盘方向键向右键
if (shell->cursor < shell->length)
{
shellDisplayByte(shell, shell->buffer[shell->cursor]);
shell->cursor++;
}
break;
case 0x44: // 键盘方向键向左键
if (shell->cursor > 0)
{
shellDisplayByte(shell, '\b');
shell->cursor--;
}
break;
default:
break;
}
shell->status = SHELL_IN_NORMAL;
break;
case SHELL_ANSI_ESC:
if (data == 0x5B)
{
shell->status = SHELL_ANSI_CSI;
}
else
{
shell->status = SHELL_IN_NORMAL;
}
break;
default:
break;
}
}
上述void shellAnsi(SHELL_TypeDef *shell, char data)函数为shellAnsi处理。//shell正常按键处理函数
static void shellNormal(SHELL_TypeDef *shell, char data)
{
if (data == 0)
{
return;
}
if (shell->length < SHELL_COMMAND_MAX_LENGTH - 1)
{
if (shell->length == shell->cursor)
{
shell->buffer[shell->length++] = data;
shell->cursor++;
shellDisplayByte(shell, data);
}
else
{
for (short i = shell->length - shell->cursor; i > 0; i--)
{
shell->buffer[shell->cursor + i] = shell->buffer[shell->cursor + i - 1];
}
shell->buffer[shell->cursor++] = data;
shell->buffer[++shell->length] = 0;
for (short i = shell->cursor - 1; i < shell->length; i++)
{
shellDisplayByte(shell, shell->buffer[i]);
}
for (short i = shell->length - shell->cursor; i > 0; i--)
{
shellDisplayByte(shell, '\b');
}
}
}
else
{
shellDisplay(shell, "\r\nWarnig: Command is too long\r\n");
shellDisplay(shell, shell->command);
shellDisplay(shell, shell->buffer);
shell->cursor = shell->length;
}
}
基于上述的两个类型代码,即可封装得到shell的处理代码,如下所示://shell处理
void shellHandler(SHELL_TypeDef *shell, char data) //shell处理函数
{
if (shell->status == SHELL_IN_NORMAL) //shell工作在正常模式
{
char keyDefFind = 0;
SHELL_KeyFunctionDef *base = (SHELL_KeyFunctionDef *)shell->keyFuncBase;
for (short i = 0; i < shell->keyFuncNumber; i++)
{
if (base[i].keyCode == data) {
if (base[i].keyFunction) {
base[i].keyFunction(shell);
}
keyDefFind = 1;
}
}
if (keyDefFind == 0)
{
for (short i = 0;
i < sizeof(shellDefaultKeyFunctionList) / sizeof(SHELL_KeyFunctionDef);
i++)
{
if (shellDefaultKeyFunctionList[i].keyCode == data) {
if (shellDefaultKeyFunctionList[i].keyFunction) {
shellDefaultKeyFunctionList[i].keyFunction(shell);
}
keyDefFind = 1;
}
}
}
if (keyDefFind == 0)
{
shellNormal(shell, data);
}
}
else
{
shellAnsi(shell, data);//shell ansi处理
}
}
以上就是shell的全部介绍,融合两节的代码,如下:int main(void)
{
int GetKey;
delay_init();
LED_Init();
uart_nvic_init(115200); //串口初始化为115200
//uart_shell.read = shellRead;
uart_shell.write = Uart_PutChar;
shellInit(&uart_shell);
/* 配置通道 0,上行配置*/
SEGGER_RTT_ConfigUpBuffer(0,"RTTUP",NULL,0,SEGGER_RTT_MODE_NO_BLOCK_SKIP);
/* 配置通道 0,下行配置*/
SEGGER_RTT_ConfigDownBuffer(0,"RTTDOWN",NULL,0,SEGGER_RTT_MODE_NO_BLOCK_SKIP);
//rtt_shell.read = shellRead;
rtt_shell.write = RTT_PutChar;
shellInit(&rtt_shell);
while (1)
{
if (SEGGER_RTT_HasKey())
{
GetKey = SEGGER_RTT_GetKey();
shellHandler(&rtt_shell, GetKey);
}
}
}
通过上述代码,可以同时支持串口方式和J-Link RTT模式的shell,方便用户根据自己实际条件来辅助调试代码。 以上实现方式可能会影响MCU的运行效率,我们在本教程中优先考虑提供实现shell的方式。往期精彩:
基于MM32 MCU的shell调试教程(一)
基于MM32 MCU的shell调试教程(二)
MM32W无线MCU系列产品应用笔记 —— 数据采集仪器
MM32W无线MCU系列产品应用笔记 —— 数据透传
MM32W无线MCU系列产品应用笔记 —— 蓝牙智能锁方案
MM32W无线MCU系列产品应用笔记 —— 温湿度监测仪方案
MM32W无线MCU系列产品应用笔记 —— 蓝牙自拍杆方案
MM32W无线MCU系列产品应用笔记 —— 智能炫彩遥控灯方案
MM32W无线MCU系列产品应用笔记 —— 自定义AT指令
MM32W无线MCU系列产品应用笔记 —— 自定义服务和特征值
MM32W无线MCU系列产品应用笔记 —— 接口函数调用
MM32W无线MCU系列产品应用笔记 —— 低功耗BLE蓝牙应用
MM32W无线MCU系列产品应用笔记 —— 阻塞式例程
MM32W无线MCU系列产品应用笔记——中断式例程
MM32W无线MCU系列产品应用笔记——蓝牙开发套件介绍
MM32W无线MCU系列产品应用手册——模组与AT指令
MM32SPIN2x 电机专用MCU功能特色——CRC计算单元
MM32SPIN2x 电机专用MCU功能特色——ADC DMA模块配置
MM32SPIN2x 电机专用MCU功能特色 —— I2C功能
MM32SPIN2x 电机专用MCU功能特色 —— SPI功能
MM32SPIN2x 电机专用MCU功能特色 —— 独立看门狗低功耗唤醒
MM32SPIN2x 电机专用MCU功能特色 —— 高集成度产品的电源管理
基于MM32SPIN电机/电源专用芯片的无感方波驱动应用方案——中小功率水泵
基于MM32SPIN电机/电源专用芯片的无传感弦波驱动应用方案——手持式吸尘器
基于MM32SPIN电机/电源专用芯片的有刷电机驱动应用方案——机器人舵机
更多信息请访问:www.mm32mcu.com,微信公众号请搜索“灵动MM32MCU”,QQ技术讨论群:294016370。