需求分析

用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;
}
}

C51 原创电子琴 (蜂鸣器/计时器/中断/矩阵按键)的更多相关文章

  1. 【C51】单片机独立按键与矩阵按键

    独立按键 首先既然是检测输入,对于当然要用到拉电阻,来检测引脚电平变化变化.51单片机中,除了P0口外,P2,P3,P4都是内置上拉电阻的准双向IO口,一般 的 51 P0引脚都外接了上拉电阻,当然也 ...

  2. C51 矩阵按键 个人笔记

    矩阵按键 电路 每个按键一端和同行一端相连(JP4的高4位),另一端和同列一端相连(JP4的低4位) 判断按键是否按下: 法一:逐行扫描 for(int i = 8 ; i>3 ; i-- ) ...

  3. AD按键-矩阵按键-独立按键:

    原理:利用数组分压+AD采集: 优点:一个IO口可以做成多个按键,节省IO口(矩阵键盘在>4时优点才能体现出来):可备用作为AD基准输入. 缺点:不能做成组合按键(或者电阻要精确选择):且离IO ...

  4. AD按键-矩阵按键:

    原理:利用数组分压+AD采集: 优点:一个IO口可以做成多个按键,节省IO口(矩阵键盘在>4时优点才能体现出来):可备用作为AD基准输入. 缺点:不能做成组合按键(或者电阻要精确选择):且离IO ...

  5. TI-RTOS 之 GPIO中断(按键)

    TI-RTOS 之 GPIO中断(按键) 前面已经用过LED, 定时器,这次来了解GPIO的中断是怎么用的,从CC1310+TI-RTOS的例程可以直接找到相应的例子程序,它的关键是在于要使能中断,也 ...

  6. 【.NET 与树莓派】矩阵按键

    欢迎收看火星卫视,本期节目咱们严重探讨一下矩阵按键. 所谓矩阵按键,就是一个小键盘(其实一块PCB板),上面有几个 Key(开关),你不按下去的时候,电路是断开的,你按下去电路就会接通.至于说有多少个 ...

  7. 矩阵按键的试验---verilog

    矩阵键盘的试验,采用三段式状态机处理方法. 难点在于检测状态机中:按键消抖以后逐列检测. 电路图: 代码 /********************************Copyright***** ...

  8. 字符设备驱动笔记——中断方式按键驱动之linux中断处理结构(五)

    一.单片机下的中断处理 )分辨是哪一个中断 )调用处理函数 )清中断 二.linux下的中断处理 1)/arch/arm/kernel/irq.c asmlinkage void __exceptio ...

  9. 字符设备驱动笔记——中断方式按键驱动之linux异常处理结构(四)

    .中断方式获取按键值 单片机: )按键按下 )cup发生中断,跳转到异常向量入口执行 )b 函数 a.保存被中断的现场 b.执行中断处理函数 c.恢复 linux: )trap_init()函数构造异 ...

随机推荐

  1. Styles and Themens(4)android自定义主题时可使用的属性

    A list of the standard attributes that you can use in themes can be found at R.styleable.Theme. Cons ...

  2. CentOS 6.5上安装GlassFish4.0 过程笔记

    CentOS 6.5上安装GlassFish4.0 过程笔记 1.安装JDK, 注意操作系统的位数, 64 or 32: [root@linuxidc ~]# mkdir /usr/java  [ro ...

  3. mysql各个版本下载地址

    之所记录下来是因为我找了好久才找到:这下记着了:http://downloads.mysql.com/archives/community/ 希望对没有找到的朋友有帮助

  4. [转]Php MySql Class

    本文转自:http://www.cnblogs.com/noevil/archive/2010/11/06/1870864.html <?php /**  * 数据库操作类  *  * @aut ...

  5. Android开发学习——ButterKnife使用

    为了码代码的效率,我们有了ButterKnife;其基本使用如下步骤: 1.在Android Studio的Setting中,下载plugin 2.在整个Project的build.gradle中添加 ...

  6. Android开发学习——高德地图的实现

    1.首先做好下边的准备: 1.1  http://lbs.amap.com/   注册账号 1.2  下载 定位sdk 和 地图sdk 下载后是这样的 1.3  对下载的进行解压 将他们加入 中,对每 ...

  7. 30天自制操作系统 DAY6

    _load_gdtr: 这个函数用来将指定的段上限(limit)和地址赋值给名为GDTR的48位寄存器. 给GDTR赋值唯一的办法是指定一个内存地址,从指定的地址读取6个字节(48位),然后赋值给GD ...

  8. Android动态权限申请

    Android系统中,目前Dangerous级别的权限都需要动态申请.步骤如下: 1.AndroidManfiest.xml中申明需要的动态权限 <?xml version="1.0& ...

  9. eval()将json 字符串转换为数组

    json ={ GW:[{id:"655",mc:"董事"},{id:"656",mc:"书记"},{id:" ...

  10. vue ---- Object的一些常用的方法

    在对象上添加新属性的几种方法: 直接附代码: 法一:Es6扩展运算符添加属性 法二:利用语法Object.assign(target, ...sources)    target目标对象.source ...