基于stc89c52电子钟综合设计

   1、基本功能:

 实现时间自动显示和音响报时

① 按实时时间显示时分秒

② 每隔60秒自动短响一声        

③ 按日期显示-日             

④ 每隔60连续响多声,几点响几声

⑤ 可设置每天4次闹钟功能

⑥ 设有调整日期、时间和止闹按钮

⑦ 有按秒闪动的双LED

⑧  闹铃需急促响多声            

⑨ 日期与时间轮流显示

51单片机_外部中断 与 定时/计数器中断

外部中断其实隶属于按键处理,外部中断最著名的当属IT0了,若IT0赋值为0,这个按钮其实是低电平触发;若IT0赋值为1,这个按钮其实是下边沿触发。

(1条消息) 51单片机外部中断 与 定时/计数器中断踏过山河,踏过海的博客-CSDN博客_51单片机定时器中断计数

定时器其实就是倒计时,而定时器T0和T1分别对应的引脚是P3.4和P3.5。

(插播一条广告:EA代表总闸,不管是外部中断,还是定时器中断要开启,首先都要EA开闸,外部中断或定时器中断也开闸才能运行.)

设计4次闹钟思路:(这里运用比较简单方式 数组)

设置一次 然后按下k2 表示设置成功 刷新 success1

设置第二次 继续按下k2 表示设置成功 刷新 success2

设置成功把数据存放到数组中。 判断数组成员的hour min 是否相等 相等的话就响应

代码实现

 

下面是代码演示:此项目主要也是基于定时器实现时间的计时,利用按钮调节模式切换 设置闹钟 调节时间等功能 

main函数:

#include <REGX52.H>
#include "sys.h"
#include "mode.h"
#include "beep.h"
#include "LCD1602.h"
#include "key.h"
#include <stdio.h>

uchar mod;uchar naomin=0;uchar naohour=2;uchar naosec=0;//闹钟的时分秒

uchar sec=59,min=59,hour=5,day,month,countmin,counthour,n;
uchar day=2; uchar month=9; uint year=2022;
uint i,j;
int cont_res_flag = 0;
extern u8 stop_clock_flag;



void main()
{
	Timer1Init();
	Int0Init();
	Int1Init();
	LCD_Init();
	
	LCD_ShowString(1,1,"    /  /  ");
	LCD_ShowString(2,1,"  :  :  ");
	
	while(1)
	{
		
		Mode();
		key_control();
		
		
	}
}


void Int0() interrupt 0  //外部中断 按键操作 关闭开启闹钟响
{
	delay(10);//消抖
	if(K3==0)
	{
		Buzzer_Time(100);
		stop_clock_flag = ~stop_clock_flag;

	}
	
}


	
void Int1() interrupt 2
{
	delay(15);
	if(K4==0)
	{
		if(mod==1)
		{
			
			LCD_ShowString(1,1,"    /  /        ");
			LCD_ShowString(2,1,"  :  :          ");
			delay(10);
			mod=0;
			delay(10);
		
		}
		else
		{
			
			
			LCD_ShowString(2,1,"  :  :           ");
			delay(10);
			mod=1;
			
		}
	}
}

		
		
		

	int k = 0;
void Timer1() interrupt 3
{
	int j= 0;
	TH1=0xd8;
	TL1=0xf0;
	i++;
	k++;
	if(i==100)//1秒
	{
		sec++; i=0; j++; 
		Led2_on();
		Led1_on();
	}
	if(j==10)
	{
		j=0;
		Led1_on();
	}
	if(sec==60)
	{
		min++; sec=0; n=0; countmin++;
		Buzzer_Time(50);
	}
	if(min==60)
	{
		hour++; min=0; counthour++;
		cont_res_flag = 1;

		for( ; j <hour+1; j++)
		{
			Buzzer_Time(100);
			delay(60);
			
		}

	}
	if(hour==24)      		
	{
		day++; hour=0;
	}
	if(day==30)
	{
		month++; day=1;
	}
	if(month==12)
	{
		year++; month=1;
	}
	
	
	if(k == 70)
	{
		k = 0;
		if(hour == bufhour[0] && min == bufmin[0] && stop_clock_flag == 1)
		{
			Buzzer_Time(100);
		}
		if(hour == bufhour[1] && min == bufmin[1] && stop_clock_flag == 1)
		{
			Buzzer_Time(100);
		}
		if(hour == bufhour[2] && min == bufmin[2] && stop_clock_flag == 1)
		{
			Buzzer_Time(100);
		}
		if(hour == bufhour[3] && min == bufmin[3] && stop_clock_flag == 1)
		{
			Buzzer_Time(100);
		}		

	}
}



sys.c

#include <REG52.H>

sbit LED1=P2^0;
sbit LED2=P2^1;
//sbit LED3=P2^2;
//sbit LED4=P2^3;

void delay(unsigned int xms)		//@12.000MHz
{
	while(xms)
	{
		unsigned char i, j;
		i = 2;
		j = 239;
		do
		{
			while (--j);
		} 
		while (--i);
		xms--;
	}
}

void time0_init(void)
{
	TMOD|=0X01;//选择为定时器0模式,工作方式1
	TH0=0XFC;	//给定时器赋初值,定时1ms
	TL0=0X18;	
	ET0=1;//打开定时器0中断允许
	EA=1;//打开总中断
	TR0=1;//打开定时器		
}

void Timer1Init()
{
	TMOD=0x10;
	TH1=0xd8;
	TL1=0xf0;     //10ms
	ET1=1;
	EA=1;
	TR1=1;
}


void Int0Init()
{
	EX0=1;
	IT0=1;
	EA=1;
}

void Int1Init()
{
	EX1=1;
	IT1=1;
	EA=1;
}




void Led1_on()
{
	LED1=~LED1;
	delay(20);
	LED1=~LED1;
}

void Led2_on()
{
	LED2=~LED2;
	delay(20);
	LED2=~LED2;
}

//void Led3_on()
//{
//	LED3=~LED3;
//	delay(20);
//	LED3=~LED3;
//}

//void Led4_on()
//{
//	LED4=~LED4;
//	delay(20);
//	LED4=~LED4;
//}




sys.h

#ifndef __SYS_H__
#define __SYS_H__

#include <REGX52.H>

typedef unsigned char uchar;
typedef unsigned int uint;


sbit K1=P3^0;
sbit K2=P3^1;
sbit K3=P3^2;
sbit K4=P3^3;

//蜂鸣器端口:
sbit Buzzer=P1^5;

extern uchar sec,min,hour,day,month,countmin,counthour,mod,naomin,naohour,n,naosec;
extern uint year;

void Led1_on();
void Led2_on();
void Led3_on();
void Led4_on();
void Timer1Init();
void Int0Init();
void Int1Init();
void delay(unsigned int xms);
void time0_init(void);


#endif

beep.c

#include <REGX52.H>
#include <INTRINS.H>
#include "sys.h"



/**
  * @brief  蜂鸣器私有延时函数,延时500us
  * @param  无
  * @retval 无
  */
void Buzzer_Delay500us()		//@12.000MHz
{
	unsigned char i;

	_nop_();
	i = 247;
	while (--i);
}

/**
  * @brief  蜂鸣器发声
  * @param  ms 发声的时长,范围:0~32767
  * @retval 无
  */
void Buzzer_Time(unsigned int ms)
{
	unsigned int i;
	for(i=0;i<ms*2;i++)
	{
		Buzzer=!Buzzer;
		Buzzer_Delay500us();
	}
}

beep.h

#ifndef __BEEP_H_
#define __BEEP_H_

void Buzzer_Time(unsigned int ms);

#endif

lcd1602.c

#include <REGX52.H>

//引脚配置:
sbit LCD_RS=P2^6;
sbit LCD_RW=P2^5;
sbit LCD_EN=P2^7;
#define LCD_DataPort P0

//函数定义:
/**
  * @brief  LCD1602延时函数,12MHz调用可延时1ms
  * @param  无
  * @retval 无
  */
void LCD_Delay()
{
	unsigned char i, j;

	i = 2;
	j = 239;
	do
	{
		while (--j);
	} while (--i);
}

/**
  * @brief  LCD1602写命令
  * @param  Command 要写入的命令
  * @retval 无
  */
void LCD_WriteCommand(unsigned char Command)
{
	LCD_RS=0;
	LCD_RW=0;
	LCD_DataPort=Command;
	LCD_EN=1;
	LCD_Delay();
	LCD_EN=0;
	LCD_Delay();
}

