Clion开发STM32之日志模块(参考RT-Thread)

news2024/11/18 17:43:09

前言

  1. 日志对于开发和排错方面有着很重要的影响。
  2. 通过查看RT-Thread的源码,将日志的打印输出划分到具体的文件和通过宏定义对具体的日志等级进行划分,这样就比较方便。
  3. 结合此源码的形式将其分离出来,作为自己项目的日志框架进行使用
  4. 分为日志驱动和从RT-Thread那边移植过来的dbg头文件

相关函数类型定义(根据需要自行选取)

/*------------------------------------------------通用函数类型定义-----------------------------------------------*/
/*基础函数类型定义(无参,无返回)*/
typedef void (*fn_base_def_t)(void);

/*基础函数类型定义(无参,有返回)*/
typedef void *(*fn_base_ret_def_t)(void);

/*基础函数类型定义(有参,无返回)*/
typedef void (*fn_base_par_def_t)(void *data);

/*基础函数类型定义(有参,有返回)*/
typedef void *(*fn_base_par_ret_def_t)(void *data);
/*------------------------------------------------通用函数类型定义----------------------------------------------*/
/*发送数据函数类型定义*/
typedef void (*fn_send_def_t)(void *data, uint16_t len);

/*接收数据函数类型定义*/
typedef uint16_t (*fn_rec_data_def_t)(void *retData);

/*发送数据(带地址)函数类型定义*/
typedef bool (*fn_send_addr_def_t)(uint16_t addr, void *data, uint16_t len);

/*接收数据(带地址)函数类型定义*/
typedef bool (*fn_rec_data_addr_def_t)(uint16_t addr, void *data, uint16_t len);

/*延迟函数类型定义*/
typedef void (*fn_delay_def_t)(uint32_t delay);

/*日志函数类型定义*/
typedef void (*fn_debug_log_def_t)(char *format, ...);

日志驱动(作为具体对接硬件,这里是通过函数回调的方式进行解耦)

头文件

/*******************************************************************************
 *  Copyright (c) [scl]。保留所有权利。
 ******************************************************************************/
#ifndef STM32F103VET6_PROJECT_SYS_CORE_LOG_H
#define STM32F103VET6_PROJECT_SYS_CORE_LOG_H

#include "sys_core_conf.h"
#include "sys_core_typedef.h"
/**
 * @brief 日志缓存大小
 */
#define LOG_BUFFER_SIZE 512


/**
 * @brief 自定义格式化打印输出
 * @param format
 * @param ...
 */
void os_ps(char *format, ...);


/**
 * @brief 源数据记录
 * @param data 数据
 * @param len  数据长度
 */
void os_log(uint8_t *data, uint16_t len);

/**
 * 设置日志回调(如果没有设置,os_ps和os_log不生效)
 * @param call
 */
void os_log_call_set(fn_send_def_t call);
/****************************************不能保证输出完整性,则需要设置以下回调***********************************************/
/**
 * @brief 设置加锁
 * @param lock_call
 */
void os_log_set_lock(fn_base_def_t call);

/**
 * @brief 设置解锁
 * @param lock_call
 */
void os_log_set_unlock(fn_base_def_t call);

#endif //STM32F103VET6_PROJECT_SYS_CORE_LOG_H

源文件

/*******************************************************************************
 *  Copyright (c) [scl]。保留所有权利。
 ******************************************************************************/
#include "sys_core_log.h"
#include <stdio.h>
#include <stdarg.h>

#define log_not_null_run(fn) if(fn!=NULL) fn()

static void (*lock)(void) =NULL;

static void (*unlock)(void) =NULL;

static void (*log_cal)(void *data, uint16_t len) =NULL;

static char os_tx_buf[LOG_BUFFER_SIZE];

void os_ps(char *format, ...) {
    log_not_null_run(lock);
    if (log_cal != NULL) {
        va_list v_args;
        va_start(v_args, format);
        // 如果成功,则返回写入的字符总数,否则返回一个负数。
        int len = vsnprintf((char *) &os_tx_buf[0], (size_t)
                sizeof(os_tx_buf), (char const *) format, v_args);
        va_end(v_args);
        if (len > 0) {
            log_cal(os_tx_buf, len);
        }
    }
    log_not_null_run(unlock);
}


void os_log(uint8_t *data, uint16_t len) {
    if (log_cal != NULL) {
        log_cal(data, len);
    }
}

/**
 *
 * @param call 日志记录回调注册
 */
void os_log_call_set(fn_send_def_t call) {
    log_cal = call;
}

/**
 * @brief 设置加锁
 * @param lock_call
 */
void os_log_set_lock(fn_base_def_t call) {
    lock = call;
}

/**
 * @brief 设置解锁
 * @param lock_call
 */
void os_log_set_unlock(fn_base_def_t call) {
    unlock = call;
}

RT-Thread的日志模块

通过 #define PRINTF os_ps 与日志驱动进行绑定,根据需要可以换成自定义的格式输出

头文件

#ifndef STM32_F1XX_TEMPLATE_SYS_DBG_H
#define STM32_F1XX_TEMPLATE_SYS_DBG_H

#include "sys_core_log.h"

#define PRINTF os_ps
#ifdef DBG_ENABLE

#ifdef DBG_LVL
#ifndef DBG_LEVEL
#define DBG_LEVEL         DBG_LVL
#endif
#else
/* compatible with old version */
#ifndef DBG_LEVEL
#define DBG_LEVEL         DBG_WARNING
#endif
#endif /* DBG_LVL */

/*
 * The color for terminal (foreground)
 * BLACK    30
 * RED      31
 * GREEN    32
 * YELLOW   33
 * BLUE     34
 * PURPLE   35
 * CYAN     36
 * WHITE    37
 */
#ifdef DBG_COLOR
#define _DBG_COLOR(n)        PRINTF("\033["#n"m")
#define _DBG_LOG_HDR(lvl_name, color_n)                    \
    PRINTF("\033["#color_n"m[" lvl_name "/" DBG_SECTION_NAME "] ")
#define _DBG_LOG_X_END                                     \
    PRINTF("\033[0m\n")
#else
#define _DBG_COLOR(n)
#define _DBG_LOG_HDR(lvl_name, color_n)                    \
    PRINTF("[" lvl_name "/" DBG_SECTION_NAME "] ")
#define _DBG_LOG_X_END                                     \
    PRINTF("\r\n")
#endif /* DBG_COLOR */

/*
 * static debug routine
 * NOTE: This is a NOT RECOMMENDED API. Please using LOG_X API.
 *       It will be DISCARDED later. Because it will take up more resources.
 */
#define dbg_log(level, fmt, ...)                            \
    if ((level) <= DBG_LEVEL)                               \
    {                                                       \
        switch(level)                                       \
        {                                                   \
            case DBG_ERROR:   _DBG_LOG_HDR("E", 31); break; \
            case DBG_WARNING: _DBG_LOG_HDR("W", 33); break; \
            case DBG_INFO:    _DBG_LOG_HDR("I", 32); break; \
            case DBG_LOG:     _DBG_LOG_HDR("D", 0); break;  \
            default: break;                                 \
        }                                                   \
         PRINTF(fmt, ##__VA_ARGS__);                     \
        _DBG_COLOR(0);                                      \
    }

#define dbg_here                                            \
    if ((DBG_LEVEL) <= DBG_LOG){                            \
        PRINTF(DBG_SECTION_NAME " Here %s:%d\n",__FUNCTION__, __LINE__);\
    }

#define dbg_log_line(lvl, color_n, fmt, ...)                \
    do                                                      \
    {                                                       \
        _DBG_LOG_HDR(lvl, color_n);                         \
        PRINTF(fmt, ##__VA_ARGS__);                     \
        _DBG_LOG_X_END;                                     \
    }                                                       \
    while (0)

#define dbg_raw(...)         PRINTF(__VA_ARGS__);

#else
#define dbg_log(level, fmt, ...)
#define dbg_here
#define dbg_enter
#define dbg_exit
#define dbg_log_line(lvl, color_n, fmt, ...)
#define dbg_raw(...)
#endif /* DBG_ENABLE */

#if (DBG_LEVEL >= DBG_LOG)
#define LOG_D(fmt, ...)      dbg_log_line("D", 33, fmt, ##__VA_ARGS__)
#else
#define LOG_D(...)
#endif

#if (DBG_LEVEL >= DBG_INFO)
#define LOG_I(fmt, ...)      dbg_log_line("I", 32, fmt, ##__VA_ARGS__)
#else
#define LOG_I(...)
#endif

#if (DBG_LEVEL >= DBG_WARNING)
#define LOG_W(fmt, ...)      dbg_log_line("W", 33, fmt, ##__VA_ARGS__)
#else
#define LOG_W(...)
#endif

#if (DBG_LEVEL >= DBG_ERROR)
#define LOG_E(fmt, ...)      dbg_log_line("E", 31, fmt, ##__VA_ARGS__)
#else
#define LOG_E(...)
#endif
#define LOG_RAW(...)         dbg_raw(__VA_ARGS__)
#endif //STM32_F1XX_TEMPLATE_SYS_DBG_H

示例

/*******************************************************************************
 *  Copyright (c) [scl]。保留所有权利。
 ******************************************************************************/

#include "app_conf.h"

#if APP_CONFIG_LOG
#define DBG_ENABLE
#define DBG_SECTION_NAME "log_conf"
#define DBG_LEVEL DBG_LOG

#include "sys_dbg.h"

static void com_send(void *data, uint16_t len) {
    HAL_UART_Transmit(com1_handle, data, len, 100);
}

static void init(void) {
    bsp_SerialInit(com1_id, 115200);
    os_log_call_set(com_send);
}


static void after_init(void) {
    UART_HandleTypeDef *ptr = conv_uart_handle_ptr(handle_get_by_id(com1_id));
    LOG_D("app start:%lu", ptr->Init.BaudRate);
    ptr = conv_uart_handle_ptr(handle_get_by_id(com1_id));
    LOG_D("app start:%d", ptr->Init.BaudRate);
}

sys_init_export(app_log, init);
sys_after_init_export(app_log, after_init);
#endif

结果

在这里插入图片描述

注意

  1. 在使用RTOS的框架时,建议设置以下函数
/**
 * @brief 设置加锁
 * @param lock_call
 */
void os_log_set_lock(fn_base_def_t call);

/**
 * @brief 设置解锁
 * @param lock_call
 */
void os_log_set_unlock(fn_base_def_t call);

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

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

相关文章

crossover软件下载2023最新版虚拟机

在Mac系统中一直存在一个比较令用户们头疼的问题&#xff0c;那就是安装不了想要的Windows软件。如果使用的第一台电脑就是MacBook那接触到的Windows软件想必并不是很多。但我们中的大多数人都是从小先学习了Windows的操作系统&#xff0c;再过渡到Mac系统上的。 那有小伙伴会…

最新基于MATLAB 2023a的机器学习、深度学习实践应用

MATLAB 2023版的深度学习工具箱&#xff0c;提供了完整的工具链&#xff0c;使您能够在一个集成的环境中进行深度学习的建模、训练和部署。与Python相比&#xff0c;MATLAB的语法简洁、易于上手&#xff0c;无需繁琐的配置和安装&#xff0c;能够更快地实现深度学习的任务。 M…

Flink流批一体计算(4):Flink功能模块

目录 Flink功能架构 Flink输入输出 Flink功能架构 Flink是分层架构的分布式计算引擎&#xff0c;每层的实现依赖下层提供的服务&#xff0c;同时提供抽象的接口和服务供上层使用。 Flink 架构可以分为4层&#xff0c;包括Deploy部署层、Core核心层、API层和Library层 部署层…

基于SSM的宠物领养系统的设计与实现

1.引言 动物作为人类的宠物已经有几千年的历史了&#xff0c;尤其是猫和狗因其天性被人类所喜爱和推崇&#xff0c;好多的成语故事、俗语等都及它们有关。但是&#xff0c;近几年来由于生活节奏的加快&#xff0c;人们的压力增大&#xff0c;没有时间和空间去照顾宠物&#xf…

ProGuard 进阶系列(三) Java 类文件解析

书接上文&#xff0c;当我们从用户的配置文件中读取到所有的配置信息后&#xff0c;下一步便是将配置中的指定的类文件进行读取&#xff0c;构建需要混淆的 Java 类文件的语法树。在阅读类文件之前&#xff0c;先来看一下输入输出参数中的内容&#xff0c;我使用的是一个 Andro…

大一下暑期计划 + 2023字节青训营预告直播

目录 &#x1f33c;前言 &#x1f339;后端学习方法 &#x1f333;1&#xff0c;层次 &#x1f333;2&#xff0c;体系 &#x1f333;3&#xff0c;算法和数据结构 &#x1f333;4&#xff0c;总结 &#x1f339;前端学习方法 &#x1f333;基础 &#x1f339;求职中如…

如何在Microsoft Excel中使用LEN函数

如果你曾经想尝试查找一行文本中的字符数&#xff0c;你可以使用Microsoft Excel来查找&#xff0c;这要归功于LEN函数。以下是如何使用它。 一、什么是 LEN 函数 LEN函数是一个简单的计算函数&#xff0c;用于计算给定文本字符串中的所有字符&#xff0c;包括数字、字母、特…

【数据库课设】图书馆资源管理系统 源码+流程图+结构设计(借还图书 逾期罚款 图书管理 读者管理 信息查询)python实现

文章目录 一 实现功能&#xff08;1&#xff09;管理员功能&#xff08;2&#xff09;读者功能 二 数据流图三 概念结构设计四 文件目录五 源码&#xff1a;main.py六 运行截图 一 实现功能 &#xff08;1&#xff09;管理员功能 一个管理员编号对应一个密码&#xff0c;且需…

redis—安装以及可视化

前言 redis 是一种非关系型数据库&#xff0c;什么是非关系型数据库&#xff0c;之前我们在mysql专栏 也有提到过&#xff0c;这边就不再过多的赘述&#xff0c;忘记了的小伙伴可以再次阅读这篇文章 终于明白了数据库的【关系型】与【非关系型】 其实这还是挺重要的&#xff…

ruoyi+vue回显数字的问题,解决方案

在项目中用ruoyi框架和前端vue进行开发&#xff0c; 需求是在前端生成下拉框&#xff0c;下拉框中的内容需要调用后端接口进行数据返回&#xff0c; 现在新增的时候&#xff0c;数据已经返回了&#xff0c;但是再修改的时候&#xff0c;进行回显数据导致前端列表中展示出来的…

城市排水监测系统为城市排水防涝提质增效

城市化进程中&#xff0c;城市排水系统成为城市基础设施建设的重要组成部分。然而&#xff0c;随着气候变化和城市建设规模的扩大&#xff0c;极端天气和内涝风险不断增加&#xff0c;城市的排水系统面临巨大挑战。因此&#xff0c;建立一套智能化城市排水监测系统&#xff0c;…

【python】一些常用的pandas技巧

有了gpt之后&#xff0c;确实很多代码都可以让gpt给改错。嘎嘎香 merge多个dateframe https://stackoverflow.com/questions/44327999/how-to-merge-multiple-dataframes data_net [a,b,c,d] net_merged reduce(lambda left,right: pd.merge(left,right,on[key column],ho…

小程序安全指南:保护用户数据的最佳实践

第一章&#xff1a;引言 近年来&#xff0c;小程序已成为移动应用开发的重要组成部分。它们为用户提供了方便的功能和个性化的体验&#xff0c;然而&#xff0c;与此同时&#xff0c;小程序安全问题也引起了广泛的关注。保护用户数据是开发者应该高度重视的问题。在本指南中&a…

JavaScript ES11新特性

文章目录 导文可选链操作符&#xff08;Optional Chaining Operator&#xff09;空值合并操作符&#xff08;Nullish Coalescing Operator&#xff09;动态 import() 函数BigInt 类型Promise.allSettled() 导文 JavaScript ES11&#xff0c;也被称为ES2020&#xff0c;引入了一…

经纬度、时差知识整理(理解与应用)

经纬度是经度与纬度的合称组成一个坐标系统&#xff0c;称为地理坐标系统&#xff0c;它是一种利用三度空间的球面来定义地球上的空间的球面坐标系统&#xff0c;能够标示地球上的任何一个位置。初一的同学在学地理这门课的时候&#xff0c;一上来很快就会学到经纬度这个概念。…

PC市场寒冬,大众还需要PC吗?

PC市场寒冬&#xff0c;大众还需要PC吗&#xff1f; PC&#xff08;个人电脑&#xff09;市场从2016年智能手机兴起之时便进入下滑态势&#xff0c;到2020年疫情发生后&#xff0c;居家办公、在线教育等需求曾给PC市场带来连续六个季度的增长。⁴ 好景不长&#xff0c;进入202…

mybatisplus分页total总数为0

mybatisplus分页total总数为0 背景&#xff1a;最近初始化新项目时&#xff0c;使用mybatisplus分页功能发现 records 有记录&#xff0c;但是 total 总是为0&#xff0c;于是开启了一顿“知识寻求”之路SpringBoot版本 <parent><groupId>org.springframework.boo…

Makerbase CANable V2.0 固件升级或替换

第1部分 应用软件与固件 应用软件CANable V2.0CANable V1.0cangaroocandleLight/slcan(支持CAN FD)candleLight/slcan/cantactBUSMASTER V3.2.2candleLightcandleLight/pcan/cantactTSMastercandleLightcandleLight/pcan/cantactPCAN-Explorer 5、pcan view不支持pcancantacts…

一文带你全面理解 MySQL 中的常用函数

0️⃣前言 MySQL是一种常用的关系型数据库管理系统&#xff0c;它提供了许多内置函数来处理数据。本文将介绍MySQL中的各种常用函数&#xff0c;包括字符串函数、日期函数、数学函数、聚合函数等。 文章目录 0️⃣前言1️⃣字符串函数1.1CONCAT函数1.2SUBSTRING函数1.3REPLACE函…

建设一个网站需要多长时间?

&#x1f482; 个人网站:【海拥】【游戏大全】【神级源码资源网】&#x1f91f; 前端学习课程&#xff1a;&#x1f449;【28个案例趣学前端】【400个JS面试题】&#x1f485; 寻找学习交流、摸鱼划水的小伙伴&#xff0c;请点击【摸鱼学习交流群】 目录 前言网站建设的基本步骤…