This project mainly uses the ESP32 module as the main control, connects to the mobile phone through the Bluetooth MIDI protocol, and cooperates with the mobile APP (GarageBand, etc.) to implement an electronic keyboard.
The rendering is as follows:
Demo video
None yet
This design uses the real kalimba as a reference, and 鼠标按键
uses the metal shrapnel shown in the figure below instead of the kalimba 蜂鸣器
as the generating component.
Simply using a buzzer as a sound-generating component may not perform very well. Therefore, this project uses the ESP32 module as the main control, uses its Bluetooth function to connect to the mobile phone, and enhances its expressiveness through interaction with the mobile phone.
ESP32 is a powerful IoT chip that can support WiFi and Bluetooth functions at the same time. It has 20+ available GPIOs and a running frequency of up to 240MHz. It can be developed using methods such as C语言
, Ardiuno
, etc.MicroPython
In order to simulate the feel of a real kalimba, before designing the hardware, we first measured the dimensions of the 17-key kalimba shown in the picture above , 尺寸
and 键距
finally determined the size of 141mm*88mm and the key spacing of 7.6mm.
In addition to buttons and buzzers, a serial port chip is also used CH340
for burning programs, and several WS2812
colored lights enhance the music atmosphere.
The complete schematic is as follows:
PCB layout reference:
In order to pursue aesthetics, all circuits are arranged on the back of the PCB board.
In addition, for the sake of beauty, the USB interface is placed below the antenna. This design will affect the wireless signal, so please do not imitate it!
Hardware open source address:
As mentioned earlier, there are many development methods for ESP32. I used the MicroPython development method here. The advantage is that the development environment is relatively simple to set up and the amount of code is not small. The current program is not perfect. The core code is as follows:
from machine import Pin, Timer
from time import sleep_ms
import ubluetooth
from esp32 import raw_temperature
class BLE():
def __init__(self, name):
self.name = name
self.ble = ubluetooth.BLE()
self.ble.active(True)
self.led = Pin(14, Pin.OUT)
self.timer1 = Timer(0)
self.timer2 = Timer(1)
self.disconnected()
self.ble.irq(self.ble_irq)
self.register()
self.advertiser()
self.isConnected = False
def connected(self):
self.timer1.deinit()
self.timer2.deinit()
def disconnected(self):
self.timer1.init(period=1000, mode=Timer.PERIODIC, callback=lambda t: self.led(1))
sleep_ms(200)
self.timer2.init(period=1000, mode=Timer.PERIODIC, callback=lambda t: self.led(0))
def ble_irq(self, event, data): # 蓝牙事件处理
if event == 1: # Central disconnected
self.isConnected = True
self.connected()
self.led(1)
elif event == 2: # Central disconnected
self.isConnected = False
self.advertiser()
self.disconnected()
elif event == 4: # New message received
buffer = self.ble.gatts_read(self.midi)
message = buffer.decode('UTF-8')[:-1]
print(message)
if received == 'blue_led':
blue_led.value(not blue_led.value())
def register(self): # 注册MIDI蓝牙服务
MIDI_SERVER_UUID = ubluetooth.UUID('03B80E5A-EDE8-4B33-A751-6CE34EC4C700')
MIDI_CHAR_UUID = (ubluetooth.UUID('7772E5DB-3868-4112-A1A9-F2669D106BF3'),
ubluetooth.FLAG_READ | ubluetooth.FLAG_WRITE | ubluetooth.FLAG_NOTIFY , )
BLE_MIDI_SERVER = (MIDI_SERVER_UUID, (MIDI_CHAR_UUID , ) , )
SERVICES = (BLE_MIDI_SERVER, )
((self.midi,), ) = self.ble.gatts_register_services(SERVICES)
def send(self, data):
if self.isConnected :
self.ble.gatts_notify(0, self.midi, data)
def advertiser(self): # 设置广播及扫描响应数据
name = bytes(self.name, 'UTF-8')
self.ble.gap_advertise(100, adv_data = b'x02x01x05' + bytearray((len(name) + 1, 0x09)) + name ,
resp_data = b'x11x07x00xC7xC4x4ExE3x6Cx51xA7x33x4BxE8xEdx5Ax0ExB8x03')
ble = BLE("ESP32")
k_d6 = Pin(32, Pin.IN, Pin.PULL_UP)
k_b5 = Pin(33, Pin.IN, Pin.PULL_UP)
k_g5 = Pin(25, Pin.IN, Pin.PULL_UP)
k_e5 = Pin(26, Pin.IN, Pin.PULL_UP)
k_c5 = Pin(27, Pin.IN, Pin.PULL_UP)
k_a4 = Pin(12, Pin.IN, Pin.PULL_UP)
k_f4 = Pin(13, Pin.IN, Pin.PULL_UP)
k_d4 = Pin(15, Pin.IN, Pin.PULL_UP)
k_c4 = Pin(4, Pin.IN, Pin.PULL_UP)
k_e4 = Pin(16, Pin.IN, Pin.PULL_UP)
k_g4 = Pin(17, Pin.IN, Pin.PULL_UP)
k_b4 = Pin(5, Pin.IN, Pin.PULL_UP)
k_d5 = Pin(18, Pin.IN, Pin.PULL_UP)
k_f5 = Pin(19, Pin.IN, Pin.PULL_UP)
k_a5 = Pin(21, Pin.IN, Pin.PULL_UP)
k_c6 = Pin(22, Pin.IN, Pin.PULL_UP)
k_e6 = Pin(23, Pin.IN, Pin.PULL_UP)
key_pin_list = [k_c4,k_d4,k_e4,k_f4,k_g4,k_a4,k_b4,k_c5,k_d5,k_e5,k_f5,k_g5,k_a5,k_b5,k_c6,k_d6,k_e6]
key_name_list = ['k_c4','k_d4','k_e4','k_f4','k_g4','k_a4','k_b4','k_c5','k_d5','k_e5','k_f5','k_g5','k_a5','k_b5','k_c6','k_d6','k_e6']
key_value_last = [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
key_value_now = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
midi_start = 0x48 #C4键的音高
# 与C4相比的音程查
midi_inve = [0,2,4,5,7,9,11,12,14,16,17,19,21,23,24,26,28]
while True :
for i in range(17):
key_value_now[i] = key_pin_list[i].value()
if not key_value_last[i] == key_value_now[i] :
if key_value_now[i] == 0:
print("on_" + key_name_list[i])
ble.send(bytearray([0x80, 0x80, 0x90, midi_start + midi_inve[i] , 0x63]))
else :
print("off_" + key_name_list[i])
ble.send(bytearray([0x80, 0x80, 0x80, midi_start + midi_inve[i] , 0x00]))
key_value_last[i] = key_value_now[i]
sleep_ms(10)
If you like to change the article, welcome 点赞
评论
收藏
转发
!
I am Teacher Peng!
All reference designs on this site are sourced from major semiconductor manufacturers or collected online for learning and research. The copyright belongs to the semiconductor manufacturer or the original author. If you believe that the reference design of this site infringes upon your relevant rights and interests, please send us a rights notice. As a neutral platform service provider, we will take measures to delete the relevant content in accordance with relevant laws after receiving the relevant notice from the rights holder. Please send relevant notifications to email: bbs_service@eeworld.com.cn.
It is your responsibility to test the circuit yourself and determine its suitability for you. EEWorld will not be liable for direct, indirect, special, incidental, consequential or punitive damages arising from any cause or anything connected to any reference design used.
Supported by EEWorld Datasheet