① 求89c51单片机制作简易电子琴的c程序及源代码
#include
#include
#include
#include
#include
#define uchar unsigned char
typedef unsigned char uint8; // 无符号8位整型变量
typedef signed char int8; // 有符号8位整型变量
typedef unsigned short uint16; // 无符号16位整型变量
typedef signed short int16; // 有符号16位整型变量
typedef unsigned int uint32; // 无符号32位整型变量
typedef signed int int32; // 有符号32位整型变量
typedef float fp32; // 单精度浮点数(32位长度)
typedef double fp64; // 双精度浮点数(64位长度)
sbit row1 = P1 ^ 0;
sbit row2 = P1 ^ 1;
sbit row3 = P1 ^ 2;
sbit col1 = P0 ^ 1;
sbit col2 = P0 ^ 2;
sbit col3 = P0 ^ 3;
sbit col4 = P0 ^ 4;
sbit col5 = P0 ^ 5;
sbit col6 = P0 ^ 6;
sbit col7 = P0 ^ 7;
#define uint unsigned int
uchar STH0; //定时器计数初值
uchar STL0;
bit FY=0; //放乐曲时FY=1, 电子琴弹奏时FY=0
uchar Song_Index=0,Tone_Index=0; //放音乐的参数
uchar k, key;
sbit SPK=P3^7;
sbit LED1=P1^0;
sbit LED2=P1^1;
sbit LED3=P3^4;
sbit LED4=P3^5;
sbit LED5=P3^6;
void Delay(uint16 count)
{
uint8 i;
while(--count != 0)
{
for(i = 0; i < 125; i++); // ";" 表示空语句,CPU空转。
} // i 从0加到125,在12M晶体下CPU大概耗时1毫秒
}
uint8 KeyDown(void)
{
col1=0; col2=0; col3=0; col4=0; col5=0; col6=0; col7=0; // 列线全部置低
if((row1==0) || (row2==0) || (row3==0)) // 若有任一行线读回状态为低
{
Delay(80); // 延时消抖
if((row1==0) || (row2==0) || (row3==0)) // 再次读行线状态,若有任一行线读回状态为低
return 1; // 返回1,表明有键盘按下
else
return 0; // 返回0,表明无键盘按下
}
else
return 0;
}
uint8 KeyUp(void)
{
col1=0; col2=0; col3=0; col4=0; col5=0; col6=0; col7=0;
if((row1==1) && (row2==1) && (row3==1))
{
Delay(80);
if((row1==1) && (row2==1) && (row3==1))
return 1;
else
return 0;
}
else
return 0;
}
uint8 KeyNum(void)
{
uint8 KeyTemp;
KeyTemp=0;
if(KeyDown()==1)
{
col1=0; col2=1; col3=1; col4=1; col5=1; col6=1; col7=1; // 将列线1置低,其他列线置高
if (row1==0) KeyTemp=1; // 若行线1读回状态为低,则表明按键1被按下
if (row2==0) KeyTemp=8; // 若行线2读回状态为低,则表明按键8被按下
if (row3==0) KeyTemp=15; // 若行线3读回状态为低,则表明按键15被按下
col1=1; col2=0; col3=1; col4=1; col5=1; col6=1; col7=1;
if (row1==0) KeyTemp=2;
if (row2==0) KeyTemp=9;
if (row3==0) KeyTemp=16;
col1=1; col2=1; col3=0; col4=1; col5=1; col6=1; col7=1;
if (row1==0) KeyTemp=3;
if (row2==0) KeyTemp=10;
if (row3==0) KeyTemp=17;
col1=1; col2=1; col3=1; col4=0; col5=1; col6=1; col7=1;
if (row1==0) KeyTemp=4;
if (row2==0) KeyTemp=11;
if (row3==0) KeyTemp=18;
col1=1; col2=1; col3=1; col4=1; col5=0; col6=1; col7=1;
if (row1==0) KeyTemp=5;
if (row2==0) KeyTemp=12;
if (row3==0) KeyTemp=19;
col1=1; col2=1; col3=1; col4=1; col5=1; col6=0; col7=1;
if (row1==0) KeyTemp=6;
if (row2==0) KeyTemp=13;
if (row3==0) KeyTemp=20;
col1=1; col2=1; col3=1; col4=1; col5=1; col6=1; col7=0;
if (row1==0) KeyTemp=7;
if (row2==0) KeyTemp=14;
if (row3==0) KeyTemp=21;
return KeyTemp;
}
else
return 0; //无按键按下
}
uchar code DSY_CODE[]= {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
0x06,0x5b,0x4f, 0x66,0x6d,0x7d,0x07,0x06};
uchar code GE_CODE[]={0x3f,0x06,0x5b,0x4f, 0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c, 0x39,0x5e,0x79,0x71};
uchar code Song[][100]= //任意选几首音乐的旋律
{
{5,3,5,3,5,3,1,2,4,3,2,5,5,3,5,3,5,3,1,2,4,3,2,1,2,2,4,4,3,1,5,2,4,3,2,5,5,3,5,3,5,3,1,2,4,3,2,1,-1}, //《粉刷匠》
{1,2,3,4,5,3,1,8,6,4,5,5,3,1,2,3,4,5,3,2,1,2,3,2,5,1,2,3,4,5,3,1,8,6,4,5,3,1,2,3,4,5,3,2,1,2,3,1,1,8,6,4,5,5,1,8,6,4,5,3,1,2,3,4,5,3,2,1,2,3,1,1,-1},//《小红帽》
{1,2,3,1,1,2,3,1,3,4,5,3,4,5,5,6,5,4,3,1,5,6,5,4,3,1,1,5,1,1,5,1,-1}, //《两只老虎》
{5,8,6,8,5,3,5,2,3,5,0,3,5,6,8,5,6,5,3,5,1,3,2,0,3,2,1,2,3,6,5,3,5,6,0,5,8,6,5,3,5,2,5,2,3,2,1,-1}, //《一分钱》
{5,3,5,3,5,3,2,3,5,5,5,3,6,5,3,5,3,2,1,2,3,5,3,2,1,2,3,6,5,6,5,2,3,5,6,5,6,5,2,3,1,-1}, //《丢手绢》
{5,3,5,3,5,6,5,3,6,5,1,1,2,3,5,3,2,0,3,5,5,5,6,5,3,5,5,6,5,8,6,5,1,5,3,2,1,2,3,5,5,2,3,1,10,9,8,6,5,5,6,6,5,6,8,10,8,9,0,5,10,9,8,6,5,5,6,6,5,6,10,9,9,10,9,8,6,5,5,8,6,5,3,2,1,0,2,3,5,5,0,5,6,8,-1}, //《七子之歌-澳门》
{5,6,5,6,5,6,5,5,8,7,6,5,3,5,5,3,4,5,5,3,1,4,3,2,1,2,1,-1}, //《找朋友》
{5,10,9,10,3,8,7,6,6,9,8,9,6,8,9,9,9,9,8,10,10,9,9,5,10,9,10,3,8,7,6,5,6,8,8,8,9,10,9,8,7,8,8,-1},//《感恩的心》
{3,3,4,5,5,4,3,2,1,1,2,3,3,2,2,3,3,4,5,5,4,3,2,1,1,2,3,2,1,1,2,2,3,1,2,3,4,3,1,2,3,4,3,2,1,2,1,3,3,3,4,5,5,4,3,4,2,1,1,2,3,2,1,1,-1}, //《欢乐颂》
{5,8,5,4,3,2,1,1,1,2,3,3,1,3,4,5,5,5,8,5,4,3,5,2,4,3,2,6,5,2,3,1,1,0,5,3,6,8,7,6,7,5,3,9,9,9,8,7,6,8,5,5,5,3,6,8,7,6,7,8,9,5,6,7,8,9,5,8,8,-1}, //《我爱北京天安门》
{3,5,8,5,6,0,6,5,3,3,5,5,3,5,6,8,9,8,5,3,2,5,3,3,3,3,5,8,5,6,0,8,9,8,5,3,5,7,6,0,3,2,3,5,10,9,7,8,3,5,8,3,5,8,5,6,0,8,9,8,5,3,5,7,6,0,3,2,3,5,10,9,7,8,3,5,2,3,5,10,9,9,9,7,8,-1},//《北京欢迎你》
{1,2,3,1,5,6,6,8,6,5,6,6,8,5,6,5,6,5,3,5,3,1,2,3,1,-1}, //《上学歌》
{10,9,9,10,8,0,3,8,6,5,3,5,0,5,5,6,8,8,8,6,8,3,5,5,6,5,3,2,2,0,10,9,9,10,8,0,3,8,6,5,3,5,0,5,5,6,8,8,6,5,6,3,0,3,10,10,10,10,9,6,8,-1},//《当兵的人》
{3,3,5,6,8,8,6,5,5,6,5,3,3,5,6,8,8,6,5,5,6,5,5,5,5,3,5,6,6,5,3,2,3,5,3,2,1,1,2,1,-1},//《茉莉花》
{3,1,3,3,1,3,3,5,6,5,0,6,6,5,5,4,4,4,2,3,2,1,2,0,3,1,0,3,1,0,3,3,5,6,6,0,8,5,5,6,3,2,1,2,3,5,8,5,5,6,3,2,1,2,3,1,-1},//《数鸭子》
{1,1,3,4,5,5,5,3,4,4,4,2,1,3,5,0,1,1,3,4,5,5,5,3,4,4,4,2,1,3,1,0,6,6,4,5,5,5,5,3,4,4,4,2,1,3,5,0,6,6,4,5,5,5,5,3,4,4,4,2,1,3,1,0,-1},//《洋娃娃和小熊跳舞》
};
uchar code Len[][100]= //上面几首音乐的旋律每个音符对应的节拍
{
{2,2,2,2,2,2,4,2,2,2,2,4,2,2,2,2,2,2,4,2,2,2,2,4,2,2,2,2,2,2,4,2,2,2,2,4,2,2,2,2,2,2,4,2,2,2,2,4,-1}, //《粉刷匠》
{2,2,2,2,4,2,2,4,2,2,2,2,4,2,2,2,2,2,2,2,2,4,4,4,4,2,2,2,2,4,2,2,4,2,2,4,4,2,2,2,2,2,2,2,2,4,4,4,4,4,2,2,2,2,4,4,2,2,4,4,2,2,2,2,2,2,2,2,4,4,4,4,-1}, //《小红帽》
{2,2,2,2,2,2,2,2,2,2,4,2,2,4,2,2,2,2,4,4,2,2,2,2,4,4,2,2,4,2,2,4,2,2,4,-1}, //《两只老虎》
{4,4,2,2,4,2,2,2,2,4,4,2,2,2,2,2,2,2,2,2,4,2,4,4,2,2,2,2,8,2,2,2,2,4,4,2,2,2,2,2,2,4,2,2,2,2,8,-1}, //《一分钱》
{6,2,6,2,2,2,2,2,8,2,4,2,4,4,2,2,2,2,4,4,4,4,2,2,2,2,8,2,2,2,2,2,2,4,2,2,2,2,4,4,8,-1}, //《丢手绢》
{4,2,2,2,6,2,2,2,2,8,4,2,2,4,2,2,4,2,2,8,2,2,2,2,2,4,2,2,2,2,2,8,4,2,2,2,2,4,2,6,2,2,4,16,4,2,1,2,2,4,2,4,2,2,1,2,2,12,2,2,4,2,1,2,2,4,2,4,2,4,2,2,16,4,2,1,2,2,4,4,2,2,2,2,4,4,2,2,8,8,4,2,2,16,-1}, //《七子之歌-澳门》
{2,2,2,2,2,2,4,2,2,2,2,4,4,2,2,2,2,2,2,4,2,2,2,2,2,2,4,-1}, //《找朋友》
{2,4,2,6,2,4,2,6,2,4,2,5,1,1,2,1,1,2,1,1,2,2,4,2,4,2,6,2,4,2,6,2,2,1,1,2,2,2,4,2,2,2,8,-1},//《感恩的心》
{4,4,4,4,4,4,4,4,4,4,4,4,5,2,6,4,4,4,4,4,4,4,4,4,4,4,4,5,2,6,4,4,4,4,4,2,2,4,4,4,2,2,4,4,4,4,4,4,4,4,4,4,4,4,4,2,2,4,4,4,4,5,2,6,-1},//《欢乐颂》
{2,2,2,2,2,2,4,2,2,2,2,2,2,2,2,6,6,2,2,2,2,2,2,4,2,2,2,2,4,2,2,6,4,4,5,2,4,4,4,2,2,4,4,2,2,2,2,4,2,2,6,6,5,2,4,4,2,2,2,2,6,2,2,2,2,4,4,6,4,-1},//《我爱北京天安门》
{4,4,2,2,4,2,2,2,2,2,2,6,2,2,2,2,2,2,2,2,2,2,2,2,6,2,2,2,2,4,2,2,2,2,2,2,2,2,4,2,2,2,2,2,2,5,2,8,2,2,8,2,2,2,2,4,2,2,2,2,2,2,2,2,4,2,2,2,2,2,2,5,2,8,2,2,2,2,2,2,6,10,8,4,10,-1},//《北京欢迎你》
{2,2,2,2,6,2,2,2,2,6,2,2,4,2,2,4,2,2,2,2,2,2,2,2,6,-1},//《上学歌》
{6,4,3,2,8,4,4,4,2,2,4,8,4,4,2,2,4,3,2,4,4,6,4,2,2,4,2,2,8,4,6,4,3,2,8,4,4,4,2,2,4,8,4,2,4,2,4,4,4,2,2,4,2,2,2,4,2,4,2,2,8,4,-1},//《当兵的人》
{4,2,2,2,2,2,2,4,2,2,6,4,2,2,2,2,2,2,4,2,2,6,4,4,4,2,2,4,4,6,4,2,2,4,2,2,4,2,2,8,-1},//《茉莉花》
{4,4,2,2,4,2,2,2,2,4,4,2,2,2,2,2,2,4,2,2,2,2,4,4,4,2,2,4,2,2,2,2,2,2,4,4,4,2,2,4,4,2,2,2,2,6,4,2,2,4,4,2,2,2,2,6,-1},//《数鸭子》
{2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,-1},//《洋娃娃和小熊跳舞》
};
uint code tab[]=
{
0,63628,63835,64021,64103,64260,64400,64524,
64580,64684,64777,64820,64898,64968,65030,
65058,65110,65157,65178,65217,65252,65283
};
void delay1(uint ms) //播放歌曲时实现节拍的延时函数
{
uchar t;
while(ms--) for (t=0;t<120;t++);
}
void delay(void)
{
uchar i;
for (i=300;i>0;i--);
}
void EX0_INT() interrupt 0
{
FY=0; LED1=0; LED2=1; STL0=STL0;
}
void EX1_INT() interrupt 2
{
FY=1; LED1=1; LED2=0;LED3=1;LED4=1;LED5=1;P2=0xff; Tone_Index=-1;Tone_Index++;
STH0=(tab[Song[k][Tone_Index]])/256;
STL0=(tab[Song[k][Tone_Index]])%6;
}
void time0_int(void) interrupt 1 using 0
{
TH0 = STH0;
TL0 = STL0;
SPK=!SPK; // 反相,产生输出脉冲
if(FY==0)
{P2=~DSY_CODE[k] ;}
else {if(FY==1) {P2=~GE_CODE[k];}}
}
void main(void)
{ LED1=0;
LED2=1;
LED3=1;LED4=1;LED5=1;
P2=0xff;
IE=0x87;
TMOD=0x01;
IT0=1;
IT1=1;
while(1)
{
if (KeyDown())
{
k = KeyNum(); // 调用键盘扫描函数
if(FY==0)
{
STH0 = tab[k]/256;
STL0 = tab[k]%6;
TR0 = 1; // 开始计数
while (KeyUp()==0); // 若没有松开按键,则等待,等待期间弹奏该音符
TR0 = 0; // 若按键松开,则停止计数,不产生脉冲输出
}
else
{
while (FY==1)
{
if (Song[k][Tone_Index]==-1)
Tone_Index=0;
STH0=(tab[Song[k][Tone_Index]])/256;
STL0=(tab[Song[k][Tone_Index]])%6;
P2=~GE_CODE[Song[k][Tone_Index]] ;
TR0 = 1;
delay1(150*Len[k][Tone_Index]);
Tone_Index++;
TR0 = 0;
}
}
if(k>=1&&(k<=7)){LED3=0;LED4=1;LED5=1;}
else
{if(k>=8&&(k<=14)){LED3=1;LED4=0;LED5=1;}
else
{if (k==0){LED3=1;LED4=1;LED5=1;}
else
{LED3=1;LED4=1;LED5=0;}} }
}
}
}
② 用89C51单片机设计开发简易电子琴,能7个音,并存一首歌就好,要简单点的,做为课程设计用,急需!!!
//本程序的单片机晶振采用11.0592M
#include <reg51.h>
sbit speaker=P1^2;
unsigned char timer0h,timer0l,time;
//世上只有妈妈好数据表
code unsigned char sszymmh[]={ 6,2,3, 5,2,1, 3,2,2, 5,2,2, 1,3,2, 6,2,1, 5,2,1,
6,2,4, 3,2,2, 5,2,1, 6,2,1, 5,2,2, 3,2,2, 1,2,1,
6,1,1, 5,2,1, 3,2,1, 2,2,4, 2,2,3, 3,2,1, 5,2,2,
5,2,1, 6,2,1, 3,2,2, 2,2,2, 1,2,4, 5,2,3, 3,2,1,
2,2,1, 1,2,1, 6,1,1, 1,2,1, 5,1,6, 0,0,0
};
// 音阶频率表 高八位
code unsigned char FREQH[]={
0xF2,0xF3,0xF5,0xF5,0xF6,0xF7,0xF8,
0xF9,0xF9,0xFA,0xFA,0xFB,0xFB,0xFC,0xFC, //1,2,3,4,5,6,7,8,i
0xFC,0xFD,0xFD,0xFD,0xFD,0xFE,
0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFF,
} ;
// 音阶频率表 低八位
code unsigned char FREQL[]={
0x42,0xC1,0x17,0xB6,0xD0,0xD1,0xB6,
0x21,0xE1,0x8C,0xD8,0x68,0xE9,0x5B,0x8F, //1,2,3,4,5,6,7,8,i
0xEE,0x44, 0x6B,0xB4,0xF4,0x2D,
0x47,0x77,0xA2,0xB6,0xDA,0xFA,0x16,
};
void delay(unsigned char t)
{
unsigned char t1;
unsigned long t2;
for(t1=0;t1<t;t1++)
{
for(t2=0;t2<8000;t2++)
{
;
}
}
TR0=0;
}
void t0int() interrupt 1
{
TR0=0;
speaker=!speaker;
TH0=timer0h;
TL0=timer0l;
TR0=1;
}
void song()
{
TH0=timer0h;
TL0=timer0l;
TR0=1;
delay(time);
}
void main(void)
{
unsigned char k,i;
TMOD=1; //置CT0定时工作方式1
EA=1;
ET0=1;//IE=0x82 //CPU开中断,CT0开中断
while(1)
{
i=0;
while(i<100){ //音乐数组长度 ,唱完从头再来
k=sszymmh[i]+7*sszymmh[i+1]-1;
timer0h=FREQH[k];
timer0l=FREQL[k];
time=sszymmh[i+2];
i=i+3;
song();
}
}
}
自己改改吧。。你说的不太清。。是不是还要用到键盘作为电子琴按键。。。。提问也有技巧的。。下次说清要求 所要结果 需要语言。。。
③ 用51单片机 制作简易电子琴 的两个问题
内部大循环只要把扫描程序等需要不停执行的程序写在
while(1)
{
。。。。。。(这里)
}
识别按键只要与按键相连的引脚检测到低电平即可
给你一个按键范例:
假如按键接到单片机P2^0引脚
sbit K = P2^0;
if(K == 0)
{
delay(5); //延时去抖
if(K == 0) //确定键按下
{
while(!K); //判断松手
。。。。。(功能函数)
}
}
④ 用单片机做电子琴,复音(合音)怎么实现
解析MIDI电子琴的设计用单片机是如何实现的
摘要:用单片机控制通用MIDI音源模块制作制作出的电子琴,结构简单,可靠性高,并且价格低廉,具有实用的价值。这种电子琴能够支持单音和复音弹奏,如果与高品质的音源芯片连接,音质更可与高档电子琴相媲美。我们在实验过程中,也曾采用手机中通用的音乐芯片构成音源模块,效果不错,价格更低廉,如韩国产的QS6400 等,这些芯片的驱动要复杂一些,需要对芯片进行初始化设置,详细内容可参看国防工业出版社出版的《MIDI原理与开发应用》一书中的相关章节。
关键字:电子琴,单片机,音源板,MD2064
1、电子琴的硬件设计方案
本电子琴包含48个按键键盘,即具有4个8度的音域,单片机AT89C51通过对所弹按键的识别,产生相应的MIDI消息。它支持单音弹奏和最多16个复音弹奏。电子琴结构示意图和电路原理图分别如图1和图2所示。AT89C51作为主控芯片,它使得键盘矩阵模块、通道和音色选择以及串口发送等各功能模块协调工作。48按键行列式键盘矩阵构成MIDI电子琴的键盘扫描输入端,由于89C51的P0口内部没有上拉电阻,故这里采用电阻R14——R21将列线拉至高电平,与六条行线组合完成48个琴键的扫描识别,在图1中,单片机与键盘矩阵间的双箭头线表示单片机在扫描键盘矩阵时,P0口和P2口分别作为输入/输出口使用。人机接口电路则利用了单片机P1口的大部分口线,并通过或门向INT0发出中断请求,该部分电路主要完成MIDI电子琴的通道设置和音色选择等人机交互功能。键盘的弹奏信息以及通道、音色信息经CPU处理后,由串口将标准的MIDI数据发送给MIDI音源及放大器,推动扬声器发声。
图1:MIDI电子琴结构示意图
图2:MIDI电子琴电路图
音源模块采用MD2064 套板,如图3所示。它是一种模块化的MIDI音源产品,由得理电子公司开发,具有标准MIDI接口,该板能接受标准GM MIDI命令进行音乐播放,自带3D, REVERB, CHORUS等效果处理。由于该套板的MIDI 接口采用了光耦合器,电流驱动,故设计了由Q1、Q2等器件组成的驱动电路,使单片机串口数据得以正常传输。在模块的耳机输出端取得信号后,经小功率放大即可推动扬声器发声。
2、电子琴的软件设计特点
该电子琴软件采用模块化设计方法,程序也较简单。软件中各功能模块都由相应的子程序完成,主要包含通道选择模块,音色选择模块,48按键键盘扫描模块,串口发送模块等,其中为了及时完成用户命令,音色选择模块采用了中断服务子程序,可以在演奏中快速响应使用者的请求。
主程序在完成串口初始化、相关变量的初始化以及设置通道后,即进入键盘扫描、发送音符消息流程,为了使按键识别准确可靠,还设置了两个缓冲区BUFF1和BUFF2保存键盘扫描值。主程序流程图如图3。
图3:MIDI电子琴程序的流程图
以下是部分功能模块的程序设计介绍。
2.1 音色选择模块的设计
该模块的功能是使MIDI电子琴能按要求快速改变音色,所以采用了中断服务子程序。当某个音色选择按键压下时,通过或门向单片机的INT0发出中断请求,CPU响应后进入该中断服务子程序。MIDI技术规范规定,标准MIDI含有128种音色,它们的编号范围是0~127,为了能够快速找到所需音色,硬件中设置3个按键,其中2个用于音色编号的单步增加和减小,每次增加或减小1个音色编号,另外一个键用于音色快进,当快进键有效时,每次增加8个音色编号,选择增加8个音色的原因是:标准MIDI的128种音色是按每8个音色一组编排的,共包含16个乐器组。电子琴开机时默认的音色编号是0,即大钢琴音色。
单片机的P1.2口线连接着音色增加按键,P1.3则连接音色减小按键,P1.4连接音色快进键。低电平时按键有效,这三个按键通过与门连接外部中断INT0,以便实时响应音色设置。该外部中断0的中断服务子程序流程图见图4,(图中省去了按键延时去抖动部分):
图4:音色改变子程序流程图
在该子程序中,变量TAMBER中存放当前音色,其值可在0~127间循环,当TAMBER是最大值127时,加1后又变为0;而当TAMBER为0时,减1则变为127;在边界范围加8取模后,刚好为其对应的音色值。
2.2 串口发送模块
串口发送模块主要用于发送产生的MIDI消息,串口采用的模式1,发送的波特率是31.25KBPS。串口通过驱动电路连接MIDI音源,发送MIDI消息。通道号存放在变量CHANNEL中,通过与90H相与,所得值就是当前所设置的通道号。
2.3 键盘扫描模块
本电子琴提供了48个MIDI按键,即4个8度音的音域范围,当按下单个键时,产生一条MIDI消息,当按下多个键值时产生对应键值的多条MIDI音符开消息,当某个键值被释放时,发送对应的音符关消息。这些MIDI消息通过串口发送给MIDI音源,产生MIDI音乐。音乐的时值由按键的时间长度控制,当按键被释放,实时产生MIDI消息,关闭被释放的键值音。
由P0口和P2口的P2.0~P2.5构成行列式键盘,也可继续扩展键盘,例如改为常用的49键或64键。因为支持复音按键,键盘扫描程序必须扫描到行列式键盘的每个键值,扫描所得的键值存放在缓冲区BUFF1或BUFF2中。键盘扫描程序获得的键盘编号范围是0~47,还需将这个键盘编号值转换为MIDI设备能够识别的钢琴键盘编号,这个功能由一个子程序来完成,限于篇幅本文不再详述。键盘扫描子程序流程如图5。
图5:键盘扫描子程序