怎么在单片机裸机程序中移植EasyLogger?

news2024/12/22 19:05:14

 1、介绍

        EasyLogger 是一款超轻量级、高性能的C日志库,非常适合对资源敏感的软件项目。例如:IoT产品、可穿戴设备、智能家居等等。相比log4c、zlog这些知名的C日志库,EasyLogger的功能更加简单,提供给用户的接口更少,但上手会很快,更多实用功能支持以插件形式进行动态扩展。

目前EasyLogger支持以下功能:

  • 日志输出方式支持串口、Flash、文件等;

  • 日志内容可包含级别、时间戳、线程信息、进程信息等;

  • 支持多种操作系统,支持裸机;

  • 各级别日志支持不同颜色显示;

EasyLogger的GitHub代码地址:
GitHub - armink/EasyLogger: An ultra-lightweight(ROM<1.6K, RAM<0.3k), high-performance C/C++ log library. | 一款超轻量级(ROM<1.6K, RAM<0.3k)、高性能的 C/C++ 日志库icon-default.png?t=O83Ahttps://github.com/armink/EasyLogger

2、移植EasyLogger过程 

    2.1整体的移植思路

        (1)添加源码到裸机工程中;
        (2)实现需要的接口; 

    2.2 具体添加源码到工程的操作

     在移植的时候,可以参考从上面的链接中下载的ZIP文件解压出来的EasyLogger-master项目的readme文档和demo工程。

        通过这些可以对EasyLogger有一个大致的了解。docs中的API和port中的kernel.md有对于EasyLogger 核心功能移植说明和EasyLogger 核心功能 API 说明。重点看一下这部分!!!
        然后准备一份裸机工程文件,将printf重定向到串口打印,准备好之后开始移植easylogger。
首先是将下载好的开源文件中的easylogger复制到裸机工程中。(本人使用的是STM32F407芯片的板子,仅有LED和串口两部分的代码)

       将这个部分的源码,复制到准备好的裸机工程的third_lib文件夹下。然后打开keil工程,进行添加easylogger组件的源码文件。

  • port/elog_port.c:elog移植接口文件;

  • src/elog.c:           elog核心功能源码;

  • src/elog_utils.c:elog所用到的一些c库工具函数实现;

  • src/elog_buf.c(可选添加):elog缓冲输出模式源码;

  • src/elog_async.c(可选添加):elog异步输出模式源码;

 在像上图中添加了以后,再将easylogger/inc的头文件路径添加到keil中。如下图:
 

 对于串口的重定向部分的代码如下:(后续的输出日志信息要使用printf函数,所以需要进行添加这个串口重定向代码!)

int fputc(int ch, FILE *stream)
{
    /* 堵塞判断串口是否发送完成 */
    while((USART1->ISR & 0X40) == 0);

    /* 串口发送完成,将该字符发送 */
    USART1->TDR = (uint8_t) ch;

    return ch;
}

我将这部分代码放到了elog_port.c文件中,如下图:

     2.3 实现elog移植接口

      elog的移植接口都已经写好了,在elog_port.c文件中,只需要在函数体中添加代码即可。

① elog初始化接口

ElogErrCode elog_port_init(void);

如果涉及到后续elog使用资源的初始化,比如动态申请分配缓冲区内存,可以放在此接口中,本文中保持默认。这个暂时不需要调用,因为该接口会在调用elog_init函数中被调用。
② elog日志输出接口(重点)

//开头添加
#include <stdio.h>
....

void elog_port_output(const char *log, size_t size) {
    
    /* add your code here */
    //日志使用printf输出,printf已经重定向到串口USART1
    printf("%.*s", size, log);              //%s表示字符串输出,.<十进制数>是精度控制格式符,输出字符时表示输出字符的位数
}

 ③ 日志输出上锁/解锁接口
       该接口可以对日志输出接口进行上锁/解锁,以保证日志在并发输出时的正确性,本文中使用的是裸机程序,所以在此使用关闭全局中断来加锁,打开全局中断来解锁(STM32开关全局中断的方式很多,这里是直接操作 PRIMASK 寄存器来快速的屏蔽/打开全局中断)

//开头添加
#include "stm32f4xx.h"

void elog_port_output_lock(void) {
    
    /* add your code here */
    //关闭全局中断
     __set_PRIMASK(1);                       //使用的是裸机程序,所以在此使用关闭全局中断来加锁,打开全局中断来解锁:
}

/**
 * output unlock
 */
