?? 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
|