实用STM32的串口控制平台的实现

发布者:Qingfang最新更新时间:2019-04-10 来源: eefocus关键字:STM32  串口控制  平台 手机看文章 扫描二维码
随时随地手机看文章

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;


2) 可注入的命令脚本(CLI)实现

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

/*---------------------* 

*       CLI指令

*----------------------*/

typedef struct

{

const char * const  pcCmdStr;     //指令字符串(只能为小写字母)

const char * const  pcHelpStr;     //指令描述,必须以:"rn结束". 比如:"help: Returns a listrn".

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]rn"

" wiz helprn"

" wiz rd inforn"

" wiz resetrn"

" wiz wr ip

" wiz wr mask

" wiz wr way

" wiz wr mac

" wiz wr port

" wiz wr sip

" wiz wr cip

" wiz load defaultrn"

"[WIZ Test mode]rn"

" wiz loop openrn"

" wiz loop closern"

"rn",


//处理函数

.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.250rn”则可以了

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]rn"

" mcu rd

"rn",


//处理函数

&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%dKBrn",retval);

            return true;

        }

        else if(1==wval) {

            FLASH_ioctl(1,buff);

            printf("->MAC:t ");

            for(i=0; i

            printf("%02Xrn",buff[i+1]);

            return true;

        }

        else return false;

    }

    else if(StrComp(ptRxd,"helprn"))      //指令帮助

    {

        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指令:




关键字:STM32  串口控制  平台 引用地址:实用STM32的串口控制平台的实现

上一篇:stm32 PUSH 按键控制LED闪烁
下一篇:STM32串口控制不同亮度等级的小灯

推荐阅读最新更新时间:2024-03-16 16:27

多家EDA公司与GLOBALFOUNDRIES合作开发22FDX平台iPDK
GLOBALFOUNDRIES今天宣布发布针对其22FDX(22nm FD-SOI)平台优化的OpenAccess iPDK库。凭借其一流的性能、功耗和广泛的功能集成能力,GF的差异化22FDX平台是5G 毫米波、边缘AI、物联网(IoT)、汽车、卫星通信、安全等应用领域的设计师和创新者的首选解决方案。 基于开放标准的iPDK提供了与为特定供应商工具设计的pdk相同级别的功能和性能,同时有助于实现不同设计工具套件之间的互操作性和兼容性。工具包括:Synopsys的自定义编译器、Mentor的Tanner软件解决方案、Keysight Technologies的PathWave高级设计系统(ADS)以及任何其他支持OpenAcc
[半导体设计/制造]
STM32使用DMA加串口空闲中断接收数据
STM32中,需要用串口接收数据,是使用串口中断来接收数据。但是用这种方法的话,就要频繁进入串口中断,然后处理,效率就比较低。于是就想到用DMA来接收串口数据,这个STM32也是支持的。但是关键的一点,怎么知道数据接收完毕了呢?如果接收的数据长度固定,那就好办,直接设置DMA的接收数据个数就行了。但是如果长度不固定了,那应该怎么办了? 这个时候,就要用到STM32在串口中提供的另一个好用的东西了,就是串口空闲中断。在STM32的串口控制器中,设置了有串口空闲中断,即如果串口空闲,又开启了串口空闲中断的话,就触发串口空闲中断,然后程序就会跳到串口中断去执行。有了这个,是不是可以判断什么时候串口数据接收完毕了呢?因为串口数据
[单片机]
<font color='red'>STM32</font>使用DMA加<font color='red'>串口</font>空闲中断接收数据
STM32单片机中使用SPI通信的方法
  在本教程中,我们将使用 STM32F103C8 的 Blue Pill 板替换一个 Arduino 板,并将使用 SPI 总线与 Arduino 板进行通信。在这个STM32 SPI 示例中,我们将使用Arduino UNO作为 Slave,STM32F103C8 作为 Master,两个16X2 LCD 显示器分别连接在一起。两个电位器还与STM32(PA0)和Arduino(A0)相连,通过改变电位器来确定主机到从机和从机到主机的发送值(0到255)。   STM32F103C8中的SPI   比较 Arduino 和 STM32F103C8 Blue Pill 板中的 SPI 总线,STM32 有2 条 SPI 总线
[单片机]
在<font color='red'>STM32</font>单片机中使用SPI通信的方法
OLED产业亟须开放平台
OLED(有机发光二极管)技术可谓是全球最耀眼的平板显示技术之一。目前,OLED产业不仅是四川长虹发展的战略重点,更是四川省平板显示产业的发展战略重点之一。四川虹视显示技术有限公司成立于2008年1月,位于成都市高新技术产业开发区西区。四川虹视产品技术部部长田朝勇在接受《中国电子报》记者采访时说,虹视是迄今为止中国唯一一家开发出AM-OLED(主动有机发光二极管)产品的企业,拥有110多项OLED专利。他表示,OLED在我国起步并不算晚,行业内的各个单位应该用更开放的心态把我国OLED产业共同做大做强。     5年后市场将放量    目前,OLED面板的生产厂商主要集中在日本、韩国、中国台湾等国家和地区。随着三星SDI
[电源管理]
STM32】ADC库函数、一般步骤详解 实例:内部温度传感器
STM32F1xx官方资料: 《STM32中文参考手册V10》-第11章 模拟/数字转换(ADC) 《STM32中文参考手册V10》-第11章 第11.10小节 温度传感器 ADC采样数值 如何STM32的ADC模块,得到接入ADC管脚上的实际电压值? 会读到什么值 由于STM32的ADC是12位逐次逼近型的模拟数字转换器,也就是说ADC模块读到的数据是12位的数据。 因此:STM32读到的ADC值,是从0到4095(111111111111)。当把ADC引脚接了GND,读到的就是0;当把ADC引脚接了VDD,读到的就是4095。 读到的值怎么换算成实际的电压值 前面提到了,我们输入GND,读到的值是0,输入V
[单片机]
【<font color='red'>STM32</font>】ADC库函数、一般步骤详解 实例:内部温度传感器
第 12 代酷睿 HX 处理器问世,再攀移动计算平台性能新巅峰
2022 年 5 月 10 日——在今天举行的 2022 英特尔 ON 产业创新峰会上,英特尔宣布推出全新 第12 代英特尔® 酷睿™ HX 处理器 家族,7 款新品在移动平台封装中采用了媲美台式机的芯片,为 CAD、动画和视觉特效等专业工作负载提供迅猛性能。HX 处理器覆盖酷睿 i5、酷睿 i7 和酷睿 i9 不同型号,均带来开箱即用的未锁频性能。 英特尔公司副总裁兼移动客户端平台总经理 Chris Walker 表示:“第 12 代英特尔酷睿 HX 处理器具有全新的内核架构和更高一级的功率设定,使内容创建者能够以更迅猛的性能处理更为苛刻的工作负载,例如在后台执行 3D 渲染工作的同时,继续在设计场景中遍历其他三维模型素材。
[网络通信]
第 12 代酷睿 HX 处理器问世,再攀移动计算<font color='red'>平台</font>性能新巅峰
STM32——串口通信升级版(队列方式)
#ifndef _USART_QUEUE_H_ #define _USART_QUEUE_H_ #include type.h typedef enum { USART_QUEUE_EMPTY = 0, USART_QUEUE_FULL = 1, USART_QUEUE_OK = 2, } usart_queue_status_t; #define USART_QUEUE_SIZE 1024 typedef struct { uint16_t front; uint16_t rear; uint16_t size; char data ; } usart_queue_t; extern usa
[单片机]
Android成为美国智能手机用户首选平台
最近6个月美国用户对智能手机平台的需求 -->   北京时间10月5日晚间消息,据国外媒体报道,调研公司尼尔森周二发布报告称,谷歌Android平台已经超越iPhone和黑莓,成为美国新用户首选智能手机平台。   尼尔森报告显示,在过去6个月购买智能手机的美国消费者中,Android是他们的首选智能手机平台,RIM黑莓和苹果iPhone并列第二。   Android之所以发展如此迅速,主要是因为它是一款免费操作系统,任何厂商都可以使用。目前,Android已得到摩托罗拉和宏达电等诸多手机厂商的支持,就连iPhone在美国的独家运营商AT&T也开始销售多款Android手机。   尼尔森分析师罗杰·恩特纳(Roge
[手机便携]
Android成为美国智能手机用户首选<font color='red'>平台</font>
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved