Skip to main content

2. Output Devices

2.1. Grove device

I have some grove interface device, such as :rgb led, button,oled display,buzzer etc. I use ESP32Uno and Seed's Base Shield Grove extension board to connect them.

Here is the ESP32 Uno D1 pinout :

Here is the Base Shield Grove extension board:

2.1.1 OLED Display 0.96

The Grove OLED Display 0.96" is a compact, high-contrast display module featuring 128×64 pixels for showing text, graphics, and simple animations in Grove-based projects.

PinFunction
GNDGround
VCCPower supply
SDAI2C Data
SCLI2C Clock

2.1.2 RGB LED

The Grove RGB LED is a full-color output module featuring a single LED capable of displaying millions of colors by mixing Red, Green, and Blue light.

PinFunctionDescription
GNDGroundCommon ground reference
VCCPower supply5V or 3.3V input
D1Data InDigital signal input (I2C data or serial data stream)
C1Clock InClock signal for synchronous data transfer

2.1.3 Buzzer

The Grove Buzzer is a simple audio output module that produces sound for alerts, notifications, or simple tones in Grove-based projects.

PinFunction
GNDGround
VCCPower supply
NCNot connected
SIGControl signal (Digital/PWM)

2.2 Connection Diagram

I connet Buzzer to D2 , RGB Led to D3, Button to D4,and OLED to I2C port. The ESP32 with Base Shield Connection Diagram :

2.3 coding

2.3.1 with MicroBlocks

2.3.1.1 Block Code in MicroBlocks

Here is the block code in MicroBlocks:

Here is the code of block code above:


script 107 52 {
whenStarted
OLEDInit_I2C 'OLED_0.96in' '3C' 0 false
OLEDshowGDBuffer
OLEDclear
OLEDwrite 'Output Device' 0 0 false
}

script 109 242 {
whenCondition ('拨动开关' 'D4')
OLEDclear
OLEDwrite 'OLED display ok' 0 0 false
waitMillis 500
RGB灯 (colorSwatch 35 190 30 255) 'D3'
OLEDwrite 'RGB ok' 0 15 false
waitMillis 500
waitMillis 500
OLEDwrite 'Buzzer ok' 0 30 false
'连接蜂鸣器' 'D2'
'play tone' 'nt;c' 0 500
'play tone' 'nt;d' 0 500
'play tone' 'nt;e' 0 500
waitMillis 500
'RGB灯关闭 端口 D' 'D3'
}

2.3.1.2 Run and Debug the program

Here is the video of block code program runing in MicroBlocks:

Here is the video of testing the buttons and rotary:

2.3.1.3 Source code

2.3.2 coding in VSCode+PlatformIO

Here is the platformio.ini file:

[env:esp32dev]
platform = espressif32
board = esp32dev
framework = arduino
lib_deps =
adafruit/Adafruit SSD1306 @ ^2.5.7
adafruit/Adafruit GFX Library @ ^1.11.5


Here is the main.cpp file:

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

// 引脚定义
#define PIN_SWITCH 17 // D4 拨动开关
#define PIN_BUZZER 26 // D2 蜂鸣器
#define PIN_RGB_DAT 25 // D3 数据
#define PIN_RGB_CLK 16 // D3 对应的时钟 (基于源码 wr32_GPIO_D 处理)

// OLED 设置
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

// 音符频率定义 (nt;c, nt;d, nt;e)
#define NOTE_C 262
#define NOTE_D 294
#define NOTE_E 330

// 模拟 MicroBlocks 的 RGB 灯关闭逻辑
void disableRGB() {
pinMode(PIN_RGB_DAT, OUTPUT);
pinMode(PIN_RGB_CLK, OUTPUT);
digitalWrite(PIN_RGB_DAT, LOW);
digitalWrite(PIN_RGB_CLK, LOW);
}

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

// 初始化引脚
pinMode(PIN_SWITCH, INPUT_PULLUP);
pinMode(PIN_BUZZER, OUTPUT);

// 初始化 OLED
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
for(;;);
}

// Initial Display (whenStarted)
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.print("Output Device");
display.display();
}

void loop() {
// 检查拨动开关 (whenCondition D4)
// 注意:MicroBlocks 的拨动开关通常在按下/拨动时为 HIGH
if (digitalRead(PIN_SWITCH) == LOW) { // 假设低电平触发,根据硬件可改 HIGH

// 1. OLED display ok
display.clearDisplay();
display.setCursor(0, 0);
display.print("OLED display ok");
display.display();
delay(500);

// 2. RGB ok (这里简化为逻辑占位,因为 Minode 协议较特殊)
display.setCursor(0, 15);
display.print("RGB ok");
display.display();
// 模拟点亮 RGB (此处建议根据实际灯珠型号换用 FastLED 库)
Serial.println("RGB LED On (D3)");
delay(1000);

// 3. Buzzer ok
display.setCursor(0, 30);
display.print("Buzzer ok");
display.display();

// 播放 C, D, E 音符 (每个 500ms)
tone(PIN_BUZZER, NOTE_C, 500); delay(500);
tone(PIN_BUZZER, NOTE_D, 500); delay(500);
tone(PIN_BUZZER, NOTE_E, 500); delay(500);

delay(500);

// 4. 关闭 RGB
disableRGB();
Serial.println("RGB LED Off");

// 等待开关松开,防止重复触发
while(digitalRead(PIN_SWITCH) == LOW);
}
}

2.4 Servo device

