3.自定义工程目录配置CMakeLists

news2024/12/24 8:49:55

问题背景

        熟悉stm32keil开发的都知道,我们在编写不同的外设时,通常都会单独编写一个app文件夹或者是user文件夹之类的来存放不同外设功能的源文件和头文件。

        在前面一节2.构建第一个工程并烧录到ESP32开发板-CSDN博客中,我们是使用了一个乐鑫的官方所提供的一个hello world工程模板,这个工程里面我们表面上是用到了GPIO功能和USART功能,其他的一些功能我们暂时还没有用到,或者说暂时还没有包含其他功能模块。

        那么如果我一开始使用了模板是generic_gpio这个模板工程,在项目设计的前期实现我只需要gpio功能就够了,所以我就直接使用的是generic_gpio模板,后来我有需要使用到定时器功能,可能generic_gpio模板里面并没有包含这个功能,我们难道再去打开一个timer外设的模板工程吗,显然是比较麻烦的。

        虽然第二节我提到了我们一般会使用官方模板而不是自己新建一个空工程,但是那只是初期新建工程的时候是用官方模板,当我们新建工程完毕以后,我们需要对官方提供的模板进行修改,添加自己的文件目录以存放之后所使用的其他外设文件。因为官方的外设模板工程里面只有main文件夹下一个主函数的文件,我们总不可能把所有的外设实现函数统统写到这个主函数文件里面。

解决方案

        事实上官方已经提前想到了这个问题,乐鑫官方对 components 路径的介绍:“可选的 “components” 目录中包含了项目的部分自定义组件,并不是每个项目都需要这种自定义组件,但它有助于构建可复用的代码或者导入第三方(不属于 ESP-IDF)的组件。或者,您也可以在顶层 CMakeLists.txt 中设置 EXTRA_COMPONENT_DIRS 变量以查找其他指定位置处的组件。有关详细信息,请参阅 重命名 main 组件。如果项目中源文件较多,建议将其归于组件中,而不是全部放在 “main” 中。

        我们从官方的说明中可以获得两个方法来构建自己的工程文件

  • 1 在顶层目录下的 components 路径下添加组件。
  • 2 在顶层目录下的 CMakeLists.txt 中设置 EXTRA_COMPONENT_DIRS 变量以查找其他指定位置处的组件。

两种方法的实现原理:

我们观察顶层CMakeLists文件可以发现里面已有三行语句,其中第二行语句为include($ENV{IDF_PATH}/tools/cmake/project.cmake)

而配置项目、检索组件等任务都是 $ENV{IDF_PATH}/tools/cmake/project.cmake 决定的。

组件默认的搜索目录为 IDF_PATH/components、 PROJECT_DIR/components、和 EXTRA_COMPONENT_DIRS。

  • ESP-IDF内部组件 IDF_PATH/components
  • 扩展组件 EXTRA_COMPONENT_DIRS
  • 项目组件 PROJECT_DIR/components

IDF_PATH/components 用于系统组件。我们一般不会将文件放在这里面。

PROJECT_DIR/components、和 EXTRA_COMPONENT_DIRS 对应上面两种添加组件的方法。

在 PROJECT_DIR/components 中添加组件

步骤:

  1. 首先新建 PROJECT_DIR/components 路径。
  2. 在PROJECT_DIR/components 中添加我们自定义的组件,比如我添加了 led_key
  3. 将组件相关的头文件和源文件放到 led_key中,并新建 CMakeLists.txt 文件。
  4. 在 CMakeLists.txt 中添加源文件与头文件的路径。格式为:
idf_component_register(SRCS "led_key.c"
                    INCLUDE_DIRS "."
                    REQUIRES driver
                    )

        相信前两个SRC和INCLUDE_DIRS都很好理解,分别是包含源文件和头文件的路径,那么后一个QEQUIRES到底是干什么的,为啥要后面跟上driver?

        这里我先解释第一个问题,QEQUIRES可以理解为添加依赖。在说第二个问题之前我们先来看看现在的文件目录是个什么情况:

然后看下源文件和头文件里面的内容:

