ESP32(Arduino)

本篇内容在熟知51单片机与C语言基础上编写

一,开发板介绍和引脚图

USB接口用于下载程序,电源输入和烧录驱动等等。BOOT启动模式选择,按下为下载模式,放开为运行模式。ESP-32-WROOM-32模组集成了蓝牙,wifi等模块

共48个引脚。但并不是所有引脚都暴露在外面,有些引脚不能使用就没有暴露出来。这个单片机就只有30个引脚。ESP32芯片有34个可编程的GPIO引脚,每个引脚执行多个功能

 二,开发方式

三,编程基础

在Arduino IDE中变量的声明必须放在文件开始。Arduino支持的变量类型有int float char bool string等 

Arduino中的void setup()函数是在开发板通电或者复位后执行的初始化程序(比如配置IO口状态,初始化串口等等),只会执行一次。void loop(){}函数是一个死循环,里面的程序会不断执行

Arduino常见函数介绍:

四,Arduino控制ESP32GPIO口输入输出

ESP32上D开头的引脚就是GPIO引脚,只是输入和输出两种模式

1,输出模式

以下为LED闪烁实验代码

int led_pin = 12;

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

void loop()
{
    digitalWrite(led_pin, HIGH);
    delay(1000); //1s
    digitalWrite(led_pin, LOW);
    delay(1000);
}

点亮流水灯

int pin_list[5] = {13, 12, 14, 27, 26};
int len = sizeof(pin_list) / sizeof(pin_list[0]); //数组长度

void setup()
{
    for(int i=0;i<num;i++)
    {
        pinMode(pin_list[i], OUTPUT);
    }
}

void loop()
{
    for(int i=0;i<num;i++)
    {
        digitalWrite(pin_list[i], HIGH);
        delay(50);
    }

    for(int i=0;i<num;i++)
    {
        digitalWrite(pin_list[i], LOW);
        delay(50);
    }   
}

2,输入模式

设置引脚的输入模式pinMode(1, INPUT)

设置为上拉输入模式pinMode(1, INPUT_PULLUP)

设置为下拉输入模式pinMode(1, INPUT_PULLDOWN)

五,数码管

数码管按照显示位数分为1位,2位,3位,4位,5位,6位,7位等数码管。其基本单元仍然是LED

按发光二极管的连接方式可分为共阳极数码管和共阴极数码管。在数码管引脚图中,COM就是公共端,共阴数码管这个COM端接地,共阳数码管接电源正极,剩下的abcdefg被称为段选线,分别对应不同位置的LED。

1,一位数码管 

接线

int pin_a = 4;
int pin_b = 5;
int pin_c = 19;
int pin_d = 21;
int pin_e = 22;
int pin_f = 2;
int pin_g = 15;
int pin_dp = 18;

//定义存放所有输出引脚的数组
int pin_array[8] = {pin_a, pin_b, pin_c, pin_d, pin_e, pin_f, pin_g, pin_dp}

//定义数字显示逻辑的二维数组
int number_array[][8] = 
{//a,b,c,d,e,f,g,dp
{0, 0, 0, 0, 0, 0, 1, 1},//0
{1, 0, 0, 1, 1, 1, 1, 1},//1
{0, 0, 1, 0, 0, 1, 0, 1}//2
//以及3 4 5 6 7 8 9几个数字,这里就不一一列举了
};

//定义显示数字的函数
void display_number(int num)
{
    for(int i=0;i<8;i++)
    {
        digitalWrite(pin_array[i], number_array[num][i]);
    }
}

void setup()
{
    for(int i=0;i<8;i++)
    {
        pinMode(pin_array[i], OUTPUT);
        digitalWrite(pin_array[i], LOW);//初始化所有引脚为高电平,即默认不亮
    }
}

void loop()
{
    display_number(2);//显示数字2
}

 2,四位数码管

(1)原理

1位数码管有两个相同的公共(COM)端,而4位数码管没有公共端,但是有四个控制不同位置显示的选通端。如下图,SEG1 SEG2 SEG3 SEG4就是四个独立的选通端(也可以看作公共端),SEG1就是控制第一个数码管亮灭,SEG2控制第二个。选通端是相互独立的,而负责显示数字的段选线是接到一起的。   一位数码管10个引脚,四位数码管12个引脚

下图所示的D0 D1 D2 D3就是选通端(位选线),也就是四位数码管的公共端,相互独立。上面的八根段选线全都是接到一起的。独立的公共端决定哪一个数码管点亮,连在一起的段选线控制点亮的数码管亮什么数字 

 

接线图

 

(2)静态显示 

// 定义位选线引脚
int seg_1 = 5;
int seg_2 = 18;
int seg_3 = 19;
int seg_4 = 21;

// 定义位选线数组;
int seg_array[4] = {seg_1, seg_2, seg_3, seg_4};

// 定义段选线引脚
int a = 32;
int b = 25;
int c = 27;
int d = 12;
int e = 13;
int f = 33;
int g = 26;
int dp = 14;

// 定义段选线数组
int led_array[8] = {a, b, c, d, e, f, g, dp};

// 定义共阴极数码管不同数字对应逻辑电平的二维数组
int logic_array[10][8] = {
 //a, b, c, d, e, f, g, dp
  {1, 1, 1, 1, 1, 1, 0, 0}, // 0
  {0, 1, 1, 0, 0, 0, 0, 0}, // 1
  {1, 1, 0, 1, 1, 0, 1, 0}, // 2
  {1, 1, 1, 1, 0, 0, 1, 0}, // 3
  {0, 1, 1, 0, 0, 1, 1, 0}, // 4
  {1, 0, 1, 1, 0, 1, 1, 0}, // 5
  {1, 0, 1, 1, 1, 1, 1, 0}, // 6
  {1, 1, 1, 0, 0, 0, 0, 0}, // 7
  {1, 1, 1, 1, 1, 1, 1, 0}, // 8
  {1, 1, 1, 1, 0, 1, 1, 0}, // 9
  };


void setup() {
  // 设置所有的位选线引脚为输出模式,初始化所有的位选线引脚为高电平
  for (int i=0;i<4;i++) {
    pinMode(seg_array[i], OUTPUT);
    digitalWrite(seg_array[i], HIGH);
    }
  // 设置所有的段选线引脚为输出模式,初始化所有的段选线引脚为低电平
  for (int i=0;i<8;i++){
    pinMode(led_array[i], OUTPUT);
    digitalWrite(led_array[i], LOW);
    }
}

void loop() {
//  display_number(2, 4);
//  delay(1000);

  // 按顺序让所有位置显示0-9
  for (int i=0;i<4;i++) {
    for (int j=0;j<10;j++) {
      display_number(i, j);
      delay(200);
      }
    }
}


void display_number(int order, int number) {

  // 清屏
  clear();
  
  // 设置对应的位选线引脚为低电平
  digitalWrite(seg_array[order], LOW);

  // 给对应的段选线引脚设置对应的电平
  for (int i=0;i<8;i++) {
    digitalWrite(led_array[i], logic_array[number][i]);
  }
  }


void clear(){
  // 设置所有的位选线引脚为输出模式,初始化所有的位选线引脚为高电平
  for (int i=0;i<4;i++) {
    pinMode(seg_array[i], OUTPUT);
    digitalWrite(seg_array[i], HIGH);
    }
  // 设置所有的段选线引脚为输出模式,初始化所有的段选线引脚为低电平
  for (int i=0;i<8;i++){
    pinMode(led_array[i], OUTPUT);
    digitalWrite(led_array[i], LOW);
    }
}

(3)动态显示

 动态扫描是对位选线进行扫描,通过刷新位选线来实现显示多个数字的效果

// 定义位选线引脚
int seg_1 = 5;
int seg_2 = 18;
int seg_3 = 19;
int seg_4 = 21;

// 定义位选线数组;
int seg_array[4] = {seg_1, seg_2, seg_3, seg_4};

// 定义段选线引脚
int a = 32;
int b = 25;
int c = 27;
int d = 12;
int e = 13;
int f = 33;
int g = 26;
int dp = 14;

// 定义段选线数组
int led_array[8] = {a, b, c, d, e, f, g, dp};

// 定义共阴极数码管不同数字对应逻辑电平的二维数组
int logic_array[10][8] = {
 //a, b, c, d, e, f, g, dp
  {1, 1, 1, 1, 1, 1, 0, 0}, // 0
  {0, 1, 1, 0, 0, 0, 0, 0}, // 1
  {1, 1, 0, 1, 1, 0, 1, 0}, // 2
  {1, 1, 1, 1, 0, 0, 1, 0}, // 3
  {0, 1, 1, 0, 0, 1, 1, 0}, // 4
  {1, 0, 1, 1, 0, 1, 1, 0}, // 5
  {1, 0, 1, 1, 1, 1, 1, 0}, // 6
  {1, 1, 1, 0, 0, 0, 0, 0}, // 7
  {1, 1, 1, 1, 1, 1, 1, 0}, // 8
  {1, 1, 1, 1, 0, 1, 1, 0}, // 9
  };


// 清屏函数
void clear(){
  for (int i=0;i<4;i++) {
    digitalWrite(seg_array[i], HIGH);
  }
  
  for (int i=0;i<8;i++){
    digitalWrite(led_array[i], LOW);
  }
}


// 显示数字的函数
void display_number(int order, int number) {

  // 清屏
  clear();

  // 把对应位选线的电平拉低
  digitalWrite(seg_array[order], LOW);

  // 显示数字
  for (int i=0;i<8;i++) {
    digitalWrite(led_array[i], logic_array[number][i]);
    }
}


// 4 位数码管显示函数
void display_4_number(int number) {
  // 把输入的数字转化为 4 位数的数组
  if (number < 10000){
    // 获取每一位对应的数字
    /*
    4567
    4567 % 10 = 7
    4567 / 10 = 456
    456 % 10 = 6
    456 / 10 = 45
    45 % 10 = 5
    45 / 10 = 4
    4 % 10 = 4

    1 
    1 % 10 = 1
    1 / 10 = 0
    
    */
    // 定义格式化数组
    int number_array[4];

    // 使用循环获取数组元素
    for (int i=3;i>=0;i--) {
      number_array[i] = number % 10;
      number /= 10;
      }

    // 显示 4 位数字
    for (int i=0;i<4;i++) {
      display_number(i, number_array[i]);
      delay(5);
      }
    }

}


