ESP32 IDF开发 驱动篇④调试打印hello world讲解


别迷路-导航栏
快速导航找到你想要的(文章目录)

此篇文章如果对你有用,请点赞收藏,您的支持就是博主坚持的动力。

1、博主写这篇技术文章的目的:

(1)熟悉esp_log相关API;
(2)掌握esp_log相关API的使用方法;
(3)学会如何建自己的功能;
(4)系统启动流程的基本分析;

2、前言

我们在开发项目中,很多时候为了方便调试,会在关键的地方打印出自己想输出的信息,以便观察程序运行的当前状态。

3、原理

打印调试信息采用的是串口通讯(具体的串口通讯将在后续介绍)是ESP32 自有一个串口用于程序下载和 log 打印。

4、相关函数

esp32 idf串口打印的在esp_log.h文件中定义

*void esp_log_level_set(const char tag, esp_log_level_t level)
设置给定标签的日志级别。此功能不能将日志级别提高到menuconfig中的CONFIG_LOG_DEFAULT_LEVEL所设置的级别。要将日志级别提高到给定文件的默认级别以上,请在esp_log.h包含在文件中之前,将LOG_LOCAL_LEVEL定义为ESP_LOG_ *值之一。
tag:要启用的日志条目的标签。 必须为非NULL 0终止字符串。 值“ *”将所有标签的日志级别重置为给定值。
level:选择要启用的日志级别。 仅显示此级别和较低详细级别的日志。

uint32_t esp_log_timestamp(void)
返回在日志输出中使用的时间戳的函数,以毫秒为单位。(注:系统启动后将以FreeRTOS滴答计数。)

*char esp_log_system_timestamp(void)
该函数返回要在日志输出中使用的系统时间戳,格式HH:MM:SS.sss

uint32_t esp_log_early_timestamp(void)
返回时间戳,以毫秒为单位。该功能使用硬件周期计数器,并且不依赖于操作系统,因此可以在应用程序崩溃后安全使用。

**void esp_log_write(esp_log_level_tlevel, const char tag, const char format, …)

将消息写入日志。此功能不能直接使用。 而是使用ESP_LOGE,ESP_LOGW,ESP_LOGI,ESP_LOGD和ESP_LOGV宏之一。不应在中断中使用此功能或这些宏。

ESP_LOGE(tag, format, …) E error级别(最低)
ESP_LOGW(tag, format, …) W warning 级别
ESP_LOGI(tag, format, …) I info 级别
ESP_LOGD(tag, format, …) D debug 级别
ESP_LOGV(tag, format, …) V verbose 级别(最高)
ESP_LOG_LEVEL(level, tag, format, …)

参数
tag:日志的标签,可在运行时通过esp_log_level_set更改日志级别。
level:输出日志的级别。

format:输出日志的格式。 参考printf
…:要替换到日志中的变量。参考printf

Log level 的枚举过程:

typedef enum {
    ESP_LOG_NONE,       /*没有日志输出 */
    ESP_LOG_ERROR,      /*严重错误,软件模块无法自行恢复 错误消息*/
    ESP_LOG_WARN,       /*已采取恢复措施的错误条件  警告消息*/
    ESP_LOG_INFO,       /* 描述事件正常流程的信息消息 正常消息*/
    ESP_LOG_DEBUG,      /*正常使用不需要的额外信息(值,指针,大小等) 调试消息*/
    ESP_LOG_VERBOSE     /*较大的调试信息块或频繁出现的消息 详细消息*/
} esp_log_level_t;

5、新建自己的工程

在msys32\esp-idf\examples目录下复制get-started基本工程的文件夹,改名字为自己的工程名字,我这里改为hello_world,然后在Makefile文件中将PROJECT_NAME := 工程名字

PROJECT_NAME := hello_world

CMakeLists相关文件是在使用cmake编译使用的,这里不使用。

6、实例分析

Make menuconfig
进入配置界面在此目录下默认的输出级别是ESP_LOG_INFO
component config-> Log output-> Default log verbosity
然后需要设置下载的串口Serial flasher config -> Default serial port修改为自己的端口
在这里插入图片描述
make flash monitor开始编译

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"

static const char *TAG = "hello_world";

