手摸手教你使用Ardunio开发ESP32---开始篇

381 阅读6分钟

啥是ardunio??

Arduino是一个开放源码电子原型平台,拥有灵活、易用的硬件和软件。Arduino专为设计师,工艺美术人员,业余爱好者,以及对开发互动装置或互动式开发环境感兴趣的人而设的。啊吧啊吧......

直接上链接[www.arduino.cc]

代码结构

其中主要分两部分组成分别为:setup()函数和loop()函数;setup()在生命周期中只会运行一次一般用于初始化参数的配置或组件的初始化。loop()在setup()执行完成后紧接着运行,在运行完成一次后紧接着继续运行loop(),其实这部分是个循环结构(死循环)。代码可参看以下图表;根据代码的结构特性可以理解为执行结构为第三个图所示的。

Ardunio

启动后在115200波特率下监控器中可每隔5秒打印一次“哈喽 !!”

#include <Ardunio.h>

void setup(){
    Serial.begin(115200);      // 设置通信波特率为115200
}

void loop(){
    Serial.println("哈喽 !!");// 在串口中打印 “哈喽 !!”
    delay(5000);               // 休眠/挂起/延时 5秒
}

Ardunio 主要两函数运行结构图

graph TD;

func_setup["setup()"]
func_loop["loop()"]

init("开始")-->func_setup
func_setup-->func_loop
func_loop-->func_loop

Ardunio 结构对应C实现

#include <stdio.h>

void setup();
void loop();

int main(){
    setup();
    while(true){
        loop();
    }
    return 0;
}

void setup(){
}

void loop(){
    printf("哈喽!!\n");
    sleep(5000);
}

什么是ESP32

ESP32是由我国的乐鑫公司设计研发的一款可作为独立系统运行应用程序或是主机 MCU 的从设备,通过 SPI / SDIO 或 I2C / UART 接口提供 Wi-Fi 和蓝牙功能。. 该芯片专为移动设备、可穿戴电子产品和物联网应用而设计,具有业内高水平的低功耗性能,包括精细分辨时钟门控、省电模式和动态电压调整等。. 其次ESP32将天线开关、RF balun、功率放大器、接收低噪声放大器、滤波器、电源管理模块等功能集于一体,这使得ESP32 只需极少的外围器件,即可实现强大的处理性能、可靠的安全性能,和 Wi-Fi & 蓝牙功能。. 同时,ESP32 具备极其稳定的性能,工作温度范围达到 -40°C 到 +125°C。

上链接[www.espressif.com.cn/zh-hans/pro…]

总之他是个开发版,国产的有蓝牙(BLE)有wifi,主频240MHz,有内存有外存的一个单片机。其中有wifi就说明了他有联网的能力所以我们可以做很多的线上控制功能给他。某宝几十块轻松入手,当然他的ESP8266也不错不过ESP32更强,具体的可以去官网看哦!!!。

IMG_1284.jpeg

关于开发工具 IDE

ide有ardunio官方的ide,微软商店或ardunio官网下载即可,但是使用下来我们做软件的可能不习惯他的单页流水账代码结构(当然他也提供了文件引入的工程目录,不过不友好)。所以我推荐使用 VS-code搭配platformio插件进行开发。

截屏2023-03-27 17.15.09.png

文档链接[docs.platformio.org/page/projec…]

安装步骤网上有很多在此就不在赘述。

工程的创建

在安装好软件环境后点击创建新项目直接进行创建,所选参数如下图:

第一次创建过程较长,一般是网络原因,如果着急请使用魔法🪄

截屏2023-03-27 17.19.27.png

目录结构

生成的工程文件中主要有这么几个文件需要注意,/src/main.cpp,platformio.ini;其中/src/main.cpp为程序入口文件,platformio.ini为工程配置文件。

截屏2023-03-27 17.23.05.png

我的第一个组件

现在基本的概念我们已经懂了,让我们开始做一个组件吧(模块或功能)。

我们创建一个链接wifi的功能。

platformio.ini

[env:esp32dev]
platform = espressif32
board = esp32dev
framework = arduino
board_build.f_cpu = 240000000L
board_build.f_flash = 80000000L
monitor_speed = 115200 ;检测器波特率 波特率不一致将出现乱码
upload_speed = 115200 ;win 921600 ;mac 115200 烧写速度
build_flags =
  '-D EK_HUB_VERSION="3.0.7.4"' ;自定义全局宏

main.cpp

#include <Arduino.h>
#include <WiFi.h>

#define WIFI_SSID "simonDEV" // wifi 名称
#define WIFI_PASSWORD "1700009456." // wifi 密码

void setup() {
   Serial.begin(115200); // 初始化设备串口波特率
   Serial.println("\n");
   Serial.println("开始执行 setup");
   WiFi.disconnect(); // 清除之前的连接配置
   WiFi.mode(WIFI_STA); // 设置STA模式
   WiFi.begin(WIFI_SSID, WIFI_PASSWORD); // 初始化wifi
   Serial.printf("尝试链接wifi[%s]...", WIFI_SSID);
}

void loop() {
   if (WiFi.isConnected()) {
       Serial.println("wifi 链接成功!!");
       delay(1000);
   }
   delay(1000);
}

烧录代码

截屏2023-03-27 17.53.58.png

查看结果

截屏2023-03-27 17.58.04.png

我们就完成了联网的功能

模块化

现在我们创建模块的业务流为,初始化wifi模块设置用户名和密码,设置模块回调函数成功回调和失败回调。启动链接,和主循环检查。

