【ESP32 C++教程】Unit1-3 ESP32 Arduino 开发框架

ESP32 Arduino Framework是专门针对ESP32开发板的Arduino应用开发框架,为用户开发IOT应用、HMI应用提供一致的开发体验。

ESP32 Arduino Framework是专门针对ESP32开发板的Arduino应用开发框架,为用户开发IOT应用、HMI应用提供一致的开发体验。 目前支持以下功能: 提供常用LCD、OLED显示屏设备的驱动

  • 提供常用音频编解码器设备的驱动
  • 提供LED、灯珠等设备的驱动
  • 提供统一的抽象化接口来操作UI、音频编解码等
  • 提供WiFi信息配置界面
  • 提供OTA在线升级
  • 内置支持LVGL、TFT_eSPI、U8G2、GFX_Library图形化开发库

框架使用Board类及派生类来封装硬件驱动,使用Application类及派生类来实现业务逻辑处理。Board类和Application类之前通过公开方法互相访问,如下图:

【ESP32 C++教程】Unit1-3 ESP32 Arduino 开发框架

这样实现有以下优点:

  1. 分离业务代码和硬件驱动代码,便于维护和扩展;
  2. 规范业务代码与硬件驱动代码间的交互设计,利于代码移植;
  3. 降低代码故障率,节省异常排查时间;


下面以点亮LED为例,来说明ESP32 Arduino框架的使用

不使用框架的实现

#define LED_PIN       4

void setup() {
    pinMode(LED_PIN, OUTPUT);
}

void loop() {
    digitalWrite(LED_PIN, HIGH);
    delay(1000);
    digitalWrite(LED_PIN, LOW);
    delay(1000);
}

简单到不言自明了,相信大家都写过很多次类似点亮LED的代码。

这就是面向过程的代码,这里没有LED灯对象,我们操作的是一个连接着LED灯的引脚。

使用框架的实现

第一步:实现一个自定义的Board派生类MyBoard,然后创建一个GpioLed类的实例。

在my_board.h文件中,定义MyBoard类:

class MyBoard : public Board {
private:
    Led* led_ = nullptr;

public:
    MyBoard();
    Led* GetLed() override { return led_; }
};

在my_board.cpp文件中,创建GpioLed类实例,这里GpioLed类是Led类的一个子类:


MyBoard::MyBoard() : Board() {
    Log::Info(TAG, "===== Create Board ...... =====");

    Log::Info(TAG, "initial led.");
    led_ = new GpioLed(BUILTIN_LED_PIN, false); // no pwm

    Log::Info( TAG, "===== Board config completed. =====");
}

第二步:实现一个自定义的Application派生类MyApplication,然后实现点亮LED的代码。

在my_application.h文件中,定义MyApplication类和继承的方法:

class MyApplication : public Application {
public:
    MyApplication();
    
    const std::string& GetAppName() const override { return "Unit1-Lesson13"; }
    const std::string& GetAppVersion() const override { return "1.0.0"; }

protected:
    void OnInit() override;
    void OnLoop() override;
};

这里我们重写父类的OnInit方法用于执行初始化的相关代码、重写OnLoop方法用于执行要重复执行的业务代码。

在my_application.cpp文件中,实现点亮LED的代码:

void MyApplication::OnInit() {
    // do your init.
    Log::Info(TAG, "OnInit");
}

void MyApplication::OnLoop() {
    Led *led = Board::GetInstance().GetLed();
    led->TurnOn();
    delay(1000);
    led->TurnOff();
    delay(1000);
}

可以看到此处先取得Board类实例(即MyBoard类实例),再取得Led类实例变量,
然后调用Led类实例的TurnOn方法点亮LED、调用TurnOff方法熄灭LED,
这就是面向对象的代码,动作都是基于对象实例的方法来完成的。
而在TurnOn和TurnOff方法里,我们才具体调用digitalWrite方法来控制led的引脚电平。

GpioLed类的具体实现代码请参照src/framework/led/gpio_led.cpp文件


那么OnInit和OnLoop方法是在何处被调用的呢?

main.cpp是ESP32 Arduino框架的入口程序,它替代了ino文件的功能,即定义setup方法和loop方法,代码如下:

Application *app = nullptr;

void setup() {
    Serial.begin(115200);

    Log::Info(TAG, "application starting.");

    // 创建应用实例
    app = &Application::GetInstance();

    app->Init();
}

void loop() {
    app->Loop();
}

可以看到在setup方法里,先取得Application类实例(即MyApplication实例),然后调用Application类实例的Init方法,在loop方法里,直接调用Application类实例的Loop方法。