I have some Servo device,such as: 90° Servo, 180° Servo,270° Servo. I use ESP32 dev kit and the common extension board to connect the servo devices.

2.4.1 90° Servo

The 90° servo offers quarter-turn rotation (0°–90°) for compact, precise applications like grippers and triggers.

2.4.2 180° Servo

The 180° servo is the standard half-turn (0°–180°) servo for general use in robot arms, camera mounts, and steering.

2.4.3 270° Servo

The 270° servo provides extended three-quarter turn (0°–270°) for wide-coverage applications like surveillance systems.

2.5 Connection Diagram

The Servo has 3 pin . G (Ground) is the common ground, V (Voltage) accepts 3.3V–5V power, and S (Signal) receives PWM pulses to set the angle.

Here is the ESP32 dev kit and the common extension board:

2.6 coding

2.6.1 code in MicroBlocks

Here is the block code in MicroBlocks:

Here is the source code of block code above:



spec ' ' 'servo270' 'set servo270 _ to _ degress(-135 to 135)' 'auto auto' '10' '10'

to servo270 pin val {
'[io:setServo]' pin ('[misc:rescale]' val -135 135 500 2500)
}


script 58 74 {
whenStarted
sendBroadcast 'servo_90'
waitMillis 5000
sendBroadcast 'servo_180'
waitMillis 5000
sendBroadcast 'servo_270'
}

script 474 40 {
whenBroadcastReceived 'servo_180'
setServoAngle 14 -90
waitMillis 1000
setServoAngle 14 -45
waitMillis 1000
setServoAngle 14 0
waitMillis 1000
setServoAngle 14 45
waitMillis 1000
setServoAngle 14 90
waitMillis 1000
}


script 56 316 {
whenBroadcastReceived 'servo_270'
servo270 13 -135
waitMillis 1000
servo270 13 0
waitMillis 1000
servo270 13 135
waitMillis 1000
}

script 485 362 {
whenBroadcastReceived 'servo_90'
setServoAngle 26 0
waitMillis 1000
setServoAngle 26 45
waitMillis 1000
setServoAngle 26 90
waitMillis 1000
setServoAngle 26 45
waitMillis 1000
setServoAngle 26 0
waitMillis 1000
}

2.6.2. Run the program

Here is the video of block code program runing in MicroBlocks:

2.6.3 Source code

2.6.4 coding with VSCode+PlatformIO

2.4 coding with VSCode+PlatformIO

Here is the platformio.ini file:

[env:esp32dev]
platform = espressif32
board = esp32dev
framework = arduino
lib_deps =
madhephaestus/ESP32Servo @ ^1.1.0


Here is the main.cpp file:

#include <Arduino.h>
#include <ESP32Servo.h>

// 定义引脚
const int PIN_SERVO_90 = 26;
const int PIN_SERVO_180 = 14;
const int PIN_SERVO_270 = 13;

// 创建舵机对象
Servo servo90;
Servo servo180;
Servo servo270;

// 模拟 MicroBlocks 中的 setServoAngle (-90 到 90 度)
// 根据 MicroBlocks 源码: pulseWidth = 1500 - (10 * degrees)
void setServoAngle(Servo &s, int degrees) {
int pulseWidth = 1500 - (10 * degrees);
s.writeMicroseconds(pulseWidth);
}

// 模拟 MicroBlocks 中的 servo270 (-135 到 135 度)
// 根据源码: rescale val -135 135 500 2500
void setServo270(Servo &s, int val) {
int pulseWidth = map(val, -135, 135, 500, 2500);
s.writeMicroseconds(pulseWidth);
}

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

// 分配硬件定时器资源 (ESP32Servo 特有)
ESP32PWM::allocateTimer(0);
ESP32PWM::allocateTimer(1);
ESP32PWM::allocateTimer(2);
ESP32PWM::allocateTimer(3);

// 初始化舵机,设置标准脉宽范围 (500us - 2500us)
servo90.setPeriodHertz(50);
servo180.setPeriodHertz(50);
servo270.setPeriodHertz(50);

servo90.attach(PIN_SERVO_90, 500, 2500);
servo180.attach(PIN_SERVO_180, 500, 2500);
servo270.attach(PIN_SERVO_270, 500, 2500);

Serial.println("Servos Initialized.");
}

void loop() {
// --- 任务 1: 90度舵机逻辑 (servo_90) ---
Serial.println("Task: Servo 90");
setServoAngle(servo90, 0); delay(1000);
setServoAngle(servo90, 45); delay(1000);
setServoAngle(servo90, 90); delay(1000);
setServoAngle(servo90, 45); delay(1000);
setServoAngle(servo90, 0); delay(1000);

delay(5000); // 对应 MicroBlocks 中间的等待

// --- 任务 2: 180度舵机逻辑 (servo_180) ---
Serial.println("Task: Servo 180");
setServoAngle(servo180, -90); delay(1000);
setServoAngle(servo180, -45); delay(1000);
setServoAngle(servo180, 0); delay(1000);
setServoAngle(servo180, 45); delay(1000);
setServoAngle(servo180, 90); delay(1000);

delay(5000);

// --- 任务 3: 270度舵机逻辑 (servo_270) ---
Serial.println("Task: Servo 270");
setServo270(servo270, -135); delay(1000);
setServo270(servo270, 0); delay(1000);
setServo270(servo270, 135); delay(1000);

// 程序运行一次后停止,或根据需要循环
Serial.println("All sequences finished.");
while(1) { delay(1000); }
}