基于 STC89C52 的计时器、倒计时、音乐播放

52单片机课设,基于普中STC89C52的计时器、倒计时、音乐播放。使用了蜂鸣器、矩阵键盘、数码管、定时器等。附带代码以及Proteus仿真,最右边的显示的是工作模式,2为倒计时,1为闹钟计时,3为音乐播放茉莉花。
最近找工作有点头疼,什么都学过但是又只学上皮毛,电子硬件Layout嵌入式也只是了解,最想找的还是模拟版图却没人招,BOSS上投的第一个就碰到的招骗培,唉。
请添加图片描述
闹钟计时
请添加图片描述

分析使人进步,copy使人落后。

/*
        Timer.c is a c source file for C51 team project.
        Version:               15(Final version,total 15)
        Author:                isYou/Aston/CSDN-yukPung
        Link:					https://blog.csdn.net/qq_36770091/article/details/142071464
        Time:                  2023.04.27(Before 51 vacation)
        Title:                 Timer
        Project:               A simple timer
        Device model:           Prechin STC A2
        HAPPY VACATION
*/


#include<reg52.h>
#define uint unsigned int
#define uchar unsigned char

//管脚定义
#define ledio P0                    //led段码输出管脚
#define ButtonIO P1                 //独立键盘管脚

sbit a=P2^2;                        //P2.2口位码输出
sbit b=P2^3;                        //P2.3口位码输出
sbit c=P2^4;                        //P2.4口位码输出
sbit buzz=P2^5;                     //P2.5口蜂鸣器输出
//uint button;

/*
    变量说明
    lednum[]        数码管0-9编码,10为横杠,11为空 
    ledcur[]        数码管当前显示状态,0-7分别从左到右对应第几个数码管
    workstatus[]    工作模式,0为等待输入,1为计时,2为倒计时,3为播放音乐
    model[]         存放着从低八度到高八度的每一个音的换算频率
    music[]         播放曲子用的音符
    beat[]          每一个音符对应的拍子,一个beat为250ms,一个节拍为1秒,速度60
*/

uchar code lednum[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x40,0x00};
uchar code workstatus[]={0x3f,0x06,0x5b,0x4f};
code unsigned char model[37]={
							191,180,170,161,151,143,135,128,120,114,107,101,
							96,90,85,80,76,72,68,64,60,57,54,51,
							48,45,43,40,38,36,34,32,30,28,27,25,
							0};
code unsigned char music[]={36,17,16,17,16,17,12,15,13,10,
							1,5,10,12,
							5,9,12,13,
							5,17,16,17,16,17,12,15,13,10,
							1,5,10,12,
							5,13,12,10};
code unsigned char beat[]={36,1,1,1,1,1,1,1,1,3,
							1,1,1,3,
							1,1,1,3,
							1,1,1,1,1,1,1,1,1,3,
							1,1,1,3,
							1,1,1,3};
uint ledcur[]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
uint timeB[]={0,0,0,0};

void flushled(uint ms);                 //刷新LED屏幕显示
void delay(uint ms,uint val);           //定时器延时函数
void playmusic();                       //播放音乐函数
void timer_button(uint type);           //获取用户自定时间,传递给倒计时和计时器
uint getButton();                       //获取按钮函数
uint timecounter(uint min,uint sec);    //计时器函数
uint cutdown(uint min,uint sec);        //倒计时函数

void main()
{
    uint button;
    while(1)
    {
        button=getButton();
        ledcur[7]=workstatus[0];
        
        switch(button)
        {
            case(67):timer_button(2);break;
            case(80):playmusic();break;
            case(55):break;
            case(84):timer_button(1);break;
            default:break;break;
        }
        
        flushled(10);
        delay(10,0x38);
    }
}

/*
    函数名:    getButton()
    作用:      获取键盘输入、消抖、返回键盘的预设值
*/
uint getButton()
{
/*	键盘说明 :
	[9] [8] [7] [C] | [0x77] [0x7b] [0x7d] [0x7e]
	[6] [5] [4] [T] | [0xb7] [0xbb] [0xbd] [0xbe]
	[3] [2] [1] [P] | [0xd7] [0xdb] [0xdd] [0xde]
	[0] [Y] [N] [B] | [0xe7] [0xeb] [0xed] [0xee]
	
	Y:确定            C:倒计时模式 
	N:取消            T:计时器模式 
	B:回主菜单        P:播放音乐 
    
    变量说明:
	button:    最终预设的键盘值
	buttona:   保存的列键值
	buttonb:   保存的行键值
	buttonc:   列键值与行键值相或
*/ 
	uint button,buttona,buttonb,buttonc;
    button=buttona=buttonb=buttonc=0x00;
	button=55;                      //键盘初始化值55

	ButtonIO=0x0f;                  //列检测,判断是否有键按下
	if(ButtonIO!=0x0f)
	{
		delay(1,0x38);              //消抖
		if(ButtonIO!=0x0f)
		{
			ButtonIO=0x0f;          //再次检测列
			buttona=ButtonIO;       //保存列键值

			ButtonIO=0xf0;          //检测行
			buttonb=ButtonIO;       //保存行键值
		}
		while(ButtonIO!=0xf0);      //等待键松开
	}
	
	buttonc=(buttona|buttonb);      //将两次结果相或
	
	//判断按键类型
	switch(buttonc)
	{
		case(0x77):button=9;break;
		case(0x7b):button=8;break;
		case(0x7d):button=7;break;
		case(0xb7):button=6;break;
		case(0xbb):button=5;break;
		case(0xbd):button=4;break;
		case(0xd7):button=3;break;
		case(0xdb):button=2;break;
		case(0xdd):button=1;break;
		case(0xe7):button=0;break;
		case(0xeb):button=89;break;	//Y 89 为其ASCII码 
		case(0xed):button=78;break;	//N 78
		case(0xee):button=66;break;	//B 66
		case(0x7e):button=67;break;	//C 67
		case(0xbe):button=84;break;	//T 84
		case(0xde):button=80;break;	//P 80
	}
	return button;                  //返回对应的预设键值
}

/*
    函数名:timecounter()
    参数:
        min:从键盘输入的分,开始计时时用来计时分
        sec:从键盘输入的秒,开始计时时用来计时秒
    作用:当输入了分与秒时,该函数可以从0:0计数到设定的分秒
          若没有设定分秒,则无限计时,可以由B键打断
*/
uint timecounter(uint min,uint sec)
{
/*
    变量解释
    i       循环计数用变量
    min_s   保存键盘输入的分设定值
    sec_s   保存键盘输入的秒设定值
*/
    uint i,min_s,sec_s;
    min_s=min;sec_s=sec;
    i=min=sec=0;

    while(1)
    {
        //ledcur[7]=workstatus[2];
        ledcur[0]=lednum[min/10];           //分离分的十位
        ledcur[1]=lednum[(min-min/10*10)];  //分离分的个位
        ledcur[2]=lednum[10];               //中间的横线
        ledcur[3]=lednum[sec/10];           //分离秒的十位
        ledcur[4]=lednum[(sec-sec/10*10)];  //分离秒的个位

        if(sec_s==0&&min_s==0)              //判断有没有输入值,如果没有输入值则传来两个0,特殊处理
        {
            for(i=0;i<218;i++)
            {
                delay(10,0x38);
                flushled(10);
            }
            sec++;
            sec_s=65535;
            min_s=65535;
            continue;
        }

        if(sec==sec_s&&min==min_s)              //计时部分
        {
            playmusic();
            return 0;
        }

        if(sec!=59)
        {
            sec++;
        } else {
            if(min<=min_s)
            {
                min++;
                sec=0;
            } 
        }
        
        for(i=0;i<218;i++)
        {
            if(getbutton()==66)
                {
                    ledcur[0]=ledcur[1]=ledcur[2]=ledcur[3]=ledcur[4]=lednum[11];
                    return 1;
                }
            delay(10,0x38);
            flushled(10);
        }
    }
}

/*
    函数名:cutdown()
    参数:
        min:从键盘输入的分,开始计时时用来计时分
        sec:从键盘输入的秒,开始计时时用来计时秒
    作用:当输入了分与秒时,该函数可以从min:sec倒计时到0
          若没有设定分秒,则无限计时,可以由B键打断
*/
uint cutdown(uint min,uint sec)
{
    uint i;

    while(1)
    {
        ledcur[0]=lednum[min/10];
        ledcur[1]=lednum[(min-min/10*10)];
        ledcur[2]=lednum[10];
        ledcur[3]=lednum[sec/10];
        ledcur[4]=lednum[(sec-sec/10*10)];
        
        if(sec!=0)
        {
            sec--;
        } else {
            if(min!=0)
            {
                min--;
                sec=59;
            } else {
                playmusic();
                return 0;
            }
        }
    
        for(i=0;i<218;i++)
        {
            if(getbutton()==66)
            {
                ledcur[0]=ledcur[1]=ledcur[2]=ledcur[3]=ledcur[4]=lednum[11];
                return 1;
            }
            delay(10,0x38);
            flushled(10);
        }
    }
}

/*
    函数名:        delay()
    参数解释:
        ms:        延迟毫秒数
        val:       装配的初值
    作用:          延时函数使用定时器延时,方式2,通过查询中断标志TF0达到延时目的
*/
void delay(uint ms,uint val)
{
/*
    变量说明
    mst:计数用中间变量
    msn:计数用中间变量
*/
	uint mst,msn;
	mst=0;
	msn=0;

	TMOD=0x02;              //方式2定时
	TH0=val;                //装载复位初值
	TL0=val;                //装载初值
	
	TR0=1;                  //定时器开始
	while(1)
	{
		if(TF0==1)
		{
			TF0=0;
			mst++;
		
			if(mst==1)
			{
				mst=0;
				msn++;
			}
		
			if(msn==ms)     //若达到目标毫秒则关闭定时器
			{
				TR0=0;
				return;
			}
		}
	}
}

/*
    函数名:flushled()
    参数解释:
        ms:刷新一次用时,在播放音乐的时候恢复占空比而存在
    作用:LED动态显示时用来刷新LED显示内容的函数
*/
void flushled(uint ms)
{
	uint i;
	for(i=0;i<8;i++)
	{
		switch(i)//通过对p2.2、p2.3、p2.4输出电平操控74HC138来达到控制位选的目的
		{
			case(7):a=0;b=0;c=0;break;
			case(6):a=1;b=0;c=0;break;
			case(5):a=0;b=1;c=0;break;
			case(4):a=1;b=1;c=0;break;
			case(3):a=0;b=0;c=1;break;
			case(2):a=1;b=0;c=1;break;
			case(1):a=0;b=1;c=1;break;
			case(0):a=1;b=1;c=1;break;
		}
		ledio=ledcur[i];
		delay(ms,0xff);
        ledio=0x00;
	}
}

/*
    函数名:playmusic()
    作用:播放一段音乐
*/
void playmusic()
{
/*	变量解释
	i:		代表着音符数量
	k:		从1到ubeat的中间变量
	ubeat:	代表着每一个音符对应的波持续的周期倍数
*/
	uint i,k,ubeat;
    ledcur[7]=workstatus[3];
	buzz=0;
	
	for(i=1;i<music[0];i++)
	{
		ubeat=10000*beat[i]/model[music[i]+12];
		
		for(k=0;k<=ubeat;k++)
		{
			buzz=~buzz;
			delay(model[music[i]+12]-35,0xf6);
            flushled(1);
		}
	}
		
	if(i==music[0])
	{
		TR0=0;
	}
}

/*
    函数名:timer_button
    参数说明:
        button      用户按下的按键
        i           计数用中间变量
        min         用户输入的分
        sec         用户输入的秒
    作用:从键盘获取到用户设定的时间,传递给定时器以及倒计时
*/
void timer_button(uint type)
{
    uint button,i,min,sec;
    i=0;
    ledcur[2]=lednum[10];
    while(1)
    {
        button=getButton();
            ledcur[7]=workstatus[type];
        switch(button)
        {
            //输入数字操作
            case(0):case(1):case(2):case(3):case(4):case(5):case(6):case(7):case(8):case(9):{
                if(i<4)
                {
                    if(i>1)
                    {
                        ledcur[i+1]=lednum[button];
                        timeB[i]=button;
                    } else {
                        ledcur[i]=lednum[button];
                        timeB[i]=button;
                    }
                    i++;
                }
            };break;

            //确认操作
            case(89):{
                min=timeB[0]*10+timeB[1];
                sec=timeB[2]*10+timeB[3];
                switch(type)
                {
                    case(2):{
                        if(cutdown(min,sec)==1)
                        {
                            return;
                        } else {
                            i=0;
                            ledcur[0]=ledcur[1]=ledcur[3]=ledcur[4]=lednum[11];
                        }
                        };break;
                    case(1):{
                        if(timecounter(min,sec)==1)
                        {
                            return;
                        } else {
                            i=0;
                            ledcur[0]=ledcur[1]=ledcur[3]=ledcur[4]=lednum[11];
                        }
                    };break;
                }
            };break;

            //删除操作
            case(78):{
                if(i>0)
                {
                    if(i<3)
                    {
                        ledcur[i-1]=lednum[11];
                        timeB[i]=0;
                    } else { 
                        ledcur[i]=lednum[11];
                        timeB[i]=0;
                    }
                    i--;
                }
            };break;

            //返回主菜单
            case(66):{
                ledcur[0]=ledcur[1]=ledcur[2]=ledcur[3]=ledcur[4]=lednum[11];
                return;
            };break;
        }
        flushled(10);
    }
}

感觉代码排版比刚开始的C语言电话订餐系统好多了。

分析使人进步,copy使人落后。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值