文档章节

STM32模块化调试技巧

OceanStack
 OceanStack
发布于 2014/10/24 09:50
字数 962
阅读 918
收藏 29

通过 《STM32串口向世界问好》介绍了如何重定向后,利用printf打印出信息,这个在程序调试中很有用。

但当一个项目软件代码多了以后,尤其是分了很多模块后,这样打印就不方便了,因为有时我只想看本模块的打印的信息,而又不想被其他模块信息干扰,怎么办呢?
一种简单直观的方法是为本模块单独写一个打印信息的函数来调用。然而当模块很多时,这样做就效率就不高了,并显得冗余。下面介绍我设计的一个可配置的模块打印信息的方法(此适用于裸机程序) 。

在此我单独写了一个debug模块,包含debug.c和debug.h两文件,.c定义了所要调用打印信息函数等, .h可配置,以方便地选择性打印你需要的模块信息。


如我一个工程中包含有系统模块、温度检测模块、电机控制模块,则首先在debug.c中定义如下字符串数组

char *DEBUG_MODULE_MSG[] =
{
    "NOTHING",
    "SYS",
    "TEMP",
    "MOTOR",
};

在.h中作如下定义 

#if 1
#define SYS_DEBUG
#define TEMP_DEBUG
#define MOTOR_DEBUG
#endif
//-------
#ifdef  SYS_DEBUG
#define SYS   (1<<0)
#else
#define SYS    0
#endif
//-------
#ifdef  TEMP_DEBUG
#define TEMP  (1<<1)
#else
#define TEMP    0
#endif
//-------
#ifdef  MOTOR_DEBUG
#define MOTOR (1<<2)
#else
#define MOTOR 0
#endif
#define DEBUG_MODULE_NUM  3
//-------

其中通过最上面几个宏定义你就可以选择性地打印需要的模块的调试信息,不要打印的直接屏蔽掉就好了,如果再增加模块,只需再多定义一个宏,然把模块数量增加,并在字符串数组里依次添加此模块要打印出名称。


下面介绍如何对以上配置进行解析并按要求打印出来,在.c里如下实现代码

/**
  * @brief  检测询要打印的模块
  * @param  module: 宏定义模块名
  * @retval 对应模块字符串偏移量
  */
static u16 check_debug_sw(u module)  
{
    u16 i ;
    
    if (0 == module)
    {
        return 0;
    }
    else
    {
        for (i = 0; i < DEBUG_MODULE_NUM ; i++)
        {
            if (module & (1 << i))
            {
                return (i + 1);
            }
        }
    }
    
    return 0;
}

此函数用于检测要打印的模块是否开启,如开启则返回模块对应的偏移量,以方便打印字符串数组中对应的模块名,若没找到,则返回0。

下面就是调试信息打印函数了,其实只需模仿printf函数的实现,并作简单的修改就可实现模块化打印。如下


/**
  * @brief  可进行模块选择的可变参数的打印调试函数
  * @param  module: 宏定义模块名  ...
  * @retval None
  */
void Debug_Msg_Module_Printf(u16 module, char *fmt, ...)
{
    va_list ap;
    char *p = NULL , *sval = NULL;
    int  ival;
    unsigned uval;
    double dval;
    u16 flag = 0 ;
    
    if (0 != (flag = check_debug_sw(module)))
    {
        printf("[ %s ]", DEBUG_MODULE_MSG[flag]);
        va_start(ap, fmt);
        
        for (p = fmt; *p; p++)
        {
            if (*p != '%')
            {
                putchar(*p);
                continue;
            }
            
            switch (*++p)
            {
                case 'd':
                case 'i':
                    ival = va_arg(ap, int);
                    printf("%d", ival);
                    break;
                    
                case 'c':
                    ival = va_arg(ap, int);
                    putchar(ival);
                    break;
                    
                case 'u':
                    uval = va_arg(ap, unsigned);
                    printf("%u", uval);
                    break;
                    
                case 'x':
                    uval = va_arg(ap, unsigned);
                    printf("%x", uval);
                    break;
                    
                case 'X':
                    uval = va_arg(ap, unsigned);
                    printf("%X", uval);
                    break;
                    
                case 'o':
                    uval = va_arg(ap, unsigned);
                    printf("%o", uval);
                    break;
                    
                case 'e':
                    dval = va_arg(ap, double);
                    printf("%e", dval);
                    break;
                    
                case 'f':
                    dval = va_arg(ap, double);
                    printf("%f", dval);
                    break;
                    
                case 'g':
                    dval = va_arg(ap, double);
                    printf("%g", dval);
                    break;
                    
                case 's':
                    for (sval = va_arg(ap, char *); *sval; sval++)
                    {
                        putchar(*sval);
                    }
                    
                    break;
                    
                default :
                    putchar(*p);
                    break;
            }
        }
        
        va_end(ap);
    }
}

至此,模块化信息打印方法就实现了。

要进行打印信息调试,如温度检测模块可以如下调用

Debug_Msg_Module_Printf(TEMP,"Temp is %d \n",temp);


电机控制模块可如此调用:

