第30课从24c02中读出音乐来并播放音乐.pdf

返回 相似 举报
第30课从24c02中读出音乐来并播放音乐.pdf_第1页
第1页 / 共10页
第30课从24c02中读出音乐来并播放音乐.pdf_第2页
第2页 / 共10页
第30课从24c02中读出音乐来并播放音乐.pdf_第3页
第3页 / 共10页
第30课从24c02中读出音乐来并播放音乐.pdf_第4页
第4页 / 共10页
亲,该文档总共10页,到这儿已超出免费预览范围,如果喜欢就下载吧!
资源描述:
第第 30 课,从课,从 24c02 中读出音乐来并播放音乐中读出音乐来并播放音乐 这是本入门教程的最后一课,也是最复杂的一个程序。 我们要从 24c02 中读出上一课写入的一个乐谱,并播放出来。这是模拟 mp3 的工作方 式。获取外部的存储器的音乐数据并播放,而这个音乐数据是任意的,只要符合播放规则就 可以。 本课我们还要学习函数模块的做法。请打开第 30 课的工程 可以看到, 在左边的列表中, 有3个文件, 我们称为3个功能模块, main.c,24c02.c,music.c。 我们把对应功能的函数放入其中,这样可以使整个程序工程简洁易懂,维护方便。 那么,我们怎么使各个模块联合工作呢 答案是, 如果在当前模块要调用其他模块里的函数或者变量, 在这个模块的前面声明一 下就可以了。 如在 main.c 模块的前面,就有 extern uchar Read24c02uchar address; //声明外部的读 24c02 函数 extern void playuchar *songdata; //声明外部的音乐播放函数 这样,在 main.c 中就可以直接调用这两个函数了。 如果调用了其他函数中声明的公共变量,也可以这样声明一下就可以了。 在编译的时候,keilC51 会将每个模块分别编译,再一起连接,整个过程不用你操心。 把里面的 error 和 warning 仔细解决掉就可以了。本程序已经编译好了,可以直接使用。 下面分别列出每个模块 main.c define uchar unsigned char //定义一下方便使用 define uint unsigned int define ulong unsigned long include //包括一个 52 标准内核的头文件 extern uchar Read24c02uchar address; //声明外部的读 24c02 函数 extern void playuchar *songdata; //声明外部的音乐播放函数 char code dx516[3] _at_ 0 x003b;//这是为了仿真设置的 sbit P10P10; sbit K1 P32; sbit K2 P35; sbit K3 P24; sbit K4 P25; //从 24c02 中读出音乐来并播放音乐 void mainvoid // 主程序 { uchar i; uchar xdata yinyue[256]; //设立一个缓冲区 TMOD 0 x01; //使用定时器 0 的 16 位工作模式 TR0 0; ET0 1; //定时器 0 中断 EA 1; //打开总中断 fori0;yinyue[i]0;i //读出音乐来放到缓冲中 { yinyue[i]Read24c02i; } yinyue[i]0; while1 { playyinyue; //播放音乐 } } 24c02.c define uchar unsigned char //定义一下方便使用 define uint unsigned int define ulong unsigned long include //包括一个 52 标准内核的头文件 define WriteDeviceAddress 0 xa0 //定义器件在 IIC 总线中的地址 define ReadDviceAddress 0 xa1 sbit SCLP27; sbit SDAP26; sbit P10P10; /* //定时函数 void DelayMsunsigned int number { unsigned char temp; for;number0;number-- { fortemp112;temp0;temp-- ; } } */ //开始总线 void Start { SDA1; SCL1; SDA0; SCL0; } //结束总线 void Stop { SCL0; SDA0; SCL1; SDA1; } //发 ACK0 void NoAck { SDA1; SCL1; SCL0; } //测试 ACK bit TestAck { bit ErrorBit; SDA1; SCL1; ErrorBitSDA; SCL0; returnErrorBit; } //写入 8 个 bit 到 24c02 Write8Bitunsigned char { unsigned char temp; fortemp8;temp0;temp-- { SDAbit SCL1; SCL0; 1; } } /* //写入一个字节到 24c02 中 void Write24c02uchar ch,uchar address { Start; Write8BitWriteDeviceAddress; TestAck; Write8Bitaddress; TestAck; Write8Bitch; TestAck; Stop; DelayMs10; } */ //从 24c02 中读出 8 个 bit uchar Read8Bit { unsigned char temp,rbyte0; fortemp8;temp0;temp-- { SCL1; rbyterbyte1; rbyterbyte|unsigned charSDA; SCL0; } returnrbyte; } //从 24c02 中读出 1 个字节 uchar Read24c02uchar address { uchar ch; Start; Write8BitWriteDeviceAddress; TestAck; Write8Bitaddress; TestAck; Start; Write8BitReadDviceAddress; TestAck; chRead8Bit; NoAck; Stop; returnch; } music.c define uchar unsigned char //定义一下方便使用 define uint unsigned int define ulong unsigned long include //包括一个 52 标准内核的头文件 sbit BEEPP17; //喇叭输出脚 sbit K1 P32; sbit K2 P35; sbit K3 P24; sbit K4 P25; uchar th0_f; //在中断中装载的 T0 的值高 8 位 uchar tl0_f; //在中断中装载的 T0 的值低 8 位 //T0 的值,及输出频率对照表 uchar code freq[36*2]{ 0 xA9,0 xEF,//00220HZ ,1 //0 0 x93,0 xF0,//00233HZ ,1 0 x73,0 xF1,//00247HZ ,2 0 x49,0 xF2,//00262HZ ,2 0 x07,0 xF3,//00277HZ ,3 0 xC8,0 xF3,//00294HZ ,4 0 x73,0 xF4,//00311HZ ,4 0 x1E,0 xF5,//00330HZ ,5 0 xB6,0 xF5,//00349HZ ,5 0 x4C,0 xF6,//00370HZ ,6 0 xD7,0 xF6,//00392HZ ,6 0 x5A,0 xF7,//00415HZ ,7 0 xD8,0 xF7,//00440HZ 1 //12 0 x4D,0 xF8,//00466HZ 1 //13 0 xBD,0 xF8,//00494HZ 2 //14 0 x24,0 xF9,//00523HZ 2 //15 0 x87,0 xF9,//00554HZ 3 //16 0 xE4,0 xF9,//00587HZ 4 //17 0 x3D,0 xFA,//00622HZ 4 //18 0 x90,0 xFA,//00659HZ 5 //19 0 xDE,0 xFA,//00698HZ 5 //20 0 x29,0 xFB,//00740HZ 6 //21 0 x6F,0 xFB,//00784HZ 6 //22 0 xB1,0 xFB,//00831HZ 7 //23 0 xEF,0 xFB,//00880HZ 1 0 x2A,0 xFC,//00932HZ 1 0 x62,0 xFC,//00988HZ 2 0 x95,0 xFC,//01046HZ 2 0 xC7,0 xFC,//01109HZ 3 0 xF6,0 xFC,//01175HZ 4 0 x22,0 xFD,//01244HZ 4 0 x4B,0 xFD,//01318HZ 5 0 x73,0 xFD,//01397HZ 5 0 x98,0 xFD,//01480HZ 6 0 xBB,0 xFD,//01568HZ 6 0 xDC,0 xFD,//01661HZ 7 //35 }; //定时中断 0,用于产生唱歌频率 timer0 interrupt 1 { TL0tl0_f;TH0th0_f; //调入预定时值 BEEPBEEP; //取反音乐输出 IO } //****************************** //音乐符号串解释函数 //入口要解释的音乐符号串,输出的音调串,输出的时长串 changedatauchar *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; fori0,i10;; { gaodi0; //高低0 banyin0;//半音0 yinchang4;//音长 1 拍 if*songi| || *songi i; //拍子间隔和一个空格过滤 switch*songi { case , gaodi-12;i;//低音 break; case gaodi12;i; //高音 break; } if*songi0 //遇到 0 结束 { *diaoi10; //加入结束标志 0 *jiei10; return; } j*songi-0 x30; i; //取出基准音 jjie7[j]gaodi; //加上高低音 yinc switch*songi { case //有半音 j 加一个音阶 i;j; goto yinc; case - //有一个音节加长 yinchang4; i; goto yinc; case _ //有一个音节缩短 yinchang/2; i; goto yinc; case . //有一个加半拍 yinchangyinchangyinchang/2; i; goto yinc; } *diaoi1j; //记录音符 *jiei1yinchang; //记录音长 i1; } } //****************************************** //奏乐函数 //入口要演奏的音乐符号串 void playuchar *songdata { uchar i,c,j0; uint n; uchar xdata diaodata[112]; //音调缓冲 uchar xdata jiedata[112]; //音长缓冲 changedatasongdata,diaodata,jiedata; //解释音乐符号串 TR01; fori0;diaodata[i]0;i //逐个符号演奏 { tl0_ffreq[diaodata[i]*2]; //取出对应的定时值送给 T0 th0_ffreq[diaodata[i]*21]; forc0;cjiedata[i];c //按照音长延时 { forn0;n32000;n; ifK1||K2||K3||K4//发现按键,立即退出播放 { TR00; return; } } TR00; forn0;n500;n; //音符间延时 TR01; } TR00; } 请打开工程,好好体验一下分模块的好处,并仔细查看一下各个函数模块,试着编译一 次。 点全速运行,看结果。 可以看到,上一课预先写入的“老鼠爱大米”被不断地播放。 作业返回第 29 课,写入一首新的音乐。再回到第 30 课,播放你写入的音乐。 结束语 这 30 个 C51 课程,只是在一个小小的试验板实现,试验板上只有 4 个按钮,4 个 LED, 1 个蜂鸣器,1 个 24c02。但是我们却学到了各种复杂的控制和编程方法。我们已经熟悉了 C51 的编程,甚至可以进行已经学习过的资源的程序开发。相信你已经兴趣倍增,对于更加 深入地学习单片机系统充满信心 由于您已经在学习本系列课程中形成了基础,也就是已经入门并基本可以熟练操作了, 对于本系列课程没有涉及到的资源,如串口、总线等,你都可以在日后信手拈来,自己在探 索中去研究。 本教程由大虾电子网()创办人聂小猛(网名丁丁)在 2006 年 6 月足球世界杯期间编写,版权所有,请勿用在商业场合 大虾电子网简介 大虾电子网前身 51 单片机世界, 在 2000 年创办。 本站拥有国内人气最旺的单片机类专 业技术论坛,并拥有大量资料,访问量在国内同类网站名列前茅。2006 年计划增加开放性 商城板块和大虾博客板块,欢迎各界电子网友前来访问。
展开阅读全文

资源标签

最新标签

长按识别或保存二维码,关注学链未来公众号

copyright@ 2019-2020“矿业文库”网

矿业文库合伙人QQ群 30735420