void elog_port_output_unlock(void) {
    
    /* add your code here */
    //开启全局中断
    __set_PRIMASK(0);
}

④ 系统信息获取接口
        elog提供了三个接口用来获取当前时间、获取进程号、获取线程号,因为本文中移植到裸机工程中,并且没有提供时间支持,所以这三个接口都返回空字符串。

/**
 * get current time interface
 *
 * @return current time
 */
const char *elog_port_get_time(void) {      //elog提供了三个接口用来获取当前时间、获取进程号、获取线程号,因为本文中移植到裸机工程中,并且没有提供时间支持,所以这三个接口都返回空字符串
    
    /* add your code here */
    
	return "";

}

/**
 * get current process name interface
 *
 * @return current process name
 */
const char *elog_port_get_p_info(void) {
    
    /* add your code here */
    return "";
}

/**
 * get current thread name interface
 *
 * @return current thread name
 */
const char *elog_port_get_t_info(void) {
    
    /* add your code here */
    return "";
    
}

        2.4 配置elog

        elog的核心功能开启宏定义和核心参数宏定义都在配置文件elog_cfg.h中,下面讲述其中重要的宏定义。
       这三个地方要特别的注意,第一个是日志输出的总开关,该宏必须要在这里进行定义。第二个是换行符宏定义,修改成\r\n。第三个是带有颜色的日志输出开关,在这里进行定义。
       移植时并没有添加异步输出和缓冲区输出的源码,所以将这两个功能关掉:
到此为止,就算移植并且配置完成了,下面就可以进行使用了。

3、使用EasyLogger

    3.1. 初始化elog

   ​​elog使用之前需要初始化,过程有三步
        ① 初始化elog 

    /* 初始化elog */
void elog_init(void);

         ② 设置日志输出格式

void elog_set_fmt(uint8_t level, size_t set);

       其中第一个参数表示设置哪个日志输出级别对应的输出格式,其二个参数是日志输出格式,枚举给出,可以自由组合搭配。

        ③ 启动elog

void elog_start(void);

接下来在main函数中的串口初始化函数之后,while(1)之前编写elog初始化代码:

    /* 初始化elog */
    elog_init();
    elog_set_text_color_enabled(true);                                     //要想五彩缤纷的日志,仅在elog_cfg.h中使能颜色输出还不够,还需要使用API开启输出

    /* 设置每个级别的日志输出格式 */
    //输出所有内容
    elog_set_fmt(ELOG_LVL_ASSERT, ELOG_FMT_ALL);
    //输出日志级别信息和日志TAG
    elog_set_fmt(ELOG_LVL_ERROR, ELOG_FMT_LVL | ELOG_FMT_TAG);
    elog_set_fmt(ELOG_LVL_WARN, ELOG_FMT_LVL | ELOG_FMT_TAG);
    elog_set_fmt(ELOG_LVL_INFO, ELOG_FMT_LVL | ELOG_FMT_TAG);
    //除了时间、进程信息、线程信息之外,其余全部输出
    elog_set_fmt(ELOG_LVL_DEBUG, ELOG_FMT_ALL & ~(ELOG_FMT_TIME | ELOG_FMT_P_INFO | ELOG_FMT_T_INFO));
    //输出所有内容
    elog_set_fmt(ELOG_LVL_VERBOSE, ELOG_FMT_ALL);

    /* 启动elog */
    elog_start();
    

    3.2. elog日志输出

        elog中每种级别都有一种完整方式,两种简化方式,使用时自行选择: 

#define elog_assert(tag, ...) 
#define elog_a(tag, ...) //简化方式1,每次需填写 LOG_TAG
#define log_a(...)       //简化方式2,LOG_TAG 在文件顶部定义,使用前无需填写 LOG_TAG

        比如上面这个elog_assert函数就有两种表达方法,我选择的是简化方式2。前两种在使用的时候只需要包含<elog.h>头文件即可,第三种方式除了包含头文件之外,还需要在文件开始定义TAG宏定义,使用起来和printf相同
首先在main.c文件开始定义TAG宏,包含头文件:


#define LOG_TAG    "main"   //使用简化方式2,LOG_TAG 在文件顶部定义,使用前无需填写 LOG_TAG(必须是在下面包含的头文件前进行定义,因为程序顺序执行)
#include "elog.h"
 

然后在main函数中编写的elog初始化代码之后,继续添加代码,测试elog的使用:

    
    log_a("Hello EasyLogger!");
    log_e("Hello EasyLogger!");
    log_w("Hello EasyLogger!");
    log_i("Hello EasyLogger!");
    log_d("Hello EasyLogger!");
    log_v("Hello EasyLogger!");

