硬件(esp32),服务器(python),前端,三端联调的电子琴项目(未完整)

硬件(esp32),服务器(python),前端,三端联调的电子琴项目(未完整),第1张

关于本次项目的简略介绍:

大体分为硬件端和软件端,硬件端包括:esp32在面包板上的连接,画pcb电路图,焊接调试pcb电路,最后用三维设计外壳。软件端包括:用python编写的后端服务器,页面展示的客户端。(本项目要用到有关乐理知识)

我们的项目总的流程图

 文字描述:esp32硬件先连接WiFi,蓝灯亮了表示连接成功,不亮就用蜂鸣器发声,亮的话,esp32的琴键摁下将对应摁键通过udp通讯发送到服务端,服务端收到udp信息 可以利用pygame发声,也可以通过服务端和前端的websocket连接,将信息发送到前端,前端收到信息,去实现对应的琴键变颜色,记录简谱。 还可以通过前端的琴键摁下,让服务端的pygame发声,并变颜色和记录简谱。 拓展部分:1.作弊模式:硬件摁下一个摁键,不管硬件摁下哪个按键,都发出前端已经规定好的音谱。 软件端要达到的效果如下: 一 后端(thonny)

        1.使esp32发出不同的声音

        2.esp32发声(奏乐)

        2.录制esp32发音,判断摁键摁下的长短

        3.利用pygame发声

        4.用udp连接使服务器和硬件建立联系,硬件摁下琴键服务端收到udp信息,发出对应的音调

        5.esp32的WiFi连接

二 前端(vscode)

        1.在页面绘制UI琴键

        2.构建电子琴结构

        3.服务端和前端建立websocket连接

        4.硬件发送udp向服务端,服务端收到信息通过websocket连接发送到前端

以下是拓展部分:

        1.开启作弊模式

        2.切换上一首下一首,清除页面前一个音符,清空页面全部音符

        3.播放音乐

硬件端要达到的效果如下:

        1.esp32在面包板上的连接

        2.画pcb电路图

        3.pcb电路板的焊接

        4.三维模型的设计打印

------------------------------------------------------------------------------

在动手做之前我们应该了解基本乐理知识:音乐基础乐理知识大全 | 乐理知识 - 知乎 (zhihu.com)

在发音之前我们一个了解蜂鸣器有关知识:蜂鸣器原理 - 单片机教程 - C语言网 (dotcpp.com)

ESP32 MicroPython上手指南 — MicroPython 1.14 文档 (01studio.org)esp32官网:ESP32 MicroPython上手指南 — MicroPython 1.14 文档 (01studio.org)

了解面包板:(4条消息) 面包板使用简介_countofdane的博客-CSDN博客_面包板的详细使用方法

用到的硬件有esp32  剥线钳 导线 蜂鸣器(下图是esp32)

 "万事俱备只欠东风  --------------------------------"

        首先我们需要先将esp32在面包板上的连线完成

 完成连线过后我们可以去实现功能了

①当面包板上的琴键摁出发出不同音调并且亮蓝灯

        代码如下:

                        

from machine import TouchPad, Pin,PWM  
from time import sleep

LED = Pin(2,Pin.OUT)

pwm0 = PWM(Pin(23))
freq_val=5
duty_val=0
pwm0.freq(freq_val)
pwm0.duty(duty_val)


PINn = (32,33,27,13,12,14,15,4)#元组

TPx = [TouchPad(Pin(i)) for i in PINn]#TPx 所有的触摸管脚定义

Tone2 = (#对应管脚要演奏声音的频率
    523,
    586,
    658,
    697,
    783,
    879,
    987,
    1045,
    )

def dzq():
    global freq_val,duty_val
    '电子琴子程序'
    for ton,tp in zip(Tone2,TPx):
        '遍历所有的触摸按钮'
        if tp.read()<200:
            freq_val=ton
            duty_val = 1024//2
            LED.on()
            break
    else:
        #'如果运行完所有的循环,没有break,就执行这个else'
        freq_val = 10
        duty_val = 0
        LED.off()
        
    freq1 = pwm0.freq()#读取当前频率
    
#     pwm0.freq(freq_val)
#     sleep(0.01)
#     pwm0.duty(duty_val)
    
    if freq1 != freq_val:
        '只有频率被修改的时候,才去重新配置频率和占空比'
        pwm0.freq(freq_val)
        sleep(0.01)#需要一定时间的延时,否则的话,同时修改评论和占空比会导致占空比修改失败
        pwm0.duty(duty_val)
        
