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

一. 硬件定时器

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

1. 初始化定时器 timerBegin

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

参数:

  • num : 定时器编号
  • divider:分频数
  • countUp: 是否是累加模式

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

hw_timer_t*  tim1= NULL;
tim1 = timerBegin(0,80,true);  //80MHZ, ESP32主频80MHz

2. 取消初始化定时器 timerEnd

void timerEnd(hw_timer_t *timer)

参数:

  • *timer : 目标定时器 ( 计时器结构体指针 hw_timer_t * )

2. 配置定时器中断 timerAttachInterrupt

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

参数:

  • *timer : 目标定时器 ( 计时器结构体指针 hw_timer_t * )
  • void (*fn)(void) : 中断函数入口地址
  • 中断边沿触发 : 是否跳变沿触发中断 定时器中断触发方式有: 电平触发中断(level type) 边缘触发中断(edge type)
timerAttachInterrupt(tim1,tim1Interrupt,true);

4. 取消定时器中断 timerDetachInterrupt

void timerDetachInterrupt(hw_timer_t *timer)

5. 定时器设置timerAlarmWrite

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

参数:

  • *timer : 目标定时器 ( 计时器结构体指针 hw_timer_t * )
  • alarm_value : 计数上限值
  • autoreload : 是否重装载.
timerAlarmWrite(tim1, 100000, true);

6. 使能定时器 timerAlarmEnable

void timerAlarmEnable(hw_timer_t *timer){}

参数:

  • *timer : 目标定时器 ( 计时器结构体指针 hw_timer_t * )
timerAlarmEnable(tim1);

7. 失能定时器 timerAlarmDisable

void timerAlarmDisable(hw_timer_t *timer)

8. 判断定时器是否启动 timerAlarmEnabled

bool timerAlarmEnabled(hw_timer_t *timer)

Serial.println(timerAlarmEnabled(tim1));

例子:

#include <Arduino.h>

hw_timer_t *tim1 = NULL;
int tim1_IRQ_count = 0;

void tim1Interrupt()
{
  Serial.println("haha");
  tim1_IRQ_count++;
  Serial.println(timerAlarmEnabled(tim1));
}

void setup()
{
  Serial.begin(115200);
  tim1 = timerBegin(0, 80, true);
  timerAttachInterrupt(tim1, tim1Interrupt, true);
  timerAlarmWrite(tim1, 100000, true);
  timerAlarmEnable(tim1);
}

void loop()
{
  if (tim1_IRQ_count > 10)
  {
    Serial.println("count trigger");
    tim1_IRQ_count = 0;
  }
}

二. IIC (主机)

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

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

#include "Wire.h"

1. 初始化IIC (以主机身份) begin

Wire.begin();

2. 以主机身份像从机请求数据 requestFrom

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

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

参数:

  • address : 从机地址
  • size: 请求字节数
  • sendStop : 是否发送停止 , 如果为true, 释放IIC总线. 如果为false, 发送一个重新开始的信息, 并继续保持IIC总线的连接.
Wire.requestFrom(adress,10,true);

3. 主机开始传输 beginTransmission()

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

参数:

  • address : 从机地址
Wire.beginTransmission(120);

4. 结束数据传输 endTransmission()

结束传输, 并释放IIC

Wire.endTransmission();

5. 结束数据传输但不释放IIC占用 endTransmission(false)

返回值: uint8_t 类型

含义
0 成功
1 数据过长,超出发送缓冲区
2 在地址发送时接收到NACK信号
3 在数据发送时接收到NACK信号
4 其他错误
Wire.endTransmission(false);

6. 写 write()

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

参数:

  • Wire.write(value); //单字节发送
  • Wire.write(string); //以一系列字节发送
  • Wire.write(data,length); //以字节形式发送,指定长度

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

7. 接收数据寄存器有值 available()

返回接收到的字节数

返回值: byte类型

  • 可读字节数

8. 读取1byte数据 read()

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

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

9.读取多个字节的数据 readBytes()

