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语言电话订餐系统好多了。