led_key.c

#include "led_key.h"


void LED_Init(void)
{
	gpio_config_t io_config;
	io_config.intr_type = GPIO_INTR_DISABLE;
	io_config.mode = GPIO_MODE_OUTPUT;
	io_config.pin_bit_mask = 1<<2;
	io_config.pull_down_en = GPIO_PULLDOWN_DISABLE;
	io_config.pull_up_en = GPIO_PULLUP_DISABLE;
	gpio_config(&io_config);

	//	esp_rom_gpio_pad_select_gpio (GPIO_NUM_2);
	//	gpio_set_direction(GPIO_NUM_2,GPIO_MODE_OUTPUT);
}

void KEY_Init(void)
{
	gpio_config_t io_config;
	io_config.intr_type = GPIO_INTR_POSEDGE;
	io_config.mode = GPIO_MODE_INPUT;
	io_config.pin_bit_mask = 1<<0;
	io_config.pull_down_en = GPIO_PULLDOWN_DISABLE;
	io_config.pull_up_en = GPIO_PULLUP_DISABLE;
	gpio_config(&io_config);
}

void led_blink( void * pvParameters )
{
	while(1)
	{
		gpio_set_level(GPIO_NUM_2,0);
		vTaskDelay(1000 / portTICK_PERIOD_MS);//FreeRTOS延时函数--毫秒级
		gpio_set_level(GPIO_NUM_2,1);
		vTaskDelay(1000 / portTICK_PERIOD_MS);
	}
}

void gpio_isr_handler(void* arg)
{
	static int flag = 0;
	flag ^= 1;
	gpio_set_level(GPIO_NUM_2,flag);
}

led_key.h

#ifndef __LED_KEY__
#define __LED_KEY__

#include "driver/gpio.h"

#define ESP_INTR_FLAG_DEFAULT 0

void LED_Init(void);
void KEY_Init(void);
void led_blink( void * pvParameters );
void gpio_isr_handler(void* arg);

#endif

        看完文件结构和文件内容之后,我们大体可以明白为什么要添加一个driver依赖了,因为我们在led_key.h里面包含了driver/gpio.h,而如果我们不去进行依赖的包含,在编译的时候就会报出这样的错误:

fatal error: driver/gpio.h: No such file or directory

这就是由于依赖问题没有解决导致,我们编写的led_key.h文件没有指定依赖,那么编译器将不知道去哪里找这个driver/gpio.h文件。

在自定义的 EXTRA_COMPONENT_DIRS 中添加组件

        有时候我们不想用官方所提供的存放组件集的组件目录components,我们仍然希望创建单独的组件目录,这时候就需要在最顶层CMakeLists文件里面添加一语句用于设置外部组件的路径

# The following lines of boilerplate have to be in your project's CMakeLists
# in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.16)

include($ENV{IDF_PATH}/tools/cmake/project.cmake)
set(EXTRA_COMPONENT_DIRS "./src")
project(myProject)

        比方说我们创建了一个叫做src的外部组件,就需要在最顶层CMakeLists文件添加set(EXTRA_COMPONENT_DIRS "./src"),

        创建自己存放组件集的组件目录,之后在组件目录下创建组件,不能直接创建组件目录,什么意思呢,就是我们要创建一个led的程序,需要在src下面再创建一个led的文件夹作为组件目录,再在led组件目录里面新建led.c源文件。src是一个组件集的目录。

        接下来的操作就和在PROJECT_DIR/components 中添加组件的操作一样了。其实这样做无非是吧官方提供的组件集文件名字替换为了自己起的组件集名字,然后由于顶层CMakeLists默认包含components组件集所以不需要我们添加,而我们自己创建的非components组件集属于外部组件,那么就需要在顶层说明一下外部组件集的路径了。

        

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

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

相关文章

数据管道架构设计一览

数据管道架构设计一览 今天来聊聊数据管道。 数据管道是现代系统中有效管理和处理数据的基本组成部分。 这些管道通常包括 5 个主要阶段&#xff1a; 收集&#xff08;Collect&#xff09;摄取&#xff08;Ingest&#xff09;存储&#xff08;Store&#xff09;计算&#x…

