玩转 ESP32 + Arduino (六) 硬件定时器, IIC, SPI

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了玩转 ESP32 + Arduino (六) 硬件定时器, IIC, SPI相关的知识,希望对你有一定的参考价值。

参考技术A

ESP32 芯片包含两个硬件定时器组。每组有两个通用硬件定时器。它们都是基于 16 位预分频器和 64 位自动重载功能的向上/向下计数器的 64 位通用定时器。

hw_timer_t * timerBegin(uint8_t num, uint16_t divider, bool countUp)

参数:

返回值:
返回一个计时器结构体指针 hw_timer_t * ,我们预定义一个指针接收他

void timerEnd(hw_timer_t *timer)

参数:

void timerAttachInterrupt(hw_timer_t timer, void ( fn)(void), bool edge)

参数:

void timerDetachInterrupt(hw_timer_t *timer)

void timerAlarmWrite(hw_timer_t *timer, uint64_t alarm_value, bool autoreload)

参数:

void timerAlarmEnable(hw_timer_t *timer)

参数:

void timerAlarmDisable(hw_timer_t *timer)

bool timerAlarmEnabled(hw_timer_t *timer)

ESP32有两个I2C控制器(也称为端口),负责处理两条I2C总线上的通信。每个I2C控制器都可以作为主机或从机运行。引脚21 默认的SDA, 引脚22是默认的SCL

IIC需要引入自带库 Wire.h Wire继承steam类 steam类有的他都有

void requestFrom(uint16_t address, uint8_t size, bool sendStop)

请求完成后 主机可以用 Wire.available() 和 Wire.read() 等函数等待并获取从机的回答

参数:

void beginTransmission(int address)
随后, 主机可以使用 Wire.write(); 写数据并使用 Wire.endTransmission(); 结束传输

参数:

结束传输, 并释放IIC

返回值: uint8_t 类型

当作为主机时: 主机将要发送的数据加入发送队列;
当作为从机时: 从机发送的数据给主机;

参数:

返回值: byte类型
输入的字节数

返回接收到的字节数

返回值: byte类型

当作为主机时: 主机使用requestFrom()后 要使用此函数获取数据;
当作为从机时: 从机读取主机给的数据;

返回值: 读到的字节数据 byte

size_t readBytes(char *buffer, size_t length)

参数:

返回值: 数据长度

size_t readBytesUntil(char terminator, char *buffer, size_t length)

参数:

返回值: 数据长度

Wire.busy();

返回布尔值

继承自steam类, 个人感觉iic不会用到的

parseFloat
parseInt
find
findUntil
setTimeout
这些都是steam继承来的 大家灵活应用

从机有些函数和主机是一样的, 请看上一章节,本章节只有不一样的部分

Wire.begin(adress); //adress取值0~127

void onRequest(void (*)())

参数:

void onReceive(void (*)(int))

参数:

ESP32有四个SPI外设,分别为SPI0、SPI1、HSPI和VSPI。

SPI通讯流程如下:

SPI接口默认VSPI. 接口频率1 000 000, 数据默认采用MSBFIRST(低有效位优先), 时钟模式:SPI_MODE0(SCLK闲置为0, SCLK上升沿采样)

参数:

参数:

参数:

采用该函数,可以代替上面三个函数了.

参数:

结束SPI通信

参数:

返回值: 接收到的数据

掌控板IO接口编程入门 | 用Arduino玩转掌控板(ESP32)系列

众所周知,掌控板在创客教育中用的非常广泛,它是一块基于 ESP32 的学习开发板。大家对掌控板编程,用的比较多的都是图形化编程的方式,比如 mPython、Mind+ 等。但是,既然掌控板是基于 ESP32 芯片的,所以我们也可以用 Arduino 软件对其编程。所以,有时间的话,我准备给大家分享一系列用 Arduino 代码对掌控板(ESP32)编程的教程:用 Arduino 玩转掌控板(ESP32)系列

本系列历史文章目录:

本期给大家带来的是:掌控板IO接口编程入门,教你用 Arduino IDE 学会掌控板 IO 接口的简单编程操作。IO 就是 INPUT 与 OUTPUT 的缩写,即输入与输出

其实本篇是这个系列的入门篇之一,但是由于我一直偷懒,这篇一直放着没写,先写了一些进阶的内容。本篇比较简单,所以就不放案例演示视频了。

# 概述

掌控板的 IO 接口主要是用来连接外部传感器、执行器等相关外设的。平时我们使用最多最常见的一些外设,一般都是数字量或模拟量的,传感器一般都是输入设备、执行器一般都是输出设备。所以,一般情况下学习一个主控板的 IO 接口基本操作,我们都是从数字输入数字输出模拟输入模拟输出这个 4 个方面来进行学习的,本篇也不例外。