#         while pwm0.duty() != duty_val:
#             pwm0.duty(duty_val)
#         print(pwm0.freq(),pwm0.duty())
    
while True:
    dzq()
    sleep(0.01)

------------------------------------------------------------------------

②实现录制播放并且记录摁下时间长短:

import time #引入时间类
from machine import TouchPad, Pin, PWM #引入触摸管脚
import threading

switch = TouchPad(Pin(32))
switch_mode = 0

PINn = (33,27,13,12,14,15,4)#元组
TPx = [TouchPad(Pin(i)) for i in PINn]#TPx 所有的触摸管脚定义

LED = Pin(2, Pin.OUT)

pwm0 = PWM(Pin(26))
time.sleep(0.5)
pwm0.duty(0)
time.sleep(0.01)
pwm0.freq(1)

Tone = (#对应管脚要演奏声音的频率
    523,
    586,
    658,
    697,
    783,
    879,
    987,
    )

my_rhythm = [] #创建节拍空数组
my_tones = [] #创建音调空数组

release=0 #松开状态
press=1 #按下状态
key_state = [release]*8 #按键状态缓存变量
ALLkey_state = release
start = time.ticks_ms() #记录开始的时间戳
end = 0 #记录结束的时间戳
time_diff = 0 #开始和结束的时间差


def Record_time():
    global start,end,time_diff
    end = time.ticks_ms() #记录这一次按键变化结束的时间戳
    time_diff = time.ticks_diff(end, start) #根据这一次按键变化的开始和结束时间戳,计算出按键变化的时间差
    my_rhythm.append(time_diff/1000) #将时间差存入数组末尾
#     print(my_rhythm) #打印数组
    #-----------------------------------------------------
    start = time.ticks_ms() #记录下一次按键变化开始的时间戳

def playtone(frequency):
    pwm0.duty(512)
    time.sleep(0.01)
    pwm0.freq(frequency)

def bequiet():
    pwm0.duty(0)
    time.sleep(0.01)
    pwm0.freq(1)

def playsong():
    global switch_mode
    for i in range(len(my_rhythm)):
        if (my_tones[i] == 0 ):
            bequiet()
        else:
            playtone(my_tones[i])
        time.sleep(my_rhythm[i])
    bequiet()
    switch_mode=0
    print('music_OK')

my_music = threading.Thread(target=playsong)


def switchkey():
    global switch_mode,start
    while True:
        if switch.read()<200:
            if switch_mode==0:
                my_rhythm.clear()
                my_tones.clear()
                switch_mode=1
                start = time.ticks_ms() #记录开始的时间戳
                my_tones.append(0) #第一个项为空拍,与节拍数组格式对应
                LED.on()
            elif switch_mode==1:
                Record_time()
                print(my_tones)
                print(my_rhythm)
                switch_mode=2
                LED.off()
                my_music.start()
            while switch.read()<200:
                time.sleep(0.01)
        
sw_key = threading.Thread(target=switchkey)
sw_key.start()

while True:
    for i in range(7): #循环7次,读取7个按键状态
        if TPx[i].read()<200: #读取按键电容值,判断按键是否按下
            if key_state[i] != press: #如果按键状态缓存变量 非 此按键键值,表示按键发生了改变
                key_state[i] = press #将按键状态缓存变量 置为 此按键键值
                if switch_mode==1:
                    Record_time() #记录按键改变的时间差
                    my_tones.append(Tone[i]) #记录当前按键的音调
                playtone(Tone[i]) #发出对应频率的音调
            ALLkey_state = press #表示有按键按下
        else:
            key_state[i] = release #将当前按键状态置为松开
        
    if press not in key_state:
        if ALLkey_state != release : #全部松开状态下 判断之前是否有按键按下
            ALLkey_state = release #将按键状态置为全部松开状态
            if switch_mode==1:
                Record_time() #记录按键改变的时间差
                my_tones.append(0) #记录当前空拍音调
            bequiet() #不发声
              
    time.sleep(0.1) #延时

③利用pygame发声   a~z摁下都可以发声,记录并打印摁下时间:

import pygame.midi
import pygame
import time

# 初始化设置
volume = 127  # 音量 0-127
pygame.init()  # 初始化PYgame
windowSurface = pygame.display.set_mode((800, 600))  # 建立窗口
device = 0  # device number in win10 laptop
instrument = 0  # 乐器 http://www.ccarh.org/courses/253/handout/gminstruments/
# initize Pygame MIDI ----------------------------------------------------------
pygame.midi.init()  # PYGAMEMIDI库的初始化
# 初始化设置结束