OpenCV(七)——灰度图像的阙值处理以及图像的边界填充

灰度图像的阙值处理 在OpenCV中利用threshold()对灰度图像进行阙值处理&#xff0c;该函数通过将图像中的每个像素值与一个给定的阈值进行比较来工作。如果像素值超过这个阈值&#xff0c;那么像素值将被设置成指定的最大值&#xff1b;如果没有超过阈值&#xff0c;则根据不同…

【干货】【常用电子元器件介绍】【晶体三极管】(二)--晶体三极管的应用

声明:本人水平有限,博客可能存在部分错误的地方,请广大读者谅解并向本人反馈错误。 一、 三极管电路的链接形式 三极管(transistor)是近代电子电路的核心组件。其 主要功能是做电流的开关,就如同控制水管中水流量的阀 (valve)。三极管工作情况模拟示意图如下图所示。   …

企业网站为什么要用OV级别的SSL证书?

部署OV SSL证书的网站&#xff0c;可在SSL证书详情中查看网站所属企业名称&#xff0c;可以让用户有效区分出钓鱼网站&#xff0c;鉴别网站的真实身份。企业网站为啥要选OV&#xff08;组织验证&#xff09;SSL证书呢&#xff1f;主要有这么几个原因&#xff1a; 1.安全等级更高…

uiCA模拟器和bHive benchmark的使用

概念 uiCA 基本块吞吐量预测器 github地址&#xff1a;GitHub - andreas-abel/uiCA: uops.info Code Analyzer uiCA是一个模拟器&#xff0c;可以预测基本块在最新的英特尔微体系结构上的吞吐量。除此之外&#xff0c;它还提供了代码执行的洞察。 uiCA基于来自uops.info的数…

SpringCloud Hystrix 断路器

一、前言 接下来是开展一系列的 SpringCloud 的学习之旅&#xff0c;从传统的模块之间调用&#xff0c;一步步的升级为 SpringCloud 模块之间的调用&#xff0c;此篇文章为第五篇&#xff0c;即介绍 Hystrix 断路器。 二、概述 2.1 分布式系统面临的问题 复杂分布式体系结构中…

深入探究Java中的TransferQueue:机制、特性与应用场景

码到三十五 &#xff1a; 个人主页 心中有诗画&#xff0c;指尖舞代码&#xff0c;目光览世界&#xff0c;步履越千山&#xff0c;人间尽值得 ! TransferQueue是Java并发包中的一个强大工具&#xff0c;专为需要精确的数据传递场景而设计。它实现了BlockingQueue接口&#xf…

Midjourney绘图欣赏系列(十)

Midjourney介绍 Midjourney 是生成式人工智能的一个很好的例子&#xff0c;它根据文本提示创建图像。它与 Dall-E 和 Stable Diffusion 一起成为最流行的 AI 艺术创作工具之一。与竞争对手不同&#xff0c;Midjourney 是自筹资金且闭源的&#xff0c;因此确切了解其幕后内容尚不…

快速构建Vue2/Vue3项目

1.创建一个空文件夹 我创建了一个vue的空文件夹 2.使用vscode打开 3.终端输入npm init -y npm init -y 含义是项目初始化 运行后会出现一个文件&#xff1a;package.json 在运行第四步前&#xff0c;我的项目出现的问题&#xff01;&#xff01;&#xff01; 就是我的文件…

Go——运算符,变量和常量,基本类型

一.运算符 Go语言内置的运算符有&#xff1a; 算术运算符 关系运算符 逻辑运算符 位运算符 赋值运算符 1.1 算术运算符 注意&#xff1a;(自增)和--(自减)在go语言中是单独的语句&#xff0c;并不是运算符。 1.2 关系运算符 1.3 逻辑运算符 1.4 位运算符 位运算符对整数在内存…

【每日八股】Java基础经典面试题2

前言&#xff1a;哈喽大家好&#xff0c;我是黑洞晓威&#xff0c;25届毕业生&#xff0c;正在为即将到来的秋招做准备。本篇将记录学习过程中经常出现的知识点以及自己学习薄弱的地方进行总结&#x1f970;。 本篇文章记录的Java基础面试题&#xff0c;适合在学Java基础的小白…

给多篇文章注音 只要拼音不要汉字 怎么办?快看过来 小编帮你解决

在日常办公和学习中&#xff0c;我们有时需要对Word文档中的文字进行拼音标注&#xff0c;特别是当我们需要教授儿童识字或者制作一些特殊的文档时。然而&#xff0c;很多时候&#xff0c;我们可能只需要拼音而不需要汉字本身。那么&#xff0c;如何在Word中给文字注音&#xf…

【你也能从零基础学会网站开发】Web建站之javascript入门篇 认识Document文档对象

&#x1f680; 个人主页 极客小俊 ✍&#x1f3fb; 作者简介&#xff1a;程序猿、设计师、技术分享 &#x1f40b; 希望大家多多支持, 我们一起学习和进步&#xff01; &#x1f3c5; 欢迎评论 ❤️点赞&#x1f4ac;评论 &#x1f4c2;收藏 &#x1f4c2;加关注 Document对象 …

Rust异步编程 Async Await 入门

Rust Async Await 入门 在本文中&#xff0c;我们将仔细研究 Rust 中的异步编程。到目前为止&#xff0c;我对 Rust 异步的体验主要是从 Stack Overflow 复制代码。本文旨在帮助您了解什么是异步代码以及如何有效地使用它。 什么是异步代码&#xff1f; 要了解什么是异步代码…

openGauss使用BenchmarkSQL进行性能测试(上)

一、前言 本文提供openGauss使用BenchmarkSQL进行性能测试的方法和测试数据报告。 BenchmarkSQL&#xff0c;一个JDBC基准测试工具&#xff0c;内嵌了TPC-C测试脚本&#xff0c;支持很多数据库&#xff0c;如PostgreSQL、Oracle和Mysql等。 TPC-C是专门针对联机交易处理系统…

金融知识分享系列之:MACD指标精讲

金融知识分享系列之&#xff1a;MACD指标精讲 一、MACD指标二、指标原理三、MACD指标参考用法四、MACD计算步骤五、MACD分析要素六、根据快线DIF位置判断趋势七、金叉死叉作为多空信号八、快线位置交叉信号九、指标背离判断行情反转十、差离值的正负十一、差离值的变化十二、指…

K 近邻算法

为什么学习KNN算法 KNN是监督学习分类算法&#xff0c;主要解决现实生活中分类问题。 &#xff08;1&#xff09;首先准备数据&#xff0c;可以是视频、音频、文本、图片等等 &#xff08;2&#xff09;抽取所需要的一些列特征&#xff0c;形成特征向量 &#xff08;3&…

iPhone, Android 手机是如何收到推送通知的?

本文转自 公众号 ByteByteGo&#xff0c;如有侵权&#xff0c;请联系&#xff0c;立即删除 iPhone, Android 手机是如何收到推送通知的&#xff1f; 我们的手机或电脑是如何收到推送通知的&#xff1f; 通常我们可以使用消息解决方案 Firebase 来支持通知推送。下图显示了 Fi…

云数据库Redis配置用户名密码连接

一般情况,生产环境6379端口是禁止对外开放的, 所有用户名密码可以不设置。 但是如果有格鲁需求,需要开放redis公网访问,建议端口限制IP,并设置用户密码 spring中配置 阿里云数据库 云数据库 Redis_缓存数据库_高并发_读写分离-阿里云 添加白名单 申请公网访问地址 配…

2024年共享WiFi项目到底怎么样?

共享WiFi项目是近年来兴起的一种新型商业模式&#xff0c;商家通过在自己店铺升级wifi链接模式使其数字化&#xff0c;让用户能够方便地连接到互联网&#xff0c;提升到店体验&#xff0c;增加线上引流。这一项目的出现&#xff0c;为人们的生活带来了诸多便利&#xff0c;同时…