MIDI信号的解码及实时音符显示
摘要:介绍了MIDI数据的格式,讨论了一种使用AT89C51系列单片机完成MIDI信号的实时解码,从中提高音符数据,并随时利用专用LED驱动芯片将音符显示出来的设计方案。该方案经实际产品应用,证明合理可靠。
关键词:MIDI 串行接口 LED显示
MIDI是音乐设备数字接口的简答,是各种电子音乐设备之间数据传输的标准接口,广泛应用于各种电子乐器上,目前较高档的电子琴子均带有MIDI接口。笔者在开发用于音乐教学的产品“音乐电教板”的过程中,遇到了有关MIDI信号解码的问题,产品要求能够接受电子琴传送来的MIDI信号,并将相应的音符显示出来。经过对MIDI协议的研究,用AT89C51单片机和128段LED显示控制芯片BC7281构成的系统完成了设计要求。
1 MIDI信号简介及与单片机的接口
MIDI信号的传输采用异步串行方式,javascript:window.open(this.src);" style="cursor:pointer;"/>其速率为31.5kbps,数据格式为8个数据位、1个起始位和1个停止位。因此,完全可以采用MCS51单片机内部的硬件UART串口完成MIDI信号的接收和发送(本设计中只用到其接收部分),在硬件方面只需采取适当的电路进行电平转换即可。
MIDI接口采用标准的5芯DIN连接器,如图1。传送电缆使用屏蔽层的双绞线电缆,因为信号的传输利用的是电流信号而不是电压信号,所以其抗干扰能力比较强,尽管其速率高达31.5kbps,传输距离仍可以达到15m,比常见的RS-232接口的传送距离要远。一般的MIDI接收电路如图2,本文采用与之相同的电路。
其中RX接单片机的串口RX端,电路中的光耦既起到隔离的作用,又有电平转换的作用,因为速率较高,必须选用开关速度较高的型号,这里使用的是6N136。D1是保护二极管。
MIDI中共有16个通道(channel),一般称之为通道1至通道16,每个通道相当于乐曲中的个声部,使用者可以为每个通道指定一种音色。音色可以是MIDI规范中规定的128种音色中的任何一种,每一个通道只能有一种音色。也就是说,在一个标准的MIDI系统中,最多相当于可以有16种乐器同时演奏。
按照MIDI协议的规定,传送的数据可以分为两类:状态字节和数据字节。所谓状态字节实际就是命令字,表明其后所跟数据的种类,状态字节总是大于等于80H,而数据字节总是小于80H,因此,可以很容易地区分状态字节和数据字节。在状态字节中,用数据的低4位表示通道号,高4位表示不同的命令。比如,设定音色为ChH指令,其中n是通道号。
在各种MIDI的指令中,与本机有关的只有两种:8nH和9nH(n为通道号),两种指令的基本格式一样,一般由3个字节组成,格式是:
8n(9n) aa bb
其中,aa是音符数据,表明所演奏的音符,其范围为0~7fH,这样共有128个音符,足以覆盖整个音域;bb是速度数据,表明击键的速度,又称力度数据,其范围也是0~7fH。
javascript:window.open(this.src);" style="cursor:pointer;"/>
第一个字节是状态字节(指令),其具体含义说明如下:
8nH——“音符关”指令,在多数MIDM设备中,该指令中的速度数据bb被忽略。
9nH——“音符开”指令,如果速度数据等于0,则等同于8nH指令。在本机中,因为只需要显示音符的开关,而不必考虑其声音的大小,故速度数据被忽略(速度数据不等于0时)。
MIDI中有一个特殊的通道即通道10,通道10是节奏乐器的专用通道,与其它通道不同,其它通道中不同的音符表示不同的音高,而在通道1中,不同音符表示不同的节奏乐器,因为节奏乐器是没有音高的,一般如各种鼓等,在本机中,所要显示的是各种旋律的音符,因此,通道10的数据要过滤掉。
2 显示电路
音符的显示,通过一个钢琴键盘的面板,在键盘的每个键上,都有一个LED指示灯,用LED的亮和灭代表音符的开和关。一个完整的钢琴键盘,83个键,再加上系统中用于指示工作状态的指示灯等,本机需要显示LED达100多个。因此,选用了16位数码管(128位LED)及64键键盘接口芯片BC7281,该芯片可以驱动128个独立的LED,同时还可以提供键盘管理,笔者设计的系统中16个按键,完全可以满足要求。而其本身仅为18脚DIP封装,体积小巧。
javascript:window.open(this.src);" style="cursor:pointer;"/>
该芯片与MCU之间采用串行通信,只需要3根引线,为简单起见,这里只给出本系统中键盘、显示部分的电路框图如图3。
BC7281中有16位显示寄存器,其每一数据位都对应着显示矩阵中的一个LED,每个数据位都有一个位地址,用以做寻址,样每一个LED的开关都可以单独控制,其地址范围是07FH。将地址0~52H的LED作为音符显示用,69H~7FH的地址作为系统状态指示用,共余LED显示不用。
3 程序设计
因为MIDI数据的传送速率较高,因此,决定采用中断的方式来处理MIDI数据。对于显示部分,则在数据区中设立一个特定的缓冲区,处理MIDI数据的中断程序只负责对缓冲区内的数据进行更新,而不直接完成对显示芯片的操作,这样可以提高中断处理速度。显示的刷新,则放在程序的主循环中来完成。
用于处理MIDI数据的串口中断程序,必须完成以下工作:
(1)根据状态字节,过滤掉不必要的数据;
(2)根据保留下的“音符开”和“音符关”数据,更新显示数据缓冲区。
javascript:window.open(this.src);" style="cursor:pointer;"/>
因为设计要求所有旋律通道的音符都要显示出来,也就是说,除第10通道外,每个通道的音符都要显示出来。这样就存在着音符重叠的问题,比如第一通道中的C音和第二通道中的C音同时演奏,这时如果单片机收到一个“音符关”指令,则必须判断其它通道中有没有相同的音符处在“开”的状态,如果有,则相应的音符指示灯就不能关闭。为了到达这个目的,将音符显示的缓冲区设置为一个128单元的数组,数组单元和MIDI的128个音符一一对应(虽然只需要显示其中的8个音符),但是为了简化程序及日后升级的方便,仍将数组设为128单元,只在主程序中显示刷新的部分才将多余的数据忽略),每当收到一个“音符开”指令时,相应的数组单元就加一,而收到“音符关”指令时,则减一,在显示时,只要数组单元不等于零,对应的音符指示LED就点亮,而只有在数组单元等于零时,才将已经点亮的LED关闭,“音符关”指令不直接控制LED,这样就很好地解决了省符重叠的问题。
AT89C51串口中断处理程序流程图如图4。
目前该产品已经批量生产,并已成功进入市场销售一年有余,实践证明该设计方案是合理和可靠的。