screen = pygame.display.set_mode((400,400))

# 设置窗口的标题,即游戏名称
pygame.display.set_caption('pygame 钢琴')

# 引入字体类型
f = pygame.font.Font('C:/Windows/Fonts/simhei.ttf',135)
# 生成文本信息,第一个参数文本内容;第二个参数,字体是平滑;
# 第三个参数,RGB模式的字体颜色;第四个参数,RGB模式字体背景颜色;
text = f.render("Zhang",True,(255,244,255),(31,56,99))
#获得显示对象的rect区域坐标
textRect =text.get_rect()
# 设置显示对象居中
textRect.center = (200,200)
# 将准备好的文本信息,绘制到主屏幕 Screen 上。
screen.blit(text,textRect)

# 固定代码段,实现点击"X"号退出界面的功能,几乎所有的pygame都会使用该段代码
Tone = {  # 音调字典,不全,需要大家完善。从C1-C5都完善起来
   'A0':21,'A#0':22,'B0':23,
   
   'C1':24,'C#1':25,'D1':26,'D#1':27,'E1':28,'F1':29,'F#1':30,'G1':31,'G#1':32,'A1':33,'A#1':34,'B1':35,
   
   'C2':36,'C#2':37,'D2':38,'D#2':39,'E2':40,'F2':41,'F#2':42,'G2':43,'G#2':44,'A2':45,'A#2':46,'B2':47,
   
   'C3':48,'C#3':49,'D3':50,'D#3':51,'E3':52,'F3':53,'F#3':54,'G3':55,'G#3':56,'A3':57,'A#3':58,'B3':59,
   
   'C4':60,'C#4':61,'D4':62,'D#4':63,'E4':64,'F4':65,'F#4':66,'G4':67,'G#4':68,'A4':69,'A#4':70,'B4':71,
   
   'C5':72,'C#5':73,'D5':74,'D#5':75,'E5':76,'F5':77,'F#5':78,'G5':79,'G#5':80,'A5':81,'A#5':82,'B5':83,
   
   'C6':84,'C#6':85,'D6':86,'D#6':87,'E6':88,'F6':89,'F#6':90,'G6':91,'G#6':92,'A6':93,'A#6':94,'B6':95,
   
   'C7':96,'C#7':97,'D7':98,'D#7':99,'E7':100,'F7':101,'F#7':102,'G7':103,'G#7':104,'A7':105,'A#7':106,'B7':107,
   
   'C8':108,
   }
# set the output device --------------------------------------------------------
player = pygame.midi.Output(device)  # 定义了一个输出音轨

# set the instrument -----------------------------------------------------------
player.set_instrument(instrument)  # 设置乐器音色

key_value = ('a','s','d','f','g','h','j','q','w','e','r','t','y','u','z','x','c','v','b','n','m','1','2','3','4','5','6','7','i','o','p','k','l',)
key_tone = {
   'a':"C2",'s':"D2",'d':"E2",'f':"F2",'g':"G2",'h':"A2",'j':"B2",
   
   'q':"C3",'w':"D3",'e':"E3",'r':"F3",'t':"G3",'y':"A3",'u':"B3",
   
   'z':"C1",'x':"D1",'c':"E1",'v':"F1",'b':"G1",'n':"A1",'m':"B1",
   
   '1':"C4",'2':"D4",'3':"E4",'4':"F4",'5':"G4",'6':"A4",'7':"B4",
   
   'i':'C5','o':'D5','p':'E5','k':'F5','l':'G5',
   }

while True:
   for event in pygame.event.get(): # 检测事件
       
       if event.type == pygame.QUIT:
           exit()    
       if event.type == pygame.KEYDOWN:
           for i in range(33):
              if event.key == pygame.__dict__[ 'K_'+key_value[i] ]:
                  print('正在发第'+str(i)+'个的音')
                  t1 = time.time()
                  player.note_on(Tone[ key_tone[ key_value[i] ] ], volume)
                 
       elif event.type == pygame.KEYUP:# 按键=松开的话,关闭对应的音调
           for i in range(33):
               if event.key == pygame.__dict__[ 'K_'+key_value[i] ]:
                   print('停止发第'+str(i)+'个')
                   t2 = time.time()
                   t3 = t2 - t1
                   print(str(t3)+'s')
                   player.note_off(Tone[ key_tone[ key_value[i] ] ], volume)

