# 前言

开发板:ESP32-S3-DEVKIT-C

开发环境:Clion + Platformio

开发方式:Arduino

# 正文

# 关于 ESP32-S3

为什么选择使用 ESP32-S3?

在 TMD 芯片贵上天的今天,一片 STM32F103C8T6 也要接近 20 块钱,在加一个 NF24L01 价格上跟一片 ESP32-S3-WROOM-1/ESP32-S3-WROOM-1U N16R8 差不多,但是资源上被 ESP32-S3 甩了 10086 条街。

先看一下 ESP32-S3-WROOM-1 N16R8 这个模组 (ESP32-S3-WROOM-1 采用 PCB 板载天线,ESP32-S3-WROOM-1U 采用连接器连接外部天线,资源一致)

  • Xtensa® 32 位 LX7 双核处理器,五级流水线架构,主频高达 240 MHz
  • 2.4 GHz WiFi & Bluetooth 5
  • PSRAM:8MB
  • FALSH: 16MB
  • GPIO: 45
  • SPI: 4
  • I2C: 2
  • I2S: 2
  • ADC: 12
  • TOUCH: 14

除此之外,ESP32-S3 安全机制也非常完善

  • 安全启动
  • Flash 加密
  • 4-Kbit OTP,用户可用的高达 1792 位
  • 加密硬件加速器:
    • AES-128/256 (FIPS PUB 197)
    • Hash (FIPS PUB 180-4)
    • RSA
    • 随机数生成器 (RNG)
    • HMAC
    • 数字签名

如此丰富的硬件资源足够做很多 “大玩具”,是折腾用的不二选择,以下内容记录 ESP32-S3 的使用和踩的坑,不定时更新...

下面为 ESP32-S3-DEVKIT-C 开发板引脚定义图

# SPI SD 卡

官方示例如下,在官方示例中引脚为默认,在实际场景中往往需要自定义引脚。

/*
 * Connect the SD card to the following pins:
 *
 * SD Card | ESP32
 *    D2       -
 *    D3       SS
 *    CMD      MOSI
 *    VSS      GND
 *    VDD      3.3V
 *    CLK      SCK
 *    VSS      GND
 *    D0       MISO
 *    D1       -
 */
