博客
关于我
51单片机 音乐播放器
阅读量:362 次
发布时间:2019-03-04

本文共 14526 字,大约阅读时间需要 48 分钟。

在这里插入图片描述

在这里插入图片描述
main.c

#include
#include
#include
#include
#include
#include "lcd1602.h"#define uchar unsigned char #define uint unsigned int#define u8 unsigned char #define u16 unsigned int//以下是C调低音的音频宏定义#define L1 262 //将"L1"宏定义为低音"1"的频率262Hz 时间是1/262=3826/2 us 取半周期#define L2 286 //将"L2"宏定义为低音"2"的频率286Hz#define L3 311 //将"L3"宏定义为低音"3"的频率311Hz#define L4 349 //将"L4"宏定义为低音"4"的频率349Hz#define L5 392 //将"L5"宏定义为低音"5"的频率392Hz#define L6 440 //将"l_a"宏定义为低音"6"的频率440Hz#define L7 494 //将"L7"宏定义为低音"7"的频率494Hz//以下是C调中音的音频宏定义#define Z1 523 //将"Z1"宏定义为中音"1"的频率523Hz#define Z2 587 //将"Z2"宏定义为中音"2"的频率587Hz#define Z3 659 //将"Z3"宏定义为中音"3"的频率659Hz#define Z4 698 //将"Z4"宏定义为中音"4"的频率698Hz#define Z5 784 //将"Z5"宏定义为中音"5"的频率784Hz#define Z6 880 //将"Z6"宏定义为中音"6"的频率880Hz#define Z7 987 //将"Z7"宏定义为中音"7"的频率523H //以下是C调高音的音频宏定义#define H1 1046 //将"H1"宏定义为高音"1"的频率1046Hz#define H2 1174 //将"H2"宏定义为高音"2"的频率1174Hz#define H3 1318 //将"H3"宏定义为高音"3"的频率1318Hz#define H4 1396 //将"H4"宏定义为高音"4"的频率1396Hz#define H5 1567 //将"H5"宏定义为高音"5"的频率1567Hz#define H6 1760 //将"H6"宏定义为高音"6"的频率1760Hz#define H7 1975 //将"H7"宏定义为高音"7"的频率1975Hz/* ****************************************** */// ******** 硬件端口定义 /* ****************************************** */sbit sound = P1 ^ 4; //蜂鸣器sbit KAISHI = P1 ^ 0; //开始sbit ZANTING = P1 ^ 1; //暂停sbit PRE_KEY = P1 ^ 2; //上一首sbit NEXT_KEY = P1 ^ 3; //下一首sbit yianjian = P1 ^ 5; //1sbit eranjian = P1 ^ 6; //1sbit sananjian = P1 ^ 7; //1/* ****************************************** */// ******** 程序变量定义/* ****************************************** */unsigned int C; //储存定时器的定时常数unsigned char u, t; //音乐所用的变量unsigned char velocity = 60; //控制节拍使用的 这里100表示一个拍子100msunsigned char press_key = 0; //按键 按下后会改变数值 初始值为0unsigned char open_flag = 1; //暂停时为0 播放时为1unsigned char music_crr = 0; //当前是播放哪一首音乐 可以为0 1 2 分别是是三首歌char rtc_hour = 0;char rtc_min = 0;char rtc_sec = 0;char num2 = 0; /* 计数 *//* ****************************************** */// ******** 音乐0 天空之城/* ****************************************** *///以下是《天空之城》简谱 //每行对应一小节音符unsigned int code music0[]={ Z6,Z7,/**/H1,Z7,H1,H3,/**/Z7,Z3,Z3, /**/Z6,Z5,Z6,H1,/**/Z5,Z3,Z3, /**/Z4,Z3,Z4,H1, Z3,H1,H1,H1,/**/Z7,Z4,Z4,Z7,/**/Z7,Z6,Z7, /**/H1,Z7,H1,H3,/**/Z7,Z3,Z3, /**/Z6,Z5,Z6,H1, Z5, Z3,/**/Z4,H1,Z7,H1,/**/H2,H2,H2,H1,/**/H1,Z6,Z7,Z5,/**/Z6,H1,H2, /**/H3,H2,H3,H5, H2,Z5,Z5, /**/H1,Z7,H1,H3,/**/H3, /**/Z6,H1,Z7,H2,/**/H1,Z5,Z5, /**/H4,H3,H2,H1, H3, /**/Z3,H3, /**/H6,H5,H5, /**/H3,H2,H1,H1,/**/H2,H1,H2,H5,/**/H3,H3, H6,H5, /**/H3,H2,H1,H1,/**/H2,H1,H2,Z7,/**/Z6,Z6,Z7, /**/Z6,0xff}; //以0xff作为音符的结束标志 //以下是简谱中每个音符的节拍//"4"对应4个延时单位,"2"对应2个延时单位,"1"对应1个延时单位 unsigned char code music0_JP[ ]={ 4,4, /**/12,4,8,8, /**/20,4,4, /**/12,4,8,8, /**/20,4,4, /**/12,4,4,12, 20,4,4,4, /**/12,4,8,8, /**/20,4,4, /**/12,4,8,8, /**/20,4,4, /**/12,4,8,8, 32, 4, /**/8,4,6,8, /**/4,4,4,16, /**/8,4,6,8, /**/24,4,4, /**/12,4,8,8, 24,4,4, /**/4,4,8,8, /**/32, /**/4,8,8,6, /**/12,4,16, /**/8,8,8,8, 30, /**/20,8, /**/16,8,8, /**/4,4,16,8, /**/8,4,4,8, /**/20,8, 16,16, /**/4,20,8, /**/8,4,4,8, /**/20,4,4,8,8, /**/8};/* ****************************************** */// ******** 音乐2/* ****************************************** */unsigned int code music1[]={ Z3,Z3,Z5,Z6,H1,H1,Z6, Z5,Z5,Z6,Z5, Z3,Z3,Z5,Z6,H1,H1,Z6, Z5,Z5,Z6,Z5, Z5,Z5,Z5,Z3,Z5, Z6,Z6,Z5, Z3,Z2,Z3,Z5,Z3,Z2, Z1,Z1,Z2,Z1,0xff}; //以0xff作为音符的结束标志 //以下是简谱中每个音符的节拍//"4"对应4个延时单位,"2"对应2个延时单位,"1"对应1个延时单位 unsigned char code music1_JP[ ]={ 16,8,8,8,8,8,8, 16,8,8,32, 16,8,8,8,8,8,8, 16,8,8,32, 16,16,16,8,8, 16,16,32, 16,8,8,16,8,8, 16,8,8,32,1,8,8};/* ****************************************** */// ******** 音乐3 小星星/* ****************************************** */unsigned int code music2[]={ H3,H3,H3,H2,H1,H2,H5,H5,H1,H1,H1,H1,Z6, Z7,H3,H3,Z5,Z6,H6,H5,H4,H3,H2,H1,H1, Z6,H1,H2,H5,H5,H2,H1,H2,H2,Z1,H3,H3, H3,H2,H1,H2,H5,H5,H1,H1,H1,H1,Z6,Z7, H3,H3,Z5,Z6,H6,H5,H4, H3,H2,H1,H1,Z6,H1,H2,H5,H5,Z5,H2,H1, 0xff}; //以0xff作为音符的结束标志 //以下是简谱中每个音符的节拍//"4"对应4个延时单位,"2"对应2个延时单位,"1"对应1个延时单位 unsigned char code music2_JP[ ]={ 8,2,2,2,2,4,4,8, 8,2,2,2,2, 4,4,4,4,8,4,2,2,4,2,2,8, 2,2,2,2,2,2,2,2,8,8,8,2,2,2,2,4,4,8,8,2,2,2,2,4,4,4,4,8,4,2,2, 8,2,2,4,2,2,2,2,2,2,4,12,8,8};/* ****************************************** */// ******** 延时1ms 用于一般延时/* ****************************************** */void delay(uint z){ uint x; while (z--) { for (x = 125; x > 0; x--) ; }}/* ****************************************** */// ******** 延时100ms 控制音乐节拍/* ****************************************** */void delay1(){ uint i, j; for (i = 0; i < velocity; i++) for (j = 0; j < 125; j++) ;}/* ****************************************** */// ******** 定时器初始化函数 用了定时器1/* ****************************************** */void init_timer(void){ EA = 1; //开总中断 ET1 = 1; //定时器T1中断允许 TMOD &= 0x0f; TMOD |= 0x00; // 使用定时器T1的模式1(13位计数器) TR1 = 1; TMOD |= 0x01; // 使用定时器T1的模式1(13位计数器) TR0 = 1; ET0 = 1; //定时器T1中断允许}/* ****************************************** */// ******** 按键扫描 返回值 1 2 3 4 5 代表五个按键/* ****************************************** */unsigned char ScanKey(void){ if (KAISHI == 0) //是否按下 { delay(1); //延时防止电平抖动 if (KAISHI == 0) { while (KAISHI == 0) ; //等待松开 return 1; } } if (ZANTING == 0) { delay(1); if (ZANTING == 0) { while (ZANTING == 0) ; return 2; } } if (PRE_KEY == 0) { delay(1); if (PRE_KEY == 0) { while (PRE_KEY == 0) ; return 3; } } if (NEXT_KEY == 0) { delay(1); if (NEXT_KEY == 0) { while (NEXT_KEY == 0) ; return 4; } } if (yianjian == 0)//选择第1首歌的按键按下 { delay(1); if (yianjian == 0) { while (yianjian == 0) ; return 5; } } if (eranjian == 0) //选择第二首歌的按键按下 { delay(1); if (eranjian == 0) { while (eranjian == 0) ; return 6; } } if (sananjian == 0)//选择第3首歌的按键按下 { delay(1); if (sananjian == 0) { while (sananjian == 0) ; return 7; } } return 0;}/* ****************************************** */// ******** 处理按键 按下按键后 相应变量改变 /* ****************************************** */void delay_key(void){ if (press_key == 1) //开始 { open_flag = 1; //开始 press_key = 0; } if (press_key == 2) //暂停 { open_flag = 0; //暂停 press_key = 0; } if (press_key == 3) //上一首 { press_key = 0; if (music_crr > 0) { music_crr = (music_crr - 1) % 3; } else { music_crr = 2; //如果是第0首歌 那么按上一首就是第2首 } LCD_write_char(9,0,music_crr+'1');//显示歌曲号 rtc_hour=0;rtc_min=0; rtc_sec=0; } if (press_key == 4) //下一首 { press_key = 0; music_crr = (music_crr + 1) % 3; LCD_write_char(9,0,music_crr+'1'); //显示歌曲号 rtc_hour=0;rtc_min=0; rtc_sec=0; } if (press_key == 5) //1 { press_key = 0; music_crr=0; LCD_write_char(9,0,music_crr+'1'); //显示歌曲号 rtc_hour=0;rtc_min=0; rtc_sec=0; open_flag = 1; //开始 } if (press_key == 6) //2 { press_key = 0; music_crr=1; LCD_write_char(9,0,music_crr+'1'); //显示歌曲号 rtc_hour=0;rtc_min=0; rtc_sec=0; open_flag = 1; //开始 } if (press_key == 7) //3 { press_key = 0; music_crr=2; LCD_write_char(9,0,music_crr+'1'); //显示歌曲号 rtc_hour=0;rtc_min=0; rtc_sec=0; open_flag = 1; //开始 } if (open_flag == 1) { TR0=1; }else { TR0=0; } LCD_dis_TIME( 6, 1, rtc_hour, rtc_min, rtc_sec );}uint changdu = 0;/* ****************************************** */// ******** 主函数 程序逻辑/* ****************************************** */void main(){ LCD_init(); LCD_write_str(0,0," WELCOME!"); delay(1000); LCD_write_str(0,0,"Playing: "); LCD_write_char(9,0,'1'); LCD_write_str(0,1,"Time:"); LCD_dis_TIME( 6, 1, rtc_hour, rtc_min, rtc_sec ); init_timer(); TR1 = 0; //关闭定时器 sound = 0; //关闭蜂鸣器 open_flag = 0; //关闭音乐 TR0 = 0; //关闭定时器 LCD_dis_TIME( 6, 1, rtc_hour, rtc_min, rtc_sec ); while (1) { press_key = ScanKey(); //获取按下的键 delay_key(); //将按下的键值传入处理函数 改变状态变量 if (music_crr == 0 && open_flag == 1) { u = 0; //从第1个音符f[0]开始播放 changdu = sizeof(music0); while (music0[u] != 0xff) //只要没有读到结束标志就继续播放 { press_key = ScanKey(); //获取按下的键 delay_key(); //将按下的键值传入处理函数 改变状态变量 if (music_crr != 0) //切换音乐 { init_timer(); TR1 = 0; //关闭定时器 sound = 1; //关闭蜂鸣器 break; } if (open_flag == 0) //如果暂停音乐 { while (open_flag == 0) { press_key = ScanKey(); //获取按下的键 delay_key(); //将按下的键值传入处理函数 改变状态变量 } } C = 460830 / music0[u]; TH1 = (8192 - C) / 32; //可证明这是13位计数器TH0高8位的赋初值方法 5 TL1 = (8192 - C) % 32; //可证明这是13位计数器TL0低5位的赋初值方法 TR1 = 1; //启动定时器T0 changdu--; for (t = 0; t < music0_JP[u]; t++) //控制节拍数 delay1(); //延时1个节拍单位 TR1 = 0; //关闭定时器T1 u++; //播放下一个音符 } init_timer(); TR1 = 0; //关闭定时器 sound = 1; //关闭蜂鸣器 } if (music_crr == 1 && open_flag == 1) { u = 0; //从第1个音符f[0]开始播放 changdu = sizeof(music1); while (music1[u] != 0xff) //只要没有读到结束标志就继续播放 { press_key = ScanKey(); //获取按下的键 delay_key(); //将按下的键值传入处理函数 改变状态变量 if (music_crr != 1) //切换音乐 { init_timer(); TR1 = 0; //关闭定时器 sound = 1; //关闭蜂鸣器 break; } if (open_flag == 0) //如果暂停音乐 { while (open_flag == 0) { press_key = ScanKey(); //获取按下的键 delay_key(); //将按下的键值传入处理函数 改变状态变量 } } C = 460830 / music1[u]; TH1 = (8192 - C) / 32; //可证明这是13位计数器TH0高8位的赋初值方法 5 TL1 = (8192 - C) % 32; //可证明这是13位计数器TL0低5位的赋初值方法 TR1 = 1; //启动定时器T0 changdu--; for (t = 0; t < music1_JP[u]; t++) //控制节拍数 delay1(); //延时1个节拍单位 TR1 = 0; //关闭定时器T1 u++; //播放下一个音符 } init_timer(); TR1 = 0; //关闭定时器 sound = 1; //关闭蜂鸣器 } if (music_crr == 2 && open_flag == 1) { u = 0; //从第1个音符f[0]开始播放 changdu = sizeof(music2); while (music2[u] != 0xff) //只要没有读到结束标志就继续播放 { press_key = ScanKey(); //获取按下的键 delay_key(); //将按下的键值传入处理函数 改变状态变量 if (music_crr != 2) //切换音乐 { init_timer(); TR1 = 0; //关闭定时器 sound = 1; //关闭蜂鸣器 break; } if (open_flag == 0) //如果暂停音乐 { while (open_flag == 0) { press_key = ScanKey(); //获取按下的键 delay_key(); //将按下的键值传入处理函数 改变状态变量 } } C = 460830 / music2[u]; TH1 = (8192 - C) / 32; //可证明这是13位计数器TH0高8位的赋初值方法 5 TL1 = (8192 - C) % 32; //可证明这是13位计数器TL0低5位的赋初值方法 TR1 = 1; //启动定时器T0 changdu--; for (t = 0; t < music2_JP[u] / 2; t++) //控制节拍数 delay1(); //延时1个节拍单位 TR1 = 0; //关闭定时器T1 u++; //播放下一个音符 } init_timer(); TR1 = 0; //关闭定时器 sound = 1; //关闭蜂鸣器 } }}void Time1(void)interrupt 3 //T1定时器的中断等级要注意 是3{ sound=!sound; //将P3.7引脚输出电平取反,形成方波 TH1=(8192-C)/32;//可证明这是13位计数器TH0高8位的赋初值方法 TL1=(8192-C)%32;//可证明这是13位计数器TL0低5位的赋初值方法 }void Time0(void)interrupt 1 //T1定时器的中断等级要注意 是3{ TH0=(65535-50000)/255; //可证明这是13位计数器TH0高8位的赋初值方法 TL0=(65535-50000)%255;//可证明这是13位计数器TL0低5位的赋初值方法 num2++; if ( num2 == 20 ) { num2 = 0; rtc_sec++; if ( rtc_sec == 60 ) { rtc_sec = 0; rtc_min++; if ( rtc_min == 60 ) { rtc_min = 0; rtc_hour++; if ( rtc_hour == 24 ) { rtc_hour = 0; } } } } }

lcd1602.h

#include 
#include
#include
#include
/*LCD_init();LCD_write_str(1,1,"2223123");*/sbit lcd_rs=P2^5;sbit lcd_rw=P2^6;sbit lcd_en=P2^7;#define DataPort P0#define RS_CLR lcd_rs=0#define RS_SET lcd_rs=1#define RW_CLR lcd_rw=0#define EN_CLR lcd_en=0#define EN_SET lcd_en=1void delay_lcd_ms(unsigned int a) { unsigned int i, j; for (i = a; i > 0; i--) for (j = 100; j > 0; j--) ;}//***********************************************************************// 显示屏命令写入函数//***********************************************************************void LCD_write_com(unsigned char com) { RS_CLR; RW_CLR; EN_SET; DataPort = com; //命令写入端口 delay_lcd_ms(5); EN_CLR;}//***********************************************************************// 显示屏数据写入函数//***********************************************************************void LCD_write_data(unsigned char dataa) { RS_SET; RW_CLR; EN_SET; DataPort = dataa; //数据写入端口 delay_lcd_ms(5); EN_CLR;}//***********************************************************************// 显示屏单字符写入函数//***********************************************************************void LCD_write_char(unsigned char x,unsigned char y,unsigned char dataa) { if (y == 0) { LCD_write_com(0x80 + x); //第一行显示 } else { LCD_write_com(0xC0 + x); //第二行显示 } LCD_write_data( dataa); }//***********************************************************************// 显示屏字符串写入函数//***********************************************************************void LCD_write_str(unsigned char x,unsigned char y,unsigned char *s) { EA=0; if (y == 0) { LCD_write_com(0x80 + x); //第一行显示 } else { LCD_write_com(0xC0 + x); //第二行显示 } while (*s) { LCD_write_data( *s); s ++; } EA=1;}//***********************************************************************// 显示一个数字 传入坐标和数值//***********************************************************************void LCD_dis_TIME(unsigned char x,unsigned char y, int hour,int min,int sec) { char disp[10]; memset(disp,0,10); sprintf(disp,"%02d:%02d:%02d",hour,min,sec); LCD_write_str(x,y,disp); }//***********************************************************************// 显示屏初始化函数//***********************************************************************void LCD_init(void) { LCD_write_com(0x38); //显示模式设置 delay_lcd_ms(5); LCD_write_com(0x38); //显示模式设置 delay_lcd_ms(5); LCD_write_com(0x38); //显示模式设置 delay_lcd_ms(5); LCD_write_com(0x38); //显示模式设置 delay_lcd_ms(5); LCD_write_com(0x08); //显示关闭 delay_lcd_ms(5); LCD_write_com(0x01); //显示清屏 delay_lcd_ms(5); LCD_write_com(0x06); //显示光标移动设置 delay_lcd_ms(5); LCD_write_com(0x0C); //显示开及光标设置 delay_lcd_ms(5);}

