shell if判断_灵动微课堂(第98讲) | 基于MM32 MCU的shell调试教程(三)

f4a5d3913f2ddaed964cba81490d2944.png 在前两节中,我们讲解了如何在MM32 MCU上使用shell来辅助开发,分别介绍的是通过串口方式和J-Link RTT方式的shell,本次课程我们分析源码来讲解shell实现原理。

软件资源如下:

以下为函数初始化配置及相关全局变量定义内容,代码如下:

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的方式。 b3433d105ce7c8ee02a4fcde5d5d98c9.gif

往期精彩:

基于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电机/电源专用芯片的有刷电机驱动应用方案——机器人舵机

8c643594324cb5ba3577125432e36a84.png

更多信息请访问:www.mm32mcu.com,微信公众号请搜索“灵动MM32MCU”,QQ技术讨论群:294016370。

8199c178d02ca388c6ee505ab10820bd.png
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值