ESP32学习笔记(6)——Log日志库使用
一、printf是不可重入函数
printf不能在中断中被调用的原因是它是一个不可重入函数,而在中断中要避免调用不可重入函数,首先我们先说说什么是不可重入函数。
简单说来,区分一个函数是否可重入就是看这个函数能否在未返回的时候再次被调用。而造成一个函数不可重入的原因往往是使用了全局变量,如果一个函数未返回再执行一次会导致对全局变量的操作是不安全的。就例如我们常用的printf、malloc、free都是不可重入的函数,printf会引用全局变量stdout,malloc,free会引用全局的内存分配表,在多线程的环境下,如果没有很好的处理数据保护和互斥访问,就会发生错误。
二、ESP_LOGx日志
日志记录库提供了两种设置日志详细程度的方法:
-
在编译时:在menuconfig中,使用选项设置详细程度
CONFIG_LOG_DEFAULT_LEVEL
。详细程度高于的所有日志记录语句CONFIG_LOG_DEFAULT_LEVEL
将被预处理器删除。 -
在运行时:详细级别低于的所有日志
CONFIG_LOG_DEFAULT_LEVEL
默认情况下启用。该功能esp_log_level_set()
可用于按模块设置日志记录级别。模块由其标签标识,这些标签是可读的ASCII零终止字符串。
该功能
esp_log_level_set()
无法将日志记录级别设置为高于CONFIG_LOG_DEFAULT_LEVEL
。要在编译时增加特定文件的日志级别,请使用宏LOG_LOCAL_LEVEL
有以下详细级别:
-
ESP_LOGE
-错误(最低) -
ESP_LOGW
- 警告 -
ESP_LOGI
-信息 -
ESP_LOGD
-调试 -
ESP_LOGV
-详细(最高)
此外,ESP_EARLY_LOGx
每个宏都有相应的版本,例如ESP_EARLY_LOGE
。在初始化堆分配器和syscalls之前,只能在早期启动代码中显式使用这些版本。普通ESP_LOGx
宏也可以在编译引导加载程序时使用,但是它们将退回到与ESP_EARLY_LOGx
宏相同的实现方式。
考虑到线程安全,在FreeRTOS中尽量使用ESP_LOGx
来输出调试信息和打印消息。
三、包含头文件
#include "esp_log.h"
四、如何使用这个库
4.1 打印信息
在每个使用日志记录功能的C文件中,定义TAG变量,如下所示:
static const char* TAG = "MyModule";
然后使用日志记录宏之一生成输出,例如:
uint16_t ap_count = 0;
ESP_LOGI(TAG, "Total APs scanned = %u", ap_count);
4.2 更改详细级别
要在文件或组件范围内覆盖默认的详细级别,请定义LOG_LOCAL_LEVEL
宏。
在文件范围内,在包含之前定义它esp_log.h
,例如:
#define LOG_LOCAL_LEVEL ESP_LOG_VERBOSE
#include "esp_log.h"
在组件范围内,在组件makefile中定义它:
CFLAGS += -D LOG_LOCAL_LEVEL=ESP_LOG_DEBUG
要在运行时配置每个模块的日志记录输出,请esp_log_level_set()
按以下方式向函数添加调用:
esp_log_level_set("*", ESP_LOG_ERROR); // set all components to ERROR level
esp_log_level_set("wifi", ESP_LOG_WARN); // enable WARN logs from WiFi stack
esp_log_level_set("dhcpc", ESP_LOG_INFO); // enable INFO logs from DHCP client
4.3 通过JTAG登录到主机
默认情况下,日志记录库使用类似于vprintf的函数将格式化的输出写入专用UART。通过调用一个简单的API,所有日志输出都可以路由到JTAG,从而使日志记录速度提高了几倍。有关详细信息,请参阅“登录到主机”部分。
• 由 Leung 写于 2021 年 4 月 20 日