如何用c语言编写8051单片机音乐程序

如何用c语言编写8051单片机音乐程序,第1张

#define uchar unsigned char //定义一下方局皮便使用

#define uint unsigned int

#define ulong unsigned long

#include <reg52.h>//包括一个52标准内核的头文件

char code dx516[3] _at_ 0x003b//这是为了仿真设置的

sbitBEEP=P1^7//喇叭输出脚

sbit P10=P1^0

sbit K1= P3^2

sbit K2= P3^5

sbit K3= P2^4

sbit K4= P2^5

uchar th0_f//在中断中装载的T0的值高8位

uchar tl0_f//在中断中装载的T0的值低8位

//T0的值,及输出频率对照表

uchar code freq[36*2]={

0xA9,0xEF,//00220HZ ,1 //0

0x93,0xF0,//00233HZ ,1#

0x73,0xF1,//00247HZ ,2

0x49,0xF2,//00262HZ ,2#

0x07,0xF3,//00277HZ ,3

0xC8,0xF3,//00294HZ ,4

0x73,0xF4,//00311HZ ,4#

0x1E,0xF5,//00330HZ ,5

0xB6,0xF5,//00349HZ ,5#

0x4C,0xF6,//00370HZ ,6

0xD7,0xF6,//00392HZ ,6#

0x5A,0xF7,//00415HZ ,7

0xD8,0xF7,//00440HZ 1 //12

0x4D,0xF8,//00466HZ 1#//13

0xBD,0xF8,//00494HZ 2 //14

0x24,0xF9,//00523HZ 2#//15

0x87,0xF9,//00554HZ 3 //16

0xE4,0xF9,//00587HZ 4 //17

0x3D,0xFA,//00622HZ 4#//18

0x90,0xFA,//00659HZ 5 //19

0xDE,0xFA,//00698HZ 5#//20

0x29,0xFB,//00740HZ 6 //21

0x6F,0xFB,//00784HZ 6#//22

0xB1,0xFB,//00831HZ 7 //23

0xEF,0xFB,//00880HZ `1

0x2A,0xFC,//00932HZ `1#

0x62,0xFC,//00988HZ `2

0x95,0xFC,//01046HZ `2#

0xC7,0xFC,//01109HZ `3

0xF6,0xFC,//01175HZ `4

0x22,0xFD,//01244HZ `4#

0x4B,0xFD,//01318HZ `5

0x73,0xFD,//01397HZ `5#

0x98,0xFD,//01480HZ `6

0xBB,0xFD,//01568HZ `6#

0xDC,0xFD,//01661HZ `7//35

}

//定时中断0,用于产生唱歌频率

timer0() interrupt 1

{

TL0=tl0_fTH0=th0_f //调入预银腊槐定时值

BEEP=~BEEP //取反音乐输出IO

}

//******************************

//音乐符号串解释函数

//入口:要解释的音乐符号串,输出的音调串,输出的时长串

changedata(uchar *song,uchar *diao,uchar *jie)

{

uchar i,i1,j

char gaodi//高低+/-12音阶

uchar banyin//有没有半个升音阶

uchar yinchang//音长

uchar code jie7[8]={0,12,14,16,17,19,21,23}//C调的7个值

*diao=*song

for(i=0,i1=0)

{

gaodi=0//高低=0

banyin=0//半音=0

yinchang=4//音长1拍

if((*(song+i)=='|') || (*(song+i)==' ')) i++

//拍子间隔和一个空锋友格过滤

switch(*(song+i))

{

case ',': gaodi=-12i++//低音

break

case '`': gaodi=12i++//高音

break

}

if(*(song+i)==0) //遇到0结束

{

*(diao+i1)=0//加入结束标志0

*(jie+i1)=0

return

}

j=*(song+i)-0x30i++//取出基准音

j=jie7[j]+gaodi//加上高低音

yinc: switch(*(song+i))

{

case '#': //有半音j加一个音阶

i++j++

goto yinc

case '-': //有一个音节加长

yinchang+=4

i++

goto yinc

case '_': //有一个音节缩短

yinchang/=2

i++

goto yinc

case '.': //有一个加半拍

yinchang=yinchang+yinchang/2

i++

goto yinc

}

*(diao+i1)=j//记录音符

*(jie+i1)=yinchang//记录音长

i1++

}

}

//******************************************

//奏乐函数

//入口:要演奏的音乐符号串

void play(uchar *songdata)

{

uchar i,c,j=0

uint n

uchar xdata diaodata[112]//音调缓冲

uchar xdata jiedata[112] //音长缓冲

changedata(songdata,diaodata,jiedata)//解释音乐符号串

TR0=1

for(i=0diaodata[i]!=0i++) //逐个符号演奏

{

tl0_f=freq[diaodata[i]*2]//取出对应的定时值送给T0

th0_f=freq[diaodata[i]*2+1]

for(c=0c<jiedata[i]c++) //按照音长延时

{

for(n=0n<32000n++)

if((!K1)||(!K2)||(!K3)||(!K4))//发现按键,立即退出播放

{

TR0=0

return

}

}

TR0=0

for(n=0n<500n++) //音符间延时

TR0=1

}

TR0=0

}

//仙剑

uchar code xianjian[]={

"|3_3_3_2_3-|2_3_2_2_,6,6_,7_|12_1_,7,6_,5_|,6---|"

"3_3_3_2_3.6_|5_6_5_5_22_3_|45_4_32_1_|3.--3_|"

"67_6_55_3_|5--3_5_|26_5_32_3_|3---|"

"26_6_6-|16_6_66_7_|`17_6_76_7_|3.--3_|"

"67_6_55_3_|5--3_5_|67_6_76_7_|3---|"

"26_6_6-|16_6_66_7_|`17_6_7.5_|6---|"

}

uchar code song3[]={

"5-5_3_2_1_|3---|6-6_4_2_1_"

",7--,5_|1.3_5.1_|,7.3_5 5_|"

"6.7_`1.6_|6_5_5-3_2_|1.1_13_2_|"

"1.1_12_3_|2.1_,62_3_|2-- ,5_|"

"1.3_5.1_|,7.3_55_|6.7_`1.6_|"

"6_5_5-3_2_|1.1_13_2_|1.1_12_3_"

"2.,6_,71_2_|1--"

}

//世上只有妈妈好

uchar code mamahao[]={

"6.5_35|`16_5_6-|35_6_53_2_|1_,6_5_3_2-|"

"2.3_55_6_|321-|5.3_2_1_,6_1_|,5--"

}

//三个按键选择三首不同的音乐播放,一个键停止播放

void main(void) // 主程序

{

TMOD = 0x01 //使用定时器0的16位工作模式

TR0 = 0

ET0 = 1 //定时器0中断

EA = 1 //打开总中断

while(1)

{

if(!K1)

{

while(!K1)

play(xianjian) //播放音乐

}

if(!K2)

{

while(!K2)

play(song3) //播放音乐

}

if(!K3)

{

while(!K3)

play(mamahao) //播放音乐

}

}

}

一、设计题目:

设计一简易电子琴,要求能够发出1、2、3、4、5、6、7等七个音符。

使用元件:AT89C51、LM324,喇叭,按键等

二、 设计目的

(1)能够对电子电路、电子元器件、印制电路板等方面的知识有进一步的认识,独立对其进行测试与检查。

(2)熟悉8051单片机的内部结构和功能,合理使用其内部寄存器,能够完成相关软件编程设计工作。

(3)为实现预期功能,能够对系统进行快速的调试,并能够对出现的功能故障进行分析,及时修改相关软硬件。

(4)对软件编程、排错调试、焊接技术、相关仪器设备的使用技能等方面得到较全面的锻炼和提高。

三、系统硬件图

原嫌码理:

(一) 音乐产生原理及硬件设计

由于一首音乐是许多不同的音阶组成的,而每个音阶对应着不同的频率,这样我们就可以利用不同的频率的组合,即可构成我们所想要的音乐了,当然对于单片机来产生不同的频率非常方便,我们可以利昌者高用单片机的定时/计数器T0来产生这样方波频率信号,因此,我们只要把一首歌曲的音阶对应频率关系弄正确即可。

本次设计中单片机晶振为12MHZ,那么定时器的计数周期为1MHZ,假如选择工作方式1,那T值便为T= 216--5﹡105/相应的频率 ,那么根据不同的频率计算出应该赋给耐尺定时器的计数值,列出不同音符与单片机计数T0相关的计数值如下表所示:

音符 频率(HZ) 简谱码(T值)

中 1 DO 523 64580

中 2 RE 587 64684

中 3 M 659 64777

中 4 FA 698 64820

中 5 SO 784 64898

中 6 LA 880 64968