graph TD;
init["init(ssid,password,succCb,faileCb)"]
WIFI_SUCCESS_CALLBACK["successCallback()"]
WIFI_FAILED_CALLBACK["failedCallback()"]
loopHandle["loopHandle()"]

init-->loopHandle
WIFI_SUCCESS_CALLBACK-->loopHandle
loopHandle-->|链接成功|WIFI_SUCCESS_CALLBACK
WIFI_FAILED_CALLBACK-->loopHandle
loopHandle-->|链接失败|WIFI_FAILED_CALLBACK

实施

在main文件同级目录创建 EkWiFi.hpp 文件

#pragma once

#include <Arduino.h>
#include <WiFi.h>
#include <functional>

#define WIFI_period_overtime 10 * 1000 // wifi链接超时(ms)
#define WIFI_LOCK_ON 0
#define WIFI_LOCK_OFF 1

#define WIFI_SUCCESS_CALLBACK std::function<void()> successCallback
#define WIFI_FAILED_CALLBACK std::function<void()> failedCallback
#define WIFI_CONNECTED_HOOK std::function<void()> connectedHook

class EkWiFi {
private:
   char *staSSID;
   char *staPassword;
   WIFI_SUCCESS_CALLBACK;
   WIFI_FAILED_CALLBACK;
   WIFI_CONNECTED_HOOK;

   bool lock;
   long overtime;
   bool connectedHookMark; // hook 是否运行

/**
*回调检查检查是否具有callback
*/
void checkCallback() {
   this->lock = WIFI_LOCK_ON;
   do {
       bool isNull = this->successCallback == nullptr || this->failedCallback == nullptr;
       bool isNullptr = this->successCallback == nullptr || this->successCallback == nullptr;
       if (isNull || isNullptr) {
           Serial.println("回调函数缺失。请添加回调函数!或将回调函数注册写于WifiSupport::init()之前");
           this->lock = WIFI_LOCK_OFF;
       }
   } while (WIFI_LOCK_OFF == this->lock);
}

public:
EkWiFi() {
   this->lock = WIFI_LOCK_ON;
   this->overtime = 0;
   this->connectedHookMark = false;
}

~EkWiFi() {
}

EkWiFi *setConfig(const char *staSSID, const char *staPassword) {
   this->staSSID = strdup(staSSID);
   this->staPassword = strdup(staPassword);
   return this;
}

EkWiFi *init() {
   this->checkCallback();
   WiFi.disconnect(); // 清除之前的连接配置
   WiFi.mode(WIFI_STA); // 设置STA模式
   WiFi.begin(this->staSSID, this->staPassword); // 配置连接信息, 开始连接
   WiFi.setAutoReconnect(true);
   Serial.printf("尝试链接wifi[%s]...\n", this->staSSID);
   vTaskDelay(100 / portTICK_PERIOD_MS);
   return this;
}

EkWiFi *setSuccessCallback(WIFI_SUCCESS_CALLBACK) {
   this->successCallback = successCallback;
   return this;
}

EkWiFi *setFailedCallback(WIFI_FAILED_CALLBACK) {
   this->failedCallback = failedCallback;
   return this;
}

EkWiFi *setConnectedHook(WIFI_CONNECTED_HOOK) {
   this->connectedHook = connectedHook;
   return this;
}

void loopHandle() {
   if (WiFi.isConnected()) {
       if (nullptr != this->connectedHook && !this->connectedHookMark) {
           Serial.printf("wifi连接成功==>[SSID: %s,PSW: %s,IP: %s,MAC:%s]\n", WiFi.SSID().c_str(), WiFi.psk().c_str(),
           WiFi.localIP().toString().c_str(), WiFi.macAddress().c_str());
           this->successCallback();
           this->connectedHook();
           this->connectedHookMark = true; // 执行标识 connectedHook() 只运行一次
       }
       this->successCallback();
       return;
   }

   long now = millis();
   if (now - this->overtime > WIFI_period_overtime) {
       this->failedCallback();
       this->overtime = now;
   }
}

};

使用

#include <Arduino.h>
#include "EkWiFi.hpp"

#define WIFI_SSID "simonDEV" // wifi 名称
#define WIFI_PASSWORD "1700009456." // wifi 密码

EkWiFi *support = nullptr;

void setup() {
    Serial.begin(115200); // 初始化设备串口波特率
    Serial.println("\n");
    Serial.println("开始执行 setup");
    
    support = new EkWiFi();
    support->setConfig(WIFI_SSID, WIFI_PASSWORD)
    ->setConnectedHook([]() {
        Serial.println("链接成功 init");
        delay(4000); // 运行速度过快 延时方便观察
    })
    ->setSuccessCallback([]() {
        Serial.println("链接成功");
        delay(4000);// 运行速度过快 延时方便观察
    })
    ->setFailedCallback([]() {
        Serial.println("链接失败");
        delay(4000);// 运行速度过快 延时方便观察
    })
    ->init();
}

void loop() {
    support->loopHandle();
}

执行结果

截屏2023-03-27 18.21.19.png

有啥用??

这个模块主要关心的是是否链接到网络,提供了链接成功一瞬的回调函数和链接成功和链接失败的回调函数。链接一瞬的回调函数可以作为其他需要联网基础进行初始化的功能代码接入点;链接成功和链接失败的回调函数可以作为全局的网络状态设置,使得代码功能解耦。

本文章旨在于技术实现与分享,不探讨C写硬件好还是ardunio写好等问题。所属内容仅个人理解,且本人非硬件从业者(本人软件码农),如描述或相关概念有误,欢迎大佬指正,本人积极学习。