IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> 【C/C++开源库】单片机/嵌入式中的C语言日志库 -> 正文阅读

[嵌入式]【C/C++开源库】单片机/嵌入式中的C语言日志库

日志系统在系统开发和调整过程中的重要性,大家应该都清楚,特别是项目出问题之后,却没有日志可以帮忙定位问题,就非常令人痛苦。

因为我们不可能一直通过调试器去单步调试程序,所以设备的运行日志显得尤为重要。

通常我们对日志有这些要求:

  • 不同的日志级别(Debug,Warning, Info, Error, Fatal);
  • 日志打印要和printf一样简单易用;
  • 能够设置日志级别;
  • 占用空间小;
  • 可配置,甚至可以禁用日志;
  • 基于不同日志级别,支持颜色高亮;
  • 可以自定义配置,时间戳;
  • 支持RTOS;

以上是比较基本的功能,但是在嵌入式设备中,有的时候我们希望可以保存设备的运行日志,我们需要以下的一些功能;

  • 支持多种访问方式,比如串口终端,保存到嵌入式文件系统中;
  • 支持shell命令行通过串口终端进行访问;

以上这些需求不一定会全部实现。

除了常用的log4clog4cpp,下面给大家推荐3个非常不错的开源日志库,比较适合用在单片机的项目中。从开始的轻量,到后面的功能丰富,最后一个很强大,所以请耐心看到最后。



我们平时开发中,log打印必不可少,仅仅使用printf,则log信息不好定位。一些开源稳定、成熟的log模块功能往往比较强大,而我们可能又不需要那么多功能。

这里简单分享一个我自己用的一个极简的log模块:log颜色可设置、带时间戳、文件、行号、函数。

这个log模块仅包含log.h与log.c两个文件。

log模块代码

log.h:

#ifndef LOG_H
#define LOG_H

#ifdef __cplusplus
extern "C" {
#endif

#define LOG_BUF_SIZE 1024

typedef long long (*get_sys_time_ms_def)(void);

enum log_color
{
    COLOR_NULL  = 0,
    RED    = 1,
    GREEN  = 2,
    YELLOW = 3,
    BLUE   = 4
};

void log_print(enum log_color color, const char *file, int line, const char *func, const char* fmt, ...);
void log_time_register(get_sys_time_ms_def p_get_sys_time_ms);

#define LOG_D(...) log_print(BLUE, __FILE__, __LINE__, __FUNCTION__, __VA_ARGS__)

#ifdef __cplusplus
}
#endif
#endif

log.c:

#include <stdio.h>
#include <stdarg.h>
#include "log.h"

static long long default_get_sys_time_ms(void)
{
     return (long long)0;
}

static get_sys_time_ms_def s_get_sys_time_ms = default_get_sys_time_ms;

void log_time_register(get_sys_time_ms_def p_get_sys_time_ms)
{
    s_get_sys_time_ms = p_get_sys_time_ms;
}

void log_print(enum log_color color, const char *file, int line, const char *func, const char* fmt, ...)
{
    va_list ap;
    char buf[LOG_BUF_SIZE] = {0};
    long long time = s_get_sys_time_ms();

    va_start(ap, fmt);
    vsnprintf(buf, sizeof(buf), fmt, ap);
    va_end(ap);

 switch(color)
    {
  case COLOR_NULL:
   printf("<%lld ms>[%s:%d %s] %s ", time, file, line, func, buf);
   break;
  case RED:
   printf("\033[31m<%lld ms>[%s:%d %s] %s\033[0m", time, file, line, func, buf);
   break;
  case GREEN:
   printf("\033[32m<%lld ms>[%s:%d %s] %s\033[0m", time, file, line, func, buf);
   break;
  case YELLOW:
   printf("\033[33m<%lld ms>[%s:%d %s] %s\033[0m", time, file, line, func, buf);
   break;
  case BLUE:
   printf("\033[34m<%lld ms>[%s:%d %s] %s\033[0m", time, file, line, func, buf);
   break;
        default:
            break;
    }
}

其中,默认打印ms级的系统时间。因为不同的平台(Linux、Windows、STM32等),获取系统时间的方式都不一样。

使用时,再根据不同的平台自己定义一个获取系统时间的函数,以注册的方式进行绑定。不注册获取时间函数也不影响使用,时间戳打印为0。

log模块测试

1、Linux平台

log_test.c:

#include <stdio.h>
#include <sys/time.h>
#include "log.h"

static long long linux_get_sys_time_ms(void)
{
    long long time_ms = 0;
    struct timeval tv;

    gettimeofday(&tv, NULL);
    time_ms = (long long)tv.tv_sec * 1000 + tv.tv_usec / 1000;

    return (long long)time_ms;
}