void setup() {
  // 设置所有的位选线引脚为输出模式,初始化所有的位选线引脚为高电平
  for (int i=0;i<4;i++) {
    pinMode(seg_array[i], OUTPUT);
    digitalWrite(seg_array[i], HIGH);
    }

  // 设置所有的段选线引脚为输出模式,并初始化为低电平
  for (int i=0;i<8;i++){
    pinMode(led_array[i], OUTPUT);
    digitalWrite(led_array[i], LOW);
    }
}

void loop() {
  display_4_number(9876);
}

六,PWM输出

使用ESP32的LEDC外设,LEDC外设专门用于输出PWM波形,LED PWM这个控制器可以生成16路通道(0~15),波形的频率和占空比可以配置。按照驱动时钟的频率分为高低两组,高速通道是0~7,由80MH时钟驱动,低速通道是8~15,由1MHz时钟驱动。另外,每路LED PWM支持自动步进式的增加或者减少占空比,可用于LED RGB彩色梯度发生变化

结合下图图像看各函数

ledcSetup();函数,用来设置LEDC通道对应的频率和分辨率,返回值为最终的频率。分辨率的意思就是将一个周期等分成2的resolution_bits的平方份,比如我们传入的分辨率是8,那就是2的8次方,256,256对应了占空比0~100%

ledcWrite();函数,用来指定通道输出一定的占空比波形。输入参数范围为0到2的resolution_bits次方-1

ledcWriteTone()和ledcWriteNote。这两个函数作用是使蜂鸣器发声的

ledcRead();返回指定通道占空比的值

ledcReadFreq();返回指定通道当前频率(如果当前占空比为0,则该方法返回0)

ledcAttachPin();将LEDC通道绑定到指定的GPIO口。ESP32中只有部分引脚可以被绑定到PWM控制器通道上,具体哪个引脚需要查看手册

ledcDetachPin();解绑

ESP32 的 LEDC 模块具有多个通道,每个通道可以被配置为产生一个 PWM 信号。这些通道可以被映射到不同的 GPIO 引脚(以 “D” 开头的引脚)上。 

LEDC产生PWM的过程一般为以下步骤

  1. 使用ledcSetup()函数建立LEDC通道
  2. 使用ledcAttachPin()将GPIO口与LEDC通道关联 
  3. 通过ledcWrite() ledcWriteTone() ledcWriteNote设置频率,设置蜂鸣器音调等
  4. 使用完成后,通过ledcDetachPin()解除GPIO口与LEDC通道的关联

 代码示例

#include &lt;Arduino.h&gt;

// 定义要使用的数字引脚,例如 D2
const int pwmPin = 2; 

void setup() {
  // 配置引脚为PWM输出模式
  ledcSetup(0, 5000, 8); 
  // 将引脚与PWM通道绑定
  ledcAttachPin(pwmPin, 0); 
}

void loop() {
  // 设置PWM占空比,范围是 0 到 255
  ledcWrite(0, 128); 
  delay(1000); 
}

也可以通过analogWrite来实现PWM输出

ESP32 中的 analogWrite 函数是通过调用 LEDC 模块的相关函数实现的,当调用 analogWrite 函数时,它会先检查是否已经为该引脚配置了相应的 LEDC 通道。如果没有,它会调用 ledcSetup 函数来配置一个通道,然后调用 ledcAttachPin 函数将指定的 GPIO 引脚(以 “D” 开头的引脚)映射到已配置的 LEDC 通道。通过配置通道、映射引脚和设置占空比来产生 PWM 信号,从而实现模拟控制效果。使用时需要注意通道的数量有限,不同引脚可能有不同的功能复用,在使用前最好查阅 ESP32 的官方文档,以确保所使用的引脚可以被配置为 PWM 输出,并且满足所需的频率和分辨率要求。同时,根据具体应用场景选择合适的频率和分辨率,以达到最佳的控制效果。

以下为调用analogWrite的简单示例,可以看到使用analogWrite不需要再配置LEDC等通道的函数,而是直接调用,但是使用analogWrite 函数,ESP32 通常会使用默认的 PWM 频率,约为 500Hz其占空比的范围为0~255,255时输出电压最大,一般为3.3V

#include <Arduino.h>

const int ledPin = 2; // 定义 LED 连接的引脚

void setup() {
  pinMode(ledPin, OUTPUT); // 将引脚设置为输出模式
}

void loop() {
  analogWrite(ledPin, 128); // 输出 PWM 信号,占空比为 50%(255 的一半)
  delay(1000); // 延迟 1 秒
}

七,ADC控制

1,analogWrite和analogRead实现ADC

使用PWM输出电压值类似于模拟信号输出,如果需要使用ESP32检测外部输入的模拟信号就要使用ADC模数转换器,通过ADC将模拟信号转换为数字信号

 ADC模数转换器可以将模拟信号转换为数字信号。由于单片机只能识别二进制数字,所以外界模拟信号常常会通过ADC转换成可以识别的数字信号,常见的应用就是将变化的电压转成数字信号。需要注意的是,我们在使用ADC默认配置的时候,ADC引脚的输入电压必须是介于0到1之间,任何高于1V的电压都会视为一个最高值,如果需要增加测量范围需要配置一下衰减器。