这里需要注意的是,输入和输出是相对主控板来说的

  • 当信号是由主控板向外设发送时,相应的外设就是主控板的输出设备;

  • 当信号是由外设向主控板发送时,也就是主控板去读取外设的信号时,相应的外设就是主控板的输入设备。

所以:

  • 大部分传感器都是输入设备,因为他们的功能是测量数据,然后主控板去读取他们的数据;

  • 大部分执行器都是输出设备,因为是主控板向他们发送信号、控制他们完成相应的操作。

# 数字输入

数字输入(或数字量输入)设备是生活中最常见的设备,比如房间里的开关、按钮、楼道里的人体感应设备,这些设备有一个共同的特点,即只有 2 种情况:有或无、开或关、1 或 0,这些只有 2 种情况的设备,一般称为数字量设备。相应地,如果他们是传感器,则称为数字输入设备,或数字输入传感器。

掌控板上的按键 A 和 B,其实就是数字输入传感器。所以本节就以读取掌控板上的按键 A 和 B 为例,教你对数字输入设备编程。

先来看一下完整的程序:

// 设置掌控板按键 A 的引脚编号
const int buttonAPin = P5;
// 设置按键 A 的状态值变量
int buttonAState = 0;


void setup() 
  // 初始化串口监视器
  Serial.begin(9600);
  // 初始化按键 A 对应的引脚为输入模式
  pinMode(buttonAPin, INPUT);



void loop() 
  // 读取按键 A 的值
  buttonAState = digitalRead(buttonAPin);
  // 如果按键 A 被按下了,串口监视器输出信息
  if (buttonAState == LOW) 
    Serial.println("Button A pressed");
  


  delay(100);

这个程序很简单,程序中也有相应的注释了,我们简单来讲解一下。

首先在程序开头定义了两个变量,buttonAPin 用来定义按键 A 对应的引脚,buttonAState 用来存储按键 A 的状态。

// 设置掌控板按键 A 的引脚编号
const int buttonAPin = P5;
// 设置按键 A 的状态值变量
int buttonAState = 0;

这里讲一下命名变量的小技巧,变量一般要命名成方便用户辨别、并且有一定实际字面意义的名称,这样当程序比较长的时候更加容易读懂。尽量不要命名成 a、b 这些没有太多实际字面意义的名称,当然特殊情况除外。

那么我们是如何知道按键 A 对应的引脚编号是 P5 呢

实际上掌控板官方 Wiki 上提供了非常详细的说明和电路图,我们阅读相应的文档,就可以知道掌控板上的板载资源对应的引脚了。我们可以直接点击下方链接,查看掌控板官方 Wiki 资料。

https://mpython.readthedocs.io/zh/master/board/hardware.html

在上面的网页中,我们可以查到一张表格,上面记录了掌控板上所有板载资源对应的引脚。从这里我们可以查到按键 A 对应的引脚编号为 P5。

接下来在初始化程序 setup() 中,我们可以看到下面两句代码,分别用来对串口监视器进行初始化、以及设定按键 A 引脚的模式。对串口监视器初始化时,我们要设定串口波特率,常用的波特率是 9600 和 115200,设置波特率的作用是让电脑和掌控板保持相同的通信速率,以便可以互相收发信息。引脚模式,最常用的一般为输入模式 INPUT 和输出模式 OUTPUT,我们知道按键是数字输入传感器,所以要设置为输入模式 INPUT。

// 初始化串口监视器
Serial.begin(9600);
// 初始化按键 A 对应的引脚为输入模式
pinMode(buttonAPin, INPUT);

这里顺便再提一下,在 Arduino IDE 中编程,一般会有两个自带的函数,分别为初始化函数 setup() 和循环函数 loop()。setup() 函数的功能是在程序开始前做相应的设置,设备上电后(或者按下 RESET 按键之后)只执行一次;loop() 函数是在 setup() 运行完成之后开始运行的,它的功能是不断重复执行其中的代码,因此需要重复运行的代码或任务,一般放在 loop() 函数中,比如不断读取按键的状态。当然也有一些特殊情况,比如中断的设置等,是不用放在 loop() 中的,这部分等讲到相应内容的时候再来展开。

接下来在 loop() 函数中,首先读取按键 A 的状态值,并且赋值给变量 buttonAState。读取数字量输入的程序为 digitalRead(),跟变量命名一样,程序中函数命名也是带有一定的意义、简单易读的。

// 读取按键 A 的值
buttonAState = digitalRead(buttonAPin);