int main(void)
{
    log_time_register(linux_get_sys_time_ms);

    char ch = 'a';
    char str[10] = "ZhengN";
    float float_val = 10.10;
    int num = 88;
    double double_val = 10.123456;
    LOG_D("字符为 %c \n", ch);
    LOG_D("字符串为 %s \n" , str);
    LOG_D("浮点数为 %f \n", float_val);
    LOG_D("整数为 %d\n" , num);
    LOG_D("双精度值为 %lf \n", double_val);
    LOG_D("八进制值为 %o \n", num);
    LOG_D("十六进制值为 %x \n", num);

    return 0;
}

编译,运行:

图片

第18行屏蔽掉:

图片

2、Windows平台

log_test.c:

#include <stdio.h>
#include <windows.h>
#include "log.h"

static long long win_get_sys_time_ms(void)
{
    long long time_ms = 0;

    time_ms = GetTickCount();

    return time_ms;
}

void test(void)
{
    LOG_D("Hello world\n");
}

int main(void)
{
    log_time_register(win_get_sys_time_ms);

    char ch = 'a';
    char str[10] = "ZhengN";
    float float_val = 10.10;
    int num = 88;
    double double_val = 10.123456;
    LOG_D("字符为 %c \n", ch);
    LOG_D("字符串为 %s \n" , str);
    LOG_D("浮点数为 %f \n", float_val);
    LOG_D("整数为 %d\n" , num);
    LOG_D("双精度值为 %lf \n", double_val);
    LOG_D("八进制值为 %o \n", num);
    LOG_D("十六进制值为 %x \n", num);
    test();

    return 0;
}

编译,运行:

图片



rxi_log

项目地址:https://github.com/rxi/log.c

基于 C99 实现的简单日志库,具体输出如下所示;

图片image-20211204142024466

具体用法

将源码中的log.clog.h集成到你的项目中即可,需要打印日志的话,调用下面的API即可,如下所示;

log_trace(const char *fmt, ...);
log_debug(const char *fmt, ...);
log_info(const char *fmt, ...);
log_warn(const char *fmt, ...);
log_error(const char *fmt, ...);
log_fatal(const char *fmt, ...);

除了这些API,还有log_set_quietlog_set_lockLOG_USE_COLOR等等,详情请看原项目。


ulog

项目地址:https://github.com/rdpoor/ulog

uLog 为嵌入式微控制器或任何资源有限的系统提供结构化的日志记录机制。它继承了流行的 Log4cLog4j 平台背后的一些概念,但开销更低。

uLog 的一些特点:

  • uLog 易于集成到几乎任何环境中,由一个头文件和一个源文件组成,并且是用纯 C 编写的。
  • uLog 提供熟悉的严重级别(CRITICAL、ERROR、WARNING、INFO、DEBUG、TRACE)。
  • uLog 支持多个用户定义的输出(控制台、日志文件、内存缓冲区等),每个输出都有自己的报告阈值级别。
  • uLog 是具有最小依赖性的“积极独立”,仅需要 stdio.h、string.h 和 stdarg.h。
  • 当您不使用 uLog 时,它不会妨碍您:如果 ULOG_ENABLED 在编译时未定义,则不会生成日志记录代码。
  • uLog 已经过很好的测试。有关详细信息,请参阅随附的 ulog_test.c 文件。

图片color coding



EasyLogger

项目地址:https://github.com/armink/EasyLogger

图片TextColor

这个项目我用了很长时间,强烈推荐,是RT-Thread大佬的作品,已经集成到RTOS的内部了,支持的功能非常丰富,基本满足各种开发的需求。

特点如下:

  • 轻量,ROM<1.6K, RAM<0.3K
  • 支持多种访问模式(例如:终端、文件、数据库、串口、485、Flash…);
  • 日志内容可包含级别、时间戳、线程信息、进程信息等;
  • 线程安全,并支持 异步输出缓冲输出 模式;
  • 支持多种操作系统(RT-Thread、UCOS、Linux、Windows…),也支持裸机平台
  • 日志支持 RAW格式 ,支持 hexdump
  • 支持按 标签级别关键词 进行动态过滤;
  • 各级别日志支持不同颜色显示;
  • 扩展性强,支持以插件形式扩展新功能。

以上只是这个项目的其中一部分,具体可以参考项目地址。


总结

在单片机/嵌入式上使用的C语言日志库,一般来说,要求该日志库不能依赖出C语言标准库之外的库,因此这也决定了在嵌入式领域的C语言日志库不可能有非常丰富的功能。

如果只是想有一个比printf功能更强大的打印,那么可以考虑用 rxi_log。

如果想将打印输出到串口,或者嵌入式文件系统中,那么建议适配 EasyLogger。

一般在单片机/嵌入式领域,都是裸机或者RTOS,如果是嵌入式Linux操作系统,那就可以使用一些更加强大的日志系统,比如zlog日志系统模块基础、C语言实现一个日志模块、zlog日志模块基础

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2022-03-11 22:23:57  更:2022-03-11 22:25:11 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 6:18:02-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码