int value; //存放输入模拟值

void setup()
{
    Serial.begin(9600);// 设置串口通信波特率
    pinMode(26, INPUT);// 26号引脚输入模拟量
}
void loop()
{
    //读取模拟输入值
    value = analogRead(26); // analogRead范围是0~4095
    Serial.println(value); //打印数据到串口监视器
    delay(50);
}

2,使用ADC模拟通道输入 

ADC模块它的读取方式和analogRead()是一致的 

在 ESP32 中,adcAttachPin 函数主要用于将一个 GPIO 引脚配置为模拟输入引脚并关联到 ADC(模拟数字转换器)通道。它是 ESP32 提供的用于 ADC 操作的高级函数之一,方便用户将物理引脚与 ADC 通道相连接,以便后续使用 analogRead 等函数进行模拟信号的读取和处理。adcAttachPin 函数可以让你使用一些普通的 GPIO 引脚进行模拟信号的读取,但其性能可能会受到限制,如更高的噪声、更低的精度和更慢的采样速度,因为这些引脚并非专门为 ADC 设计。对于ESP32中专门的ADC引脚,可以不用analogAttachPin函数来映射而直接使用 analogRead读取即可,在大多数情况下,对于 ESP32 的 ADC 引脚(如 32 到 39 号引脚),analogRead 函数可能会自动处理引脚与 ADC 通道的映射关系,因此可以直接使用 analogRead 函数读取模拟输入信号。虽然对于专门的 ADC 引脚可能暂时可行,但为了确保代码的可靠性和可移植性,建议使用 adcAttachPin 函数进行明确的配置,特别是在复杂的项目中或当需要对多个 ADC 引脚进行操作时。

#define POT        26
#define LED 13
#define CHANNEL    0
#define RESOLUTION 12
#define FREQ       1000

int pot_value;

void setup()
{
    // 设置ADC分辨率
    analogReadResolutin(RESOLUTION);//默认也是12,所以可以不写这行代码
    // 配置输入衰减
    analogSetAttenuation(ADC_11db);//默认也是ADC_11db,所以这行代码可以不写
    // 建立LEDC通道,配置LEDC分辨率
    ledcSetup(CHANNEL, FREQ, RESOLUTION);
    // 关联GPIO与LEDC通道
    ledcAttachPin(LED, CHANNEL)
}
void loop()
{
    // 获取模拟信号输入值
    pot_value = analogRead(POT);
    // 输出PWM
    ledcWrite(CHANNEL, pot_value);
    delay(50);
}

当你使用 analogReadResolution 函数和analogSetAttenuation函数修改分辨率和输入衰减后,后续调用的 analogRead 函数将使用新设置的分辨率和输入衰减进行模拟值的读取,直到你再次使用 analogReadResolution 函数和analogSetAttenuation函数更改分辨率和输入衰减值。 

八,I2C驱动LCD1602显示屏

1602液晶显示屏的称呼来自于其显示的内容容量,其中的16代表每行可显示的最大字符数或数字,02代表屏幕一共两行,实际开发中根据需要显示信息的内容选择液晶显示屏,还可以选用2004屏等

1602除了电源,地以外,有3个控制引脚RS R/W E和8个数据引脚DB0-7

由于1602管脚过多,如果直接和ESP32单片机连接的话会占用大量引脚,实际使用时往往会给1602加一块I2C驱动板,将1602的16个管脚连接到由PCF8574T作为主要芯片的驱动板上,将接口转为I2C再连接开发板

根据ESP32的引脚定义图,选择I2C 的SCL和SDA引脚连接。以下为硬件连接图

 Arduino中要使用I2C控制LCD1602需要下载第三方代码LiquidCrystal_I2C,其中包含LiquidCrystal_I2C.h和LiquidCrystal_I2C.cpp文件,然后将这两个文件放到项目文件夹即可。

需要注意的是,在Arduino开发中的.h和.cpp文件的约定与传统C++开发并不完全相同,Arduino IDE在编译的过程中会将.ino文件转换成.cpp文件,并且将其中的代码放置在全局范围,因此在Arduino项目中.ino文件也可以包含全局变量函数,而不仅限于.cpp文件

以下为库的函数

显示hello world代码示例 

#include"LiquidCrystal_I2C.h"

//构造LCD对象,设置地址,列数,行数
LiquidCrystal_I2C lcd(0x27, 16, 2);

void setup()
{
    lcd.init();
    //先打开背光
    lcd.backlight();
    lcd.print("hello world");
}

void loop()
{
}

通过串口发送数据并显示示例 

//Serial.available();//返回串口缓冲区中剩余字符个数,一般用此函数判断串口缓冲区是否还有数据
//Serial.read();//从串口缓冲区读取一个字节的数据。有设备向Arduino发送数据,就可以通过此函数读取 
 //内容
#include"LiquidCrystal_I2C.h"

//构造LCD对象
LiquidCrystal_I2C lcd(0x27, 16, 2);

void setup()
{
    lcd.init();
    lcd.backlight();
    Serial.begin(9600);//开启串口通信
    lcd.print("hello world");
}

