STC学习:可同步显示歌词的ABC英文歌
程序设计目标及程序运行效果说明
程序设计目标:通过按下按键key1来控制音乐播放以及数码管的歌词显示。
程序运行效果说明:按下按键key1,此时播放音乐《I can say ABC》并显示歌词;再次按下key1键可以暂停播放音乐。
程序相关电路及原理说明
1.原理说明
本实验板采用的是无源蜂鸣器,相比与有源蜂鸣器,无源蜂鸣器的优点在于价格便宜,可以通过控制其振动频率来改变发出的声音,因此,无源蜂鸣器可以用于音乐的播放。而有源蜂鸣器的优点在于使用简单,不需要编写“乐谱”。本实验板使用的无源蜂鸣器是电磁式蜂鸣器,电磁式蜂鸣器由振荡器、电磁线圈、磁铁、振动膜片及外壳等组成。接通电源后,接收到的音频信号电流通过电磁线圈,使电磁线圈产生磁场。振动膜片在电磁线圈和磁铁的相互作用下,周期性地振动发声。
本程序中,数组music[]即是要播放的音乐,格式为音符,节拍,音符,节拍,如此循环下去。音符为要发出的音调,而节拍则是声音的持续时间。如图,在数组music[]中,音符表示的格式为:十位代表是低八度,中八度还是高八度,1代表高八度,2代表中八度,3代表高八度,个位代表简谱的音符,例如,0x15代表低八度的S0,如图即是低5S0,0x21代表中八度的DO,如图即是中1 D0。音符中,0x00代表结束符,表示整首歌曲演唱完毕,而0xff代表休止符,表示要休止100ms。遇到这两种情况,都应该重新执行循环中的第一步。其余情况则是正常播放。程序烧入单片机后,需要按下按键key1才会进行演奏。相比基础篇则添加了歌词数码管同步显示功能。
注:因使用数码管显示歌词着实有些勉强,有些字母很难在数码管上面显示,如“M”等,这个实验主要的学习重点在于歌词的同步显示和歌曲的数字编排(即由简谱变成音乐代码)。 ABC英文歌字母数码管显示对应符号表(A-Z)已另外做成文档,请见文档“ABC英文歌字母数码管显示对应符号表(A-Z)”。
2.程序相关电路
(1)无源蜂鸣器电路原理图
(2)按键控制电路
芯片相关引脚:Beep——P3^4;
代码如下:
#include "STC15F2K60S2.H"
#define uint unsigned int //宏定义
#define uchar unsigned char
sbit led_sel=P2^3; //数码管与发光二极管选通引脚
sbit sel0=P2^0; //SEL0、SEL1、SEL2组合为位选信息,0-7
sbit sel1=P2^1;
sbit sel2=P2^2;
sbit beep=P3^4; //蜂鸣器引脚
sbit key1=P3^2; //定义按键1
sbit key2=P3^3; //定义按键2
uchar timeh,timel; //定义定时器的重装值
uchar flag; //所选择点亮的数码管0-7标志位
bit zanting; //播放或暂停标志位
uchar jindu=0; //music数组中指向的位置
uchar geci[]={0x77,0x7f,0x39,0x00,0x6f,0x7b}; //显示开机画面的数码管段码 ABC ge
uchar geci1[]={0x77,0x7f,0x39,0x3f,0x79,0x71,0x3d,0x40}; //显示A-G的数码管段码 ABCDEFG-
uchar geci2[]={0x76,0x06,0x1e,0xf6,0x38,0x4f,0x37,0x40}; //显示H-N的数码管段码 HIJKLMN-
uchar geci3[]={0x3f,0x73,0xbf,0x40,0xf7,0x6d,0x07,0x40}; //显示O-T的数码管段码 OPQ-RST-
uchar geci4[]={0x62,0x3e,0xf9,0x40,0xf6,0xe6,0xdb,0x40}; //显示U-Z的数码管段码 UVW-XYZ-
uchar geci5[]={0xf6,0xe6,0xdb,0x80,0x37,0x3f,0xf9,0x00}; //XYZ,Now
uchar geci51[]={0xe6,0x3f,0x62,0x00,0x6d,0x79,0x79,0x00}; //you see
uchar geci6[]={0x0f,0x39,0x77,0x37,0x00,0x6d,0x77,0xe6}; //I can say
uchar geci61[]={0x77,0x7f,0x39,0x00,0x00,0x00,0x00,0x00}; // ABC
uchar weixuan[]={0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07}; //位选码
uchar code music[] ={ //音乐代码,歌曲为《I can say ABC》,格式为: 音符, 节拍, 音符, 节拍,
0x11,0x10,0x21,0x10, //音符的十位代表是低八度,中八度还是高八度,1代表低八度,2代表中八度,3代表高八度
0x25,0x10,0x25,0x10, //个位代表简谱的音符,例如0x15代表低八度的S0,0x21代表中八度的DO。
0x26,0x10,0x26,0x10, //节拍则是代表音长,例如:0x10代表一拍,0x20代表两拍,0x05代表1/2拍
0x25,0x10,0x25,0x10, //16
0x24,0x10,0x14,0x10,
0x23,0x10,0x13,0x10,
0x22,0x10,0x22,0x10,
0x21,0x10,0x21,0x10, //32
0x25,0x10,0x25,0x10,
0x24,0x10,0x24,0x20,
0x23,0x10,0x23,0x10,
0x22,0x10,0x22,0x10, //48
0x25,0x10,0x25,0x10,
0x24,0x10,0x24,0x20,
0x23,0x10,0x23,0x10,
0x22,0x10,0x22,0x10, //64
0x21,0x10,0x21,0x10,
0x25,0x10,0x25,0x10, //72
0x26,0x10,0x26,0x10,
0x25,0x10,0x25,0x10, //80
0x24,0x10,0x24,0x10,
0x23,0x10,0x23,0x10, //88
0x22,0x10,0x22,0x10,
0x21,0x10,0x21,0x20, //96
0x00,0x00
};
uchar code quzi[] ={ //此数组数据为各个音符在定时器中的重装值,第一列是高位,第二列是低位
0xf8,0x8c, //低八度,低1
0xf9,0x5b,
0xfa,0x15, //低3
0xfa,0x67,
0xfb,0x04, //低5
0xfb,0x90,
0xfc,0x0c, //低7
0xfc,0x44, //中央C调
0xfc,0xac, //中2
0xfd,0x09,
0xfd,0x34, //中4
0xfd,0x82,
0xfd,0xc8, //中6
0xfe,0x06,
0xfe,0x22, //高八度,高1
0xfe,0x56,
0xfe,0x6e, //高3
0xfe,0x9a,
0xfe,0xc1, //高5
0xfe,0xe4,
0xff,0x03 //高7
};
void delay(unsigned int xms)
{uint i,j; for(i=xms;i>0;i--)for(j=124;j>0;j--);
}
//功能描述:在quzi数组中,找到music数组定义的简谱音符的重装值,并返回其在quzi数组中的位置
//入口参数:tem:music数组中定义的简谱音符
//出口参数:返回的是tem音符在quzi数组中的位置值
uchar quyin(uchar tem)
{uchar qudiao,jp,weizhi; //定义曲调,音符和位置qudiao=tem/16; //高4位是曲调值jp=tem%16; //低4位是音符if(qudiao==1) //当曲调值为1时,即是低八度,低八度在quzi数组中基址为0qudiao=0;else if(qudiao==2) //当曲调值为2时,即是中八度,中八度在quzi数组中基址为14qudiao=14;else if(qudiao==3) //当曲调值为3时,即是高八度,高八度在quzi数组中,基址为28qudiao=28;weizhi=qudiao+(jp-1)*2; //通过基址加上音符作为偏移量,即可定位此音符在quzi数组中的位置return weizhi; //返回这一个位置值
}
void playmusic()//播放音乐
{uchar p,m,tem; //m为节拍 while(1) { if(zanting==1) //播放或暂停控制{p=music[jindu];if(p==0x00) //如果碰到结束符,延时1秒,回到开始再来一遍 {jindu=0;delay(1000);break;} else if(p==0xff) //若碰到休止符,延时100ms,继续取下一音符{jindu++; delay(100);TR0=0; //关定时器0break;} else //正常情况下取音符和节拍 {tem=quyin(music[jindu]); //取出当前音符在quzi数组中的位置值timeh=quzi[tem]; //把音符相应的计时器重装载值赋予timeh和timeltimel=quzi[tem+1];jindu++;TH0=timeh; //把timeh和timel赋予计时器TL0=timel;m=music[jindu]; //取得节拍jindu++;} TR0=1; //开定时器0 delay(m*180); //等待节拍完成, 通过P3^4口输出音频 TR0=0; //关定时器0 beep=0; //将beep置0,以保护蜂鸣器 }}
}
//系统初始化,功能是配置IO口
void init_sys()
{P0M0=0xff; //设置推挽模式P0M1=0x00;P2M0=0x08;P2M1=0x00;P3M0=0x10;P3M1=0x00;
}
//定时器初始化
void init()
{TMOD=0x01; //设置定时器0,工作方式1,16位手动重装初值;设置定时器1,工作方式0,16位自动重装初值TH0=0xD8; //设置定时器0初值TL0=0xEF;TH1=(65536-1000)/256; //设置定时器1初值TL1=(65536-1000)%256;EA=1; //打开总中断ET0=1; //打开定时器0中断ET1=1; //打开定时器1中断TR0=0; //定时器0暂时不启动TR1=1; //启动定时器1 EX0=1; //启动外部中断0 zanting=0; //播放或暂停标志位赋初值beep=0; //将beep置0,以保护蜂鸣器
}
void main()
{init_sys(); //系统初始化init();P0=0x00; key1=1;flag=0;while(1)playmusic(); //进入播放音乐函数
}
//定时器0中断处理,重新装值,并把beep值取反,产生方波
void tim1()interrupt 1 //计时器控制频率
{TH0=timeh; //中断后重赋初值TL0=timel;beep=~beep; //中断beep翻转产生方波,使得蜂鸣器发声
}
//按下按键1的外部中断,对标志位取反,功能是暂停和播放音乐
void exint0()interrupt 0
{if(key1==0){ delay(10);if(key1==0)zanting=~zanting;}
}
//定时器1中断处理,用作数码管显示歌词。
void timer1()interrupt 3 //把显示程序提到定时器1中断服务程序
{flag++;if(flag==8)flag=0;P0=0;P2=weixuan[flag];if(jindu==0) //通过判断播放时的jindu进而控制此时的歌词显示{ //此时为零时,显示“ABC ge”switch(flag){case 0:P0=geci[0];break;case 1:P0=geci[1];break;case 2:P0=geci[2];break;case 4:P0=geci[4];break;case 5:P0=geci[5];break;default:P0=geci[3];break;}}else if(jindu<16){ //此时进度为0-15之间,显示“ABCDEFG-”switch(flag){case 0:P0=geci1[0];break;case 1:P0=geci1[1];break;case 2:P0=geci1[2];break;case 3:P0=geci1[3];break;case 4:P0=geci1[4];break;case 5:P0=geci1[5];break;case 6:P0=geci1[6];break;default:P0=geci1[7];break;}}else if(jindu<32){ //此时进度为16-31之间,显示“HIJKLMN-”switch(flag){case 0:P0=geci2[0];break; case 1:P0=geci2[1];break; case 2:P0=geci2[2];break; case 3:P0=geci2[3];break; case 4:P0=geci2[4];break; case 5:P0=geci2[5];break; case 6:P0=geci2[6];break; default:P0=geci2[7];break; }}else if(jindu<48){ //此时进度为32-47之间,显示“OPQ- RST-”switch(flag){case 0:P0=geci3[0];break; case 1:P0=geci3[1];break; case 2:P0=geci3[2];break;case 3:P0=geci3[3];break;case 4:P0=geci3[4];break;case 5:P0=geci3[5];break;case 6:P0=geci3[6];break;default:P0=geci3[7];break;}}else if(jindu<64){ //此时进度为48-63之间,显示“UVW- XYZ-”switch(flag){case 0:P0=geci4[0];break; case 1:P0=geci4[1];break; case 2:P0=geci4[2];break; case 3:P0=geci4[3];break; case 4:P0=geci4[4];break; case 5:P0=geci4[5];break; case 6:P0=geci4[6];break; default:P0=geci4[7];break; }}else if(jindu<72){ //此时进度为64-71之间,显示“XYZ- NOW”switch(flag){case 0:P0=geci5[0];break;case 1:P0=geci5[1];break;case 2:P0=geci5[2];break;case 3:P0=geci5[3];break;case 4:P0=geci5[4];break;case 5:P0=geci5[5];break;case 6:P0=geci5[6];break;default:P0=geci5[7];break;}}else if(jindu<80){ //此时进度为72-79之间,显示“YOU SEE ”switch(flag){case 0:P0=geci51[0];break; case 1:P0=geci51[1];break; case 2:P0=geci51[2];break; case 3:P0=geci51[3];break; case 4:P0=geci51[4];break; case 5:P0=geci51[5];break; case 6:P0=geci51[6];break; default:P0=geci51[7];break; }}else if(jindu<88){ //此时进度为80-87之间,显示“ICAN SAY”switch(flag){case 0:P0=geci6[0];break;case 1:P0=geci6[1];break;case 2:P0=geci6[2];break;case 3:P0=geci6[3];break;case 4:P0=geci6[4];break;case 5:P0=geci6[5];break;case 6:P0=geci6[6];break;default:P0=geci6[7];break;}}else if(jindu<96){ //此时进度为88-95之间,显示“ABC”switch(flag){case 0:P0=geci61[0];break; case 1:P0=geci61[1];break; case 2:P0=geci61[2];break; case 3:P0=geci61[3];break; case 4:P0=geci61[4];break; case 5:P0=geci61[5];break; case 6:P0=geci61[6];break; default:P0=geci61[7];break; }}
}
STC学习:可同步显示歌词的ABC英文歌相关推荐
- android 歌词同步 换行,HTML5音乐播放器同步显示歌词
歌词文件的格式 实现之前,当然得了解一下歌词文件的格式了.常规歌词文件的格式基本是一句一行,每行由两部分组成,前面是中括号括起来的时间轴,后面紧跟歌词,像下面这样:[ti:记兰生襄铃] [ar:HIT ...
- 让Windows Media Player和MP3播放器一样可以显示歌词
为了让女儿能通过唱英文歌曲来达到提高语感的目的, 咱下载了一些儿童MP3歌曲, 但是通过Media Player播放时, 却没法与MP3播放器一样可以显示歌词, 找了半下, 终于从网上找到一文章介绍如 ...
- 网页中LRC歌词同步显示
<html><head> <title>音乐歌词同步测试</title> <style> <!-- .div { width:460p ...
- Jplayer歌词同步显示插件
http://blog.csdn.net/wk313753744/article/details/38758317 1.该插件是一个jquery的编写的跟jplayer实现歌词同步的插件,最终效果如图 ...
- Jplayer歌词同步显示插件(在以前别人基础上修改)
1.该插件是一个jquery的编写的跟jplayer实现歌词同步的插件,最终效果如图: 2.首先引入jplayer的相关的js库和样式文件. <meta http-equiv="Con ...
- Android 实现歌曲播放时歌词同步显示
我们需要读取以上歌词文件的每一行转换成成一个个歌词实体: public class LyricObject { public int begintime; // 开始时间 public int end ...
- android 歌词解析 依赖,Android实现歌曲播放时歌词同步显示具体思路
我们需要读取以上歌词文件的每一行转换成成一个个歌词实体: 代码如下: public class LyricObject { public int begintime; // 开始时间 public i ...
- ffplay.c学习-6-⾳视频同步基础
ffplay.c学习-6-⾳视频同步基础 目录 ⾳视频同步策略 ⾳视频同步概念 FFmpeg中的时间单位 ⾳视频时间换算的问题 不同结构体的time_base/duration分析 不同结构体的PTS ...
- iPhone上的lrc播放器可以在播放mp3文件时显示歌词
https://apps.apple.com/cn/app/%E6%96%B0lrc%E6%92%AD%E6%94%BE%E5%99%A82/id1535214306 长久以来,在iPhone上播放l ...
- python播放音乐同步歌词范晓萱_范晓萱同步的歌词
你是不是在找范玮琪的这首同步的歌词?下面是学习啦!小编帮你整理了这首歌词的相关的资料希望对你有用! 同步的歌词 同步-(电影<陪安东尼度过漫长岁月>主题曲)-范晓萱 相隔两地的时空 默契对 ...
最新文章
- java 多线程下载器_Java多线程的下载器(1)
- 如何遍历维数和各维上限未定的多维数组
- PaperWeekly 第28期 | 图像语义分割之特征整合和结构预测
- Oracle数据库中表格的级联删除问题
- undefined reference to `clock_gettime'
- Node.js怎么处理数据库中日期类型
- 在线HTML5,CSS3,VueJS,jQuery运行测试练习工具
- 关于逻辑或的一个小小应用注意点
- 9.运输层(3)---TCP
- c语言冒泡排序法程序填空_五种数组的排序方法(C语言)Part1
- java.lang.UnsupportedOperationException WebView is not allowed in privileged processes
- docker 删除镜像
- BAT大厂面试精选的62道高频面试题【笔试+算法+代码+逻辑题等】
- 谈谈PRNU 光响应非均匀性
- 瑞星客户端卸载操作手册
- chrome更新后,再次使用selenium打开chrome却发现闪退了?全网最详细教程,肯定能帮到你!
- sql_update
- Python自动化运维 - day9 - 进程与线程
- 《宣州谢眺楼饯别校书叔云》 李白诗两首
- live555直播startplaying
热门文章
- Nagios中NSClient++监控Windows主机
- Bash之正则表达式
- 2月中国万网域名总量净增2.1万个 份额突破24%
- 浅谈管道模型(Pipeline)
- 华为主题锁屏壁纸换不掉_华为手机中的这些默认设置一定要改,不然会导致手机卡顿加快耗电...
- SpringBoot Security 整合 thymeleaf 模板自定义登录页面,按需提示错误信息
- ARM开发6.3.1 基础实训( 1 ) 单个数码 LED 的显示输出系统设计( 1)--LPC21XX
- 程序转换实验程序流程图_智能化实验室 | # 自动智能化实验室的5大系统 #
- mac 搭建mysql环境_Mac下MySQL环境搭建的步骤详解
- abb外部轴零位校准_【ABB】ABB机器人外部轴参数(KpKvTi)调试