Debug_Msg_Module_Printf(MOTOR,"Motor Running \n");
Debug_Msg_Module_Printf(MOTOR,"Motor Stopped \n");

如若要屏蔽掉所有的电机模块打印消息,只需要.h文件中作如下修改:

#if 1
#define SYS_DEBUG
#define TEMP_DEBUG
//#define MOTOR_DEBUG  //注释掉此行宏定义
#endif

这样是不是就很方便了?! 


© 著作权归作者所有

OceanStack
粉丝 29
博文 21
码字总数 19858
作品 0
武汉
程序员
私信 提问
加载中

评论(6)

z
zytan2

引用来自“开源中国工信部部长”的评论

不是有标准库printf()可以用么?实现了putchar()就可以了。
en
OceanStack
OceanStack 博主
补充一下,Debug_Module_Printf可以如下更简单的方法实现 :

void Debug_Module_Printf(int module, char *fmt, ...)
{
va_list ap;

u8 flag = 0 ;

if (0 != (flag = check_debug_sw(module)))
{
printf("[ %s ]", DEBUG_MODULE_STR[flag]);

va_start(ap, fmt);

vprintf(fmt,ap);

va_end(ap);
}
}
OceanStack
OceanStack 博主

引用来自“开源中国工信部部长”的评论

不是有标准库printf()可以用么?实现了putchar()就可以了。
你讲到我没有听太懂哦 ?
OceanStack
OceanStack 博主

引用来自“吉迪恩”的评论

每个模块还要有日志等级,并且可以动态调整
这个想法挺好 。
吉迪恩
吉迪恩
每个模块还要有日志等级,并且可以动态调整
临峰不畏
临峰不畏
不是有标准库printf()可以用么?实现了putchar()就可以了。
一个将十六进制转换为二进制字符数组的函数

十六进制数转换为二进制数组的函数HexToBinStr 函数实现: 实际应用: 实际运行结果: 历史精选文章: Jlink使用技巧之读取STM32内部的程序 Jlink使用技巧之单独下载HEX文件到单片机 Jlink使...

whik
01/11
0
0
个人博客添加网易云音乐Flash插件

博客底部添加网易云音乐播放插件 歌单或者歌曲外链可从音乐界面“生成外链播放器”中得到,选择Flash播放插件即可 footer.html文件增加 实现效果: 历史精选文章: Jlink使用技巧之读取STM32...

whik
01/11
0
0
Keil开发环境如何生成BIN文件

为什么需要BIN文件呢? 有些烧录器只支持BIN文件。 进行OTA远程升级时,只能使用BIN文件。 使用JLink脚本文件进行一键烧录时,只支持BIN文件。 BIN文件要比HEX和AXF文件小的多。 但Keil默认生...

whik
01/11
0
0
stm32硬件调试

STM32的基本系统主要涉及下面几个部分: 一、电源  1)、无论是否使用模拟部分和AD部分,MCU外围出去VCC和GND,VDDA、VSSA、Vref(如果封装有该引脚)都必需要连接,不可悬空;   2)、对...

peng_258
2017/10/20
0
0
shentq/eBox_STM32F1

ebox_stm32 ebox_stm32特点 1.在STM32的3.5版本的库的基础上封装一层类似于Arduino的API。 2.使得STM32也可以使用arduino的大部分驱动。驱动程序从github上下载后稍作修改就可以使用。 3.减少...

shentq
2018/06/22
0
0

没有更多内容

加载失败,请刷新页面

加载更多

java通过ServerSocket与Socket实现通信

首先说一下ServerSocket与Socket. 1.ServerSocket ServerSocket是用来监听客户端Socket连接的类,如果没有连接会一直处于等待状态. ServetSocket有三个构造方法: (1) ServerSocket(int port);...

Blueeeeeee
今天
6
0
用 Sphinx 搭建博客时,如何自定义插件?

之前有不少同学看过我的个人博客(http://python-online.cn),也根据我写的教程完成了自己个人站点的搭建。 点此:使用 Python 30分钟 教你快速搭建一个博客 为防有的同学不清楚 Sphinx ,这...

王炳明
昨天
5
0
黑客之道-40本书籍助你快速入门黑客技术免费下载

场景 黑客是一个中文词语,皆源自英文hacker,随着灰鸽子的出现,灰鸽子成为了很多假借黑客名义控制他人电脑的黑客技术,于是出现了“骇客”与"黑客"分家。2012年电影频道节目中心出品的电影...

badaoliumang
昨天
15
0
很遗憾,没有一篇文章能讲清楚线程的生命周期!

(手机横屏看源码更方便) 注:java源码分析部分如无特殊说明均基于 java8 版本。 简介 大家都知道线程是有生命周期,但是彤哥可以认真负责地告诉你网上几乎没有一篇文章讲得是完全正确的。 ...

彤哥读源码
昨天
17
0
jquery--DOM操作基础

本文转载于:专业的前端网站➭jquery--DOM操作基础 元素的访问 元素属性操作 获取:attr(name);$("#my").attr("src"); 设置:attr(name,value);$("#myImg").attr("src","images/1.jpg"); ......

前端老手
昨天
7
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部