STM32的串口控制台的实现

嵌入式大杂烩 2023-09-27 20:26

来源:CSDN

1. 前言

玩过Linux的朋友, 是不是对Linux无所不能的串口Shell命令控制台羡慕不已, 要是自己做的STM32F系列低档次的MCU也有这种控制交互能力, 会给调试/维护和配置省下多少麻烦事呀, 比如启动/关闭调试或自检模式, 打印调试信息, 配置系统参数, 传输文件等等, 也有相当多的朋友凭借自己出色的编程能力可以实现这些功能, 这里提出我的这个解决方案, 以作交流.

本平台(xc_shell)具备以下性能特点:

  1. 大量主要代码, 和具体硬件无关, 移植性强,代码文件少.

  2. 只有在处理用户的输入命令时, 才占用CPU资源, 且代码可裁剪到1KB SRAM和4KB Flash;

  3. 用户可以非常灵活的添加按模板编写的命令脚本文件, 自定义扩张能力强.

  4. 支持操作系统和非操作系统两种场景应用.

  5. 支持Ymodem文件传输协议

  6. 支持将Flash的扇区开辟为参数区, 可实现本地/远程升级。

  7. 实用Led灯信号管理, 可将65535虚拟信号灯选择输出到1个实体LED灯上, 调试时序和状态非常有用

  8. 拥有基础的LED管理, 调试模式设置, 命令帮助指令, 复位指令等基础功能

功能越多设计会越复杂, 为了解释清楚代码, 先向大家解释一下以上功能的基础实现原理, 并提供一个最小的的源码工程。

2. xc_shell平台介绍

2.1 如何实现硬件无关

类比Linux会发现, 设备的硬件接口往往会被虚拟成一个文件(驱动), 而Linux内核完全与硬件系统无任何字节关联, 不同平台驱动不同而已, 故而本xc_shell的串口驱动也采用了相似的思路:

1) 串口驱动用一个结构体描述, 这样只需在xc_shell.c中用指针指向这个TTYx_HANDLE结构体对象就可以将串口(tty)硬件与内核联系在一起, 聪明的朋友可能会想到, 假如我将带网络的开发板按此结构体,虚拟一个TTY对象, 岂不是就可以实现一个网络远程控制台了!  这点确实是可以的!

2) 当然诸如多TTY串口实现接口互换等, 都是一个指针和step2中的注入回调处理交换的问题。

3)用户在使用api_TxdFrame或api_TxdByte时”bsp_ttyX.c“,会驱动具体MCU的串口将数据发送出去, 收到一帧数据后,若用户设置了inj_RcvFrame回调处理方法,则会在中断中执行用户的回调处理。

/*---------------------* 
*     指正函数定义
*----------------------*/

typedef void    (*pvFunDummy)(void);
 
//输入整行,输出逻辑
typedef void    (*pvFunVoid) (void);
typedef void    (*pvFunBool) (bool     bVal);
typedef void    (*pvFunChar) (uint8_t  cVal);
typedef void    (*pvFunShort)(uint16_t sVal);
typedef void    (*pvFunWord) (uint32_t wVal);
 
//输入整行,输出逻辑
typedef bool    (*pbFunVoid) (void);
typedef bool    (*pbFunBool) (bool     bVal);
typedef bool    (*pbFunChar) (uint8_t  cVal);
typedef bool    (*pbFunShort)(uint16_t sVal);
typedef bool    (*pbFunWord) (uint32_t wVal);
 
//输入整形指针,输出逻辑
typedef bool    (*pbFun_pVoid) (void * pVoid);
typedef bool    (*pbFun_pChar) (uint8_t  * pStr);
typedef bool    (*pbFun_pShort)(uint16_t * pShor);
typedef bool    (*pbFun_pWord) (uint32_t * pWord);
 
//输入数据帧,输出逻辑
typedef bool    (*pbFun_Buffx)(void * pcBuff, uint16_t len );
typedef bool    (*pbFun_Bytex)(uint8_t * pcByte, uint16_t len );
/*---------------------* 
*    TTYx 句柄结构
*----------------------*/

typedef struct TTYx_HANDLE_STRUCT 
{

    const char  * const name;       //驱动器名
    const uint16_t      rxSize;     //接收大小
    const uint16_t      txSize;     //发送大小
    
    //------------------------------------------------------
    //step1: 用户可用API
    const pvFunWord     init;           //初始化.
    const pbFun_Bytex   api_TxdFrame;   //发送数据帧. (发送帧)
    const pbFunChar     api_TxdByte;    //发送数据字节
    
    //------------------------------------------------------
    //step2: 注入回调函数
    pbFun_Bytex         inj_RcvFrame;   //(ISR)接收数据帧. (接收帧)
    pvFunDummy          inj_TxdReady;   //(ISR)发送完毕回调
    
    //------------------------------------------------------
    //step3: 接收回调函数
    struct TTYx_HANDLE_STRUCT * pvNext; //连接到下一个指令 
}TTYx_HANDLE;
  1. 可注入的命令脚本(CLI)实现

命令CLI也是一个结构体对象:

/*---------------------* 
*       CLI指令
*----------------------*/

typedef struct
{

 const char * const  pcCmdStr;     //指令字符串(只能为小写字母)
 const char * const  pcHelpStr;     //指令描述,必须以:"\r\n结束". 比如:"help: Returns a list\r\n".
 const pFunHook      pxCmdHook;     //指向回调函数的指针,处理成功返回真否者返回0;
 uint8_t             ucExpParam;     //指令期望的参数个数
 const MEDIA_HANDLE *phStorage;      //指向存储介质,没有的话填充NULL  
}Cmd_Typedef_t;


各位朋友可能会使用到非常多的自定义CLI命令, 格式诸如这个网卡的命令:

const Cmd_Typedef_t CLI_WizMsg=
{
    //识别关键字
    .pcCmdStr   = "wiz",
    //帮助内容
    .pcHelpStr  =
    "[WIZ contorls]\r\n"
 " wiz help\r\n"
 " wiz rd info\r\n"
 " wiz reset\r\n"
 " wiz wr ip ...\r\n"
 " wiz wr mask ...\r\n"
 " wiz wr way ...\r\n"
 " wiz wr mac -

-

-

-

-

\r\n"
 " wiz wr port    \r\n"
 " wiz wr sip ... \r\n"
 " wiz wr cip ... \r\n"
 " wiz load default\r\n"
 "[WIZ Test mode]\r\n"
 " wiz loop open\r\n"
 " wiz loop close\r\n"
 "\r\n",
 
 //处理函数
 .pxCmdHook  = &Shell_WIZ_Service,        //见实体函数
 
 //附带数据
 .ucExpParam = 0,
 
  #ifdef SHELL_USE_YMODEM  
    //存储介质
    .phStorage  = NULL,
  #endif
};
/*---------------------* 
*       CLI 链表节
*----------------------*/

Cmd_List_t  WizList   = { &CLI_WizMsg,   NULL,}; //Shell指令的头

如配置IP地址输入“wiz wr ip 192.168.1.250\r\n”则可以了

3. 环境准备

3.1 硬件开发环境

  • STM32F103系列开发板一块, 带USART1接口。
  • USB转串口线一根。

3.2 软件开发环境

  • MDK4.72或以上
  • SecureCRT串口超级终端

3.3 软件配置

在xc_shell使用“/r/n”作为命令的结束符, 而SecureCRT按下Enter不是输入“/r/n”故而需要按下图设置:此外在《终端》/仿真/高级中选取【本地回显】 

4. 代码介绍

4.1 目录结构

□ XC_SHELL
├──┬── BSP_LIB    BSP库,硬件相关驱动代买
│  ├──── bsp_ledx.c   基础LED驱动      
│  └──── bsp_tty0.c   调试串口驱动

├──┬──MDK-ARM     工程文件
│  └──── Project.uvproj

├──┬──SHELL_CFG   SHELL配置头文件
│  └──── user_eval.h

├──┬──SHELL_CORE  SHELL内核文件
│  ├──── xc_shell.c   SHELL内核文件
│  ├──── xc_ymodem.c  Ymodem传输协议(默认关闭,在xc_shell.h中启动)
│  ├──── xc_iap.c     Flash的IAP操作,需要bsp_flash.c驱动支持
│  └──── shell_iap.c  shell的用户脚本模板

├──┬──SHELL_INC   SHELL头文件
│  ├──── bsp_type.h   驱动结构定义
│  ├──── xc_shell.h   SHELL头文件
│  └──── xconfig.h    硬件无关配置文件

├──┬──STM32F10x_StdPeriph_Lib_V3.5.0  STM32的标准外设库
│  └──── ......

└──┬──USER        用户文件    
   ├─ .....       
   └──── main.c        main文件

4.2 工程设置要点

1) 设置使用微库:

2)配置包含和路径,注意使用了“--c99”标准,如图

3) 编译工程,无错误警告后烧写程序到开发板运行。

4.3 最终效果

按图输入一下指令,SHELL平台会回复相关信息。其中输入“led set 0=1”会将信号1分配到物理LED0上;输入“led set 0=2”会将信号2分配到物理LED0上。这样用户编写程序代码时相当于拥有了超级多的LED信号可用,调试时序非常有用。 

5. 添加自己的指令脚本

5.1 源代码示例

假设我要编写一个自己的指令脚本, 来读取MCU的关键信息,关键字为mcu, 文件命名为shell_mcu.c;当输入“mcu rd 0”时显示MCU的FLASH大小,输入“mcu rd 1”时读取MCU的唯一ID信息。shell_mcu.c源代码:

/*********************************Copyright (c)*********************************
**                               
**                                 FIVE工作组
**
**---------------------------------File Info------------------------------------
** File Name:               shell_mcu.c
** Last modified Date:      2017/9/17 15:13:57
** Last Version:            V1.0
** Description:             shell测试
**
**------------------------------------------------------------------------------
** Created By:              wanxuncpx
** Created date:            2017/9/17 15:14:08
** Version:                 V1.0
** Descriptions:            none
**------------------------------------------------------------------------------
** HW_CMU:                  STM32F103
** Libraries:               STM32F10x_StdPeriph_Lib_V3.5.0
** version                  V3.5
*******************************************************************************/

 
/******************************************************************************
更新说明:
******************************************************************************/

 
/******************************************************************************
*********************************  编 译 控 制 ********************************
******************************************************************************/

#define MCU_SHELL               //注释掉时屏蔽iap shell功能
 
#include "xc_shell.h"       //Shell支持文件,含bool,uint8_t..以及串口数据收发操作
/******************************************************************************
********************************* 文件引用部分 ********************************
******************************************************************************/

/*---------------------* 
*     模块驱动引用
*----------------------*/

//#include "net_w5500.h"
 
#ifdef MCU_SHELL
/******************************************************************************
********************************** Shell实例 **********************************
******************************************************************************/

/*---------------------* 
*      CLI指令服务
*----------------------*/

extern bool Shell_MCU_Service(void * pcBuff, uint16_t len );
 
/*---------------------* 
*       CLI 结构
*----------------------*/

const Cmd_Typedef_t CLI_McuMsg=
{
    //识别关键字
    "mcu",
    
    //帮助内容
 "[mcu contorls]\r\n"
 " mcu rd \t\t- Read FLASH information.\r\n"
 "\r\n",
 
 //处理函数
 &Shell_MCU_Service,
 
 //附带数据
 0,
  #ifdef SHELL_USE_YMODEM  
    //存储介质
    NULL,
  #endif
};
 
/*---------------------* 
*     CLI链表节(输出)
*----------------------*/

Cmd_List_t  McuList  = {&CLI_McuMsg      ,NULL}; //IAP指令链表
 
/******************************************************************************
********************************* 函 数 声 明 *********************************
******************************************************************************/

/******************************************************************************
/ 函数功能:STM32F103控制函数
/ 修改日期:2015/7/14 20:22:02
/ 输入参数:none
/ 输出参数:none
/ 使用说明:需要执行约10s
******************************************************************************/

static bool FLASH_ioctl(uint8_t cmd,void * param)
{
    #define UID_ADDR            0x1FFFF7E0  //闪存容量寄存器,值对应KB单位
    #define MAC_ADDR            0x1FFFF7E8  //MCU的唯一ID号,共12个字节
    #define UID_SIZE            2           //UID的字节数
    #define MAC_SIZE            12          //MAC的字节数
 
    //step1: 检查参数
    if(!param)return false;
        
    //step2: 处理数据
    switch(cmd){
      case 0 : {       //获取FLASH的的UID
        uint16_t * ptDst = (uint16_t *)((uint32_t)param+1);
        
        *ptDst = *(uint16_t *)UID_ADDR;
        *(uint8_t  *)param =  UID_SIZE;
        return true;
      }
      case 1 : {       //获取芯片的MAC地址
        uint32_t * ptDst = (uint32_t *)((uint32_t)param+1);
        uint32_t * ptSrc = (uint32_t *)MAC_ADDR;
    
        *ptDst++ = *ptSrc++;
        *ptDst++ = *ptSrc++;
        *ptDst++ = *ptSrc++;
        *(uint8_t  *)param = MAC_SIZE;
        return true;
      }
      default:return false;
    }
}
 
/******************************************************************************
/ 函数功能:文件系统Shel指令处理
/ 修改日期:2013/9/10 19:04:15
/ 输入参数:输入当前的程序版本
/ 输出参数:none
/ 使用说明:none
******************************************************************************/

