
c展开代码#include <reg52.h>
#include <intrins.h>
#include "lcd1602.h"
//按键1 暂停播放
//按键2 上一首
//按键3 下一首
//按键4  加速播放
//按键5  减速播放
#define uchar unsigned char 
#define uint 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 ^ 6;    //蜂鸣器
/*  ******************************************    */
//  ********   程序变量定义
/*  ******************************************    */
unsigned int C;     //储存定时器的定时常数
unsigned char u, t;  //音乐所用的变量
unsigned char velocity = 60; //控制节拍使用的 这里100表示一个拍子100ms
unsigned char press_key = 0; //按键  按下后会改变数值  初始值为0
unsigned char open_flag = 0; //暂停时为0  播放时为1
unsigned char music_crr = 0; //当前是播放哪一首音乐  可以为0  1  2  分别是是三首歌
unsigned char code name0[]="1 TianKongZC    ";
unsigned char code name1[]="2 LiangZhiLaoHu ";
unsigned char code name2[]="3 MoLiHua       ";
unsigned char code name3[]="4 XiaoXingXing  ";
unsigned char  *song_name[]={name0,name1,name2,name3};
/*  ******************************************    */
//  ********  音乐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, /**/32};
/*  ******************************************    */
//  ********   音乐1
/*  ******************************************    */
unsigned int code music1[]=
{ Z1,Z2,Z3,Z1,Z1,Z2,Z3,Z1,Z3,Z4,Z5,Z3,Z4,Z5,Z5,Z6,Z5,Z4,
 Z3,Z1,Z5,Z6,Z5,Z4,Z3,Z1,Z2,L5,Z1,Z2,L5,Z1,0xff}; //以0xff作为音符的结束标志      
//以下是简谱中每个音符的节拍
//"4"对应4个延时单位,"2"对应2个延时单位,"1"对应1个延时单位 
unsigned char code music1_JP[ ]=
{ 8,8,8,8,8,8,8,8,8,8,8,8,8,8,4,4,4,4,8,8,4,4,4,4,8,8,8,8,16,8,8,8,1};
/*  ******************************************    */
//  ********   音乐2
/*  ******************************************    */
unsigned int code music2[]=
{ 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 music2_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};
 /*  ******************************************    */
