学习基于51单片机的电子琴设计项目

前言

51单片机开发板自带了蜂鸣器,但是无源的,本次设计是通过定时器产生不同的频率来使蜂鸣器产生不同的音高,并让矩阵键盘来控制音高的发生。

一、硬件准备

选择一个51单片机,如AT89C51。
准备一些按键,如4x4矩阵键盘,用于输入音符。
准备一个音频输出设备,如蜂鸣器或小型扬声器,连接到单片机的某个GPIO引脚(这里单片机自带)。
如有需要,还可以添加其他硬件,如LED灯、LCD显示屏等。

二、硬件连接

定义数码管、矩阵键盘、蜂鸣器引脚。
在这里插入图片描述
在这里插入图片描述
代码如下(示例):

#define GPIO_KEY P1 //定义矩阵键盘I/O口
#define GPIO_DIG P0 //定义数码管I/O口     
sbit beep = P2^5;   //定义蜂鸣器银胶

三、代码编写

1、初始化GPIO引脚和定时器。
2、编写按键扫描函数,用于检测哪个按键被按下。
3、编写音频输出函数,根据按键值计算音符频率,并使用定时器或PWM产生音频信号。
4、在主循环中调用按键扫描函数和音频输出函数。

(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程序的逻辑。

总结

本次设计只是简单的利用定时器与键盘控制蜂鸣器发出声音,代码可能也有些许问题,后期水平提升了再修改一下吧;本期主要是学习定时器工作原理及使用、数码管显示、矩阵键盘扫描、频率计算等。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值