void loop()
{
    //检测是否有串口输入
    if(Serial.available())
    {
        //延时100ms等待所有的数据传输完成
        delay(100);
        //清屏
        lcd.clear();
        //反复读取串口缓冲区的数据,并显示在屏幕上
        while(Serial.available()){
            lcd.write(Serial.read());
        }
    }
}

九,在VSCode中使用PlatformIO开发

PlatformIO是一个开源的跨平台的物联网(IoT)开发平台,用于嵌入式系统和物联网设备的开发,它提供了一个统一的开发环境和工具链,支持多种硬件平台,如Arduino,ESP32,ESP8266,树莓派等等,支持多个开发框架,比如Arduino开发框架,ESP32-IDF,STM32,CUBE等等

下载VSCode并在里面下载PlatformIO插件即可

点击左下角房子标志(红框所示)即可进入到主页

 

点击New Project创建项目。输入项目名称,选择开发板型号(我们选择Espressif ESP32 Dev Module),开发框架为Arduino,Location是安装路径,勾选为安装到默认路径,可以取消勾选指定一个路径

安装完成后如下界面

最下边的蓝框工具栏就多出了几个选项。对勾Build是编译,箭头Upload是上传,将代码上传到单片机,垃圾桶是clean,锥形瓶是test,插头Serial Monitor为串口监视器,右边是终端,Auto是选择串口(连接后会自动检测)

我们的test项目共有6个文件夹和.gitignore文件和platformio.ini文件。.pio文件是PlatformIO的工作目录,包括编译生成的二进制文件,日志文件等等;.vscode是在VSCode中使用PlatformIO插件才会有的,这个文件包含了与这个项目相关的配置文件,比如任务配置,调试配置等等;include文件存放头文件;lib文件是用于存放项目依赖的库文件的,可以通过PlatformIO的库管理器安装所需要的库,并且会自动下载到这个文件;src问价来存放源代码的主要目录;test目录来存放项目的测试代码和测试数据的,这个目录经常用来编写单元测试或者集成测试的一些代码;.gitignore文件,如果使用了版本控制工具比如git进行项目管理,就可以在此文件中指定需要忽略上传的文件和文件夹,这个文件的作用简单来说就是如果你想要把自己的文件上传的github或者gitee时,像.vscode .pio这种文件是不需要上传的,所以就需要在.gitignore文件中将这些需要忽略的文件路径写入;platformio.ini文件是PlatformIO的配置文件,用于指定项目的配置选项,比如项目的开发平台,开发板 ,开发框架等

下面演示如何在PlatformIO里安装库,以LiquidCrystal_I2C库为例。回到主页点击Libraries

之后直接在里面搜索

搜索出来之后,直接下载第一个即可 。

点击进入库。

然后点击Add to Project,出现如下界面,选择要安装的项目即可

如果要查看某个头文件的代码内容或者某个函数内容,按住ctrl键点击即可

十,SPI控制OLED

1,SPI简介

 

 

2,OLED简介与硬件连接 

这节课使用的OLED是0.96寸的SSD1306芯片驱动的OLED显示屏,分辨率是128*64,有7个引脚,属于三线SPI接口,但是可以通过原理图改变电阻位置将其改装成4线SPI或者I2C接口。

3,程序设计 

 

Adafruit_SSD1306 

SSD1306包括I2C给SPI总线版本,所以针对不同版本又有对应的构造器方法。这里只说明SPI总线的构造方法,SPI总线也分为两种,一种是软件模拟I2C,第二种是硬件SPI。

第一个参数uint8_t w指屏幕宽度;第二个参数uint8_t h指高度;软件SPI第三个参数和第四个参数分别是MOSI和SCLK,可以任意指定两个IO引脚,硬件SPI第三个参数SPIClass*spi指定了地址,我们需要使用对应的引脚;接下来三个参数都是da_pin rst_pin cs_pin就没区别了

1,软件SPI

软件SPI构造对象如下。声明Adafruit_SSD1306类,声明对象的名字叫oled,括号里填写对应的参数

2,硬件SPI

3,函数使用

4,程序示例(静态图像)
  1. 初始化OLED,调用构造函数,调用begin方法
  2. 初始化成功后,调用绘制类函数,当然可以设置颜色,字体等
  3. 绘制完毕,调用显示类函数display 
#include <Arduino.h>
#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define WIDTH 128
#define HEIGHT 64
#define OLED_MOSI 13
#define OLED_SCK 18
#define OLED_DC 2
#define OLED_CS 4
#define OLED_RESET 15

//构造对象
Adafruit_SSD1306 oled(WIDTH, HEIGHT, OLED_MOSI, OLED_SCK, OLED_DC, OLED_RESET, OLED_CS);

void setup()
{
    //初始化
    oled.begin();
    //清除显示
    oled.clearDisplay();
    //绘制水平线。参数可以跳转到函数查看
    oled.drawFastHLine(32, 5, 48, SSD1306_WHITE);
    //绘制斜线
    oled.drawLine(32, 5, 48, 30, SSD1306_WHITE);
    //绘制空心矩形
    oled.drawRect(5, 5, 10, 25, SSD1306_WHITE);
    //绘制实心矩形
    oled.fillRect(75, 5, 10, 30, SSD1306_WHITE);
    //设置文本颜色。文本颜色默认为黑色,在OLED显示屏上看不到,所以先设置颜色
    oled.setTextColor(SSD1306_WHITE)
    //设置光标位置。更改光标位置也就改变了文本显示初始位置
    oled.setCursor(5, 50);
    //设置字体大小
    oled.setTextSize(2);
    //显示文字。使用SSD1306第三方库的话无法显示中文,除非用drawPixel()自己一个个地画点
    oled.println("hello");
    //显示内容
    oled.display();
}

void loop()
{

}
5,程序示例(动态图像) 

实现如下进度条加载效果

#include <Arduino.h>
#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define WIDTH 128
#define HEIGHT 64
#define OLED_MOSI 13
#define OLED_SCK 18
#define OLED_DC 2
#define OLED_CS 4
#define OLED_RESET 15

//构造对象
Adafruit_SSD1306 oled(WIDTH, HEIGHT, OLED_MOSI, OLED_SCK, OLED_DC, OLED_RESET, OLED_CS);

int length = 0;//进度条长度
void setup()
{
    //初始化
    oled.begin();
    //设置文本颜色。文本颜色默认为黑色,在OLED显示屏上看不到,所以先设置颜色
    oled.setTextColor(SSD1306_WHITE)
    //设置字体大小
    oled.setTextSize(2);

}
void loop()
{
    //清除显示
    oled.clearDisplay();
    
    //设置光标位置
    oled.setCursor(15, 40);
    //显示文字
    ole.println("Progress");
    //显示进度条边框。圆角矩形
    oled.drawRoundRect(0, 10, 128, 20, 5,SSD1306_WHITE);
    //进度递增
    if (length< 118){
        length++;
    }else
    {
        length = 0;
    }
    //显示进度
    oled.fillRoundRect(5, 15, length, 10, 2, SSD1306_WHITE);
    oled.display();
}

 U8G2

1,介绍

U8G2是Arduino平台上使用最广泛的OLED库。

因为U8G2库兼容很多版本的驱动以及不同尺寸的OLED,所以它的构造方法有很多,我们需要跟根据自己的OLED型号选择适合我们的构造方法

在PlatformIO地Libraries搜索U8G2,然后Add到项目中。使用时需要导入头文件#include<u8g2lib.h>

要使用这个库先要根据自己的OLED型号构造对象

按住ctrl,点击u8g2lib进入到头文件中。拉到注释有/*Arduino constructor list start */的位置,这就到了构造器列表

构造器命名规则。SSD1306是驱动芯片名,128X32是屏幕大小,1是缓存大小,4W_SW_SPI是总线,4W指的是四线,使用四线传递参数时需要传递时钟线,数据线,CS,DC和RESET,总线的SW和HW分别指软件SPI和硬件SPI

 

2,库函数 

 初始化相关函数

绘制相关函数 

显示配置相关函数 

 缓存相关函数

 3,绘制模式

分页模式不需要要求构造器必须带F了,1 2 F都可以使用 。do while循环体条件nextPage()是来判断是否有下一页的,如果有下一页则进入下一页并返回True,没有下一页就是False;如果使用F构造器就只有一页,所以它不会进入下一页,循环也就只能执行一次

还有一种普通文本模式,这种模式下只能打字,不能实现一些其他操作。 

 4,代码示例(全屏缓存模式显示汉字)
#include <Arduino.h>
#include <u8g2lib.h>

//所有构造函数第一个参数都是Rotation,这个参数表示内容是否旋转,U8G2提供了以下选项:U8G2_R0不旋转,
//U8G2_R1顺时针旋转90度,U8G2_R2,顺时针旋转180度,U8G2_R3顺时针旋转270度,U8G2_R3顺时针旋转270
//度,U8G2_MIRROR镜像翻转。此函数剩下的参数依次是时钟线,数据线,CS,DC,RESET
U8G2_SSD1306_128X64_NONAME_F_4W_SW_SPI u8g2(U8G2_R0, 18, 13, 4, 2, 15);

void setup()
{
    u8g2.begin();
    //开启中文字符集支持
    u8g2.enableUTF8Print();
    //设置字体
    u8g2.setFont(u8g2_font_wqy12_t_chinese2);
}

void loop()
{
    //清除缓存区内容
    u8g2.clearBuffer();

    //绘制内容
    u8g2.setCursor(0, 15);//设置光标位置
    u8g2.print("你好");
    //发送缓存区内容到OLED显示
    u8g2.sendBuffer();

}
5,代码示例(分页模式实现进度条效果)
#include <Arduino.h>
#include <u8g2lib.h>

U8G2_SSD1306_128X64_NONAME_2_4W_SW_SPI u8g2(U8G2_R0, 18, 13, 4, 2, 15);

//初始化进度条长度
int length = 0;
void setup()
{
    u8g2.begin();
}

void loop()
{
    //进入第一页。即清除页面的内容
    u8g2.firstPage();

    do{
        //显示边框
        u8g2.drawFrame(0, 10, 128, 20);
        //显示进度
        u8g2.drawBox(5, 15, length, 10);
    }while(u8g2.nextPage());
    if (length< 118){
        length++;
    }else
    {
        length = 0;
    }
}

 十一,外部中断