然后再进行编译,烧写,使用串口助手查看串口输出:

    另外串口助手无法显示颜色,如果想要输出有颜色的日志,请使用使用串口终端(Mobaxterm)查看串口输出!! 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2201120.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

肺腺癌预后新指标:全切片图像中三级淋巴结构密度的自动化量化|文献精析·24-10-09

小罗碎碎念 本期这篇文章&#xff0c;我去年分享过一次。当时发表在知乎上&#xff0c;没有标记参考文献&#xff0c;配图的清晰度也不够&#xff0c;并且分析的还不透彻&#xff0c;所以趁着国庆假期重新分析一下。 这篇文章的标题为《Computerized tertiary lymphoid structu…

基于springboot vue 校园失物招领平台的设计与实现

博主介绍&#xff1a;专注于Java&#xff08;springboot ssm springcloud等开发框架&#xff09; vue .net php phython node.js uniapp小程序 等诸多技术领域和毕业项目实战、企业信息化系统建设&#xff0c;从业十五余年开发设计教学工作☆☆☆ 精彩专栏推荐订阅☆☆☆☆…

【AIGC】OpenAI API在快速开发中的实践与应用:优化ChatGPT提示词Prompt加速工程

博客主页&#xff1a; [小ᶻZ࿆] 本文专栏: AIGC | ChatGPT 文章目录 &#x1f4af;前言&#x1f4af;使用最新型号确保最佳实践利用最新模型进行高效任务处理为什么要选择最新模型&#xff1f;结论 &#x1f4af;指令与上下文的分隔最佳实践分隔指令和上下文的重要性使用符…

叉车毫米波雷达防撞技术,保护叉车作业安全

在叉车作业频繁的仓库与物流中心&#xff0c;安全隐患往往隐藏于细微之处&#xff0c;稍有不便可能引发重大事故。我们的叉车毫米波防撞系统方案&#xff0c;正是针对这一痛点而精心设计的创新之作。该系统通过集成的毫米波雷达技术&#xff0c;实现了对叉车周边环境的实时、精…

【动态规划】dp之斐波那契数列模型

学习编程就得循环渐进&#xff0c;扎实基础&#xff0c;勿在浮沙筑高台 循环渐进Forward-CSDN博客 目录 循环渐进Forward-CSDN博客 第N个泰波那契序数 思路&#xff1a; 代码实现&#xff1a; 三步问题 思路&#xff1a; 代码实现&#xff1a; 使用最小花费爬楼梯 思路…

C语言 | 第十三章 | 二维数组 冒泡排序 字符串指针 断点调试

P 120 数组应用案例 2023/1/29 一、应用案例 案例一&#xff1a;创建一个char类型的26个元素的数组&#xff0c;分别 放置’A’-Z‘。使用for循环访问所有元素并打印出来。提示&#xff1a;字符数据运算 ‘A’1 -> ‘B’ #include<stdio.h>void main(){/*创建一个c…

【优选算法之BFS】No.15--- 经典BFS解决FloodFill算法和解决最短路问题

文章目录 前言一、BFS解决FloodFill算法示例&#xff1a;1.1 图像渲染1.2 岛屿数量1.3 岛屿的最⼤⾯积1.4 被围绕的区域 二、BFS解决最短路问题2.1 迷宫中离⼊⼝最近的出⼝2.2 最⼩基因变化2.3 单词接⻰2.4 为⾼尔夫⽐赛砍树 前言 &#x1f467;个人主页&#xff1a;小沈YO. &a…

Linux高级编程_31_消息队列

文章目录 消息队列作用&#xff1a;特点&#xff1a;消息队列限制值&#xff1a;注意&#xff1a;命令&#xff1a;ftok函数作用&#xff1a;语法&#xff1a; msgget函数作用&#xff1a;语法&#xff1a; msgsnd函数作用&#xff1a;语法&#xff1a; msgrcv函数作用&#xf…

QT实现QInputDialog中文按钮

这是我记录Qt学习过程心得文章的第三篇&#xff0c;主要是为了方便QInputDialog输入框的使用&#xff0c;通过自定义的方式&#xff0c;按钮中文化&#xff0c;统一封装成一个函数&#xff0c;还是写在了Skysonya类里面。 实现代码&#xff1a; //中文按钮文本输入对话框 QSt…

