main.c
c#include<reg52.h>
#include<intrins.h>
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#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; //1
sbit eranjian = P1 ^ 6; //1
sbit sananjian = P1 ^ 7; //1
/* ****************************************** */
// ******** 程序变量定义
/* ****************************************** */
unsigned int C; //储存定时器的定时常数
unsigned char u, t; //音乐所用的变量
unsigned char velocity = 60; //控制节拍使用的 这里100表示一个拍子100ms
unsigned char press_key = 0; //按键 按下后会改变数值 初始值为0
unsigned char open_flag = 1; //暂停时为0 播放时为1
unsigned 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
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^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=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)
{
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);
}
本文作者:Dong
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 CC BY-NC。本作品采用《知识共享署名-非商业性使用 4.0 国际许可协议》进行许可。您可以在非商业用途下自由转载和修改,但必须注明出处并提供原作者链接。 许可协议。转载请注明出处!