Skip to content

Instantly share code, notes, and snippets.

@acidsound
Last active October 23, 2025 17:31
Show Gist options
  • Select an option

  • Save acidsound/eebf85d2a86033d73c654b05a8d517d6 to your computer and use it in GitHub Desktop.

Select an option

Save acidsound/eebf85d2a86033d73c654b05a8d517d6 to your computer and use it in GitHub Desktop.
BLE MIDI 를 검색하고 연결. u8g2 라이브러리를 사용하여 정보를 화면에 뿌려준다.
#include <Arduino.h>
#include <NimBLEDevice.h>
#include <U8g2lib.h>
// BLE MIDI 서비스 고유 UUID
static BLEUUID midiServiceUUID("03B80E5A-EDE8-4B33-A751-6CE34EC4C700");
// 스캔 후 찾은 장치 포인터
BLEAdvertisedDevice* myDevice = nullptr;
bool connected = false;
std::string connectedDeviceName;
// there is no 72x40 constructor in u8g2 hence the 72x40 screen is mapped in the middle of the 132x64 pixel buffer of the SSD1306 controller
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, U8X8_PIN_NONE, 6, 5);
int width = 72;
int height = 40;
int xOffset = 30; // = (132-w)/2
int yOffset = 12; // = (64-h)/2
unsigned long lastMarqMillis = 0;
int marqPos = 0;
void updateU8G2(const char* name) {
u8g2.clearBuffer();
u8g2.drawFrame(xOffset - 2, yOffset + 12, width, height);
u8g2.setCursor(xOffset, yOffset + 48);
u8g2.printf("%s", "@acidsound");
u8g2.setCursor(xOffset, yOffset + 23);
u8g2.println("::MIDI FROM");
size_t nameLen = strlen(name);
const int displayLen = 11;
char displayStr[displayLen + 1]; // +1 for null terminator
if (nameLen <= displayLen) {
// 문자열이 11자 이하면 그대로 표시
strncpy(displayStr, name, displayLen);
displayStr[nameLen] = '\0';
} else {
// marquee 효과: 맨 끝과 맨 앞 사이 공백 1칸 삽입
int scrollLen = nameLen + 1; // 공백 한 칸 추가한 길이
for (int i = 0; i < displayLen; i++) {
int idx = (marqPos + i) % scrollLen;
if (idx == nameLen) {
displayStr[i] = ' '; // 공백 삽입
} else {
displayStr[i] = name[idx];
}
}
displayStr[displayLen] = '\0';
}
u8g2.setCursor(xOffset, yOffset + 35);
u8g2.printf("%s", displayStr);
u8g2.sendBuffer();
}
// 스캔 결과를 처리할 콜백 클래스
class MyAdvertisedDeviceCallbacks : public BLEAdvertisedDeviceCallbacks {
void onResult(BLEAdvertisedDevice* advertisedDevice) override {
if (advertisedDevice->isAdvertisingService(midiServiceUUID)) {
Serial.print("Found BLE MIDI Device: ");
Serial.print(advertisedDevice->getName().c_str());
Serial.print(" (Address: ");
Serial.print(advertisedDevice->getAddress().toString().c_str());
Serial.println(")");
connectedDeviceName = advertisedDevice->getName();
Serial.printf("update device: %s", connectedDeviceName.c_str());
Serial.println("");
if (myDevice == nullptr) {
Serial.println("Connecting device");
myDevice = new BLEAdvertisedDevice(*advertisedDevice);
BLEDevice::getScan()->stop();
}
}
}
};
void listenBLEMIDI() {
Serial.println("Starting BLE Scan for MIDI Controllers...");
BLEDevice::init("");
BLEScan* pBLEScan = BLEDevice::getScan();
// 디바이스 콜백 등록
pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
pBLEScan->setActiveScan(true);
pBLEScan->start(10);
// 스캔 완료 후 myDevice가 설정되었는지 확인
if (myDevice == nullptr) {
Serial.println("No MIDI device found. Restart and try again.");
return;
}
Serial.println("Attempting to connect to the device...");
connected = true;
// myDevice 메모리 해제 및 초기화
// delete myDevice;
// myDevice = nullptr;
}
void setup() {
Serial.begin(115200);
u8g2.begin();
u8g2.setContrast(255); // set contrast to maximum
u8g2.setBusClock(400000); //400kHz I2C
u8g2.setFont(u8g2_font_6x10_mr);
}
void loop() {
unsigned long currentMillis = millis();
// marquee 0.4초 간격 타이머
if (currentMillis - lastMarqMillis >= 400) {
lastMarqMillis = currentMillis;
if (connected && connectedDeviceName.length() > 11) {
marqPos++;
if (marqPos >= connectedDeviceName.length()) {
marqPos = 0;
}
}
}
// 연결이 끊어지면 재연결 시도
if (myDevice == nullptr) {
updateU8G2("no device"); // 기본 문자열 표시
} else {
updateU8G2(connectedDeviceName.c_str());
}
if (!connected) {
Serial.println("Disconnected. Scanning for a new device to connect...");
listenBLEMIDI(); // 스캔 및 재연결 재시도
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment