51单片机模拟电子琴+Proteus仿真

51单片机模拟电子琴+Proteus仿真


  • Proteus仿真
    在这里插入图片描述

示例程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331

#include<reg51.h>
#include<intrins.h>

#define uchar unsigned char //无符号字符型 宏定义 变量范围0~255
#define uint unsigned int //无符号整型 宏定义 变量范围0~65535

sbit SDA1=P0^2;//串行数据输入,对应74HC595的14脚SER
sbit SCL1=P0^1;//移位寄存器时钟输入,对应595的11脚SCK
sbit SCL2=P0^0;//存储寄存器时钟输入,对应595的12脚RCK
sbit W1=P0^3;
sbit W2=P0^4;
sbit k1=P1^0; //哆1 啦2 咪3 发4 嗦5 啦6 西7 哆
sbit k2=P1^1; //哆1 啦2 咪3 发4 嗦5 啦6 西7 哆
sbit k3=P1^2; //哆1 啦2 咪3 发4 嗦5 啦6 西7 哆
sbit k4=P1^3; //哆1 啦2 咪3 发4 嗦5 啦6 西7 哆
sbit k5=P1^4; //哆1 啦2 咪3 发4 嗦5 啦6 西7 哆
sbit k6=P1^5; //哆1 啦2 咪3 发4 嗦5 啦6 西7 哆
sbit k7=P1^6; //哆1 啦2 咪3 发4 嗦5 啦6 西7 哆
sbit D1=P2^6; //播放音乐模式
sbit D2=P2^7; //弹奏模式
sbit k8=P3^2; //功能切换键
sbit k9=P3^3; //低音
sbit k10=P3^4; //中音
sbit k11=P3^5; //高音
sbit beep=P2^2;//蜂鸣器接口

uchar code table1[]={ //共阴极数码管
0x3F,/\*0\*/
0x06,/\*1\*/
0x5B,/\*2\*/
0x4F,/\*3\*/
0x66,/\*4\*/
0x6D,/\*5\*/
0x7D,/\*6\*/
0x07,/\*7\*/
0x7F,/\*8\*/
0x6F,/\*9\*/
0x37,/\*N\*///中音
0x38,/\*L\*///低音
0x76,/\*H\*///高音
0x79 /\*E\*/
};
/格式为: 频率常数, 节拍常数, 频率常数, 节拍常数///
uchar code table2[]={ //音阶频率表 低八位
0xFC,0xFC,0xFD,0xFD,0xFD,0xFD,0xFE,//中音
0xF9,0xF9,0xFA,0xFA,0xFB,0xFB,0xFC,//低音的高8位
0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFF,
};
uchar code table3[]={
0x8E,0xED,0x44,0x6B,0xB4,0xF4,0x2D,//中音
0x21,0xDB,0x87,0xD7,0x68,0xE8,0x5B,//低音的低8位
0x47,0x77,0xA2,0xB6,0xDA,0xFA,0x16,
};
uchar code table4[]={
1,2,3,1,
1,2,3,1,
3,4,5,
3,4,5,
5,6,5,4,3,1,
5,6,5,4,3,1,
1,12/\*低音5\*/,1,
1,12,1
};
uchar code table5[]={ //演奏歌曲延时表
4,4,4,4,
4,4,4,4,
4,4,8,
4,4,8,
2,1,2,1,4,4,
2,1,2,1,4,4,
4,4,6,
4,4,6
};

uchar i;
uchar key,aa=0;
uchar bb,cc;
bit flag=0;

//延时子函数
void delay(uint z)
{
uint x,y;
for(x=z;x>0;x--)
for(y=340;y>0;y--);
}