#include "FS.h"
#include "SD.h"
#include "SPI.h"
void listDir(fs::FS &fs, const char * dirname, uint8_t levels){
    Serial.printf("Listing directory: %s\n", dirname);
    File root = fs.open(dirname);
    if(!root){
        Serial.println("Failed to open directory");
        return;
    }
    if(!root.isDirectory()){
        Serial.println("Not a directory");
        return;
    }
    File file = root.openNextFile();
    while(file){
        if(file.isDirectory()){
            Serial.print("  DIR : ");
            Serial.println(file.name());
            if(levels){
                listDir(fs, file.path(), levels -1);
            }
        } else {
            Serial.print("  FILE: ");
            Serial.print(file.name());
            Serial.print("  SIZE: ");
            Serial.println(file.size());
        }
        file = root.openNextFile();
    }
}
void createDir(fs::FS &fs, const char * path){
    Serial.printf("Creating Dir: %s\n", path);
    if(fs.mkdir(path)){
        Serial.println("Dir created");
    } else {
        Serial.println("mkdir failed");
    }
}
void removeDir(fs::FS &fs, const char * path){
    Serial.printf("Removing Dir: %s\n", path);
    if(fs.rmdir(path)){
        Serial.println("Dir removed");
    } else {
        Serial.println("rmdir failed");
    }
}
void readFile(fs::FS &fs, const char * path){
    Serial.printf("Reading file: %s\n", path);
    File file = fs.open(path);
    if(!file){
        Serial.println("Failed to open file for reading");
        return;
    }
    Serial.print("Read from file: ");
    while(file.available()){
        Serial.write(file.read());
    }
    file.close();
}
void writeFile(fs::FS &fs, const char * path, const char * message){
    Serial.printf("Writing file: %s\n", path);
    File file = fs.open(path, FILE_WRITE);
    if(!file){
        Serial.println("Failed to open file for writing");
        return;
    }
    if(file.print(message)){
        Serial.println("File written");
    } else {
        Serial.println("Write failed");
    }
    file.close();
}
void appendFile(fs::FS &fs, const char * path, const char * message){
    Serial.printf("Appending to file: %s\n", path);
    File file = fs.open(path, FILE_APPEND);
    if(!file){
        Serial.println("Failed to open file for appending");
        return;
    }
    if(file.print(message)){
        Serial.println("Message appended");
    } else {
        Serial.println("Append failed");
    }
    file.close();
}
void renameFile(fs::FS &fs, const char * path1, const char * path2){
    Serial.printf("Renaming file %s to %s\n", path1, path2);
    if (fs.rename(path1, path2)) {
        Serial.println("File renamed");
    } else {
        Serial.println("Rename failed");
    }
}
void deleteFile(fs::FS &fs, const char * path){
    Serial.printf("Deleting file: %s\n", path);
    if(fs.remove(path)){
        Serial.println("File deleted");
    } else {
        Serial.println("Delete failed");
    }
}
void testFileIO(fs::FS &fs, const char * path){
    File file = fs.open(path);
    static uint8_t buf[512];
    size_t len = 0;
    uint32_t start = millis();
    uint32_t end = start;
    if(file){
        len = file.size();
        size_t flen = len;
        start = millis();
        while(len){
            size_t toRead = len;
            if(toRead > 512){
                toRead = 512;
            }
            file.read(buf, toRead);
            len -= toRead;
        }
        end = millis() - start;
        Serial.printf("%u bytes read for %u ms\n", flen, end);
        file.close();
    } else {
        Serial.println("Failed to open file for reading");
    }
    file = fs.open(path, FILE_WRITE);
    if(!file){
        Serial.println("Failed to open file for writing");
        return;
    }
    size_t i;
    start = millis();
    for(i=0; i<2048; i++){
        file.write(buf, 512);
    }
    end = millis() - start;
    Serial.printf("%u bytes written for %u ms\n", 2048 * 512, end);
    file.close();
}
void setup(){
    Serial.begin(115200);
    if(!SD.begin()){
        Serial.println("Card Mount Failed");
        return;
    }
    uint8_t cardType = SD.cardType();
    if(cardType == CARD_NONE){
        Serial.println("No SD card attached");
        return;
    }
    Serial.print("SD Card Type: ");
    if(cardType == CARD_MMC){
        Serial.println("MMC");
    } else if(cardType == CARD_SD){
        Serial.println("SDSC");
    } else if(cardType == CARD_SDHC){
        Serial.println("SDHC");
    } else {
        Serial.println("UNKNOWN");
    }
    uint64_t cardSize = SD.cardSize() / (1024 * 1024);
    Serial.printf("SD Card Size: %lluMB\n", cardSize);
    listDir(SD, "/", 0);
    createDir(SD, "/mydir");
    listDir(SD, "/", 0);
    removeDir(SD, "/mydir");
    listDir(SD, "/", 2);
    writeFile(SD, "/hello.txt", "Hello ");
    appendFile(SD, "/hello.txt", "World!\n");
    readFile(SD, "/hello.txt");
    deleteFile(SD, "/foo.txt");
    renameFile(SD, "/hello.txt", "/foo.txt");
    readFile(SD, "/foo.txt");
    testFileIO(SD, "/test.txt");
    Serial.printf("Total space: %lluMB\n", SD.totalBytes() / (1024 * 1024));
    Serial.printf("Used space: %lluMB\n", SD.usedBytes() / (1024 * 1024));
}
void loop(){
}

需要注意的是,这里 SPI SD 卡必须接 5V,官方示例中接入为 3.3V,在实际中不行,会报错。

sdcard_mount(): f_mount failed: (3) The physical drive cannot work

正确做法应该将 SPI SD 接入 5V 后,自己初始化 SPI 引脚后传入 SD 卡初始化

#include <SPI.h>
#include <FS.h>
#include <SD.h>
// VCC 5V
#define SD_MISO     13
#define SD_MOSI     11
#define SD_SCLK     12
#define SD_CS       10
void setup() {
    Serial.begin(115200);
    SPIClass spi = SPIClass(HSPI);
    spi.begin(SD_SCLK, SD_MISO, SD_MOSI, SD_CS);
    if (!SD.begin(SD_CS, spi)) {
        Serial.println("Card Mount Failed");
        return;
    }
    uint8_t cardType = SD.cardType();
    if (cardType == CARD_NONE) {
        Serial.println("No SD card attached");
        return;
    }
    Serial.print("SD Card Type: ");
    if (cardType == CARD_MMC) {
        Serial.println("MMC");
    } else if (cardType == CARD_SD) {
        Serial.println("SDSC");
    } else if (cardType == CARD_SDHC) {
        Serial.println("SDHC");
    } else {
        Serial.println("UNKNOWN");
    }
    uint64_t cardSize = SD.cardSize() / (1024 * 1024);
    Serial.printf("SD Card Size: %lluMB\n", cardSize);
    Serial.println("initialisation done.");
}
void loop() {
}

# 遥杆模块

遥杆需要注意将摇杆模块上的轻触开关引脚上拉

以下代码实现读取两个遥杆的数据,当轻触开关被按下是触发蜂鸣器(有源低电平蜂鸣器)

#include <Arduino.h>
#define PS2_1_X_PIN 4
#define PS2_1_Y_PIN 5
#define PS2_1_Y_BUTTON 6
#define PS2_2_X_PIN 7
#define PS2_2_Y_PIN 15
#define PS2_2_Y_BUTTON 16
#define BEEP_PIN 9
void setup_ps2();
void setup_beep();
void beep(uint8_t PIN, uint8_t time, uint32_t time_len);
void setup()
{
    Serial.begin(115200);
    Serial.println("setup ...");
    setup_ps2();
    setup_beep();
    Serial.println("setup ok");
}
void loop()
{
    uint16_t ps2_lx = analogRead(PS2_1_X_PIN);
    uint16_t ps2_ly = analogRead(PS2_1_Y_PIN);
    uint16_t ps2_lb = digitalRead(PS2_1_Y_BUTTON);
    uint16_t ps2_rx = analogRead(PS2_2_X_PIN);
    uint16_t ps2_ry = analogRead(PS2_2_Y_PIN);
    uint16_t ps2_rb = digitalRead(PS2_2_Y_BUTTON);
    Serial.print("lX: ");
    Serial.print(ps2_lx);
    Serial.print(" ");
    Serial.print("lY: ");
    Serial.print(ps2_ly);
    Serial.print(" ");
    Serial.print("lZ: ");
    Serial.println(ps2_lb);
    Serial.print("rX: ");
    Serial.print(ps2_rx);
    Serial.print(" ");
    Serial.print("rY: ");
    Serial.print(ps2_ry);
    Serial.print(" ");
    Serial.print("rZ: ");
    Serial.println(ps2_rb);
    if (ps2_lb == LOW || ps2_rb == LOW)
    {
        Serial.println("in if");
        beep(BEEP_PIN, 3, 50);
    }
}
void setup_ps2()
{
    // set ps2-1
    pinMode(PS2_1_X_PIN, INPUT); // ps2-1-x
    pinMode(PS2_1_Y_PIN, INPUT); // ps2-1-y
    pinMode(PS2_1_Y_BUTTON, INPUT_PULLUP); // ps2-1-button
    digitalWrite(PS2_1_Y_BUTTON, HIGH);
    // set ps2-2
    pinMode(PS2_2_X_PIN, INPUT); // ps2-2-x
    pinMode(PS2_2_Y_PIN, INPUT); // ps2-2-y
    pinMode(PS2_2_Y_BUTTON, INPUT_PULLUP); // ps2-2-button
    digitalWrite(PS2_2_Y_BUTTON, HIGH);
}
void setup_beep()
{
    // set bee
    pinMode(BEEP_PIN, OUTPUT);
    digitalWrite(BEEP_PIN, HIGH);
}
void beep(uint8_t PIN, uint8_t time, uint32_t time_len)
{
    Serial.print("beep: ");
    Serial.println(PIN);
    for (int i = 0; i < time; i++)
    {
        digitalWrite(PIN, LOW);
        delay(time_len);
        digitalWrite(PIN, HIGH);
        delay(time_len);
    }
}

