1、5.2 如何用单片机实现 MIDI 键盘功能用 51 系列单片机实现 MIDI 键盘功能,实际上就是要解决 3 个方面的问提,那就是: 如何产生符合 MIDI 协议的串行通讯数据,如何扫描键盘和实现力度响应,如何适当的进行电器连接,本节将介绍前两个问题, 最后一个问题将放在下一节介绍。 5.2.1 如何产生符合 MIDI 协议的串行信号绝大多数系列单片机都有串行通讯控制器(UART ),配合合适的晶振,正确地设置 UART 的工作参数,就能够自动产生所需的串行数据。在单片机做串行通讯时,可以用定时计数器(T/C1 )作为波特率发生器。将串行口设置为方式工作状态(位异步收发,波特率由定时器控制)
2、 ,使用MHz晶振,T/C1 设为自动装入位计数器状态(TMOD 置为 2xH) ,SMOD1,TH=FFH,此时正好发生波特率为 31.25K 的串行通讯数据,适用于 MIDI 协议。串口及定时计数器初始化如下:(C 语言例程,下同)void format(); TMOD=0x21; /T/C1 工作于位自动装入状态/TL1=0xff; TH1=0xff ; / T/C1 常数,确定波特率/SCON=0x50 ; /设串口工作于方式,/PCON=0x80 ; /相当于 SMOD=1;/TR1=1; /T/C1 开始计数/由 51 系列单片机 UART 的工作方式可推知, 当外部晶振的频率为
3、6MHz 的倍数时,正确地设置特殊功能寄存器,可以精确的发生 31.25K 的波特率,见表 5:表 用不同的晶振频率产生波特率 31.25K 的寄存器值晶振频率 TMOD SCON PCON TL1 TH16MHz 0x21 0x50 0x80 0xFF 0xFF0x80 0xFE 0xFE12MHz 0x21 0x500x00 0xFF 0xFF0x80 0xFD 0xFD24MHz 0x21 0x500x00 0xFE 0xFE上一节已经介绍了 MIDI 命令的格式,发送一个音符的开关命令,可调用如下函数:void send(uchar cc,kk,vv) TR1=1; /开计数器/SBU
4、F=cc; /发送 cc/while(TI=0); /等待发送结束 /TI=0; /清发送标志 /SBUF=kk;while(TI=0);TI=0;SBUF=vv;while(TI=0);TI=0; TR1=0;参数 cc,kk,vv 的含义已在 MIDI 协议中介绍,不再重复。对于 1 字节和 2 字节命令,只需将上述函数简化即可,由于在演奏中主要执行的都是 3 字节命令,为提高运行速度,不在发送函数中判断命令长度,因为那样做的话固然可以减少一两个函数,但让单片机过多执行不必要的代码,得不偿失。5.2.2 键盘扫描电子乐器的键盘, 动辄就是数十个琴键,而且经常出现多个按键同时压下的情况,单片
5、机系统必须能够准确判断哪个键被压下,哪个键保持,哪个键被释放,考虑到经济性,矩阵式动态扫描是乐器键盘最理想的工作方式,图 53 给出了 64 键无力度感应的键盘原理图,配合 89c51 单片机, 能很好的完成 64 键的扫描工作。图 53 中, 每行按键为连续的 8 个键,称为一个段,每段的 8 个键通过二极管共同接在一根段选线上,按键的另外一端,分别按顺序接在各自的读入线(51 单片机的 P2 口)上,段选线(P0)为单片机输出,为低电平有效,工作时,单片机向 P0 口某根线发出低电平,选中该段,然后读 P2 口,当有相应的按键被压下时,该输入线与段选线接通, 通过二极管拉到低电平,单片机即
6、可判断是该段的哪一个按键被压下。改变段选线,则判断另一段的按键。做一个 8 次循环的函数,每一次循环改变一次段选线,每次读入 8 个键值,则可完成 64 个按键的扫描工作。图中的二极管非常重要, 它们起到阻隔无效段选线的高电平的作用,如不加二极管,在有按键压下时,将发生有效的段选线(低电平)与无效的段选线(其他线的高电平)通过按键短路的情况,将产生混乱。键盘在演奏时,有三个动作,被压下、保持压下状态、被释放,在被压下并保持时,每次扫描都会判断出该键的压下状态,但在实际工作中, 并不需要每次扫描到这种状态都发出 MIDI 命令,因此,要进行按键状态的存贮,每次扫描后,与存贮的状态比较,发现有改变
7、,再作相应的处理,并将新的状态存入。图 53 8X8 键无力度键盘电路图扫描 8X8 键盘的程序如下,程序中的 key_numberi是全局数组, 用来存贮按键状态,addition 是全局变量,是设定该键盘第一个按键对应的 MIDI 音符的键值,全局数组和全局变量要在主程序中定义,程序中调用了 send(cc,kk,vv)函数,见前一节介绍,特此说明。void scan_key() uchar i,j,k,r,mmm,xu; k=0xfe; / k 值为段选初值,第一位为 0for (i=0;i250) /超时将认为触点关闭key_number2iif(xd /后排键关闭则关音符key_nu
8、mber3i key_number2ielse if (key_number2ielse vv=255-count_beginij+ts; /时间计数器溢出处理send(0x90+chnal,i*8+j+ada*12+addition,volppvv);/音符发声key_number3i|=mmm; mmm=mmm1; /键检测指针左移/=中断服务程序,每 2 毫秒为 ttt 加 1,=void timer0() interrupt 1 using 3 /*interrupt sub of timer0*/ TH0=0xf0;/fc; /计数器初值 4000,,在主频 24MHz 时,每 2mS 中断一次TL0=0x5f;/18 ;ttt+;本程序对应的键盘的电路见图 55,为直观起见,图中完全按照琴键的结构绘制,最大可支持 64 键的力度键盘。在上述程序中,仅列出了键盘扫描的部分,由于在具体演奏中会遇到诸如音色切换等各种控制动作,实际的程序中还应加入扫描各种控制输入信号的部分,以使产品性能更加完善。图 55 64 键力度键盘的电路原理图