中 7 SI 988 65030

采用查表程序进行查表时,可以为这个音符建立一个表格,有助于单片机通过查表的方式来获得相应的数据:

TABLE DW 64580,64684,64777,64820,64898,64968,65030

源程序:

方案一:产生按键音符

ORG 0000H

LJMP MAIN

ORG 000BH

LJMP BREAK

MAIN: MOV TMOD,#01H 设置定时器0的工作方式

SETB EA

SETB ET0 设置定时器0中断

SETB TR0 启动定时器0

WAIT1: LCALL KEY 调用KEY子程序,判断有键按下否?第几个键?

CLR EA 屏蔽中断

CJNE R3,#00H,WAIT1 如果R3=0,表示有键按下

MOV A,22H 将22H里存放的按键号送给A

RL A 因为查表里都是字,所以得乘2查得数据

MOV DPTR,#TABLE 指向表头

MOVC A,@A+DPTR 查表

MOV TH0,A 将数据高位送TH0

MOV 21H,A 将高位备份

MOV A,22H 将22H里存放的按键号送给A

RL A 因为查表里都是字,所以得乘2查得数据

INC A 取低位数据

MOVC A,@A+DPTR

MOV TL0,A

MOV 20H,A

WAIT2: LCALL KEY

SETB EA

CJNE R3,#00H,WAIT1

JMP WAIT2

KEY: MOV R3,#00H KEY子程序,判断有键按下否?第几个键?

MOV R1,#0FFH

MOV R0,#00H

MOV A,R1

MOV P2,A

MOV A,P2

CLR C

CPL C 利用标志位CY来判断是哪个键按下

MOV R2,#08H

WAIT3: RLC A 移位判断

JNC STORE

INC R0

DJNZ R2,WAIT3

STORE: MOV 22H,R0将按键号存22H,R3=0有键按下

MOV R3,#00H

RET

BREAK: PUSH ACC 中断产生方波,从P1.0口输出

PUSH PSW

MOV TL0,20H

MOV TH0,21H

CPL P1.0

POP PSW

POP ACC

RETI

TABLE: DW 65030,64968,64898,64820,64777,64684,64580 7,6,5,4,3,2,1

END

方案二:产生按键音符

ORG 0000H

SJMP START

ORG 000BH

AJMP INT_0

ORG 0030H

START: MOV P1,#00H

SETB EA

SETB ET0 计数器0

MOV TMOD,#02H

MOV TH1,#09CH

MOV TL1,#09CH 定时器初植

CLR TR0定时器不允许

SCAN: 键盘扫描

MOV A,P2 判断键盘按下,跳到SCAN_1,若未按,继续扫描

CJNE A,#0FFH,SCAN_1

NOP

SJMP SCAN

SCAN_1:ACALL DELAY 是不是真的要按下?如果是,则跳转SU_KEY查询是哪个按下?

MOV A,P2

CJNE A,#0FFH,SU_KEY

NOP

SJMP SCAN

SU_KEY:JNB P2.1,MU_1 判断是哪个键按下?

JNB P2.2,MU_2

JNB P2.3,MU_3

JNB P2.4,MU_4

JNB P2.5,MU_5

JNB P2.6,MU_6

JNB P2.7,MU_7

SJMP SCAN

R1信号周期

MU_1: MOV R1,#19如果第一个按键按下,则R1=19,同时程序转NEXT

SJMP NEXT

MU_2: MOV R1,#17

SJMP NEXT

MU_3: MOV R1,#15

SJMP NEXT

MU_4: MOV R1,#14

SJMP NEXT

MU_5: MOV R1,#13

SJMP NEXT

MU_6: MOV R1,#11

SJMP NEXT

MU_7: MOV R1,#10

SJMP NEXT

NEXT: MOV A,R1

MOV R0,A

SETB TR0 启动定时器0

NEXT_1:MOV A,P2 没键按下继续执行,有键按下,返回读引脚

CJNE A,#0FFH,NEXT_1

ACALL DELAY

MOV A,P2 真的没键按下?

CJNE A,#0FFH,NEXT_1

CLR TR0不响

AJMP SCAN 扫描键盘去

INT_0: 中断程序

DJNZ R0,RE R0不等于0时,返回

CPL P1.0

MOV A,R1

MOV R0,A

RE: RETI

DELAY:MOV R7,#100延长时间等待,键盘消抖

D1: MOV R6,#10

D2: DJNZ R6,D2

DJNZ R7,D1

RET

END

生日快乐歌:(扩展功能部分程序)

ORG 0000H

JMP MAIN

ORG 000BH

JMP TT0

MAIN: MOV TMOD,#01H ;设置定时器0工作方式

MOV IE,#82H;设置中断

MAIN0:MOV 30H,#00H

NEXT: MOV A,30H

MOV DPTR,#TABLE ;查表

MOVC A,@A+DPTR

MOV R2,A

JZ STOP

ANL A,0FH

MOV R5,A

MOV A,R2

SWAP A

ANL A,#0FH

JNZ SING

CLR TR0

JMP W1

SING: DEC A

MOV 22H,A

RL A

MOV DPTR,#TABLE1 ;查表

MOVC A,@A+DPTR

MOV TH0,A

MOV 21H,A

MOV A,22H

RL A

INC A

MOVC A,@A+DPTR

MOV TL0,A

MOV 20H,A

SETB TR0

W1: CALL DELAY

INC 30H

JMP NEXT

STOP: CLR TR0

JMP MAIN0

TT0: PUSH ACC;中断服务程序

PUSH PSW

MOV TL0,20H

MOV TH0,21H

CPL P1.0

POP PSW

POP ACC

RETI

DELAY:MOV R7,#2 ;延时187ms

W2: MOV R4,#187

W3: MOV R3,#248

DJNZ R3,$

DJNZ R4,W3

DJNZ R7,W2

DJNZ R5,DELAY

RET

TABLE1:DW 64260,64400,64524,64580;音符计数植

DW 64684,64777,64820,64898

DW 64968,65030,65058,65110

DW 65157,65178,65217

TABLE:DB 82H,01H,81H,94H,84H ;节拍表

DB 0B4H,0A4H,04H

DB 82H,01H,81H,94H,84H

DB 0C4H,0B4H,04H

DB 82H,01H,81H,0F4H,0D4H

DB 0B4H,0A4H,94H

DB 0E2H,01H,0E1H,0D4H,0B4H

DB 0C4H,0B4H,04H

DB 82H,01H,81H,94H,84H

DB 0B4H,0A4H,04H

DB 82H,01H,81H,94H,84H

DB 0C4H,0B4H,04H

DB 82H,01H,81H,0F4H,0D4H

DB 0B4H,0A4H,94H

DB 0E2H,01H,0E1H,0D4H,0B4H

DB 0C4H,0B4H,04H

DB 00H

END 谢谢希望采纳

单片机c语言编程100个实例目录1

函数的使用和熟悉

实例3:用单片机控制第一个灯亮

实例4:用单片机控制一个灯闪烁:认识单片机的工作频率

实例5:将 P1口状态分别送入P0、P2、P3口:认识I/O口的引脚功能

实例6:使用P3口流樱弯水点亮8位LED

实例7:通过对P3口地址的 *** 作流水点亮8位LED

实例8:用不同数据类型控制灯闪烁时间

实例9:用P0口、P1 口分别显示加法和减法运算结果

实例10:用P0、P1口显示乘法运算结果

实例11:用P1、P0口显示除法运算结果

实例12:用自增运算控制P0口8位LED流水花样

实例13:用P0口显示逻辑"与"运算结果

实例14:用P0口显示条件运算结果

实例15:用P0口显示按位"异或"运算结果

实例16:用P0显示左移运算结果

实例17:"万能逻辑电路"实验

实例18:用右移运算流水点亮P1口8位LED

实例19:用if语句控制P0口8位LED的流水方向

实例20:用swtich语句的控制P0口8位LED的点亮状态

实例21:用for语句控制蜂鸣器鸣笛次数

实例22:用while语句控制LED

实例23:用do-while语句控制P0口8位LED流水点亮

实例24:用字符型数组控制P0口8位LED流水点亮

实例25: 用P0口显示字符串常量

实例26:用P0 口显示指针运算结果

实例27:用指针数组控制P0口8位LED流水点亮

实例28:用数组的指针控制P0 口8 位LED流水点亮

实例29:用P0 、P1口显示整型函数返回值

实例30:用有参函数控制P0口8位LED流水速度

实例31:用数组作函数参数控制流水花样

实例32:用指针作函数参数控制P0口8位LED流水点亮

实例33:用函数型指针控制P1口灯花样

实例34:用指针数组作为函数的参数显示多个字符串

