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

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
好的,针对您的问题,我可以提供以下步骤: 1. 准备工作 首先,您需要准备好以下设备和软件: - ESP32 开发板 - LED 屏幕 - LVGL 库 - ESP32 IDF 框架 2. 连接 LED 屏幕 将 LED 屏幕连接到 ESP32 开发板。您需要查看 LED 屏幕的数据手册以确定正确的引脚连接方式。建议使用 SPI 接口连接,因为这是最常见的连接方式。 3. 安装 LVGL 库 LVGL 是一个用于嵌入式系统的 GUI 库,它可以与多种平台和操作系统一起使用。在本例中,我们将使用 ESP32 IDF 框架集成的 LVGL 版本。 您需要在 ESP32 IDF 中启用 LVGL 库。打开 `sdkconfig.defaults` 文件,找到以下行: ``` # CONFIG_LVGL_ENABLED is not set ``` 将其更改为: ``` CONFIG_LVGL_ENABLED=y ``` 然后,运行以下命令安装 LVGL: ``` make menuconfig # 进入配置界面 make lvgl # 安装 LVGL 库 ``` 4. 编写代码 接下来,您需要编写代码来控制 LED 屏幕并使用 LVGL 绘制图形。以下是一个示例代码片段: ```c #include "driver/gpio.h" #include "lvgl/lvgl.h" #define LED_SCREEN_CS GPIO_NUM_5 void app_main() { // 初始化 SPI 总线和 GPIO 引脚 spi_bus_config_t bus_config = { .mosi_io_num = GPIO_NUM_23, .sclk_io_num = GPIO_NUM_18, .miso_io_num = -1, // 不使用 MISO 引脚 .quadwp_io_num = -1, .quadhd_io_num = -1, .max_transfer_sz = 320*240*2, // LED 屏幕尺寸 }; spi_device_interface_config_t dev_config = { .clock_speed_hz = 10 * 1000 * 1000, // SPI 时钟频率 .mode = 0, .spics_io_num = LED_SCREEN_CS, .queue_size = 1, }; spi_device_handle_t spi_handle; spi_bus_initialize(VSPI_HOST, &bus_config, 1); spi_bus_add_device(VSPI_HOST, &dev_config, &spi_handle); // 初始化 LVGL 库 lv_init(); // 创建屏幕对象 lv_disp_drv_t disp_drv; lv_disp_drv_init(&disp_drv); disp_drv.flush_cb = led_screen_flush; lv_disp_drv_register(&disp_drv); // 创建例程 lv_obj_t *label = lv_label_create(lv_scr_act(), NULL); lv_label_set_text(label, "Hello, world!"); lv_obj_align(label, NULL, LV_ALIGN_CENTER, 0, 0); // 主循环 while (1) { lv_task_handler(); vTaskDelay(10 / portTICK_RATE_MS); } } void led_screen_flush(lv_disp_drv_t *disp_drv, const lv_area_t *area, lv_color_t *color_p) { spi_transaction_t t; memset(&t, 0, sizeof(t)); t.length = area->size; t.tx_buffer = color_p; gpio_set_level(LED_SCREEN_CS, 0); spi_device_transmit(spi_handle, &t); gpio_set_level(LED_SCREEN_CS, 1); } ``` 这段代码使用 ESP32 IDF 的 SPI 驱动程序和 LVGL 库控制 LED 屏幕。它还创建了一个简单的例程,显示“Hello, world!”文本。 5. 编译和烧录 最后,您需要使用 ESP32 IDF 编译和烧录代码。运行以下命令: ``` make -j4 make flash ``` 在烧录完成后,您应该能够看到 LED 屏幕显示“Hello, world!”文本。 希望这些步骤对您有所帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

物联网程序猿

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

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

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

打赏作者

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

抵扣说明:

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

余额充值