📄 file8.c
字号:
// 音乐编程
//通过蜂鸣器发出讯响
//只要通过修改 后面的音乐程序里面的码
//表就可以自己谱曲唱歌!
//前一个参数为按照编码表给定,第二个参数为节拍数
#include <8051.h>
#define uchar unsigned char
#define key1 P3_4 //键盘定义
#define key2 P3_5
#define key3 P3_6
#define beep P3_7 //蜂鸣器定义
uchar timer_h;
uchar timer_l;
//****************************************************************************
void reset();
void delay(uchar times);
void dems(); //休止符延时
void display(uchar disseg,uchar disdata);
uchar keyb();
// 这里定义的是数码管对应的字符字根
code uchar disbuf_u[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,
0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e,
0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,
0x00,0x10,0x08,0x03,0x46,0x21,0x06,0x0e};
// 这里定义音乐音符表
code uchar musictabl[]={0xf0,0xf0,
0xf8,0x8b,0xf9,0x5b,0xfa,0x14,0xfa,0x0c,0xfb,0x03,0xfb,0x8f,0xfc,0x0b,
0xfc,0x43,0xfc,0xab,0xfd,0x08,0xfd,0x33,0xfd,0x81,0xfd,0xc7,0xfe,0x05,
0xfe,0x32,0xfe,0x55,0xfe,0x84,0xfe,0x99,0xfe,0xc0,0xfe,0xe3,0xff,0x02};
//这里定义音乐曲谱表格
code uchar musicdata[]={6,4, 8,4,10,4, 1,4, 9,8, 8,4, 7,4,10,8,9,8,6,16,
8,4,10,4,12,4,12,4,13,8,12,4,11,4,10,16,0};
// ***************************************************************************
void ClockIrqHandler (void) interrupt 1 using 3; //定义定时器T0中断服务程序
//下面是定时器T0的中断服务程序
void ClockIrqHandler (void) interrupt 1 using 3 {
TR0 = 0; //关闭定时器
TL0 = timer_l;
TH0 = timer_h;
beep = ~beep;
TR0 = 1; //打开定时器
}
// ***************** 定时器程序 **********************************
uchar keybuf;
void main()
{
uchar counts,mustmp,tmp,keym = 0; //键盘返回结果的缓冲区
reset(); //调用初始化程序
while(1) //设置一个无限制循环
{
for(counts=0;musicdata[counts]!=0;counts+=2)
{
mustmp = musicdata[counts];
TR0 = 0;
tmp = musictabl[mustmp];
timer_h = tmp;
tmp = musictabl[mustmp+1];
timer_l = tmp;
TR0 = 1;
display(0,musicdata[counts+1]);
delay(musicdata[counts+1]);
TR0 = 0;
dems();
}
// display(250,0);
// delay(255);
// delay(255);
// display(keybuf-1,keybuf); //在相应的位置显示返回的结果
}
}
void reset()
{
keybuf = 0;
P1 = 255; //关闭LED显示
P0 = 0; //关闭数码显示
P2 = 255; //
P3_7 = 0; //关闭蜂鸣器
//********* 上面是一些基础定义 **************
TL0 = 0xff; //初值
TH0 = 0xff; //初值
ET0=1; // 允许定时器T0中断
EA =1; // 中断总允许
}
//*****************************************************************************
//下面是延时程序。具体的延时时间不能通过表面程序看出,(为什么?)
//如果我们需要一个精密的延时程序,那么我们可以采用内嵌汇编代码的方式
void delay(uchar times)
{
int t=24000; //延时倍数
uchar i=times;
for(;i!=0;i--)
{for(;t!=0;t--){}}
}
void dems() //休止符延时
{
_asm
mov R0,#0
llp: mov R1,#100
llk: djnz R1,llk
djnz R0,llp
_endasm;
}
//这里是显示子程序,入口参数为
// disseg -> 位选 可选范围 0-7 一共8个数码管
// disdata -> 段选 可选范围 0-31 一个32个字符
// 段选 0-15 16个字符 为 "0"->"F"
// 段选 16-31 16个字符 为 "0."->"F."
void display(uchar disseg,uchar disdata)
{
uchar dataf;
if(disseg < 8) //只有当要显示的位数有效,才显示.否则,不显示
{
dataf = 1;
while(disseg)
{
dataf <<= 1;
disseg--;
}
P0 = dataf;
P2 = disbuf_u[disdata];
}
else{P0=0,P2=255;} //关闭数码管显示
}
uchar keyb()
{
uchar key,keytmp;
key1 = 1; //将输出线拉高
key2 = 1;
key3 = 1;
key = P3 ; //读回来
key = key & 0xf0; //获得键盘结果
if(key == 112 ) return 0; //如果用户没有按键返回 0
else
{
keytmp = key;
delay(1); //判断是不是干扰
key = P3 & 0xf0;
if (key != keytmp ) return 0; //是干扰,返回 0
else //不是干扰,等待用户释放按键
{
do{
key1 = 1; //输出拉高
key2 = 1;
key3 = 1;
key = P3 & 0xf0; //读回来
P1_0 = ~P1_0; //如果用户不释放,闪烁 p1.0
}while(key != 112 ); //等待用户释放
P1_0 = 1; //用户释放以后,清除p1.0指示灯
switch(keytmp)
{
case 96: return 3;//返回用户按键结果
case 80: return 2;
case 48: return 1;
}
}
}
}
//*******************************************************************************
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -