基于51单片机的电子琴设计项目教程
创作时间:
作者:
@小白创作中心
基于51单片机的电子琴设计项目教程
引用
CSDN
1.
https://blog.csdn.net/2301_80765253/article/details/139389015
51单片机开发板自带了蜂鸣器,但是无源的,本次设计是通过定时器产生不同的频率来使蜂鸣器产生不同的音高,并让矩阵键盘来控制音高的发生。
一、硬件准备
选择一个51单片机,如AT89C51。
准备一些按键,如4x4矩阵键盘,用于输入音符。
准备一个音频输出设备,如蜂鸣器或小型扬声器,连接到单片机的某个GPIO引脚(这里单片机自带)。
如有需要,还可以添加其他硬件,如LED灯、LCD显示屏等。
二、硬件连接
定义数码管、矩阵键盘、蜂鸣器引脚。
代码如下:
#define GPIO_KEY P1 //定义矩阵键盘I/O口
#define GPIO_DIG P0 //定义数码管I/O口
sbit beep = P2^5; //定义蜂鸣器银胶
三、代码编写
- 初始化GPIO引脚和定时器。
- 编写按键扫描函数,用于检测哪个按键被按下。
- 编写音频输出函数,根据按键值计算音符频率,并使用定时器或PWM产生音频信号。
- 在主循环中调用按键扫描函数和音频输出函数。
(1)以下代码是音符数值,分别给到定时器PL0、PH0赋值,与数码管数字,但是注意是共阴的;
u8 code Highs[24] = {
0xfc,0xfc,0xfd,0xfd,0xfd,0xfd,0xfe,0xfd, //高音 1 2 3 4 5 6 7
0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xff ,0xff };
u8 code Lows[24] = {
0x44,0xfac,0x09,0x34,0x82,0xc7,0x05,0x5c,
0x22,0x56,0x84,0x9a,0xc1,0xe3,0x02,0x11 }; //低音 1 2 3 4 5 6 7
//共阴的表
u8 code shumaguan [24] = { 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07,0xe6,
0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07,0xe6,
0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07,0xe6};
u8 KeyValue;
(2)定时器初始化
void T0Init() //计时器初始化
{
TMOD |= 0x01; //选择工作方式,给TMOD 赋值 ,这里选T0,方式一
ET0 = 1 ; //中断允许:总允许和T0允许
EA = 1;
}
(3)按键扫描
void keyDown()
{
//char a = 0;
GPIO_KEY = 0x0f; //高四位低电平,低四位高电平
if(GPIO_KEY!= 0x0f) //如果有按键按下
{
Delay(5); //延时防抖
if(GPIO_KEY!= 0x0f)
{
//--------------------求被按下的按键在第几列----------------------------//
switch(GPIO_KEY)
{
case(0x07): KeyValue = 0; break; //0000 0111 : 第一列
case(0x0b): KeyValue = 1; break; //0000 1011 : 第二列
case(0x0d): KeyValue = 2; break; //0000 1101 : 第三列
case(0x0e): KeyValue = 3; break; //0000 1110 : 第四列
}
//--------------------求被按下的按键在第几行----------------------------//
GPIO_KEY = 0xf0; //高四位高电平,低四位低电平
switch(GPIO_KEY)
{
case(0x70): KeyValue += 0; break; //第一行
case(0xb0): KeyValue += 4; break;
case(0xd0): KeyValue += 8; break;
case(0xe0): KeyValue += 12; break; //第四行
}
//--------------------------开始计时----------------------------------//
GPIO_DIG = shumaguan[KeyValue]; //共阳数码管,共阴的表,所以要取反
//赋初值
TH0 = Highs[KeyValue];
TL0 = Lows[KeyValue];
//开始计时
TR0=1;
//退出条件:按键松开
while(GPIO_KEY!= 0xf0) // GPIO_KEY!= 0xf0 说明按键还没松,此时CPU始终在此循环中
{
}
}
}
}
(4)主程序将定时器初始化以及按键扫描调用
void main(void)
{
uart_init();
T0Init();
while(1)
{
keyDown();
}
}
(5)定时器中断
oid Timer0() interrupt 1 // T0溢出时引用
{
//退出条件:按键松开
if(!(GPIO_KEY== 0xf0 || GPIO_KEY== 0x0f)) //如果按键还没松开,进入下一个计时
{
TH0 = Highs[KeyValue];
TL0 = Lows[KeyValue];
beep = ~beep;
}
以上代码还缺少一些定义,还有延时函数,下面展示完整代码,如有错误,欢迎指正;
#include <reg51.h>
typedef unsigned char u8;
unsigned char temp;
#define GPIO_KEY P1
#define GPIO_DIG P0
sbit beep = P2^5;
/*******************************全局变量******* *******************/
u8 code Highs[24] = {
0xfc,0xfc,0xfd,0xfd,0xfd,0xfd,0xfe,0xfd, //高音 1 2 3 4 5 6 7
0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xff ,0xff };
u8 code Lows[24] = {
0x44,0xfac,0x09,0x34,0x82,0xc7,0x05,0x5c,
0x22,0x56,0x84,0x9a,0xc1,0xe3,0x02,0x11 }; //低音 1 2 3 4 5 6 7
//共阴的表
u8 code shumaguan [24] = { 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07,0xe6,
0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07,0xe6,
0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07,0xe6};
u8 KeyValue;
/***************************************************************/
void Delay(unsigned int xms)
{
unsigned char i, j;
while(xms--)
{
i = 2;
j = 239;
do
{
while (--j);
} while (--i);
}
}
void keyDown()
{
//char a = 0;
GPIO_KEY = 0x0f; //高四位低电平,低四位高电平
if(GPIO_KEY!= 0x0f) //如果有按键按下
{
Delay(5); //延时防抖
if(GPIO_KEY!= 0x0f)
{
//--------------------求被按下的按键在第几列----------------------------//
switch(GPIO_KEY)
{
case(0x07): KeyValue = 0; break; //0000 0111 : 第一列
case(0x0b): KeyValue = 1; break; //0000 1011 : 第二列
case(0x0d): KeyValue = 2; break; //0000 1101 : 第三列
case(0x0e): KeyValue = 3; break; //0000 1110 : 第四列
}
//--------------------求被按下的按键在第几行----------------------------//
GPIO_KEY = 0xf0; //高四位高电平,低四位低电平
switch(GPIO_KEY)
{
case(0x70): KeyValue += 0; break; //第一行
case(0xb0): KeyValue += 4; break;
case(0xd0): KeyValue += 8; break;
case(0xe0): KeyValue += 12; break; //第四行
}
//--------------------------开始计时----------------------------------//
GPIO_DIG = shumaguan[KeyValue]; //共阳数码管,共阴的表,所以要取反
//赋初值
TH0 = Highs[KeyValue];
TL0 = Lows[KeyValue];
//开始计时
TR0=1;
//退出条件:按键松开
while(GPIO_KEY!= 0xf0) // GPIO_KEY!= 0xf0 说明按键还没松,此时CPU始终在此循环中
{
}
}
}
}
void T0Init() //计时器初始化
{
TMOD |= 0x01; //选择工作方式,给TMOD 赋值 ,这里选T0,方式一
ET0 = 1 ; //中断允许:总允许和T0允许
EA = 1;
}
void main(void)
{
T0Init();
while(1)
{
keyDown();
}
}
//计时器0的调用程序
void Timer0() interrupt 1 // T0溢出时引用
{
//退出条件:按键松开
if(!(GPIO_KEY== 0xf0 || GPIO_KEY== 0x0f)) //如果按键还没松开,进入下一个计时
{
TH0 = Highs[KeyValue];
TL0 = Lows[KeyValue];
beep = ~beep;
}
}
四、成果展示
当我们按下矩阵键盘时,按键扫描会扫描是哪个按键,从而调用定义的初值与数码管的数字,这里将他们做了一个绑定,当播放do时数码管显示1,代表它的音名吧,具体可以看按键扫描i程序的逻辑。
总结
本次设计只是简单的利用定时器与键盘控制蜂鸣器发出声音,代码可能也有些许问题,后期水平提升了再修改一下吧;本期主要是学习定时器工作原理及使用、数码管显示、矩阵键盘扫描、频率计算等。
热门推荐
胡雪岩故居:杭州清代巨商第一豪宅
液晶电光效应实验报告
【信号处理】CFO估计技术附Matlab代码
什么是无极?
十大美味的冷面吃法分享 10种最受欢迎的冷面美食
感冒了吃什么饭菜合适?专家给出专业建议
最古老的现代人类基因组揭示智人与尼安德特人混合新线索
空调外机怎么保护:有效维护与保养指南
身体乏力、食欲下降和睡眠不佳怎么办?
WiFi5和WiFi6穿墙效果对比:哪个更适合你的家庭网络?
黑光灯原理介绍
如何保养白色衣服不发黄
齐齐哈尔烤肉:从食材精选到烧烤技艺的极致体验
白花凤仙花:中国特有的自然瑰宝
羊水穿刺检查:潜在风险与必要性的权衡
孕期羊水穿刺检查的适应症有哪些?
逍遥丸一天吃几次
肺部手术后咳嗽怎么办?一文详解原因与应对方法
保险公司不赔误工费怎么办
丧偶之后,最理想的伴侣,并不是有钱的人
生吃大蒜的好处:营养师完整教学,高效提升免疫力并避免副作用!
做雷锋精神的传播者——第九批全国岗位学雷锋标兵孔祥慧
树脂瓦是什么材质做的
驾驶证到期了怎么换?到期换证流程都在这了!果断收藏!
孩子又拉又吐,到底是感染「甲流、诺如还是轮状病毒」?一文教你冬季高发疾病鉴别指南
最近的中产,开始穿百元拉夫劳伦平替了
Redis是什么?架构是怎么样的?
锐龙和酷睿哪个好 锐龙和酷睿的区别介绍
植物大战僵尸2闪电芦苇攻略:狂野西部最强控制植物详解
银行的理财产品的管理费怎么收?