首页 > 其他分享 >51单片机实现简易升降调电子琴

51单片机实现简易升降调电子琴

时间:2024-10-16 22:48:49浏览次数:9  
标签:KEY uchar void 51 break 单片机 key 电子琴 PORT

设计要求:

(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

相关文章