size_t readBytes(char *buffer, size_t length)

参数:

  • buffer: 接收缓冲区, 一个char型指针
  • length: 数据长度

返回值: 数据长度

10. 读取直到遇到某字符

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

参数:

  • terminator : 终结字符 char类型
  • buffer: 接收缓冲区, 一个char型指针
  • length: 数据长度

返回值: 数据长度

11. 当前IIC忙线中?

Wire.busy();

返回布尔值

12. 读取字符串 readString() readStringUntil()

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

13. 其他

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

三. IIC(从机)

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

1. 初始化IIC (以从机身份) begin(adress)

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

Wire.begin(120);

2. 当从机被请求时触发函数onRequest()

void onRequest(void (*)())

参数:

  • 回调函数

3. 当从机收到数据时触发函数

void onReceive(void (*)(int))

参数:

  • 回调函数 (接收一个int类型的参数,代表接收的字节数)

四. SPI

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

  • SPI0是专用于Flash的缓存,ESP32将连接的SPI Flash设备映射到内存中。
  • SPI1和SPI0 使用相同的硬件线,SPI1用于写入flash芯片。
  • HSPI和VSPI可以任意使用。
  • SPI1、HSPI和VSPI共有三条片选线,因此作为SPI主机允许ESP32 至多驱动三个SPI设备。

1. HSPI和VSPI的接口及引脚

SPI名 MOSI MISO SCLK SS
VSPI 23 19 18 5
HSPI 13 12 14 15

SPI通讯流程如下:

2. SPI初始化 SPI.begin()

SPI.begin();

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

3. 设置数据在SPI上的传输方式 SPI.setBitOrder(bitOrder);

参数:

  • bitOrder : 传输方式, 可选: LSBFIRST 低有效位先传 ; HSBFIRST 高有效位先传
SPI.setBitOrder(LSBFIRST);

3. 设置SPI频率 SPI.setFrequency(freq)

参数:

  • freq 频率
SPI.setFrequency(1000000);

4. 设置SPI的时钟模式 SPI.setDataMode(dataMode);

参数:

  • dataMode: 时钟模式, 可以取以下值
模式 说明
SPI_MODE0 SCLK闲置为低电平,上升沿采样(默认)
SPI_MODE1 SCLK闲置为低电平,下降沿采样
SPI_MODE2 SCLK闲置为高电平,上升沿采样
SPI_MODE3 SCLK闲置为高电平,下降沿采样
SPI.setDataMode(SPI_MODE0);

5. 按照setting的设置启动SPI通信 SPI.beginTransaction(setting);

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

参数:

  • setting 设置. 是SPISettings类型的对象, 有_bitOrder ,_clock ,_dataMode 这三个属性.
  setting1._bitOrder = LSBFIRST;
  setting1._clock = 1000000;
  setting1._dataMode = SPI_MODE0;
  SPI.beginTransaction(setting1);

6. 结束SPI通信 SPI.endTransaction();

结束SPI通信

SPI.endTransaction();

7. 接收/发送一个字节的数据 SPI.transfer(data);

参数:

  • data: 要发送的数据

返回值: 接收到的数据

uint8_t SPIClass::transfer(uint8_t data) 
  SPI.transfer(0x01);
  SPI.transfer16(0x0102);
  SPI.transfer32(0x01020304);

  uint8_t byte1;
  uint16_t bytes2;
  uint32_t bytes3;
  byte1 = SPI.transfer();
  bytes2 = SPI.transfer16();
  bytes3 = SPI.transfer32();
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 162,547评论 4 374
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,787评论 2 308
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 112,175评论 0 254
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,752评论 0 223
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 53,169评论 3 297
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 41,056评论 1 226
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,195评论 2 321
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,980评论 0 214
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,724评论 1 250
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,872评论 2 254
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,344评论 1 265
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,667评论 3 264
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,379评论 3 245
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,202评论 0 9
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,992评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 36,189评论 2 286
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,987评论 2 279