/**
  * @brief  LCD1602写数据
  * @param  Data 要写入的数据
  * @retval 无
  */
void LCD_WriteData(unsigned char Data)
{
	LCD_RS=1;
	LCD_RW=0;
	LCD_DataPort=Data;
	LCD_EN=1;
	LCD_Delay();
	LCD_EN=0;
	LCD_Delay();
}

/**
  * @brief  LCD1602设置光标位置
  * @param  Line 行位置,范围:1~2
  * @param  Column 列位置,范围:1~16
  * @retval 无
  */
void LCD_SetCursor(unsigned char Line,unsigned char Column)
{
	if(Line==1)
	{
		LCD_WriteCommand(0x80|(Column-1));
	}
	else if(Line==2)
	{
		LCD_WriteCommand(0x80|(Column-1+0x40));
	}
}

/**
  * @brief  LCD1602初始化函数
  * @param  无
  * @retval 无
  */
void LCD_Init()
{
	LCD_WriteCommand(0x38);//八位数据接口,两行显示,5*7点阵
	LCD_WriteCommand(0x0c);//显示开,光标关,闪烁关
	LCD_WriteCommand(0x06);//数据读写操作后,光标自动加一,画面不动
	LCD_WriteCommand(0x01);//光标复位,清屏
}

/**
  * @brief  在LCD1602指定位置上显示一个字符
  * @param  Line 行位置,范围:1~2
  * @param  Column 列位置,范围:1~16
  * @param  Char 要显示的字符
  * @retval 无
  */
void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char)
{
	LCD_SetCursor(Line,Column);
	LCD_WriteData(Char);
}

/**
  * @brief  在LCD1602指定位置开始显示所给字符串
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  String 要显示的字符串
  * @retval 无
  */
void LCD_ShowString(unsigned char Line,unsigned char Column,char *String)
{
	unsigned char i;
	LCD_SetCursor(Line,Column);
	for(i=0;String[i]!='\0';i++)
	{
		LCD_WriteData(String[i]);
	}
}

/**
  * @brief  返回值=X的Y次方
  */
int LCD_Pow(int X,int Y)
{
	unsigned char i;
	int Result=1;
	for(i=0;i<Y;i++)
	{
		Result*=X;
	}
	return Result;
}

/**
  * @brief  在LCD1602指定位置开始显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:0~65535
  * @param  Length 要显示数字的长度,范围:1~5
  * @retval 无
  */
void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
	unsigned char i;
	LCD_SetCursor(Line,Column);
	for(i=Length;i>0;i--)
	{
		LCD_WriteData(Number/LCD_Pow(10,i-1)%10+'0');
	}
}

/**
  * @brief  在LCD1602指定位置开始以有符号十进制显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:-32768~32767
  * @param  Length 要显示数字的长度,范围:1~5
  * @retval 无
  */
void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length)
{
	unsigned char i;
	unsigned int Number1;
	LCD_SetCursor(Line,Column);
	if(Number>=0)
	{
		LCD_WriteData('+');
		Number1=Number;
	}
	else
	{
		LCD_WriteData('-');
		Number1=-Number;
	}
	for(i=Length;i>0;i--)
	{
		LCD_WriteData(Number1/LCD_Pow(10,i-1)%10+'0');
	}
}

/**
  * @brief  在LCD1602指定位置开始以十六进制显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:0~0xFFFF
  * @param  Length 要显示数字的长度,范围:1~4
  * @retval 无
  */
void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
	unsigned char i,SingleNumber;
	LCD_SetCursor(Line,Column);
	for(i=Length;i>0;i--)
	{
		SingleNumber=Number/LCD_Pow(16,i-1)%16;
		if(SingleNumber<10)
		{
			LCD_WriteData(SingleNumber+'0');
		}
		else
		{
			LCD_WriteData(SingleNumber-10+'A');
		}
	}
}

/**
  * @brief  在LCD1602指定位置开始以二进制显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:0~1111 1111 1111 1111
  * @param  Length 要显示数字的长度,范围:1~16
  * @retval 无
  */