单片机c语言编程100个实例目录2

实例35:字符函数ctype.h应用举例

实例36:烂睁内部函数intrins.h应用举例

实例37:标准函数stdlib.h应用举例

实例38:字符串函数string.h应用举例

实例39:宏定义应用举例2

实例40:宏定义应用举例2

实例41:宏定义应用举例3

* 中断、定时器中断、定时器 *中断、定时器*中断、定时器 /

实例42:用定时器T0查询方式P2口8位控制LED闪烁

实例43:用定时脊历闷器T1查询方式控制单片机发出1KHz音频

实例44:将计数器T0计数的结果送P1口8位LED显示

实例45:用定时器T0的中断控制1位LED闪烁

实例46:用定时器T0的中断实现长时间定时

实例47:用定时器T1中断控制两个LED以不同周期闪烁

实例48:用计数器T1的中断控制蜂鸣器发出1KHz音频

实例49:用定时器T0的中断实现"渴望"主题曲的播放

实例50-1:输出50个矩形脉冲

实例50-2:计数器T0统计外部脉冲数

实例51-2:定时器T0的模式2测量正脉冲宽度

实例52:用定时器T0控制输出高低宽度不同的矩形波

实例53:用外中断0的中断方式进行数据采集

实例54-1:输出负脉宽为200微秒的方波

实例54-2:测量负脉冲宽度

实例55:方式0控制流水灯循环点亮

实例56-1:数据发送程序

实例56-2:数据接收程序

实例57-1:数据发送程序

实例57-2:数据接收程序

实例58:单片机向PC发送数据

实例59:单片机接收PC发出的数据

*数码管显示*数码管显示 数码管显示数码管显示*/

实例60:用LED数码显示数字5

实例61:用LED数码显示器循环显示数字0~9

实例62:用数码管慢速动态扫描显示数字"1234"

实例63:用LED数码显示器伪静态显示数字1234

实例64:用数码管显示动态检测结果

实例65:数码秒表设计

实例66:数码时钟设计

实例67:用LED数码管显示计数器T0的计数值

实例68:静态显示数字“59”

单片机c语言编程100个实例目录3

键盘控制*键盘控制* *键盘控制 *键盘控制 */

实例69:无软件消抖的独立式键盘输入实验

实例70:软件消抖的独立式键盘输入实验

实例71:CPU控制的独立式键盘扫描实验

实例72:定时器中断控制的独立式键盘扫描实验

实例73:独立式键盘控制的4级变速流水灯

实例74:独立式键盘的按键功能扩展:"以一当四"

实例75:独立式键盘调时的数码时钟实验

实例76:独立式键盘控制步进电机实验

实例77:矩阵式键盘按键值的数码管显示实验

//实例78:矩阵式键盘按键音

实例79:简易电子琴

实例80:矩阵式键盘实现的电子密码锁

液晶显示LCD*液晶显示LCD *液晶显示LCD * *液晶显示LCD*液晶显示LCD *液晶显示LCD */

实例81:用LCD显示字符'A'

实例82:用LCD循环右移显示"Welcome to China"

实例83:用LCD显示适时检测结果

实例84:液晶时钟设计

*一些芯片的使用*24c02 DS18B20 X5045 ADC0832 DAC0832 DS1302 红外遥控/

实例85:将数据"0x0f"写入AT24C02再读出送P1口显示

实例86:将按键次数写入AT24C02,再读出并用1602LCD显示

实例87:对I2C总线上挂接多个AT24C02的读写 *** 作

实例88:基于AT24C02的多机通信 读取程序

实例89:基于AT24C02的多机通信 写入程序

实例90:DS18B20温度检测及其液晶显示

实例91:将数据"0xaa"写入X5045再读出送P1口显示

实例92:将流水灯控制码写入X5045并读出送P1口显示

实例93:对SPI总线上挂接多个X5045的读写 *** 作

实例94:基于ADC0832的数字电压表

实例95:用DAC0832产生锯齿波电压

实例96:用P1口显示红外遥控器的按键值

实例97:用红外遥控器控制继电器

实例98:基于DS1302的日历时钟

实例99:单片机数据发送程序

实例100:电机转速表设计

模拟霍尔脉冲

http://www.dzkfw.com.cn/myxin/51c_language.chm 单片机c语言一百例子


欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/yw/12385584.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-05-23
下一篇2023-05-23

发表评论

登录后才能评论

评论列表(0条)

    保存