设计要求:
(1)实现多个音符同时演奏,支持和弦
(2)实现具体音符的声调和降调
(3)可以弹奏简单的曲目
(4)通过lcd显示屏或数码管显示具体音调
(5)尽可能提供不同的节奏模式来完成更多音乐
(6)允许用户微调音调,使其与其他乐器或音源匹配
选择单片机:
首先,选择一款适用的单片机,具备足够的计算能力,且晶振和蜂鸣器能发出不同音调的声音,使得人耳可以辨别不同音调。本实验选用的是普中51单片机,如下图所示:
设计思路:
键盘设计流程:
矩阵键盘电子琴硬件功能:如图所示,矩阵键盘的1~7代表do、re、mi、fa、sol、la、si七种音符,按键s13和s14代表升调以及降调,通过升降调以及各种独立音符的组合搭配,便可以弹奏出一些简单的乐曲。提前存好对应按键晶体管显示值以及蜂鸣器发声频率值,对应按键按下即可显示并发声。
代码部分(基于Keil,C语言):
//=========================================================
// 电子琴,4x4矩阵按键
//=========================================================
#include "reg52.h"
#include <stdio.h>
#define uchar unsigned char
#define uint unsigned int
#define KEY_PORT P1 //矩阵键盘端口
sbit LSA=P2^2; //138译码器引脚
sbit LSB=P2^3;
sbit LSC=P2^4;
sbit buzz=P2^5; //蜂鸣器
uchar key; //键值
uchar tone=0; //音符
uchar scale=2; //音阶
uchar index; //序号
uchar code tab[]={ //共阴数码管段码表
0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
uint code table[]={ //这个数组里存放的是1-7的音调的初始值
// 1 2 3 4 5 6 7 //音符
0xf88c,0xf95c,0xfa14,0xfa6c,0xfb04,0xfb90,0xfc0c,
0xfc44,0xfcab,0xfd09,0xfd34,0xfd82,0xfdc8,0xfe06,
0xfe22,0xfe56,0xfe8c,0xfe9a,0xfec1,0xfee4,0xff03
};
//=========================函数声明========================
void delayms(uint t); //延时函数
void Timer_Init(); //定时器初始化函数
void display(); //数码管显示函数
void keyscan(); //矩阵按键扫描函数
//==========================主函数=========================
void main(void)
{
LSA=LSB=LSC=0;
Timer_Init(); //定时器初始化
while(1) //主循环
{
keyscan(); //矩阵按键扫描
}
}
//=======================延时函数===========================
void delayms(uint t)
{
uchar i;
while(t--)for(i=0;i<120;i++);
}
//===================定时器初始化函数======================
void Timer_Init()
{
TMOD=0x11; //定时器T0和T1都是工作方式1
TH0=0xf8; //定时器T0初值
TL0=0xcd; //11.0592MHz,2ms定时
EA=1; //允许总中断
ET0=1; //允许定时器T0中断
TR0=1; //启动定时器T0
TH1=TL1=0; //定时器T1初值
ET1=1; //允许定时器T1中断
TR1=0; //暂不启动定时器T1
}
//===================定时器T0中断函数=====================
void T0_ISR() interrupt 1
{
TH0=0xf8; //重装初值
TL0=0xcd; //2ms定时
display(); //数码管扫描
}
//===================定时器T1中断函数=====================
void T1_ISR() interrupt 3
{
TH1=table[index]>>8; //按当前音符装载定时器数据,高8位
TL1=table[index]; //低8位
buzz=~buzz; //蜂鸣器取反以驱动无源蜂鸣器发声
}
//======================数码管显示函数=====================
void display()
{
static uchar t=0;
P0=0;
LSC=t;
if(t==0)P0=tab[tone]; //显示音符
else P0=tab[scale]; //显示音阶
t=(t+1)%2; //切换下一位
}
//====================矩阵按键扫描函数====================
void keyscan()
{
uchar key=0;
KEY_PORT=0x0f;
if(KEY_PORT!=0x0f)
{
delayms(10); //延时消抖
if(KEY_PORT!=0x0f)
{
//列扫描
KEY_PORT=0x0f;
switch(KEY_PORT)
{
case(0x07): key=1;break;
case(0x0b): key=2;break;
case(0x0d): key=3;break;
case(0x0e): key=4;break;
}
//行扫描
KEY_PORT=0xf0;
switch(KEY_PORT)
{
case(0x70): key=key;break;
case(0xb0): key=key+4;break;
case(0xd0): key=key+8;break;
case(0xe0): key=key+12;break;
}
if(key>=1 && key<=7)
{
tone=key; //记录音符
index=(scale-1)*7+key-1; //按当前音阶和音符取频率值的序号
TH1=table[index]>>8; //定时器赋初值取音符对应的数据高字节
TL1=table[index]; //取低字节
TR1=1; //启动定时器T1发音
}
else if(key==13) //降调
{
if(scale>1)scale--;
}
else if(key==14) //升调
{
if(scale<3)scale++;
}
while(KEY_PORT!=0xf0); //等待按键松开
TR1=0; //停止定时器T1
buzz=1; //关闭蜂鸣器
}
}
}
结语:
此外,还涉及了一键播放音乐的功能,由于未能和电子琴功能同步,此处不予展示,有需要可以联系博主。
代码调试好后生成hex文件,再通过stc软件烧录即可使用。
标签:KEY,uchar,void,51,break,单片机,key,电子琴,PORT From: https://blog.csdn.net/weixin_45543061/article/details/142992483