1,简介及注意事项

ESP32的外部中断有上升沿,下降沿,低电平和高电平触发模式。ISR名字可以随便起,

2,代码示例(按键触发中断) 

#define BUTTON 14

volatile bool flag = false;

void handle_interrupt() //中断函数
{
    flag = true
}

void setup()
{
    Serial.begin(9600);
    pinMode(BUTTON, INPUT_PULLDOWN);
    //配置中断引脚
    attachInterrupt(digitalPinToInterrpt(BUTTON), handle_interrupt, FALLING);
}

void loop()
{
    if(flag)
    {
        Serial.println("外部中断触发了");
        flag = false;
    }
}

 十二,定时中断

1,简介

2,硬件定时器 

(1)库函数 

timer定时器指针需要用timerBegin()方法将他创建出来。alarm_value单位为微秒。autoreload如果为自动重载就是周期性触发,如果不是自动重载就只触发一次

(2)硬件定时器使用步骤

(3)代码示例 

#define LED 2 //周期性触发的LED
#define LED_ONCE 4 //只触发一次的LED

hw_timer_t* timer = NULL;//创建定时器指针。定期触发
hw_timer_t* timer_once = NULL;//创建定时器指针。触发一次

void timer_interrupt()
{
    digitalWrite(LED, !digitalRead(LED));
}

void timer_once_interrupt()
{
    digitalWrite(LED_ONCE, !digitalRead(LED_ONCE));
}

void setup()
{
    pinMode(LED, OUTPUT);
    pinMode(LED_ONCE, OUTPUT);
    
    //初始化定时器
    timer = timeBegin(0, 80, true); //1us
    timer_once = timeBegin(1, 80, true);

    //配置定时器
    timerAttachInterrupt(timer, timer_interrupt, true);
    timerAttachInterrupt(timer_once, timer_once_interrupt, true);

    //设置定时模式
    timerAlarmWrite(timer, 1000*1000, true);//定时1s
    timerAlarmWrite(timer_once, 1000*1000, true);

    //启动定时器
    timerAlarmEnable(timer);
    timerAlarmEnable(timer_once);
}

void loop()
{

}

3,软件定时器

(1)库函数

 once_ms的第一个参数n表示n毫秒后只执行一次callback函数,图片中的写错了

 (2)代码示例

#include <Ticker.h>

#define LED 2
#define LED_ONCE 4 

//定义定时器对象
Ticker timer;
Ticker timer_once;

void timer_interrupt(int pin)
{
    digitalWrite(pin, !digitalRead(pin));
}

void timer_once_interrupt(int pin)
{
    digitalWrite(pin, !digitalRead(pin));
}

void setup()
{
    pinMode(LED, OUTPUT);
    pinMode(LED_ONCE, OUTPUT);
    
    //配置定时器
    timer.attach(0.5, timer_interrupt, LED);//0.5秒触发一次
    timer_once.attach(0.5, timer_once_interrupt, LED_ONCE);

}

void loop()
{

}

十三,舵机控制

1,控制

2,ledc输出PWM信号控制

#define FREQ 50 //频率
#define CHANNEL 0
#define RESOLUTION 8 //分辨率为256
#define SERVO 13

//控制舵机旋转角度的函数
int calculatePWM(int degree)
{
    int min_width = 0.5 / 20 * pow(2, RESOLUTION);
    int min_width = 2.5 / 20 * pow(2, RESOLUTION);

    return (max_width - min_width) * degree / 180 + min_width;
}
void setup()
{
    //建立LEDC通道
    ledcSetup(CHANNEL, FREQ, RESOLUTION);
    //关联GPIO口与LEDC通道
    ledcAttachPin(SERVO, CHANNEL);
}

void loop()
{
    ledcWrite(CHANNEL, (calculatePWM(30))); //旋转30度
}

3,使用第三方库方式控制舵机

下载第三方库ESP32Servo

#include <ESP32Servo.h>

#define SERVO_PIN 13
#define MAX_WIDTH 2500 //定义最大脉宽
#define MIN_WIDTH 500 //定义最小脉宽

//定义servo对象
Servo myservo;

void setup()
{
    //只用一个舵机,只分配一个硬件定时器即可
    ESP32PWM::allocateTimer(0);
    //设置频率
    myservo.setPeriodHertz(50);
    //关联servo对象与GPIO引脚,设置脉宽范围
    myservo.attach(SERVO_PIN, MIN_WIDTH, MAX_WIDTH);
}

void loop()
{
    myservo.write(180); //旋转180度
}

十四,WiFi模块

1,简介

ESP32通过Arduino连接WiFi和创建热点 。

WiFi模块包含两种模式,热点AP模式和客户端STA模式。热点AP模式是指电脑或手机端直接连接ESP32发出的热点,如果电脑连接模块AP热点,电脑就不能上网了。因此在使用电脑端和模块进行网络通信时,一般情况下都是使用STA模式,也就是电脑和设备同时连接到相同网段的路由器上

2,WiFi相关函数

WiFi.begin用来连接网络,需要提供网络的SSID(名字)和密码