Init方法

void Application::Init() {
    Log::Info(TAG, "Initialize...");
    // 省略部分代码

    OnInit();
    
    // 省略部分代码 
    Log::Info(TAG, "Started.");
}

在此方法中,会做一些公共的初始化操作,然后再调用OnInit方法去执行派生类的代码。

Loop方法

void Application::Loop() {
    OnLoop();
}

直接调用OnLoop方法去执行派生类的代码。

这里OnInit方法和OnLoop方法就是专门用于留给子类实现的,它们也称之为虚函数。


另外Application::GetInstance()和Board::GetInstance()使用的是静态初始方式分别调用creation_application和create_board方法来初始化的,如下代码:

文件 src/framework/app/application.h

static Application& GetInstance() {
    static Application* instance = static_cast<application*>(create_application());
    return *instance;
}

此方法保证全局只有一个Application子类实例和一个Board子类实例。


至此,我们已经解读基于框架的点亮LED的代码,与前面的不使用框架的代码相比,可以看到我们改变了代码的组织方式(从面向过程改变为面向对象),对具体的控制代码进行了封装,看起来变得有些复杂了,点亮LED的代码执行路径如下:

Application.Loop() -> MyApplication.OnLoop() -> GpioLed.TurnOn() -> digitalWrite()

如果只是写一个点亮LED的程序或是极小的项目,完全没必要用弄得这么复杂,
但当我们项目要接受若干种传感器数据,控制若干外设,有着复杂的业务处理逻辑时,使用开发框架和面向对象设计的优势才会体现出来。

实例

从 https://gitee.com/billyzh/esp32-cpp-lesson 下载本教程的源码到本地硬盘文件夹,如d:\esp32-cpp-lesson
在VSCode中,选择【文件】->【打开文件夹...】选择上一步保存的文件夹打开
选择config.h文件,修改第10行为 
#define APP_LESSON13   1
【ESP32 C++教程】Unit1-3 ESP32 Arduino 开发框架
接着打开项目中的esp32-cpp-lesson.ino文件,点击右上角的【上传/upload】按钮,开始编译lesson13示例,编译成功后会上传到开发板运行。
- 本文由用户 老张 发布,文中观点仅代表作者本人,不代表本站立场。
- 如需转载,请联系作者;如有侵权,请联系本站处理。

01-02   阅读(101)   评论(0)
 标签: 编程 ESP32

涨知识
SD卡

SD卡是一种用于存储数字数据的存储卡,它是一种非易失性存储卡,可以用于移动设备、数码相机、音乐播放器、智能手机、平板电脑等各种设备。

评论:
相关文章
ESPConnect:基于浏览器的ESP32管理器

ESPConnect是一个基于现代浏览器的管理器,在你需要快速验证、调试、管理文件、检查状态的时候,它能帮你省下大量打开和切换重型工具的时间。


用ESP32做一个FM收音机

本文介绍两种使用TEA5767收音机模块实现FM收音机的方案,感兴趣的朋友可在此基础上实现更丰富的功能。


GPIOViewer:让ESP32引脚状态一览无余!

GPIOViewer 是一个强大的 Arduino 库,专门为 ESP32 芯片设计,可以实时监控 ESP32 芯片上的所有 GPIO 引脚状态。它可以帮助你快速直观地了解每个引脚的当前状态,例如高电平、低电平、输入、输出、中断等等。


ESP32 I2S音频:初识I2S通信与配置基础

在音频处理领域,I2S是一种广泛使用的通信协议,它专门用于芯片之间的音频数据传输。ESP32 作为一款高性能的微控制器,不仅支持 I2S 通信,还提供了强大的硬件接口和灵活的软件库,使其成为音频项目开发的理想选择。


小鹏物联网自动浇花套件

小鹏物联网智能浇花系统是照顾植物的好帮手,支持自动控制和手动控制两种模式,可通过电脑端和手机端查看数据和控制浇水。


ESP32 Arduino 开发框架

Arduino开发环境下适用于ESP32芯片系列开发板的应用开发框架。


【ESP32 C++教程】Unit1-2 C++类基础知识

本小节主要介绍C++ 类相关的基础知识,包括类的定义、继承、多态,范围作用域等。


【ESP32 C++教程】Unit1-1 开发环境准备

本讲主要介绍VSCode Arduino开发环境的搭建,及与Arduino IDE开发环境的比较。


ESP32 WebServer库处理表单请求

本文主要讲解WebServer库如何来处理表单请求。