void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
	unsigned char i;
	LCD_SetCursor(Line,Column);
	for(i=Length;i>0;i--)
	{
		LCD_WriteData(Number/LCD_Pow(2,i-1)%2+'0');
	}
}
#ifndef __LCD1602_H__
#define __LCD1602_H__

//用户调用函数:
void LCD_Init();
void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char);
void LCD_ShowString(unsigned char Line,unsigned char Column,char *String);
void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length);
void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);

#endif

mode.c   

#include "sys.h"
#include "LCD1602.h"
#include "key.h"
#include "beep.h"
#include "stdio.h"

u8 reduce_plus_flag = 1;//默认加

u8 stop_clock_flag = 1;//默认1 开闹钟  0停闹钟

uchar set_time = 0;
uchar bufhour[4] ;
uchar bufmin[4] ;

void naozhongjishu()
{

}  




void key_control()
{

	u8 key_code;
	if(K1==0)
	{
		delay(50);
		if(K1==0)
		{
			if(set_time > 3)
			{
				set_time = 0;
			}
			Buzzer_Time(100);
			LCD_ShowString(1,1," set success!");
			LCD_ShowString(2,1,"                ");
			delay(80);
			bufhour[set_time] = naohour;
			bufmin[set_time] = naomin;
			set_time++;
			if(mod==1)
			{
				
				LCD_ShowString(1,1,"    /  /        ");
				LCD_ShowString(2,1,"  :  :          ");
				delay(10);
				mod=0;
				delay(10);
			
			}
			else
			{
				
				
				LCD_ShowString(2,1,"  :  :           ");
				delay(10);
				mod=1;
				
			}			
		}
	}


	key_code = key_matrix_ranks_scan();

	if(key_code == 1)
	{
		if( reduce_plus_flag == 0)
			reduce_plus_flag =1;
		else{
			reduce_plus_flag =0;
		}
	}
//1.修改日期	
	if(key_code == 2 && reduce_plus_flag == 1) //年份加
	{
		year++;;
	}else if(key_code == 3 && reduce_plus_flag == 1) //月份加
	{
		month++;
	}else if(key_code == 4 && reduce_plus_flag == 1) //日 加
	{
		day++;
	}
	
	if(key_code == 2 && reduce_plus_flag == 0) //年份减
	{
		year--;
	}else if(key_code == 3 && reduce_plus_flag == 0) //月份减
	{
		month--;
	}else if(key_code == 4 && reduce_plus_flag == 0) //日 减
	{
		day--;
	}
//2.修改时间

	if(key_code == 6 && reduce_plus_flag == 1) //时加
	{
		if(mod==0){hour++;}
			else{naohour++;}
	}else if(key_code == 7 && reduce_plus_flag == 1) //分加
	{
		if(mod==0){min++;}
			else{naomin++;}
	}else if(key_code == 8 && reduce_plus_flag == 1) //秒 加
	{
		if(mod==0){sec++;}
			else{naosec++;}
	}
	
	if(key_code == 6 && reduce_plus_flag == 0) //时减
	{
		if(mod==0){hour--;}
			else{naohour--;}
	}else if(key_code == 7 && reduce_plus_flag == 0) //分减
	{
		if(mod==0){min--;}
			else{naomin--;}
	}else if(key_code == 8 && reduce_plus_flag == 0) //秒 减
	{
		if(mod==0){sec--;}
			else{naosec--;}
	}
	
		
//3.判断时间格式
	if(sec==60)
	{
		min++; sec=0; n=0; countmin++;
	}
	if(min==60)
	{
		hour++; min=0; counthour++;
	}
	if(hour==24)      
	{
		day++; hour=0;
	}
	if(day==30)
	{
		month++; day=1;
	}
	if(month==12)
	{
		year++; month=1;
	}
	if(naosec==60)
	{
		naomin++;
		naosec=0;
	}	
	if(naomin==60)
	{
		naohour++;naomin=0;
	}
	if(naohour==24)
	{
		naohour=0;
	}	
}

void Mode()
{
	if(mod==0)
	{
		LCD_ShowNum(2,7,sec,2);
		LCD_ShowNum(2,4,min,2);
		LCD_ShowNum(2,1,hour,2);
		LCD_ShowNum(1,9,day,2);
		LCD_ShowNum(1,6,month,2);		
		LCD_ShowNum(1,1,year,4);
		
	}
	else
	{
		LCD_ShowString(1,1,"clock:          ");
		LCD_ShowNum(2,7,naosec,2);
		LCD_ShowNum(2,4,naomin,2);
		LCD_ShowNum(2,1,naohour,2);
	}
}