# FreeRTOS

Esp32 不需要引入其它东西,可以直接使用 FreeRTOS

下面代码将摇杆模块示例作为一个任务,再添加一个 RGB 灯任务,都在 ESP32 的 1 核心上运行

#include <Arduino.h>
#include <soc/soc.h>
#include <soc/rtc_cntl_reg.h>
#include "soc/timer_group_struct.h"
#include "soc/timer_group_reg.h"
#if CONFIG_FREERTOS_UNICORE
#define ARDUINO_RUNNING_CORE 0
#else
#define ARDUINO_RUNNING_CORE 1
#endif
#define RGB_R_PIN 37
#define RGB_G_PIN 36
#define RGB_B_PIN 35
#define BUTTON_K1 2
#define PS2_1_X_PIN 4
#define PS2_1_Y_PIN 5
#define PS2_1_Y_BUTTON 6
#define PS2_2_X_PIN 7
#define PS2_2_Y_PIN 15
#define PS2_2_Y_BUTTON 16
#define BEEP_PIN 9
void setup_led();
void setup_button();
void setup_ps2();
void setup_beep();
void beep(uint8_t PIN, uint8_t time, uint32_t time_len);
void turn_rgb(uint8_t R_PIN, uint8_t G_PIN, uint8_t B_PIN, uint32_t time_len);
void task_button_rgb(void *parameter);
void task_stick_beep(void *parameter);
int red_val = 255;
int green_val = 0;
int blue_val = 0;
TaskHandle_t task_1;
TaskHandle_t task_2;
void setup()
{
    Serial.begin(115200);
    setup_led();
    setup_button();
    setup_ps2();
    setup_beep();
    xTaskCreatePinnedToCore(task_stick_beep, "Task_1", CONFIG_ESP_MINIMAL_SHARED_STACK_SIZE, NULL, 1, &task_1, 1);
    xTaskCreatePinnedToCore(task_button_rgb, "Task_2", CONFIG_ESP_MINIMAL_SHARED_STACK_SIZE, NULL, 1, &task_2, 1);
}
void loop()
{
}
void task_button_rgb(void *parameter)
{
    (void) parameter;
    for (;;)
    {
        Serial.print("Task Button RGB running on core ");
        Serial.println(xPortGetCoreID());
        if (digitalRead(BUTTON_K1) == LOW)
        {
            turn_rgb(RGB_R_PIN, RGB_G_PIN, RGB_B_PIN, 5);
        }
    }
}
void task_stick_beep(void *parameter)
{
    (void) parameter;
    for (;;)
    {
        Serial.print("Task Stick Beep running on core ");
        Serial.println(xPortGetCoreID());
        uint16_t ps2_lx = analogRead(PS2_1_X_PIN);
        uint16_t ps2_ly = analogRead(PS2_1_Y_PIN);
        uint16_t ps2_lb = digitalRead(PS2_1_Y_BUTTON);
        uint16_t ps2_rx = analogRead(PS2_2_X_PIN);
        uint16_t ps2_ry = analogRead(PS2_2_Y_PIN);
        uint16_t ps2_rb = digitalRead(PS2_2_Y_BUTTON);
        Serial.print("lX: ");
        Serial.print(ps2_lx);
        Serial.print(" ");
        Serial.print("lY: ");
        Serial.print(ps2_ly);
        Serial.print(" ");
        Serial.print("lZ: ");
        Serial.println(ps2_lb);
        Serial.print("rX: ");
        Serial.print(ps2_rx);
        Serial.print(" ");
        Serial.print("rY: ");
        Serial.print(ps2_ry);
        Serial.print(" ");
        Serial.print("rZ: ");
        Serial.println(ps2_rb);
        if (ps2_lb == LOW || ps2_rb == LOW)
        {
            beep(BEEP_PIN, 3, 50);
        }
    }
}
void setup_led()
{
    pinMode(RGB_R_PIN, OUTPUT);
    pinMode(RGB_G_PIN, OUTPUT);
    pinMode(RGB_B_PIN, OUTPUT);
}
void setup_button()
{
    pinMode(BUTTON_K1, INPUT_PULLUP);
    digitalWrite(BUTTON_K1, HIGH);
}
void setup_ps2()
{
    // set ps2-1
    pinMode(PS2_1_X_PIN, INPUT); // ps2-1-x
    pinMode(PS2_1_Y_PIN, INPUT); // ps2-1-y
    pinMode(PS2_1_Y_BUTTON, INPUT_PULLUP); // ps2-1-button
    digitalWrite(PS2_1_Y_BUTTON, HIGH);
    // set ps2-2
    pinMode(PS2_2_X_PIN, INPUT); // ps2-2-x
    pinMode(PS2_2_Y_PIN, INPUT); // ps2-2-y
    pinMode(PS2_2_Y_BUTTON, INPUT_PULLUP); // ps2-2-button
    digitalWrite(PS2_2_Y_BUTTON, HIGH);
}
void setup_beep()
{
    // set bee
    pinMode(BEEP_PIN, OUTPUT);
    digitalWrite(BEEP_PIN, HIGH);
}
void beep(uint8_t PIN, uint8_t time, uint32_t time_len)
{
    Serial.print("beep: ");
    Serial.println(PIN);
    for (int i = 0; i < time; i++)
    {
        Serial.print("for: ");
        Serial.println(i);
        digitalWrite(PIN, LOW);
        vTaskDelay(time_len);
        digitalWrite(PIN, HIGH);
        vTaskDelay(time_len);
    }
}
void turn_rgb(uint8_t R_PIN, uint8_t G_PIN, uint8_t B_PIN, uint32_t time_len)
{
    for (byte i = 0; i < 255; i++)
    {
        red_val--;
        green_val++;
        analogWrite(R_PIN, red_val);
        analogWrite(G_PIN, green_val);
        vTaskDelay(time_len);
    }
    for (byte i = 0; i < 255; i++)
    {
        green_val--;
        blue_val++;
        analogWrite(G_PIN, green_val);
        analogWrite(B_PIN, blue_val);
        vTaskDelay(time_len);
    }
    for (byte i = 0; i < 255; i++)
    {
        blue_val--;
        red_val++;
        analogWrite(B_PIN, blue_val);
        analogWrite(R_PIN, red_val);
        vTaskDelay(time_len);
    }
}