void in(uchar Data)
{
uchar i;
for(i=0;i<8;i++) //循环8次,刚好移完8位
{
Data<<=1;
SCL1=CY;
SDA1=1; //先将移位寄存器控制引脚置为低
\_nop\_();
\_nop\_();
SDA1=0;
}
}
void out()
{
SCL2=0; //先将存储寄存器引脚置为低
\_nop\_();
SCL2=1; //再置为高,产生移位时钟上升沿,上升沿时移位寄存器的数据进入数据存储寄存器,更新显示数据。
\_nop\_();
SCL2=0;
}
//初始化子函数
void init()
{
beep=0; //蜂鸣器关闭
D1=1; //开始演奏音乐
D2=0; //关闭弹奏功能
EA=1; //开总中断
TCON=0x01; //外部中断0设置为边沿触发
/\* 以下是D7~D0 ,0x01=0000 0001 所以该函数相当于 IT0=1
TF1:定时器T1溢出标志位。当定时器T1溢出时,由硬件自动使TF1置1,并向CPU申请中断。CPU响应中断后,自动对TF1清零。TF1也可以用软件清零。
TR1:定时器T 1运行控制位。可由软件置1(或清零)来启动(或关闭)定时器T1,使定时器T1开始计数。用指令SETB TR1(或CLR TR1)使TR1置1(或清零)。
TF0:定时器T0溢出标志位。其功能与TF1相同。
TR0:定时器T0运行控制位。其功能与TR1相同。
IE1:外部中断1请求标志位。
IT1:外部中断1触发方式控制位。
IE0:外部中断0请求标志位。
IT0:外部中断0触发方式控制位。
\*/
EX0=1; //开外部中断0
ET0=1; //定时器0的中断打开
ET1=1; //定时器1的中断打开
TMOD=0x11; //定时器0,1工作在定时状态,均为方式1
}
//数码管显示子函数
void display1()
{
in(table1[aa]); //再传段码
out();
W1=0;;
delay(1); //延迟时间2ms以内
W1=1;
in(table1[cc+1]); //再传段码
out();
W2=0;
delay(1); //延迟时间2ms以内
W2=1;
}
//高低音选择子函数
void yinjie()
{
if(k10==0)
{
delay(5);
if(k10==0)
{
aa=10;
bb=0;//返回10为seg[10]显示C
}
}
if(k9==0)
{
delay(5);
if(k9==0)
{
aa=11;
bb=1;//返回11为seg[11]显示L
}
}
if(k11==0)
{
delay(5);
if(k11==0)
{
aa=12;
bb=2;//返回12为seg[12]显示H
}
}
if(aa==0)
{
aa=13;
}
}
//播放音乐子函数
void display\_music()
{
TH0=table2[table4[i]-1]; //取频率常数 和 节拍常数
TL0=table3[table4[i]-1];
while(flag==0)
{
if(i<32)
{
TR0=1;
delay(57\*table5[i]);
i++;
}
if(i==32) i=0;
}
}
//演奏模式子函数
void display\_play()
{
TR0=0;
TR1=0;
yinjie();
in(table1[aa]); //再传段码
out();
W1=0;;
delay(1); //延迟时间2ms以内
W1=1;
if(aa!=13&&flag==1)
{
if(k1==0)
{
TH1=table2[7\*bb+cc]; //取频率常数 和 节拍常数
TL1=table3[7\*bb+cc];
TR1=1;
while(k1==0)
{
cc=0;
display1();
}
}
if(k2==0)
{
TH1=table2[7\*bb+cc]; //取频率常数 和 节拍常数
TL1=table3[7\*bb+cc];
TR1=1;
while(k2==0)
{
cc=1;
display1();
}
}
if(k3==0)
{
TH1=table2[7\*bb+cc]; //取频率常数 和 节拍常数
TL1=table3[7\*bb+cc];
TR1=1;
while(k3==0)
{
cc=2;
display1();
}
}
if(k4==0)
{ //取频率常数 和 节拍常数
TH1=table2[7\*bb+cc];
TL1=table3[7\*bb+cc];
TR1=1;
while(k4==0)
{
cc=3;
display1();
}
}
if(k5==0)
{
TH1=table2[7\*bb+cc]; //取频率常数 和 节拍常数
TL1=table3[7\*bb+cc];
TR1=1;
while(k5==0)
{
cc=4;
display1();
}
}
if(k6==0)
{
TH1=table2[7\*bb+cc]; //取频率常数 和 节拍常数
TL1=table3[7\*bb+cc];
TR1=1;
while(k6==0)
{
cc=5;
display1();
}
}
if(k7==0)
{
TH1=table2[7\*bb+cc]; //取频率常数 和 节拍常数
TL1=table3[7\*bb+cc];
TR1=1;
while(k7==0)
{
cc=6;
display1();
}
}
}
}
//主函数
void main()
{
init(); //初始化子函数
while(1)
{
if(flag==0) display\_music(); //演奏音乐
else display\_play(); //弹奏音乐
}
}
//外部0中断子函数
void wb0() interrupt 0
{
if(k8==0)
{
delay(5);
while(k8==0);
flag=~flag;
D1=~D1;
D2=~D2;
}
}
//定时器0中断子函数
void t0() interrupt 1
{
TR0=0;
TH0=table2[table4[i]-1]; //取频率常数 和 节拍常数
TL0=table3[table4[i]-1];
beep=~beep;
TR0=1;
}
//定时器1中断子函数
void t1() interrupt 3
{
TR1=0;
TH1=table2[7\*bb+cc]; //取频率常数 和 节拍常数
TL1=table3[7\*bb+cc];
beep=~beep;
TR1=1;
}


程序源码和仿真资源

1
2
3
链接:https://pan.baidu.com/s/1Z89KAevdCD6RLFikVE02Ig 
提取码:b3ey