void zhinao()
{
	n=100;
}


mode.h

#ifndef __MODE_H_
#define __MODE_H_

void naozhongjishu();
void key_control();
void Mode();
void zhinao();

extern int set_time ;
extern uchar bufhour[4] ;
extern uchar bufmin[4] ;

//uchar bufhour[4] ;
//uchar bufmin[4] ;


#endif

key.c  (矩阵按键扫描)

#include "reg52.h"
#include "key.h"


/*******************************************************************************
* 函 数 名       : delay_10us
* 函数功能		 : 延时函数,ten_us=1时,大约延时10us
* 输    入       : ten_us
* 输    出    	 : 无
*******************************************************************************/
void delay_10us(u16 ten_us)
{
	while(ten_us--);	
}

/*******************************************************************************
* 函 数 名       : key_matrix_ranks_scan
* 函数功能		 : 使用行列式扫描方法,检测矩阵按键是否按下,按下则返回对应键值
* 输    入       : 无
* 输    出    	 : key_value:1-16,对应S1-S16键,
				   0:按键未按下
*******************************************************************************/
u8 key_matrix_ranks_scan(void)
{
	u8 key_value=0;

	KEY_MATRIX_PORT=0xf7;//给第一列赋值0,其余全为1
	if(KEY_MATRIX_PORT!=0xf7)//判断第一列按键是否按下
	{
		delay_10us(1000);//消抖
		switch(KEY_MATRIX_PORT)//保存第一列按键按下后的键值	
		{
			case 0x77: key_value=1;break;
			case 0xb7: key_value=5;break;
			case 0xd7: key_value=9;break;
			case 0xe7: key_value=13;break;
		}
	}
	while(KEY_MATRIX_PORT!=0xf7);//等待按键松开	
	
	KEY_MATRIX_PORT=0xfb;//给第二列赋值0,其余全为1
	if(KEY_MATRIX_PORT!=0xfb)//判断第二列按键是否按下
	{
		delay_10us(1000);//消抖
		switch(KEY_MATRIX_PORT)//保存第二列按键按下后的键值	
		{
			case 0x7b: key_value=2;break;
			case 0xbb: key_value=6;break;
			case 0xdb: key_value=10;break;
			case 0xeb: key_value=14;break;
		}
	}
	while(KEY_MATRIX_PORT!=0xfb);//等待按键松开	
	
	KEY_MATRIX_PORT=0xfd;//给第三列赋值0,其余全为1
	if(KEY_MATRIX_PORT!=0xfd)//判断第三列按键是否按下
	{
		delay_10us(1000);//消抖
		switch(KEY_MATRIX_PORT)//保存第三列按键按下后的键值	
		{
			case 0x7d: key_value=3;break;
			case 0xbd: key_value=7;break;
			case 0xdd: key_value=11;break;
			case 0xed: key_value=15;break;
		}
	}
	while(KEY_MATRIX_PORT!=0xfd);//等待按键松开	
	
	KEY_MATRIX_PORT=0xfe;//给第四列赋值0,其余全为1
	if(KEY_MATRIX_PORT!=0xfe)//判断第四列按键是否按下
	{
		delay_10us(1000);//消抖
		switch(KEY_MATRIX_PORT)//保存第四列按键按下后的键值	
		{
			case 0x7e: key_value=4;break;
			case 0xbe: key_value=8;break;
			case 0xde: key_value=12;break;
			case 0xee: key_value=16;break;
		}
	}
	while(KEY_MATRIX_PORT!=0xfe);//等待按键松开
	
	return key_value;		
}

key.h

#ifndef __KEY_H__
#define __KEY_H__
typedef unsigned int u16;	//对系统默认数据类型进行重定义
typedef unsigned char u8;
#define KEY_MATRIX_PORT	P1	//使用宏定义矩阵按键控制口	
u8 key_matrix_ranks_scan(void);
#endif

猜你喜欢

转载自blog.csdn.net/aaa2540567665/article/details/126754964
今日推荐