然后根据按键 A 的状态值,通过串口监视器打印出相应的信息。这里需要注意的是,一般情况下,按键弹起时的默认值为 LOW(或 0),当按键被按下时,按键的值变为 HIGH(或 1)。但是这不是绝对的,跟电路设计有关,掌控板的按键值与按键状态,就正好相反。所以当掌控板的按键 A 被按下时,它的状态值为 LOW。为了防止程序运行太快,导致串口监视器一下子输出太多信息,我们这里加了一个延时函数:delay(100),让程序每次都延时 100 毫秒再去运行下一次循环任务。

// 如果按键 A 被按下了,串口监视器输出信息
if (buttonAState == LOW) 
  Serial.println("Button A pressed");

delay(100);

在工具菜单中,将主控板选为掌控板,并选择正确的串口号,上传程序。然后打开串口监视器,我们看看程序运行的效果。在串口监视器中将波特率设置为 9600,然后按下掌控板上的按键 A。每按下一次按键 A,串口监视器中就会输出相应的信息,说明程序编写成功!

试一试:改写程序,让程序同时也可以读取按键 B 的状态,并在串口监视器输出相应的信息。你会了么?

# 数字输出

学会了数字输入,我们再来学一学数字输出。我们生活中最常见的电灯,一般情况下,都是数字输出设备。数字输出也是只有 2 种控制状态的设备,高或低、1 或 0。这里以控制 LED 灯为例,来学习一下数字输出的程序编写。我们现在掌控板的 P0 端口外接一个 LED 灯,这里你可以选择自己喜欢的任意扩展板。电路比较简单,所以这里不放电路图了。

来看一下完整的程序:

// 设置掌控板按键 A 的引脚编号
const int buttonAPin = P5;
// 设置 LED 灯的引脚编号
const int ledPin = P0;
// 设置按键 A 的状态值变量
int buttonAState = 0;


void setup() 
  // 初始化串口监视器
  Serial.begin(9600);
  // 初始化按键 A 对应的引脚为输入模式
  pinMode(buttonAPin, INPUT);
  // 初始化 LED 对应的引脚为输出模式
  pinMode(ledPin, OUTPUT);



void loop() 
  // 读取按键 A 的值
  buttonAState = digitalRead(buttonAPin);
  // 如果按键 A 被按下了,点亮 LED 灯,否则熄灭 LED 灯
  if (buttonAState == LOW) 
    Serial.println("Button A pressed");
    digitalWrite(ledPin, HIGH);
   else 
    digitalWrite(ledPin, LOW);
  
  delay(100);

仔细观察,我们发现这个程序跟上一节数字输入中的程序非常类似,我们只是在这基础之上加了几行代码。这里只讲差异部分。

首先在程序开头,定义了 LED 灯的引脚编号,我们将 LED 灯通过扩展板接在掌控板的 P0 引脚,这个与定义按键 A 引脚编号的方法一致。

// 设置 LED 灯的引脚编号
const int ledPin = P0;

然后在 setup() 初始化函数中设置了 LED 连接的引脚为输出模式 OUTPUT,这个与设置按键 A 的方法也一样,只不过一个是 LED 设置为输出模式、按键 A 设置为输入模式。

// 初始化 LED 对应的引脚为输出模式
pinMode(ledPin, OUTPUT);

然后在 loop() 函数中,当检测到按键 A 被按下时,点亮 LED,否则熄灭 LED 灯。点亮 LED 灯的代码为:

digitalWrite(ledPin, HIGH);

熄灭 LED 灯的代码为:

digitalWrite(ledPin, LOW);

将程序上传到掌控板,按下按键 A,看看 LED 灯是否点亮了呢?松开按键 A 呢?

试一试:改写程序,实现:按下按键 A,点亮 LED 灯;按下按键 B,熄灭 LED 灯。

# 模拟输入

讲完数字输入、数字输出,我们再来看一看模拟输入。模拟输入是相对数字输入来说的,数字输入只要 2 种状态,但是模拟输入有很多种连续的状态,比如各种旋钮、温度值等。

在掌控板上也有 2 个模拟输入传感器:声音传感器与光线传感器。下面我们以声音传感器为例,讲一讲模拟输入的程序编写方法。

// 设置掌控板声音传感器引脚编号
const int soundPin = P10;
// 设置声音大小值变量
int soundValue = 0;


void setup() 
  // 初始化串口监视器
  Serial.begin(9600);
  // 初始化声音传感器引脚为输入模式
  pinMode(soundPin, INPUT);



void loop() 
  // 读取声音传感器的值
  soundValue = analogRead(soundPin);
  // 串口监视器中打印声音传感器的值
  Serial.println(soundValue);


  delay(10);

这个程序与数字输入部分的程序也是非常类似的。

在程序开头,定义了两个变量,用来设置声音传感器的引脚编号、声音传感器的值。