//  ********   音乐3 小星星
/*  ******************************************    */
unsigned int code music3[]=
{ 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 music3_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
};
/*  ******************************************    */
//  ********   延时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;
}
#define GPIO_KEY P3
/* 矩阵键盘扫描 电子琴 */
unsigned char ScanKey( void )
{
 char a = 0;
 unsigned char map[]={3,7,11,15,2,6,10,14,1,5,9,13,0,4,8,12};
 unsigned char KeyValue = 0xff;
 GPIO_KEY = 0x0f;
 if ( GPIO_KEY != 0x0f )         /* 读取按键是否按下 */
 {
  delay( 5 );             /* 延时10ms进行消抖 */
  if ( GPIO_KEY != 0x0f ) /* 再次检测键盘是否按下 */
  {
   /* 测试列 */
   GPIO_KEY = 0X0F;
   switch ( GPIO_KEY )
   {
   case (0X07):
    KeyValue = 0;
    break;
   case (0X0b):
    KeyValue = 1;
    break;
   case (0X0d):
    KeyValue = 2;
    break;
   case (0X0e):
    KeyValue = 3;
    break;
   }
   /* 测试行 */
   GPIO_KEY = 0XF0;
   switch ( GPIO_KEY )
   {
   case (0X70):
    KeyValue = KeyValue;
    break;
   case (0Xb0):
    KeyValue = KeyValue + 4;
    break;
   case (0Xd0):
    KeyValue = KeyValue + 8;
    break;
   case (0Xe0):
    KeyValue = KeyValue + 12;
    break;
   }
   while ( (a < 100) && (GPIO_KEY != 0xf0) ) /* 检测按键松手检测 */
   {
    delay( 10 );
    a++;
   }
   KeyValue=map[KeyValue]+1;
  }
 }
 return KeyValue;//返回按键
}
/*  ******************************************    */
//  ********   处理按键 按下按键后 相应变量改变 
/*  ******************************************    */
void delay_key(void)
{
 if (press_key == 1)  //暂停控制
 {
  press_key = 0;
  if (open_flag == 0)
  {
   open_flag = 1;   //开始
  } else
  {
   open_flag = 0;   //暂停
  }
 }
 if (press_key == 2)   //上一首
 {
  press_key = 0;
  if (music_crr > 0)
  {
   music_crr = (music_crr - 1) % 4;
  } else
  {
   music_crr = 3;   //如果是第0首歌  那么按上一首就是第3首
  }
  LCD_write_str(0,0,song_name[music_crr]);//显示歌名
 }
 if (press_key == 3)   //下一首
 {
  press_key = 0;
  music_crr = (music_crr + 1) % 4;
  LCD_write_str(0,0,song_name[music_crr]);//显示歌名
 }
 if (press_key == 4)    //加快播放速度
 {
  press_key = 0;
  velocity = velocity - 5;
 }
 if (press_key == 5)    //降低播放速度
 {
  press_key = 0;
  velocity = velocity + 5;
 }
}
/*  ******************************************    */
//  ********   主函数 程序逻辑
/*  ******************************************    */
void main()
{
 LCD_init();
 init_timer();
 TR1 = 0;     //关闭定时器
 sound = 1;  //关闭蜂鸣器
 open_flag = 0; //关闭音乐
 LCD_write_str(0,0,song_name[music_crr]);//显示歌名
 while (1)
 {
  press_key = ScanKey();   //获取按下的键
  delay_key();   //将按下的键值传入处理函数 改变状态变量
  if (music_crr == 0 && open_flag == 1)
  {
   u = 0;   //从第1个音符f[0]开始播放
   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
    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]开始播放
   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
    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]开始播放
   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
    for (t = 0; t < music2_JP[u] / 2; t++)  //控制节拍数
     delay1();          //延时1个节拍单位
    TR1 = 0;                   //关闭定时器T1
    u++;                        //播放下一个音符
   }
   init_timer();
   TR1 = 0;     //关闭定时器
   sound = 1;  //关闭蜂鸣器
  }
  if (music_crr == 3 && open_flag == 1)
  {
   u = 0;   //从第1个音符f[0]开始播放
   while (music2[u] != 0xff)            //只要没有读到结束标志就继续播放
   {
    press_key = ScanKey();   //获取按下的键
    delay_key();   //将按下的键值传入处理函数 改变状态变量
    if (music_crr != 3)    //切换音乐
    {
     init_timer();
     TR1 = 0;     //关闭定时器
     sound = 1;  //关闭蜂鸣器
     break;
    }
    if (open_flag == 0) //如果暂停音乐
    {
     while (open_flag == 0)
     {
      press_key = ScanKey();   //获取按下的键
      delay_key();   //将按下的键值传入处理函数 改变状态变量
     }
    }
    C = 460830 / music3[u];
    TH1 = (8192 - C) / 32;   //可证明这是13位计数器TH0高8位的赋初值方法     5
    TL1 = (8192 - C) % 32;   //可证明这是13位计数器TL0低5位的赋初值方法
    TR1 = 1;             //启动定时器T0
    for (t = 0; t < music3_JP[u] ; 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位的赋初值方法 
}
c展开代码#include <reg52.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*
LCD_init();
LCD_write_str(1,1,"2223123");
*/
sbit lcd_rs=P2^4;
sbit lcd_rw=P2^5;
sbit lcd_en=P2^6;
#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=1
void 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) 
{
    if (y == 0) 
    {
     LCD_write_com(0x80 + x);        //第一行显示
    }
    else 
    {
     LCD_write_com(0xC0 + x);        //第二行显示
    }
    while (*s) 
    {
     LCD_write_data( *s);
     s ++;
    }
}
//***********************************************************************
// 显示屏初始化函数
//***********************************************************************
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);
}


本文作者:Dong
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 CC BY-NC。本作品采用《知识共享署名-非商业性使用 4.0 国际许可协议》进行许可。您可以在非商业用途下自由转载和修改,但必须注明出处并提供原作者链接。 许可协议。转载请注明出处!