1.触摸中断和外部中断
// 定义外部中断的Mode
// 0: 无中断,读取Touch值
// 1:Touch中断,执行 TouchEvent()
// 2: 外部IO的中断
#define EXT_ISR_MODE 2
void TouchEvent()
{
Serial.printf("Touch Event.\r\n");
}
void PinIntEvent()
{
Serial.printf("PinInt Event.\r\n");
}
void setup()
{
// put your setup code here, to run once:
Serial.begin(115200);
#if 1 == EXT_ISR_MODE
// Pin: T0(GPIO4), 函数指针:TouchEvent, 阈值: 40
touchAttachInterrupt(T0, TouchEvent, 40);
#elif 2 == EXT_ISR_MODE
pinMode(0, INPUT_PULLUP);
attachInterrupt(0, PinIntEvent, FALLING);
#endif
}
void loop()
{
// put your main code here, to run repeatedly:
#if 0 == EXT_ISR_MODE
Serial.printf("touch:%d\r\n", touchRead(T0));
#endif
delay(200);
}
2.定时器
// 函数名称:onTimer()
// 函数功能:中断服务的功能,它必须是一个返回void(空)且没有输入参数的函数
// 为使编译器将代码分配到IRAM内,中断处理程序应该具有 IRAM_ATTR 属性
// https://docs.espressif.com/projects/esp-idf/zh_CN/release-v4.3/esp32/api-reference/storage/spi_flash_concurrency.html
void IRAM_ATTR TimerEvent()
{
Serial.println(interruptCounter++);
if (interruptCounter > 5)
{
interruptCounter = 1;
}
}
void setup()
{
Serial.begin(115200);
// 函数名称:timerBegin()
// 函数功能:Timer初始化,分别有三个参数
// 函数输入:1. 定时器编号(0到3,对应全部4个硬件定时器)
// 2. 预分频器数值(ESP32计数器基频为80M,80分频单位是微秒)
// 3. 计数器向上(true)或向下(false)计数的标志
// 函数返回:一个指向 hw_timer_t 结构类型的指针
timer = timerBegin(0, 80, true);
// 函数名称:timerAttachInterrupt()
// 函数功能:绑定定时器的中断处理函数,分别有三个参数
// 函数输入:1. 指向已初始化定时器的指针(本例子:timer)
// 2. 中断服务函数的函数指针
// 3. 表示中断触发类型是边沿(true)还是电平(false)的标志
// 函数返回:无
timerAttachInterrupt(timer, &TimerEvent, true);
// 函数名称:timerAlarmWrite()
// 函数功能:指定触发定时器中断的计数器值,分别有三个参数
// 函数输入:1. 指向已初始化定时器的指针(本例子:timer)
// 2. 第二个参数是触发中断的计数器值(1000000 us -> 1s)
// 3. 定时器在产生中断时是否重新加载的标志
// 函数返回:无
timerAlarmWrite(timer, 1000000, true);
timerAlarmEnable(timer); // 使能定时器
}
void loop()
{
}
3.PWM
#include <Arduino.h>
#include "../lib/Motor/Motor.h"
int interruptCounter = 0;
hw_timer_t *timer = NULL;
// 绑定的IO
const int Motor_PWM_PinA = 2;
const int Motor_PWM_PinB = 4;
// PWM的通道,共16个(0-15),分为高低速两组,
// 高速通道(0-7): 80MHz时钟,低速通道(8-15): 1MHz时钟
// 0-15都可以设置,只要不重复即可,参考上面的列表
// 如果有定时器的使用,千万要避开!!!
const int Motor_channel_PWMA = 2;
const int Motor_channel_PWMB = 3;
// PWM频率,直接设置即可
int Motor_freq_PWM = 10;
// PWM分辨率,取值为 0-20 之间,这里填写为10,那么后面的ledcWrite
// 这个里面填写的pwm值就在 0 - 2的10次方 之间 也就是 0-1024
int Motor_resolution_PWM = 10;
void IRAM_ATTR TimerEvent()
{
Serial.println(interruptCounter++);
if (interruptCounter > 5)
{
interruptCounter = 1;
}
}
void Motor_Init(void)
{
ledcSetup(Motor_channel_PWMA, Motor_freq_PWM, Motor_resolution_PWM); // 设置通道
ledcSetup(Motor_channel_PWMB, Motor_freq_PWM, Motor_resolution_PWM); // 设置通道
ledcAttachPin(Motor_PWM_PinA, Motor_channel_PWMA); //将 LEDC 通道绑定到指定 IO 口上以实现输出
ledcAttachPin(Motor_PWM_PinB, Motor_channel_PWMB);
}
void PWM_SetDuty(uint16_t DutyA, uint16_t DutyB)
{
ledcWrite(Motor_channel_PWMA, DutyA);
ledcWrite(Motor_channel_PWMB, DutyB);
}
void setup()
{
Serial.begin(115200);
Motor_Init();
timer = timerBegin(0, 80, true);
timerAttachInterrupt(timer, &TimerEvent, true);
timerAlarmWrite(timer, 1000000, true);
timerAlarmEnable(timer); // 使能定时器
}
void loop()
{
PWM_SetDuty(200 * interruptCounter, 200 * interruptCounter);
}
4.WIFI
#include <WiFi.h>
// WiFi的初始化和连接
void WiFi_Connect()
{
WiFi.begin("123456", "1234567891");
while (WiFi.status() != WL_CONNECTED)
{ //这里是阻塞程序,直到连接成功
delay(300);
Serial.print(".");
}
}
5.ArduinoJson
#include <HTTPClient.h>
#include <ArduinoJson.h>
// bilibili api: follower
String UID = "247883432";
String followerUrl = "http://api.bilibili.com/x/relation/stat?vmid=" + UID; // 粉丝数
long follower = 0; // 粉丝数
DynamicJsonDocument doc(1024);
// 获取粉丝数
void getBiliBiliFollower()
{
HTTPClient http;
http.begin(followerUrl); //HTTP begin
int httpCode = http.GET();
if (httpCode > 0)
{
// httpCode will be negative on error
Serial.printf("HTTP Get Code: %d\r\n", httpCode);
if (httpCode == HTTP_CODE_OK) // 收到正确的内容
{
String resBuff = http.getString();
// 输出示例:{"mid":123456789,"following":226,"whisper":0,"black":0,"follower":867}}
Serial.println(resBuff);
// 使用ArduinoJson_6.x版本,具体请移步:https://github.com/bblanchon/ArduinoJson
deserializeJson(doc, resBuff); //开始使用Json解析
follower = doc["data"]["follower"];
Serial.printf("Follers: %ld \r\n", follower);
}
}
else
{
Serial.printf("HTTP Get Error: %s\n", http.errorToString(httpCode).c_str());
}
http.end();
}
6.蓝牙
/*
Video: https://www.youtube.com/watch?v=oCMOYS71NIU
Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleNotify.cpp
Ported to Arduino ESP32 by Evandro Copercini
Create a BLE server that, once we receive a connection, will send periodic notifications.
创建一个BLE服务器,一旦我们收到连接,将会周期性发送通知
T使用步骤:
1. 创建一个 BLE Server
2. 创建一个 BLE Service
3. 创建一个 BLE Characteristic
4. 创建一个 BLE Descriptor
5. 开始服务
6. 开始广播
*/
#include <Arduino.h>
#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>
#include "common.h"
uint8_t txValue = 0;
BLEServer *pServer = NULL; //BLEServer指针 pServer
BLECharacteristic *pTxCharacteristic = NULL; //BLECharacteristic指针 pTxCharacteristic
bool deviceConnected = false; //本次连接状态
bool oldDeviceConnected = false; //上次连接状态
// See the following for generating UUIDs: https://www.uuidgenerator.net/
#define SERVICE_UUID "12a59900-17cc-11ec-9621-0242ac130002" // UART service UUID
#define CHARACTERISTIC_UUID_RX "12a59e0a-17cc-11ec-9621-0242ac130002"
#define CHARACTERISTIC_UUID_TX "12a5a148-17cc-11ec-9621-0242ac130002"
class MyServerCallbacks : public BLEServerCallbacks
{
void onConnect(BLEServer *pServer)
{
deviceConnected = true;
};
void onDisconnect(BLEServer *pServer)
{
deviceConnected = false;
}
};
class MyCallbacks : public BLECharacteristicCallbacks
{
void onWrite(BLECharacteristic *pCharacteristic)
{
std::string rxValue = pCharacteristic->getValue(); //接收信息
if (rxValue.length() > 0)
{ //向串口输出收到的值
Serial.print("RX: ");
for (int i = 0; i < rxValue.length(); i++)
Serial.print(rxValue[i]);
Serial.println();
}
}
};
void setup()
{
Serial.begin(115200);
// 创建一个 BLE 设备
BLEDevice::init("UART_BLE");
// 创建一个 BLE 服务
pServer = BLEDevice::createServer();
pServer->setCallbacks(new MyServerCallbacks()); //设置回调
BLEService *pService = pServer->createService(SERVICE_UUID);
// 创建一个 BLE 特征
pTxCharacteristic = pService->createCharacteristic(CHARACTERISTIC_UUID_TX, BLECharacteristic::PROPERTY_NOTIFY);
pTxCharacteristic->addDescriptor(new BLE2902());
BLECharacteristic *pRxCharacteristic = pService->createCharacteristic(CHARACTERISTIC_UUID_RX, BLECharacteristic::PROPERTY_WRITE);
pRxCharacteristic->setCallbacks(new MyCallbacks()); //设置回调
pService->start(); // 开始服务
pServer->getAdvertising()->start(); // 开始广播
Serial.println(" 等待一个客户端连接,且发送通知... ");
}
void loop()
{
// deviceConnected 已连接
if (deviceConnected)
{
pTxCharacteristic->setValue(&txValue, 1); // 设置要发送的值为1
pTxCharacteristic->notify(); // 广播
txValue++; // 指针地址自加1
delay(2000); // 如果有太多包要发送,蓝牙会堵塞
}
// disconnecting 断开连接
if (!deviceConnected && oldDeviceConnected)
{
delay(500); // 留时间给蓝牙缓冲
pServer->startAdvertising(); // 重新广播
Serial.println(" 开始广播 ");
oldDeviceConnected = deviceConnected;
}
// connecting 正在连接
if (deviceConnected && !oldDeviceConnected)
{
// do stuff here on connecting
oldDeviceConnected = deviceConnected;
}
}
7.多线程
/*
// 多线程基于FreeRTOS,可以多个任务并行处理;
// ESP32具有两个32位Tensilica Xtensa LX6微处理器;
// 实际上我们用Arduino进行编程时只使用到了第一个核(大核),第0核并没有使用
// 多线程可以指定在那个核运行;
*/
#include <Arduino.h>
#define USE_MULTCORE 1
void xTaskOne(void *xTask1)
{
while (1)
{
Serial.printf("Task1 \r\n");
delay(500);
}
}
void xTaskTwo(void *xTask2)
{
while (1)
{
Serial.printf("Task2 \r\n");
delay(1000);
}
}
void setup()
{
Serial.begin(115200);
delay(10);
}
void loop()
{
#if !USE_MULTCORE
xTaskCreate(
xTaskOne, /* Task function. */
"TaskOne", /* String with name of task. */
4096, /* Stack size in bytes. */
NULL, /* Parameter passed as input of the task */
1, /* Priority of the task.(configMAX_PRIORITIES - 1 being the highest, and 0 being the lowest.) */
NULL); /* Task handle. */
xTaskCreate(
xTaskTwo, /* Task function. */
"TaskTwo", /* String with name of task. */
4096, /* Stack size in bytes. */
NULL, /* Parameter passed as input of the task */
2, /* Priority of the task.(configMAX_PRIORITIES - 1 being the highest, and 0 being the lowest.) */
NULL); /* Task handle. */
#else
//最后一个参数至关重要,决定这个任务创建在哪个核上.PRO_CPU 为 0, APP_CPU 为 1,或者 tskNO_AFFINITY 允许任务在两者上运行.
xTaskCreatePinnedToCore(xTaskOne, "TaskOne", 4096, NULL, 1, NULL, 0);
xTaskCreatePinnedToCore(xTaskTwo, "TaskTwo", 4096, NULL, 2, NULL, 1);
#endif
while (1)
{
Serial.printf("XTask is running\r\n");
delay(1000);
}
}