【gRPC】1—gRPC是什么

gRPC是什么 ⭐⭐⭐⭐⭐⭐ Github主页&#x1f449;https://github.com/A-BigTree 笔记链接&#x1f449;https://github.com/A-BigTree/Code_Learning ⭐⭐⭐⭐⭐⭐ 如果可以&#xff0c;麻烦各位看官顺手点个star~&#x1f60a; &#x1f4d6;RPC专栏&#xff1a;https://b…

鸿蒙--播放器状态控制

各个页面共享同一个播放状态&#xff0c;而且可以互相控制&#xff0c;如果传递来传递去会非常的麻烦&#xff0c;但是他们都是Tabs组件内的&#xff0c;我们在index页面提供一个状态&#xff0c;在各个组件接收即可 创建两个子组件&#xff0c;一个是播放控制的子组件&#xf…

1. Oracle 安装报错——环境变量过长

文章目录 1. 报错详细信息2. 解决方案2.1 方案一&#xff1a;修改配置文件cvu_prereq.xml2.2 方案二&#xff1a;修改环境变量配置 1. 报错详细信息 安装 Oracle 过程中&#xff0c;在执行 “先决条件检查” 时报错&#xff1a; 报错内容&#xff1a; This test checks wheth…

【自然语言处理】(3) --RNN循环神经网络

文章目录 RNN循环神经网络一、传统神经网络的问题二、RNN的基本结构三、计算过程4. RNN的局限 总结 RNN循环神经网络 循环神经网络&#xff08;RNN&#xff0c;Recurrent Neural Network&#xff09;是一种用于处理序列数据的神经网络模型。其关键特性在于网络节点&#xff08…

现代数字信号处理I-P2概率论学习笔记

目录 学习视频链接&#xff1a; 1. 三要素及关系 2. 期望和方差的定义及基本性质 2.1 期望&#xff08;均值&#xff09;定义&#xff1a; 在实际工作中很难获得随机变量的分布或者概率密度&#xff0c;用矩描述随机变量 2.2 期望基本性质&#xff1a; 2.3 方差定义 2.…

Android Studio Koala Feature Drop 稳定版现已推出

作者 / Android Studio 产品经理 Sandhya Mohan Android Studio Koala Feature Drop (2024.1.2) 现已推出&#xff01;&#x1f428; &#x1f517; Android Studio https://developer.android.google.cn/studio 今年早些时候&#xff0c;我们宣布每个 Android Studio 动物版本…

10月9日笔记(域内用户登录凭据窃取)

缺&#xff1a;BloodHound自动化分析域环境未实现&#xff08;环境问题&#xff09; 获取常见应用软件凭据 为了扩大可访问的范围&#xff0c;测试人员通常会搜索各种常见的密码存储位置&#xff0c;以获取用户凭据。一些特定的应用程序可以存储密码&#xff0c;以方便用户管…

python的特殊方法——魔术方法

前言 __init__(self[]) ​编辑 __call__(self [, ...]) __getitem__(self, key) __len__(self) __repr__(self) / __str__(self) __add__(self, other) __radd__(self, other) 参考文献 前言 官方定义好的&#xff0c;以两个下划线开头且以两个下划线结尾来命名的方法…

PostgreSQL学习笔记四:GUI管理工具

PostgreSQL 是一款广泛使用的开源关系数据库管理系统&#xff0c;拥有许多图形用户界面&#xff08;GUI&#xff09;工具来帮助用户更高效地管理数据库。以下是一些流行的 PostgreSQL 管理工具&#xff1a; pgAdmin&#xff1a; 一个流行的开源 PostgreSQL GUI 工具&#xff0c…

处理“navicat premium 2003 - 无法在 192.168.10.140 上连接到 MySQL 服务器(10060“未知错误“)”的问题:

以下是一些可能的解决方法来处理“navicat premium 2003 - 无法在 192.168.10.140 上连接到 MySQL 服务器&#xff08;10060"未知错误"&#xff09;”的问题&#xff1a; **一、检查 MySQL 服务状态** 1. 确认 MySQL 服务是否正在运行。你可以在服务器上通过任务管…

Django makemigrations时出现TypeError: ‘module‘ object is not iterable

使用Python 3.11、Django 5.1.2 写完model进行makemigrations时出现报错 报错的最下面提到了我自己创建的一个应用里的urls.py&#xff0c;尝试着给里面加上一个列表 然后问题解决了。。。 不知道为什么 makemigrations的时候会去检查urls。。。