// 设置掌控板声音传感器引脚编号
const int soundPin = P10;
// 设置声音大小值变量
int soundValue = 0;

接着在 setup() 初始化函数中,初始化串口监视器和声音传感器的引脚模式:

// 初始化串口监视器
Serial.begin(9600);
// 初始化声音传感器引脚为输入模式
pinMode(soundPin, INPUT);

接着在 loop() 函数中读取声音的值,并且在串口监视器中打印出来。读取模拟量的函数为 analogRead()。

// 读取声音传感器的值
soundValue = analogRead(soundPin);
// 串口监视器中打印声音传感器的值
Serial.println(soundValue);
delay(10);

将程序上传到掌控板中,打开串口监视器,对着声音传感器说话,我们看看效果。

我们还可以以曲线图的形式,将声音传感器数据的变化展现出来。在 Arduino IDE 菜单栏中,依次点击:工具 → 串口绘图器,打开串口绘图器,对着声音传感器说话,看看曲线图变化吧。

试一试:改写程序,让程序同时也可以读取光线传感器的值,看看串口绘图器会输出什么信息呢?

# 模拟输出

你有没有注意到,有些人家里的电灯,亮度是可以调节的?这个其实就是模拟输出。相比于数字输出只有两种状态,模拟输出可以有连续的多种状态。

由于在 Arduino IDE 中,用掌控板自带的函数功能实现模拟输出比较复杂。因此我们这里调用别人做好的适用于掌控板 ESP32 的模拟输出函数库。函数库下载地址为:

https://github.com/ERROPiX/ESP32_AnalogWrite

我们要先将这个库导入到 Arduino IDE 中。这个库的功能是可以让掌控板像 Arduino 一样,方便的使用模拟输出功能,有个这个库,掌控板模拟输出的语法,就跟 Arduino 完全一样了。

这里以控制 LED 灯实现呼吸灯效果为例,完整的程序如下:

#include <Arduino.h>
#include <analogWrite.h>


// 设置 LED 灯引脚编号
const int ledPin = P0;


void setup() 
  // 初始化 LED 灯引脚为输出模式
  pinMode(ledPin, OUTPUT);



void loop() 
  for (int brightness = 0; brightness <= 255; brightness++) 
    analogWrite(ledPin, brightness);
    delay(5);
  


  for (int brightness = 255; brightness >= 0; brightness--) 
    analogWrite(ledPin, brightness);
    delay(5);
  

在程序最开始,我们先引入两个头文件,在头文件中定义了实现模拟输出相关的功能函数。然后定义了 LED 灯的引脚编号。

#include <Arduino.h>
#include <analogWrite.h>


// 设置 LED 灯引脚编号
const int ledPin = P0;

接着在 setup() 函数中设置 LED 灯引脚为输出模式。

然后在 loop() 函数中,通过 for 循环结构,控制 LED 灯由暗变亮,再由亮变暗。亮度通过局部变量 brightness 来设置。

for (int brightness = 0; brightness <= 255; brightness++) 
  analogWrite(ledPin, brightness);
  delay(5);



for (int brightness = 255; brightness >= 0; brightness--) 
  analogWrite(ledPin, brightness);
  delay(5);

将程序上传到掌控板中,LED 灯是不是呈现呼吸灯闪烁变化的样子?说明程序编程成功了。

# 总结

在本章中,我们学习了:

  • 如何查阅掌控板各引脚相应的资源配置;

  • 数字量与模拟量的区别;

  • 简单的数字输入、数字输出、模拟输入、模拟输出的程序编写;

  • Arduino IDE 的基本使用方法。

学习了这些基础内容之后,就可以学习后面更加进阶的内容啦,其实进阶内容与入门内容类似,都是由一个个小功能组成的,有了这些基础功能的组合,通过不同的排列组合和逻辑设置,就可以实现各种好玩的创意啦!

我们下期见!如果本文对你有帮助的话,点个“ 在”支持一下喽。


欢迎转发朋友圈。如需转载,请注明出处和原作者。

我知道你在看

以上是关于玩转 ESP32 + Arduino (六) 硬件定时器, IIC, SPI的主要内容,如果未能解决你的问题,请参考以下文章

玩转 ESP32 + Arduino (十一) EEPROM NTP对时 蓝牙透传

玩转 ESP32 + Arduino (八) U8G2驱动OLED

玩转 ESP32 + Arduino(二十八) TFT_eSPI库驱动ST7789

掌控板IO接口编程入门 | 用Arduino玩转掌控板(ESP32)系列

玩转 ESP32 + Arduino (十六) 通过mqtt协议连接阿里云

玩转 ESP32 + Arduino (十九) SIM800L调试(基于TTGO T-CALL)