# 循环获取事件,监听事件状态
   for event in pygame.event.get():
       # 判断用户是否点了"X"关闭按钮,并执行if代码段
       if event.type == pygame.QUIT:
           #卸载所有模块
           print("退出")
           pygame.quit()
           #终止程序,确保退出程序
           sys.exit()
   pygame.display.flip() #更新屏幕内容

pygame发声

④窗口显示按键样式和音符:

import pygame.midi
import pygame
import time
import sys
# 初始化设置
volume = 127 # 音量 0-127
pygame.init() # 初始化PYgame

windowSurface=pygame.display.set_mode((800,600)) #建立窗口
# screen = pygame.display.set_mode((400,400))

# 设置窗口标题,即游戏名称
pygame.display.set_caption('键盘钢琴')

#引入字体
f = pygame.font.Font('C:/Windows/Fonts/simhei.ttf',75)
#生成文本信息,第一个参数文本内容;第二个参数,字体是否平滑;
#第三个参数,RGB模式的字体颜色;第四个参数,RGB模式字体背景颜色;
text = f.render("Lebron",True,'deeppink','purple')
# 获得显示对象的rect区域坐标
textRect = text.get_rect()
# 设置显示对象居中
textRect.center = (400,40)
# 将准备好的文本信息,绘制到主屏幕 Screen 上。
windowSurface.blit(text,textRect)

device = 0     # device number in win10 laptop
instrument = 0 #乐器 http://www.ccarh.org/courses/253/handout/gminstruments/
# initize Pygame MIDI ----------------------------------------------------------
pygame.midi.init()# PYGAMEMIDI库的初始化

Tone = {  # 音调字典
   'A0':21,'A#0':22,'B0':23,
   'C1':24,'C#1':25,'D1':26,'D#1':27,'E1':28,'F1':29,'F#1':30,'G1':31,'G#1':32,'A1':33,'A#1':34,'B1':35,
   'C2':36,'C#2':37,'D2':38,'D#2':39,'E2':40,'F2':41,'F#2':42,'G2':43,'G#2':44,'A2':45,'A#2':46,'B2':47,
   'C3':48,'C#3':49,'D3':50,'D#3':51,'E3':52,'F3':53,'F#3':54,'G3':55,'G#3':56,'A3':57,'A#3':58,'B3':59,
   'C4':60,'C#4':61,'D4':62,'D#4':63,'E4':64,'F4':65,'F#4':66,'G4':67,'G#4':68,'A4':69,'A#4':70,'B4':71,
   'C5':72,'C#5':73,'D5':74,'D#5':75,'E5':76,'F5':77,'F#5':78,'G5':79,'G#5':80,'A5':81,'A#5':82,'B5':83,
   'C6':84,'C#6':85,'D6':86,'D#6':87,'E6':88,'F6':89,'F#6':90,'G6':91,'G#6':92,'A6':93,'A#6':94,'B6':95,
   'C7':96,'C#7':97,'D7':98,'D#7':99,'E7':100,'F7':101,'F#7':102,'G7':103,'G#7':104,'A7':105,'A#7':106,'B7':107,
   'C8':108,
   }
# set the output device --------------------------------------------------------
player = pygame.midi.Output(device)#定义了一个输出音轨

# set the instrument -----------------------------------------------------------
player.set_instrument(instrument)#设置乐器音色


key_tone = {
    '1':"C5", '2':"D5", '3':"E5", '4':"F5", '5':"G5", '6':"A5", '7':"B5",
    'q':"C3", 'w':"D3", 'e':"E3", 'r':"F3", 't':"G3", 'y':"A3", 'u':"B3",
    'a':"C4", 's':"D4", 'd':"E4", 'f':"F4", 'g':"G4", 'h':"A4", 'j':"B4",
    'z':"C2", 'x':"D2", 'c':"E2", 'v':"F2", 'b':"G2", 'n':"A2", 'm':"B2",
   }

text_col = 'black'         # 文本颜色
bd_col1 = 'white'        # 背景颜色(初始值)
bd_col2 = 'red'       # 背景颜色(按下反显值)

def key_color (text,x,y,color): #按键改变颜色(文本内容,坐标x,坐标y,颜色R)
   key = f.render(text,True,text_col,color)
   key_rect = key.get_rect()
   key_rect.center = (x,y)
   windowSurface.blit(key,key_rect)