bool Shell_MCU_Service(void * pcBuff, uint16_t len )
{
    uint8_t    *ptRxd;          //用于接收指令处理
    int         i;
    uint16_t    retval;
    uint8_t     buff[32];
    
    //处理指令
    //--------------------------------------------------------------------------
    ptRxd = (uint8_t *)pcBuff;
    
    if(StrComp(ptRxd,"rd ")) //读取FLASH信息
    {
        int wval;
        
        if(1 != sscanf((void *)ptRxd,"%*s%d",&wval) )return false;
        if( wval>2 )return false;
        if(0==wval) {
            FLASH_ioctl(0,buff);
            retval = *(uint16_t *)(buff+1) ;
            printf("->Flash:\t%dKB\r\n",retval);
            return true;
        }
        else if(1==wval) {
            FLASH_ioctl(1,buff);
            printf("->MAC:\t ");
            for(i=0; i0]-1; i++){printf("%02X-",buff[i+1]);}
            printf("%02X\r\n",buff[i+1]);
            return true;
        }
        else return false;
    }
    else if(StrComp(ptRxd,"help\r\n"))      //指令帮助
    {
        shell_SendStr((void *)CLI_McuMsg.pcHelpStr);
        return true;
    }
    else return false;
}
 
/******************************************************************************
***********************************   END  ************************************
******************************************************************************/

#endif

5.2 实现步骤

1) 将该文件添加到工程下。

2) 在main.c中用extern 引用McuList,源代码为:

/*---------------------* 
*     Shell指令链表
*----------------------*/

extern Cmd_List_t  McuList;

3)在main.c初始化时添加:

//----------------------------------------------------------
//step1: shell初始化
shell_Init(115200,ledx_cfg);        //初始化shell接口
CLI_AddCmd(&McuList);     //添加模块指令到链表

4)编译工程文件。

5)下载到开发板运行即可在终端下看到新支持的CLI指令:

来源:https://dablelv.blog.csdn.net/article

本文来源网络,免费传达知识,版权归原作者所有。如涉及作品版权问题,请联系我进行删除。

往期推荐

《嵌入式Linux驱动大全》


在公众号聊天界面回复1024,可获取嵌入式资源