转载地址:http://fkce.baihongyu.com/

你可能感兴趣的文章
MySQL 到底能不能放到 Docker 里跑?
查看>>
mysql 前缀索引 命令_11 | Mysql怎么给字符串字段加索引?
查看>>
MySQL 加锁处理分析
查看>>
mysql 协议的退出命令包及解析
查看>>
mysql 参数 innodb_flush_log_at_trx_commit
查看>>
mysql 取表中分组之后最新一条数据 分组最新数据 分组取最新数据 分组数据 获取每个分类的最新数据
查看>>
MySQL 命令和内置函数
查看>>
MySQL 和 PostgreSQL,我到底选择哪个?
查看>>
mysql 四种存储引擎
查看>>
MySQL 在并发场景下的问题及解决思路
查看>>
MySQL 在控制台插入数据时,中文乱码问题的解决
查看>>
MySQL 基础架构
查看>>
MySQL 基础模块的面试题总结
查看>>
MySQL 处理插入重主键唯一键重复值办法
查看>>
MySQL 备份 Xtrabackup
查看>>
mysql 复杂查询_mysql中复杂查询
查看>>
mYSQL 外键约束
查看>>
mysql 多个表关联查询查询时间长的问题
查看>>
mySQL 多个表求多个count
查看>>
mysql 多字段删除重复数据,保留最小id数据
查看>>