void app_main(void)
{
    //系统默认是ESP_LOG_INFO级别
    ESP_LOGE(TAG, "ESP_LOGE test!\n");
    ESP_LOGW(TAG, "ESP_LOGW test!\n");
    ESP_LOGI(TAG, "ESP_LOGI test!\n");
    ESP_LOGD(TAG, "ESP_LOGD test!\n");//不输出
    ESP_LOGV(TAG, "ESP_LOGV test!\n");//不输出

    ESP_LOG_LEVEL(ESP_LOG_ERROR, TAG, "ESP_LOG_LEVEL test!\n") ;
    ESP_LOGI(TAG,"----------------------\n");
    while(1) 
    {
        esp_log_level_set("*", ESP_LOG_INFO);//设置输出所有的ESP_LOG_INFO消息
        ESP_LOGI(TAG, "TAG=* test!\n");
        ESP_LOGI("test", "hello world test!\n");
        ESP_LOGW(TAG,"ESP_LOGW test!\n");
        ESP_LOGE(TAG,"ESP_LOGE test!\n");
        ESP_LOGI(TAG,"----------------------\n");
        vTaskDelay(1000 / portTICK_RATE_MS);

        esp_log_level_set(TAG, ESP_LOG_INFO);//设置只输出 TAG 的ESP_LOG_INFO消息
        ESP_LOGI(TAG, "TAG=ESP_LOG_INFO test!\n");
        ESP_LOGI("test", "hello world test!\n");//输出TAG=test 系统默认是ESP_LOG_INFO级别
        ESP_LOGW(TAG,"ESP_LOGW test!\n");
        ESP_LOGE(TAG,"ESP_LOGE test!\n");
        ESP_LOGI(TAG,"----------------------\n");
        vTaskDelay(1000 / portTICK_RATE_MS);

        esp_log_level_set(TAG, ESP_LOG_DEBUG);//设置只输出 TAG 的ESP_LOG_DEBUG消息
        ESP_LOGD(TAG, "ESP_LOGD test!\n");//不输出,只能设置高于默认级别的
        ESP_LOGI(TAG, "ESP_LOGI test!\n");
        ESP_LOGW(TAG,"ESP_LOGW test!\n");
        ESP_LOGE(TAG,"ESP_LOGE test!\n");

        esp_log_level_set(TAG, ESP_LOG_WARN);//设置只输出 TAG 的ESP_LOG_DEBUG消息
        ESP_LOGD(TAG, "ESP_LOGD test!\n");//不输出
        ESP_LOGI(TAG, "ESP_LOGI test!\n");//不输出
        ESP_LOGW(TAG,"ESP_LOGW test!\n");
        ESP_LOGE(TAG,"ESP_LOGE test!\n");
        vTaskDelay(1000 / portTICK_RATE_MS);

        esp_log_level_set(TAG, ESP_LOG_DEBUG);//设置只输出 TAG 的ESP_LOG_DEBUG消息,使用函数ESP_LOG_LEVEL
        ESP_LOG_LEVEL(ESP_LOG_DEBUG, TAG, "----------------------\n") ;

        ESP_LOGI(TAG, "timestamp Start Time %d!\n",esp_log_timestamp());
        vTaskDelay(1000 / portTICK_RATE_MS);
        ESP_LOGI(TAG, "timestamp End Time %d!\n",esp_log_timestamp());

        ESP_LOGI(TAG, "timestamp system Time %s!\n",esp_log_system_timestamp());
        ESP_LOG_LEVEL(ESP_LOG_DEBUG, TAG, "----------------------\n") ;
    
    }
}

输出结果如下:
在这里插入图片描述
从输出结果可以看出在调整esp_log_level_set(TAG, ESP_LOG_DEBUG)时调用ESP_LOG_LEVEL这个函数才可以输出调试信息。

7、系统启动调用简单分析

ESP32 开发程序中有且只能有一个 app_main 函数,该函数是用户程序的入口,相当于其它系统中的 main 函数。但在 app_main 之前,系统还有一段初始化的过程,其大致可以分为以下三个过程:
1. ROM 中的第一级引导加载程序将闪存偏移 0x1000 的第二级引导加载程序映像加载到 RAM(IRAM 和 DRAM);
2. 第二级引导程序从闪存加载分区表和主应用程序映像,主应用程序包含 RAM 段和通过闪存缓存映射的只读段;
3. 主应用程序执行,此时可以启动第二个 CPU 和 RTOS 调度程序。

在cpu_start.c文件中app_main函数会被main_task调用,而main_task函数在start_cpu0_default函数中使用任务分配的方式创建一个任务
portBASE_TYPE res = xTaskCreatePinnedToCore(&main_task, “main”, ESP_TASK_MAIN_STACK,// 3584字节
NULL, ESP_TASK_MAIN_PRIO,//默认为1
NULL, 0);
main_task 的任务是可以配置主任务堆栈大小和优先级,当然我们可以使用此任务进行
初始的应用程序特定设置,例如启动其它任务。应用程序还可以使用事件循环。但是需要注意的是,如果 app_main 函数返回,main_task 将被删除。

详细的启动流程及分区表比较复杂,请参考
【ESP32 IDF开发 驱动篇⑩ 存储NVS高级应用和自定义分区表】
【ESP32 IDF开发 系统篇⑪ 系统启动流程及硬件复位问题分析】

所有文章源代码:https://download.csdn.net/download/lu330274924/88518092

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

物联网程序猿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值