3,连接WiFi代码示例

#include <WiFi.h>

#define LED 2 //板载LED引脚号

const char* ssid = "your-ssid";
const char* password = "your-password";

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

    Serial.println();
    Serial.println();//打印空行
    Serial.print("Connecting to");
    Serial.println(ssid);

    WiFi.begin(ssid, password);
    
    //判断是否连接
    while(WiFi.status() != WL_CONNECTED)
    {
        delay(500);
        Serial.print(".");
    }

    Serial.println("");
    Serial.println("WiFi connected");
    Serial.println("IP address:");
    Serial.println(WiFi.localIP());
    
    //如果ESP32没有连接电脑,看不到串口监视器,这时我们可以通过板载LED反馈wifi连接状态
    pinMode(LED, OUTPUT);
    digitalWrite(LED, HIGH);
    delay(100);
    digitalWrite(LED, LOW);
    delay(100);
    
    digitalWrite(LED, HIGH);
    delay(100);
    digitalWrite(LED, LOW);
    delay(100);
    
    digitalWrite(LED, HIGH);
    delay(1500);
    digitalWrite(LED, LOW);
}

void loop()
{

}

4,创建热点代码示例

#include <WiFi.h>

const char* ssid = "your-ssid";
const char* password = "your-password"

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

    //创建热点
    WiFi.softAP(ssid, password);
    Serial.print("Wi-Fi接入的IP:");
    Serial.println(WiFi.softAPIP());
}

void loop()
{

}

十五,获取网络请求

1,简介

esp32支持2.4G网络,我们可以通过发送HTTP请求来获取一些网络数据。一般这些网络数据都是由一些公共的API接口提供的,我们需要通过这些接口来发送HTTP请求来获取数据

当我们在浏览器中输入网址或者使用应用程序时,我们实际上是向服务器发送请求,HTTP请求是客户端与服务器之间通信的方式,用于获取或发送Web资源(文本文件,图像等等),客户端通过HTTP协议发起请求,服务端返回相应的数据

要获取数据就要调用相应的API接口 

2,相关函数

HTTPClient库是一个用于Arduino的HTTP客户端库,它提供了一组函数来发送HTTP请求并且处理服务器响应

3,代码示例

//先保证ESP32联网
#include <WiFi.h>
#include <HTTPClient.h>

const char* ssid = "your-ssid";
const char* password = "your-password"

String URL = "http://apis.juhe.cn/simpleWeather/query";
//以下为URL的两个参数,可以参考你要访问的URL给定的API定义
String city = "上海";
String key = "a418ca9d9e190c91";

void setup()
{
    Serial.begin(9600);
    
    //连接WiFi
    WiFi.begin(ssid, password);
    
    Serial.print("正在连接WiFi:");
    
    //判断是否连接
    while(WiFi.status() != WL_CONNECTED)
    {
        delay(500);
        Serial.print(".");
    }

    Serial.println("");
    Serial.println("WiFi connected");
    Serial.println("IP address:");
    Serial.println(WiFi.localIP());

    //创建HTTPClient对象
    HTTPClient http;

    //指定访问URL(接口地址)
    http.begin(url+"?city="+city"&key="+key);//网站的定义方式,URL+参数,多个参数之间用&连接

    //接收HTTP响应状态码
    int http_code = http.GET();
    Serial.printf("HTTP状态码:%d\n",http_code);

    //获取响应正文
    String response = http.getString();
    Serial.print("响应数据:");
    Serial.println(response);

    //关闭连接
    http.end();
    
}

void loop()
{

}

 

### ESP32 Arduino 开发教程 #### 示例代码与硬件连接说明 对于ESP32Arduino的开发,可以基于多种功能模块展开编程实践。下面提供了一个简单的GPIO控制LED亮灭的例子及其对应的硬件连接方法。 ```cpp // 定义使用的引脚编号为 GPIO 2 const int ledPin = 2; void setup() { // 将指定引脚配置成输出模式 pinMode(ledPin, OUTPUT); } void loop() { digitalWrite(ledPin, HIGH); // 给引脚写高电平使LED点亮 delay(1000); // 延迟一秒 digitalWrite(ledPin, LOW); // 再次给引脚写低电平让LED熄灭 delay(1000); // 又延迟一秒形成闪烁效果 } ``` 这段程序展示了如何通过改变特定IO端口的状态来操作外设,在此案例中即是指令一个LED按照一定时间间隔交替发光与关闭[^1]。 关于硬件连线部分,则需准备一块带有板载LED指示灯的ESP32开发板;如果要额外接入独立LED组件的话,建议采用限流电阻串联至电源正极再接到目标I/O接口上负极端则接地即可完成基本电路构建[^2]。 当涉及到更复杂的通信协议比如SPI时,除了上述基础之外还需要注意主从关系的确立以及相应管脚的功能定义: - MISO (Master In Slave Out): 主机接收数据线; - MOSI (Master Out Slave In): 主机发送数据线; - SCK (Serial Clock): 同步时钟信号线; - SS / CS (Slave Select or Chip Select): 片选信号线用于选定当前工作的从器件[^3]。 以上就是针对ESP32配合Arduino IDE进行初步尝试所需了解的内容概览。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值