C51 原创电子琴 (蜂鸣器/计时器/中断/矩阵按键)

需求分析

用C51的16个矩阵按键当作两个八度的琴键
按下时发出相应音调的声音,静态数码管显示相应音符的数字。
为了解锁更多曲目,两个多的琴键设计成#4,显示时加上小数点
下图分别为1和#4的显示,其中图一上标明了各按键的对应的音符:

思路

每当按键按下,判断是那个按键,
在按键尚未松开时循环以下内容:启动定时器,计时的时长为“该音调频率的一半“,每过这段时间,蜂鸣器所在引脚电平取反

各音符的频率

参考:https://blog.csdn.net/weixin_34724366/article/details/80642207

Highs 和 Lows 的计算方法:

1/(2f) s = 1000/(2f) ms = 500 / f ms
然后带入这个小程序即可

接线图

完整代码

#include <reg51.h>
typedef unsigned int u16;		 
typedef unsigned char u8;

#define GPIO_KEY P1
#define GPIO_DIG P0
sbit beep = P3^0;

/*******************************全局变量******* *******************/    
 
u8 code Highs[24] = {
0xfc,0xfc,0xfd,0xfd,0xfd,0xfd,0xfe,0xfd,
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  };

//共阴的表
u8 code ledSegment  [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(u16 i)
{
    while(i--);
}
void keyDown()
{
    //char a = 0;
    GPIO_KEY = 0x0f;  //高四位低电平,低四位高电平
    if(GPIO_KEY!= 0x0f)           //如果有按键按下
    {
        delay(1000);                    //延时防抖
        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 = ~ledSegment[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;
    }           
}
posted @ 2018-11-05 17:39  YuQiao0303  阅读(1128)  评论(0编辑  收藏  举报