for key in key_tone.keys(): #在窗口中循环打印字典中的字符key内容
    n=list(key_tone.keys()).index(key) #检索字符 是否在字符串列表中,返回字符所在位置
    key_color(key+' ',50+(n//7)*60+(n%7)*90,150+(n//7)*100,bd_col1)
  
# print( list(key_tone.keys()) )
# print( list(key_tone.keys())[0] )
# print(list(key_tone.keys()).index('r'))

while True:
   for event in pygame.event.get():  # 检测事件
       if event.type == pygame.QUIT:
            #卸载所有模块
            print("退出")
            pygame.quit()
            #终止程序,确保退出程序
            sys.exit()  
       if event.type == pygame.KEYDOWN:
          if chr(event.key) in key_tone.keys():#所按下的按键,在音符键盘的字典中
              n=list(key_tone.keys()).index(chr(event.key))#检索字符 是否在字符串列表中,返回字符所在位置
              key_color(chr(event.key)+' ',50+(n//7)*60+(n%7)*90,150+(n//7)*100,bd_col2)
              
              print('正在发'+key_tone[chr(event.key)]+'音')
              t1 = time.time() #记录t1的时间戳
              player.note_on(Tone[key_tone[chr(event.key)]], volume)
       elif event.type == pygame.KEYUP:# 按键=松开的话,关闭对应的音调
           if chr(event.key) in key_tone.keys():#所按下的按键,在音符键盘的字典中
               
               n=list(key_tone.keys()).index(chr(event.key))#检索字符 是否在字符串列表中,返回字符所在位置
               key_color(chr(event.key)+' ',50+(n//7)*60+(n%7)*90,150+(n//7)*100,bd_col1)
               
               print('停止发'+key_tone[chr(event.key)]+'音')
               t2 = time.time() #记录t2的时间戳
               t3 = t2 - t1    #根据t1和t2的时间戳,计算t3时间差
               print(str(t3)+'s') #打印出时间差
               player.note_off(Tone[key_tone[chr(event.key)]], volume)
       pygame.display.flip() #更新
       time.sleep(0.005) #每0.005s循环一次

窗口显示按键样式和音符

 ⑤udp通讯:

# -*- coding: utf-8 -*-
import socket
import time

#client 发送端
client_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
PORT = 8008

while True:
      start = time.time()  #获取当前时间
      print(time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(start)))  #以指定格式显示当前时间
      msg=input("本客户端192.168.43.131,请输入要发送的内容:")  
      server_address = ("192.168.43.82", PORT)  # 接收方 服务器的ip地址和端口号
      client_socket.sendto(bytes(msg.encode("utf-8")), server_address) #将msg内容发送给指定接收方
      now = time.time() #获取当前时间
      run_time = now-start #计算时间差,即运行时间
      print(time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(now)))
      print("run_time: %d seconds\n" %run_time)
      time.sleep(1)
###

以上是客户端,以下是服务端

# -*- coding: utf-8 -*-
import pygame.midi
import socket  #导入socket模块
import time #导入time模块

      #server 接收端
      # 设置服务器默认端口号
PORT = 8008
      # 创建一个套接字socket对象,用于进行通讯
      # socket.AF_INET 指明使用INET地址集,进行网间通讯
      # socket.SOCK_DGRAM 指明使用数据协议,即使用传输层的udp协议
server_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
address = ("", PORT)
server_socket.bind(address)  #为服务器绑定一个固定的地址,ip和端口
server_socket.settimeout(10)  #设置一个时间提示,如果10秒钟没接到数据进行提示

device = 0     # device number in win10 laptop
instrument = 0 #乐器 http://www.ccarh.org/courses/253/handout/gminstruments/
# initize Pygame MIDI ----------------------------------------------------------
pygame.midi.init()# PYGAMEMIDI库的初始化
# set the output device --------------------------------------------------------
player = pygame.midi.Output(device)#定义了一个输出音轨
volume = 127 # 音量 0-127
# set the instrument -----------------------------------------------------------
player.set_instrument(instrument)#设置乐器音色
Tone = {  # 音调字典
   'A0':21,'AS0':22,'B0':23,
   'C1':24,'CS1':25,'D1':26,'DS1':27,'E1':28,'F1':29,'FS1':30,'G1':31,'GS1':32,'A1':33,'AS1':34,'B1':35,
   'C2':36,'CS2':37,'D2':38,'DS2':39,'E2':40,'F2':41,'FS2':42,'G2':43,'GS2':44,'A2':45,'AS2':46,'B2':47,
   'C3':48,'CS3':49,'D3':50,'DS3':51,'E3':52,'F3':53,'FS3':54,'G3':55,'GS3':56,'A3':57,'AS3':58,'B3':59,
   'C4':60,'CS4':61,'D4':62,'DS4':63,'E4':64,'F4':65,'FS4':66,'G4':67,'GS4':68,'A4':69,'AS4':70,'B4':71,
   'C5':72,'CS5':73,'D5':74,'DS5':75,'E5':76,'F5':77,'FS5':78,'G5':79,'GS5':80,'A5':81,'AS5':82,'B5':83,
   'C6':84,'CS6':85,'D6':86,'DS6':87,'E6':88,'F6':89,'FS6':90,'G6':91,'GS6':92,'A6':93,'AS6':94,'B6':95,
   'C7':96,'CS7':97,'D7':98,'DS7':99,'E7':100,'F7':101,'FS7':102,'G7':103,'GS7':104,'A7':105,'AS7':106,'B7':107,
   'C8':108,
   }

player.note_on(Tone['C3'], volume)
time.sleep(1)
player.note_off(Tone['C3'], volume)


while True:
    #正常情况下接收数据并且显示,如果10秒钟没有接收数据进行提示(打印 "time out")
    #当然可以不要这个提示,那样的话把"try:" 以及 "except"后的语句删掉就可以了
  try:  
    now = time.time()  #获取当前时间
                        # 接收客户端传来的数据 recvfrom接收客户端的数据,默认是阻塞的,直到有客户端传来数据
                        # recvfrom 参数的意义,表示最大能接收多少数据,单位是字节
                        # recvfrom返回值说明
                        # receive_data表示接受到的传来的数据,是bytes类型
                        # client  表示传来数据的客户端的身份信息,客户端的ip和端口,元组
    receive_data, client = server_socket.recvfrom(1024)
    tone_temp = str(receive_data,'utf-8')#bytes转换为str字符串
    if tone_temp in Tone.keys():
        player.note_on(Tone[tone_temp], volume)
      
    print(time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(now))) #以指定格式显示时间
    print("来自客户端%s,发送的%s\n" % (client, receive_data))  #打印接收的内容
  except socket.timeout:  #如果10秒钟没有接收数据进行提示(打印 "time out")
    print("time out")
 

⑥wifi电子键盘 每个ESP32触摸键盘能够使服务器演奏对应钢琴音:

服务器用pycharm  发送端用thonny

#用thonny 做客户端 pycharm 做服务端
#用thonny 做客户端 pycharm 做服务端
def is_legal_wifi(essid, password):
   '''
   判断WIFI密码是否合法
   '''
   if len(essid) == 0 or len(password) == 0:
       return False
   return True

def do_connect():
   import json
   import network
   
   # 尝试读取配置文件wifi_confi.json,这里我们以json的方式来存储WIFI配置
   # wifi_config.json在根目录下
   
   # 若不是初次运行,则将文件中的内容读取并加载到字典变量 config
   try:
       with open('wifi_config.json','r') as f:
           config = json.loads(f.read())
   # 若初次运行,则将进入excpet,执行配置文件的创建        
   except:
       essid = ''
       password = ''

       while True:
           essid = input('wifi name:') # 输入essid
           password = input('wifi passwrod:') # 输入password

           if is_legal_wifi(essid, password):
               config = dict(essid=essid, password=password) # 创建字典
               with open('wifi_config.json','w') as f:
                   f.write(json.dumps(config)) # 将字典序列化为json字符串,存入wifi_config.json
               break
           else:
               print('ERROR, Please Input Right WIFI')
   
   #以下为正常的WIFI连接流程        
   wifi = network.WLAN(network.STA_IF)  
   if not wifi.isconnected():
       print('connecting to network...')
       wifi.active(True)
       wifi.connect(config['essid'], config['password'])
       import utime

       for i in range(200):
           print('第{}次尝试连接WIFI热点'.format(i))
           if wifi.isconnected():
               break
           utime.sleep_ms(100) #一般睡个5-10秒,应该绰绰有余
       
       if not wifi.isconnected():
           wifi.active(False) #关掉连接,免得repl死循环输出
           print('wifi connection error, please reconnect')
           import os
           # 连续输错essid和password会导致wifi_config.json不存在
           try:
               os.remove('wifi_config.json') # 删除配置文件
           except:
               pass
           do_connect() # 重新连接
       else:
           print('network config:', wifi.ifconfig())




import socket
import time
from machine import Pin
from time import sleep
LED=Pin(2,Pin.OUT)

do_connect()
LED.on()

#多键触摸发声
#-----------------------------------
from machine import TouchPad, Pin,  #引用touch库,GPIO库,PWM库
from time import sleep #引用time库
touch_do=TouchPad(Pin(13)) #创建 DO音 TouchPad对象
touch_re=TouchPad(Pin(12)) #创建 RE音 TouchPad对象
touch_mi=TouchPad(Pin(14)) #创建 MI音 TouchPad对象
touch_fa=TouchPad(Pin(27)) #创建 FA音 TouchPad对象
touch_so=TouchPad(Pin(33)) #创建 SO音 TouchPad对象
touch_la=TouchPad(Pin(32)) #创建 LA音 TouchPad对象
touch_si=TouchPad(Pin(15)) #创建 SI音 TouchPad对象
touch_si=TouchPad(Pin(4)) #创建 SI音 TouchPad对象




# LED点亮说明WIFI连接正常

#client 发送端
client_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
server_address = ("192.168.43.82", 8008)  # 接收方 服务器的ip地址和端口号
while True:
   #循环体
#     A=touch_do.read()
#     B=touch_re.read()
#     C=touch_mi.read()
#     D=touch_fa.read()
#     E=touch_so.read()
#     F=touch_la.read()
#     G=touch_si.read()
#     H=touch_si.read()
   
   PINn = (13,12,14,27,33,32,15,4)#元组
   TPx = [TouchPad(Pin(i)) for i in PINn]
   Tone2 = (
   "A3",
   "A7",
   "A5",
   "B3",
   "D3",
   "C7",
   "B5",
   "A1",
   
   )
 
   for ton,tp in zip(Tone2,TPx):
       if tp.read()<200:
           print("已经发送啦!")
           msg = ton
           client_socket.sendto(bytes(msg.encode('utf-8')), server_address) #将msg内容发送给指定接收方
           time.sleep(0.01)

⑦esp32的WiFi连接:

后期这个直接烧录进esp32

import network
import time
#WIFI连接流程
def wifi_connect():
    wifi = network.WLAN(network.STA_IF)  
    wifi.active(True) 
    wifi.connect('', '')

    for i in range(200):
        print('第{}次尝试连接WIFI热点'.format(i))
        if wifi.isconnected():
            break
        time.sleep(0.1) #一般睡个5-10秒,应该绰绰有余
        
    if not wifi.isconnected():
        wifi.active(False) #关掉连接,免得repl死循环输出
        print('wifi connection error, please reconnect')
    else:
        print('network config:', wifi.ifconfig()) 

前端: ①电子琴的完整数据结构  和点击发声:-


②建立服务端和前端的websocket连接:

服务端:

from flask import Flask  #Flask服务器库
from flask_sockets import Sockets  #WS连接库
import pygame.midi #d奏音乐的库
import pygame      #pygame的库
import json
from concurrent.futures import ThreadPoolExecutor
import socket


instruments = [1,46,25,56]

# 创建线程池执行器
executor = ThreadPoolExecutor(2)
# 初始化pygame设置
volume = 127  # 音量 0-127
device = 0  # device number in win10 laptop
instrument = 1  # 乐器 http://www.ccarh.org/courses/253/handout/gminstruments/
# initize Pygame MIDI ----------------------------------------------------------
pygame.midi.init()  # PYGAMEMIDI库的初始化
# set the output device --------------------------------------------------------
player = pygame.midi.Output(device)  # 定义了一个输出音轨
# set the instrument -----------------------------------------------------------
player.set_instrument(instrument)  # 设置乐器音色
# 初始化设置结束

Tone = {#音调字典
    'C0':12,'CS0':13,'D0':14,'DS0':15,'E0':16,'F0':17,'FS0':18,'G0':19,'GS0':20,'A0':21,'AS0':22,'B0':23, 
    'C1':24,'CS1':25,'D1':26,'DS1':27,'E1':28,'F1':29,'FS1':30,'G1':31,'GS1':32,'A1':33,'AS1':34,'B1':35,  
    'C2':36,'CS2':37,'D2':38,'DS2':39,'E2':40,'F2':41,'FS2':42,'G2':43,'GS2':44,'A2':45,'AS2':46,'B2':47,   
    'C3':48,'CS3':49,'D3':50,'DS3':51,'E3':52,'F3':53,'FS3':54,'G3':55,'GS3':56,'A3':57,'AS3':58,'B3':59,    
    'C4':60,'CS4':61,'D4':62,'DS4':63,'E4':64,'F4':65,'FS4':66,'G4':67,'GS4':68,'A4':69,'AS4':70,'B4':71,  
    'C5':72,'CS5':72,'D5':74,'DS5':75,'E5':76,'F5':77,'FS5':78,'G5':79,'GS5':80,'A5':81,'AS5':82,'B5':83,  
    'C6':84,'CS6':85,'D6':86,'DS6':87,'E6':88,'F6':89,'FS6':90,'G6':91,'GS6':92,'A6':93,'AS6':94,'B6':95,  
    'C7':96,'CS7':97,'D7':98,'DS7':99,'E7':100,'F7':101,'FS7':102,'G7':103,'GS7':104,'A7':105,'AS7':106,'B7':107,
    }

wsSev = {}
app = Flask(__name__)
sockets = Sockets(app)

cheatMode = 0
cheatIndex = 0
currentGroup = ["C4","D4","E4","F4","G4","A4","B4"]

# 服务器启动时,开启ws服务器
def main_app():
    from gevent import pywsgi
    from geventwebsocket.handler import WebSocketHandler
    server = pywsgi.WSGIServer(('192.168.10.106', 9302), app, handler_class=WebSocketHandler)
#     开启udp监听
    executor.submit(udp_conn)
    print("websocket服务启动")
    server.serve_forever()
    
def udp_conn():
    global wsSev
    global cheatMode
    global cheatIndex
    global currentGroup
    udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    address=('192.168.10.106', 9302)
    udp_socket.bind(address)
    print('UDP监听开启')
    try:
        while True:
            revc_data = udp_socket.recvfrom(1024)
            print(str(revc_data[0], encoding = "utf-8"))
            noteinfo = json.loads(str(revc_data[0], encoding = "utf-8"))
            print(cheatMode)
            if cheatMode == 1 and str(noteinfo["status"])=='1':
                noteinfo["note"] = currentGroup[cheatIndex]
                print(currentGroup[cheatIndex])
                cheatIndex = cheatIndex + 1
                if len(currentGroup) == cheatIndex:
                    cheatIndex = 0
                    
            play(noteinfo)
            if wsSev:
                wsSev.send(json.dumps(noteinfo))
    except:
        wsTarget.close()

# 持续监听客户端发送的数据
def ws_listener():
    global wsSev
    try:
        while True:
            message = wsSev.receive()
            print(message)
            if message is not None:
                noteinfo = json.loads(message)
                play(noteinfo)
                #wsSev.send("我接收到了!")
    except:
        wsSev.close()
    
# 客户端与服务器建立连接的接口
@sockets.route('/connectServer')
def connect_server(socket):
    global wsSev
    print('connected')
    wsSev = socket
    print('接收到客户端的连接')
    #wsSev.send("你已成功连接至服务器")
    ws_listener()

def play(noteinfo):  #使用Pygame调用声卡发声
    global cheatMode
    global cheatIndex
    if str(noteinfo['status']) == "1":
        print("发声")
        print(noteinfo['note'])
        if str(noteinfo['note']) == 'X1':
            cheatMode = 1
            cheatIndex = 0
            print("开启cheat模式")
        elif str(noteinfo['note']) == 'X2':
            cheatMode = 0
            cheatIndex = 0
            print("关闭cheat模式")
        else:
            player.note_on(Tone[noteinfo['note']], volume)  #d出声音
    else:
        print("停止")
        player.note_off(Tone[noteinfo['note']], volume) #关闭声音
    
if __name__ == "__main__":
    main_app()
 

前端: 1、访问初始化接口,建立连接
this.ws = new WebSocket("ws://9.7.0.65:9303/connectServer");

ws需要作为一个全局对象,在data中初始化

2、持续监听(接收数据)
this.ws.onmessage = ((event) => {
    // 将接收到的数据序列化为JSON结构(Object对象)
    let socketMessage = event.data
    console.log(socketMessage)
});
3、发送数据
this.ws.send('要发送的内容')

icon图标(前端): 用到UI控件      Element:Element - The world's most popular Vue UI framework

注意注意:

        开始前记得,安装和在main.js中引用!

播放  这样之后,但并不是我想要的结果,接下来有两种方法,第一在button按钮菜单下的图标按钮的下拉代码下选择,第二是icon图标里找寻需要的图标。  图标标签是   最终:

本项目需要三个icon,第一个:开始播放,第二个:删除前一个音符,第三个删除全部音符

代码如下:

        

           

           

           

接下来 准备写下拉选择播放音乐:

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/922520.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-16
下一篇 2022-05-16

发表评论

登录后才能评论

评论列表(0条)

保存