# TFT

在 Arduino 里,TFT LCD 屏幕的驱动方式有好几种,这里选择的是 TFT_eSPI 这个库。
TFT_eSPI 这个库使用起来非常方便,根据自己所使用的屏幕具体的参数在库中的 User_Setup.h 这个头文件里修改好就行了,具体的话需要修改屏幕的驱动、屏幕的分辨率、屏幕的所使用的引脚。

下面为头文件示例:

#define USER_SETUP_INFO "User_Setup"
#define ST7735_DRIVER      // Define additional parameters below for this display
//#define ILI9163_DRIVER     // Define additional parameters below for this display
//#define S6D02A1_DRIVER
//#define RPI_ILI9486_DRIVER // 20MHz maximum SPI
//#define HX8357D_DRIVER
//#define ILI9481_DRIVER
//#define ILI9486_DRIVER
//#define ILI9488_DRIVER     // WARNING: Do not connect ILI9488 display SDO to MISO if other devices share the SPI bus (TFT SDO does NOT tristate when CS is high)
//#define ST7789_DRIVER      // Full configuration option, define additional parameters below for this display
//#define ST7789_2_DRIVER    // Minimal configuration option, define additional parameters below for this display
//#define R61581_DRIVER
//#define RM68140_DRIVER
//#define ST7796_DRIVER
//#define SSD1351_DRIVER
//#define SSD1963_480_DRIVER
//#define SSD1963_800_DRIVER
//#define SSD1963_800ALT_DRIVER
//#define ILI9225_DRIVER
//#define GC9A01_DRIVER
 #define TFT_WIDTH  128
 #define TFT_HEIGHT 160
 #define ST7735_REDTAB
// #define ST7735_BLACKTAB
// #define ST7735_REDTAB160x80   // For 160 x 80 display with 24 pixel offset
#define TFT_MOSI 35 // In some display driver board, it might be written as "SDA" and so on.
#define TFT_SCLK 36
#define TFT_CS   39  // Chip select control pin
#define TFT_DC   38  // Data Command control pin
#define TFT_RST  37  // Reset pin (could connect to Arduino RESET pin)
#define TFT_BL   40  // LED back-light
// Comment out the #defines below with // to stop that font being loaded
// The ESP8366 and ESP32 have plenty of memory so commenting out fonts is not
// normally necessary. If all fonts are loaded the extra FLASH space required is
// about 17Kbytes. To save FLASH space only enable the fonts you need!
#define LOAD_GLCD   // Font 1. Original Adafruit 8 pixel font needs ~1820 bytes in FLASH
#define LOAD_FONT2  // Font 2. Small 16 pixel high font, needs ~3534 bytes in FLASH, 96 characters
#define LOAD_FONT4  // Font 4. Medium 26 pixel high font, needs ~5848 bytes in FLASH, 96 characters
#define LOAD_FONT6  // Font 6. Large 48 pixel font, needs ~2666 bytes in FLASH, only characters 1234567890:-.apm
#define LOAD_FONT7  // Font 7. 7 segment 48 pixel font, needs ~2438 bytes in FLASH, only characters 1234567890:-.
#define LOAD_FONT8  // Font 8. Large 75 pixel font needs ~3256 bytes in FLASH, only characters 1234567890:-.
//#define LOAD_FONT8N // Font 8. Alternative to Font 8 above, slightly narrower, so 3 digits fit a 160 pixel TFT
#define LOAD_GFXFF  // FreeFonts. Include access to the 48 Adafruit_GFX free fonts FF1 to FF48 and custom fonts
// Comment out the #define below to stop the SPIFFS filing system and smooth font code being loaded
// this will save ~20kbytes of FLASH
#define SMOOTH_FONT
// #define SPI_FREQUENCY   1000000
// #define SPI_FREQUENCY   5000000
// #define SPI_FREQUENCY  10000000
// #define SPI_FREQUENCY  20000000
#define SPI_FREQUENCY  27000000
// #define SPI_FREQUENCY  40000000
// #define SPI_FREQUENCY  55000000 // STM32 SPI1 only (SPI2 maximum is 27MHz)
// #define SPI_FREQUENCY  80000000
// Optional reduced SPI frequency for reading TFT
#define SPI_READ_FREQUENCY  20000000
// The XPT2046 requires a lower SPI clock rate of 2.5MHz so we define that here:
#define SPI_TOUCH_FREQUENCY  2500000

# GUIslice

TFT LCD 屏幕使用 GUIslice GUI 库的时候最好搭配 TFT_eSPI 库一起使用

# 红外

在 ESP32 中,红外遥控的库跟 Arduino 所有区别,Arduino 为 IRremote,ESP32 和 ESP8266 为 IRremoteESP8266。

# 红外发送

#include <Esp.h>
#include <IRremoteESP8266.h>
#include <IRsend.h>
const uint16_t kIrLed = 8;  // ESP8266 GPIO pin to use. Recommended: 4 (D2).
IRsend irsend(kIrLed);  // Set the GPIO to be used to sending the message.
// Example of data captured by IRrecvDumpV2.ino
uint16_t rawData[67] = {9000, 4500, 650, 550, 650, 1650, 600, 550, 650, 550,
                        600, 1650, 650, 550, 600, 1650, 650, 1650, 650, 1650,
                        600, 550, 650, 1650, 650, 1650, 650, 550, 600, 1650,
                        650, 1650, 650, 550, 650, 550, 650, 1650, 650, 550,
                        650, 550, 650, 550, 600, 550, 650, 550, 650, 550,
                        650, 1650, 600, 550, 650, 1650, 650, 1650, 650, 1650,
                        650, 1650, 650, 1650, 650, 1650, 600};
// Example Samsung A/C state captured from IRrecvDumpV2.ino
uint8_t samsungState[kSamsungAcStateLength] = {
        0x02, 0x92, 0x0F, 0x00, 0x00, 0x00, 0xF0,
        0x01, 0xE2, 0xFE, 0x71, 0x40, 0x11, 0xF0};
void setup()
{
    irsend.begin();
    Serial.begin(115200, SERIAL_8N1);
}
void loop()
{
    Serial.println("NEC");
    irsend.sendNEC(0x00FFE01FUL);
    delay(2000);
    Serial.println("Sony");
    irsend.sendSony(0xa90, 12, 2);  // 12 bits & 2 repeats
    delay(2000);
    Serial.println("a rawData capture from IRrecvDumpV2");
    irsend.sendRaw(rawData, 67, 38);  // Send a raw data capture at 38kHz.
    delay(2000);
    Serial.println("a Samsung A/C state from IRrecvDumpV2");
    irsend.sendSamsungAC(samsungState);
    delay(2000);
}

# 红外接收

#include <Esp.h>
#include <IRremoteESP8266.h>
#include <IRrecv.h>
#include <IRac.h>
#include <IRtext.h>
#include <IRutils.h>
const uint16_t kRecvPin = 14;
const uint32_t kBaudRate = 115200;
const uint16_t kCaptureBufferSize = 1024;
const uint8_t kTimeout = 15;
const uint8_t kTolerancePercentage = kTolerance;
IRrecv irrecv(kRecvPin, kCaptureBufferSize, kTimeout, true);
decode_results results;
void setup()
{
    irsend.begin();
    Serial.begin(115200, SERIAL_8N1);
    irrecv.setTolerance(kTolerancePercentage);
    irrecv.enableIRIn();
}
void loop()
{
    if (irrecv.decode(&results))
        {
            uint32_t now = millis();
            Serial.printf(D_STR_TIMESTAMP " : %06u.%03u\n", now / 1000, now % 1000);
            // Check if we got an IR message that was to big for our capture buffer.
            if (results.overflow)
                Serial.printf(D_WARN_BUFFERFULL "\n", kCaptureBufferSize);
            // Display the library version the message was captured with.
            Serial.println(D_STR_LIBRARY "   : v" _IRREMOTEESP8266_VERSION_STR "\n");
            // Display the tolerance percentage if it has been change from the default.
            if (kTolerancePercentage != kTolerance)
                Serial.printf(D_STR_TOLERANCE " : %d%%\n", kTolerancePercentage);
            // Display the basic output of what we found.
            Serial.print(resultToHumanReadableBasic(&results));
            // Display any extra A/C info if we have it.
            String description = IRAcUtils::resultAcToString(&results);
            if (description.length()) Serial.println(D_STR_MESGDESC ": " + description);
            yield();  // Feed the WDT as the text output can take a while to print.
#if LEGACY_TIMING_INFO
            // Output legacy RAW timing info of the result.
        Serial.println(resultToTimingInfo(&results));
        yield();  // Feed the WDT (again)
#endif  // LEGACY_TIMING_INFO
            // Output the results as source code
            Serial.println(resultToSourceCode(&results));
            Serial.println();    // Blank line between entries
            yield();             // Feed the WDT (again)
        }
}

# 在 FreeRTOS 中使用

#include <Esp.h>
#include <IRremoteESP8266.h>
#include <IRsend.h>
#include <IRrecv.h>
#include <IRac.h>
#include <IRtext.h>
#include <IRutils.h>
const uint16_t kIrLed = 8;  // ESP8266 GPIO pin to use. Recommended: 4 (D2).
IRsend irsend(kIrLed);  // Set the GPIO to be used to sending the message.
const uint16_t kRecvPin = 14;
const uint32_t kBaudRate = 115200;
const uint16_t kCaptureBufferSize = 1024;
const uint8_t kTimeout = 15;
const uint8_t kTolerancePercentage = kTolerance;
IRrecv irrecv(kRecvPin, kCaptureBufferSize, kTimeout, true);
decode_results results;
// Example of data captured by IRrecvDumpV2.ino
uint16_t rawData[67] = {9000, 4500, 650, 550, 650, 1650, 600, 550, 650, 550,
                        600, 1650, 650, 550, 600, 1650, 650, 1650, 650, 1650,
                        600, 550, 650, 1650, 650, 1650, 650, 550, 600, 1650,
                        650, 1650, 650, 550, 650, 550, 650, 1650, 650, 550,
                        650, 550, 650, 550, 600, 550, 650, 550, 650, 550,
                        650, 1650, 600, 550, 650, 1650, 650, 1650, 650, 1650,
                        650, 1650, 650, 1650, 650, 1650, 600};