嵌入式大杂烩 专注于嵌入式技术,包括但不限于C/C++、嵌入式、物联网、Linux等编程学习笔记,同时,内包含大量的学习资源。欢迎关注,一同交流学习,共同进步!
评论
  •     IPC-2581是基于ODB++标准、结合PCB行业特点而指定的PCB加工文件规范。    IPC-2581旨在替代CAM350格式,成为PCB加工行业的新的工业规范。    有一些免费软件,可以查看(不可修改)IPC-2581数据文件。这些软件典型用途是工艺校核。    1. Vu2581        出品:Downstream     
    电子知识打边炉 2025-01-22 11:12 465浏览
  • 随着AI大模型训练和推理对计算能力的需求呈指数级增长,AI数据中心的网络带宽需求大幅提升,推动了高速光模块的发展。光模块作为数据中心和高性能计算系统中的关键器件,主要用于提供高速和大容量的数据传输服务。 光模块提升带宽的方法有两种:1)提高每个通道的比特速率,如直接提升波特率,或者保持波特率不变,使用复杂的调制解调方式(如PAM4);2)增加通道数,如提升并行光纤数量,或采用波分复用(CWDM、LWDM)。按照传输模式,光模块可分为并行和波分两种类型,其中并行方案主要应用在中短距传输场景中成本
    hycsystembella 2025-01-25 17:24 473浏览
  • 飞凌嵌入式基于瑞芯微RK3562系列处理器打造的FET3562J-C全国产核心板,是一款专为工业自动化及消费类电子设备设计的产品,凭借其强大的功能和灵活性,自上市以来得到了各行业客户的广泛关注。本文将详细介绍如何启动并测试RK3562J处理器的MCU,通过实际操作步骤,帮助各位工程师朋友更好地了解这款芯片。1、RK3562J处理器概述RK3562J处理器采用了4*Cortex-A53@1.8GHz+Cortex-M0@200MHz架构。其中,4个Cortex-A53核心作为主要核心,负责处理复杂
    飞凌嵌入式 2025-01-24 11:21 293浏览
  • 书接上回:【2022年终总结】阳光总在风雨后,启航2023-面包板社区  https://mbb.eet-china.com/blog/468701-438244.html 总结2019,松山湖有个欧洲小镇-面包板社区  https://mbb.eet-china.com/blog/468701-413397.html        2025年该是总结下2024年的喜怒哀乐,有个好的开始,才能更好的面对2025年即将
    liweicheng 2025-01-24 23:18 350浏览
  • 高速先生成员--黄刚这不马上就要过年了嘛,高速先生就不打算给大家上难度了,整一篇简单但很实用的文章给大伙瞧瞧好了。相信这个标题一出来,尤其对于PCB设计工程师来说,心就立马凉了半截。他们辛辛苦苦进行PCB的过孔设计,高速先生居然说设计多大的过孔他们不关心!另外估计这时候就跳出很多“挑刺”的粉丝了哈,因为翻看很多以往的文章,高速先生都表达了过孔孔径对高速性能的影响是很大的哦!咋滴,今天居然说孔径不关心了?别,别急哈,听高速先生在这篇文章中娓娓道来。首先还是要对各位设计工程师的设计表示肯定,毕竟像我
    一博科技 2025-01-21 16:17 241浏览
  • 项目展示①正面、反面②左侧、右侧项目源码:https://mbb.eet-china.com/download/316656.html前言为什么想到要做这个小玩意呢,作为一个死宅,懒得看手机,但又想要抬头就能看见时间和天气信息,于是就做个这么个小东西,放在示波器上面正好(示波器外壳有个小槽,刚好可以卡住)功能主要有,获取国家气象局的天气信息,还有实时的温湿度,主控采用ESP32,所以后续还可以开放更多奇奇怪怪的功能,比如油价信息、股票信息之类的,反正能联网可操作性就大多了原理图、PCB、面板设计
    小恶魔owo 2025-01-25 22:09 615浏览
  • 不让汽车专美于前,近年来哈雷(Harley-Davidson)和本田(Honda)等大型重型机车大厂的旗下车款皆已陆续配备车载娱乐系统与语音助理,在路上也有越来越多的普通机车车主开始使用安全帽麦克风,在骑车时透过蓝牙连线执行语音搜寻地点导航、音乐播放控制或免持拨打接听电话等各种「机车语音助理」功能。客户背景与面临的挑战以本次分享的客户个案为例,该客户是一个跨国车用语音软件供货商,过往是与车厂合作开发前装车机为主,且有着多年的「汽车语音助理」产品经验。由于客户这次是首度跨足「机车语音助理」产品,因
    百佳泰测试实验室 2025-01-24 17:00 194浏览
  • 前篇文章中『服务器散热效能不佳有解吗?』提到气冷式的服务器其散热效能对于系统稳定度是非常重要的关键因素,同时也说明了百佳泰对于散热效能能提供的协助与服务。本篇将为您延伸说明我们如何进行评估,同时也会举例在测试过程中发现的问题及改善后的数据。AI服务器的散热架构三大重点:GPU导风罩:尝试不同的GPU导风罩架构,用以集中服务器进风量,加强对GPU的降温效果。GPU托盘:改动GPU托盘架构,验证出风面积大小对GPU散热的影想程度。CPU导风罩:尝试封闭CPU导风罩间隙,集中风流,验证CPU降温效果。
    百佳泰测试实验室 2025-01-24 16:58 189浏览
  • 故障现象 一辆2007款日产天籁车,搭载VQ23发动机(气缸编号如图1所示,点火顺序为1-2-3-4-5-6),累计行驶里程约为21万km。车主反映,该车起步加速时偶尔抖动,且行驶中加速无力。 图1 VQ23发动机的气缸编号 故障诊断接车后试车,发动机怠速运转平稳,但只要换挡起步,稍微踩下一点加速踏板,就能感觉到车身明显抖动。用故障检测仪检测,发动机控制模块(ECM)无故障代码存储,且无失火数据流。用虹科Pico汽车示波器测量气缸1点火信号(COP点火信号)和曲轴位置传感器信
    虹科Pico汽车示波器 2025-01-23 10:46 321浏览
  • 临近春节,各方社交及应酬也变得多起来了,甚至一月份就排满了各式约见。有的是关系好的专业朋友的周末“恳谈会”,基本是关于2025年经济预判的话题,以及如何稳定工作等话题;但更多的预约是来自几个客户老板及副总裁们的见面,他们为今年的经济预判与企业发展焦虑而来。在聊天过程中,我发现今年的聊天有个很有意思的“点”,挺多人尤其关心我到底是怎么成长成现在的多领域风格的,还能掌握一些经济趋势的分析能力,到底学过哪些专业、在企业管过哪些具体事情?单单就这个一个月内,我就重复了数次“为什么”,再辅以我上次写的:《
    牛言喵语 2025-01-22 17:10 494浏览
我要评论
0
点击右上角,分享到朋友圈 我知道啦
请使用浏览器分享功能 我知道啦