// Example Samsung A/C state captured from IRrecvDumpV2.ino
uint8_t samsungState[kSamsungAcStateLength] = {
        0x02, 0x92, 0x0F, 0x00, 0x00, 0x00, 0xF0,
        0x01, 0xE2, 0xFE, 0x71, 0x40, 0x11, 0xF0};
TaskHandle_t task_1;
TaskHandle_t task_2;
void esp_ir_send(void *parameter);
void esp_ir_recv(void *parameter);
void setup()
{
    irsend.begin();
    Serial.begin(115200, SERIAL_8N1);
    irrecv.setTolerance(kTolerancePercentage);
    irrecv.enableIRIn();
    xTaskCreatePinnedToCore(esp_ir_send, "Task_1", CONFIG_ESP_MINIMAL_SHARED_STACK_SIZE, NULL, 1, &task_1, 0);
    xTaskCreatePinnedToCore(esp_ir_recv, "Task_1", CONFIG_ESP_MINIMAL_SHARED_STACK_SIZE, NULL, 1, &task_2, 1);
}
void loop()
{
}
void esp_ir_send(void *parameter)
{
    (void) parameter;
    for (;;)
    {
        Serial.println("NEC");
        irsend.sendNEC(0x00FFE01FUL);
        delay(500);
        Serial.println("Sony");
        irsend.sendSony(0xa90, 12, 2);  // 12 bits & 2 repeats
        delay(500);
        Serial.println("a rawData capture from IRrecvDumpV2");
        irsend.sendRaw(rawData, 67, 38);  // Send a raw data capture at 38kHz.
        delay(500);
        Serial.println("a Samsung A/C state from IRrecvDumpV2");
        irsend.sendSamsungAC(samsungState);
        delay(500);
    }
}
void esp_ir_recv(void *parameter)
{
    (void) parameter;
    for (;;)
    {
        if (irrecv.decode(&results))
        {
            uint32_t now = millis();
            Serial.printf(D_STR_TIMESTAMP " : %06u.%03u\n", now / 1000, now % 1000);
            // Check if we got an IR message that was to big for our capture buffer.
            if (results.overflow)
                Serial.printf(D_WARN_BUFFERFULL "\n", kCaptureBufferSize);
            // Display the library version the message was captured with.
            Serial.println(D_STR_LIBRARY "   : v" _IRREMOTEESP8266_VERSION_STR "\n");
            // Display the tolerance percentage if it has been change from the default.
            if (kTolerancePercentage != kTolerance)
                Serial.printf(D_STR_TOLERANCE " : %d%%\n", kTolerancePercentage);
            // Display the basic output of what we found.
            Serial.print(resultToHumanReadableBasic(&results));
            // Display any extra A/C info if we have it.
            String description = IRAcUtils::resultAcToString(&results);
            if (description.length()) Serial.println(D_STR_MESGDESC ": " + description);
            yield();  // Feed the WDT as the text output can take a while to print.
#if LEGACY_TIMING_INFO
            // Output legacy RAW timing info of the result.
        Serial.println(resultToTimingInfo(&results));
        yield();  // Feed the WDT (again)
#endif  // LEGACY_TIMING_INFO
            // Output the results as source code
            Serial.println(resultToSourceCode(&results));
            Serial.println();    // Blank line between entries
            yield();             // Feed the WDT (again)
        }
    }
}
更新于 阅读次数

请我喝[茶]~( ̄▽ ̄)~*

Taoidle 微信支付

微信支付

Taoidle 支付宝

支付宝