目录
功能设计
- 液晶屏显示当前日期,时间,可以通过按键修改日期时间。
- 可以设置闹钟时间,到点蜂鸣器鸣叫,直至手动关闭。
- 具有计时器功能。计时结束蜂鸣器报警指定时间提醒,无需手动取消。
- 每次有按键按下时,蜂鸣器以短“滴”声报警。
- 可以通过电脑串口通信调整时间,闹钟,计时器有关参数。
实现原理
- 单片机型号:STC89C51RC2;开发板:普中A2;开发软件:Keil4(因为内置无本芯片头文件,所以部分地址需要重新定义)
- 显示模块:采用LCD1602显示。
- 时间显示功能:采用DS1302实现时钟显示功能。
- 蜂鸣器模块:由于开发板自带无源蜂鸣器引脚与LCD1602引脚冲突,采用外接有源蜂鸣器完成对应功能。
- 计时器功能:采用单片机内部定时器实现计时。
- 串口通信:采用单片机自带串口配合定时器中断实现通信。
使用说明
1.按键设置
按键号 | 对应功能 | Menu | Function |
---|---|---|---|
K1 | 按下循环切换对应功能菜单界面 | 0 | 显示时间 |
1 | 串口调整模式 | ||
2 | 时间调整 | ||
3 | 闹钟调整 | ||
4 | 计时器模式 | ||
备注 | |||
K2 | 数值加 | 具有越界判断功能,仅在选中时有效 | |
K3 | 数值减 | 具有越界判断功能,仅在选中时有效 | |
K4 | 控制调整内容 | 仅在调整页面有效,控制内容时闪烁显示 |
2.串口数据设定
用户须发送两次数据:第一次发送要控制的内容编码(对应值见下表),第二次发送调整的数值(16进制)。接收成功会返回“FF”。
注意:串口调整仅在调整页面有效,需手动切换至调整界面。
编码(16进制) | 模块 | 对应数据 |
---|---|---|
1 | 时钟 | 年 |
2 | 月 | |
3 | 日 | |
4 | 时 | |
5 | 分 | |
6 | 秒 | |
7 | 星期 | |
8 | 闹钟 | 时 |
9 | 分 | |
a | 计时器 | 时 |
b | 分 | |
c | 秒 |
3.细节设置
- 闹钟响时按下任意按键即可关闭,且不改变闹钟的运行状态,可实现每天提醒。
- 计时器运行状态中按下任意按键可暂停倒计时,再次按下任意按键可以恢复。运行状态中无法切换功能界面。
代码
主函数:main.c
#include <at89c51RC2.h>
#include "LCD1602.h"
#include "Hardware.h"
#include "DS1302.h"
sbit beep=P1^7;
char keynum,menu,mode1,mode2,mode3,flash;
int timer_flag; //1=打开,0=关闭
int timer_time[6]={0,0,0,0,1,0}; //计时器时间设定
int alarm_flag; //1=打开,0=关闭
int alarm_time[6]={0,0,0,8,0,0}; //闹钟时间设定
int run1; //计时器运行标志位(0为暂停运行,1为运行)
int buzzer,temp; //闹钟声响标志位
int uart[3]={0,0,0};
/*******************************************************************************
* 函 数 名 : Beep_Delay
* 函数功能 : 延时函数@12.000MHz 1ms
* 输 入 : y
* 输 出 : void
* 说 明 : none
*******************************************************************************/
void Beep_Delay(int y)
{
unsigned char n, m;
n = 2;
m = 239;
while(y--)
{
while (--n);
} while (--m);
}
/*******************************************************************************
* 函 数 名 : Timer_Init
* 函数功能 : 计时器界面初始化
* 输 入 : void
* 输 出 : void
* 说 明 : none
*******************************************************************************/
void Timer_Init()
{
LCD_Clean();
LCD_ShowString(1,1,"Set Timer:");
LCD_ShowNum(2,1,timer_time[3],2);
LCD_ShowString(2,3,":");
LCD_ShowNum(2,4,timer_time[4],2);
LCD_ShowString(2,6,":");
LCD_ShowNum(2,7,timer_time[5],2);
if(timer_flag == 0)
{
LCD_ShowString(2,13,"OFF");
}else{
LCD_ShowString(2,13,"ON ");
}
}
/*******************************************************************************
* 函 数 名 : Timer_Set
* 函数功能 : 计时器设置
* 输 入 : void
* 输 出 : void
* 说 明 : none
*******************************************************************************/
void Timer_Set(void)
{
if(run1==0&&keynum == 4)
{
beep=0;Beep_Delay(20);beep=1; //蜂鸣器模块
mode3++;
if(mode3>3)
{
mode3=0;
timer_flag=!timer_flag;
if(timer_flag == 0)
{
LCD_ShowString(2,13,"OFF ");
}else
{
LCD_ShowString(2,13,"ON ");
}
}
}
if(run1==0&&keynum == 2)
{
beep=0;Beep_Delay(20);beep=1; //蜂鸣器模块
timer_time[mode3+2]++;
if(timer_time[3]>23){timer_time[3]=0;}
if(timer_time[4]>59){timer_time[4]=0;}
if(timer_time[5]>59){timer_time[5]=0;}
}
if(run1==0&&keynum == 3)
{
beep=0;Beep_Delay(20);beep=1; //蜂鸣器模块
timer_time[mode3+2]--;
if(timer_time[3]<0){timer_time[3]=23;}
if(timer_time[4]<0){timer_time[4]=59;}
if(timer_time[5]<0){timer_time[5]=59;}
}
//更新显示
if(run1==0 && mode3==1 && flash==1){LCD_ShowString(2,1," ");}
else {LCD_ShowNum(2,1,timer_time[3],2);}
if(run1==0 && mode3==2 && flash==1){LCD_ShowString(2,4," ");}
else {LCD_ShowNum(2,4,timer_time[4],2);}
if(run1==0 && mode3==3 && flash==1){LCD_ShowString(2,7," ");}
else {LCD_ShowNum(2,7,timer_time[5],2);}
}
/*******************************************************************************
* 函 数 名 : Alarm_Init
* 函数功能 : 闹钟界面初始化
* 输 入 : void
* 输 出 : void
* 说 明 : none
*******************************************************************************/
void Alarm_Init(void)
{
LCD_Clean();
LCD_ShowString(1,1,"Set Alarm: ");
LCD_ShowNum(2,1,alarm_time[3],2);
LCD_ShowString(2,3,":");
LCD_ShowNum(2,4,alarm_time[4],2);
if(alarm_flag == 0)
{
LCD_ShowString(2,13,"OFF");
}else{
LCD_ShowString(2,13,"ON ");
}
}
/*******************************************************************************
* 函 数 名 : Alarm_Set
* 函数功能 : 闹钟设置
* 输 入 : none
* 输 出 : void
* 说 明 : none
*******************************************************************************/
void Alarm_Set(void)
{
if(buzzer==0&&keynum == 4)
{
beep=0;Beep_Delay(20);beep=1; //蜂鸣器模块
mode2++;
if(mode2==3)
{
mode2=0;
alarm_flag=!alarm_flag;
if(alarm_flag == 0)
{
LCD_ShowString(2,13,"OFF");
}else
{
LCD_ShowString(2,13,"ON ");
}
}
}
if(buzzer==0&&keynum == 2)
{
beep=0;Beep_Delay(20);beep=1; //蜂鸣器模块
alarm_time[mode2+2]++;
if(alarm_time[3]<0){alarm_time[3]=23;}
if(alarm_time[3]>23){alarm_time[3]=0;}
}
if(buzzer==0&&keynum == 3)
{
beep=0;Beep_Delay(20);beep=1; //蜂鸣器模块
alarm_time[mode2+2]--;
if(alarm_time[4]<0){alarm_time[4]=59;}
if(alarm_time[4]>59){alarm_time[4]=0;}
}
//更新显示
if(buzzer==0 && mode2==1 && flash==1){LCD_ShowString(2,1," ");}
else {LCD_ShowNum(2,1,alarm_time[3],2);}
if(buzzer==0 && mode2==2 && flash==1){LCD_ShowString(2,4," ");}
else {LCD_ShowNum(2,4,alarm_time[4],2);}
}
/*******************************************************************************
* 函 数 名 : Clock_Show
* 函数功能 : 时钟显示
* 输 入 : none
* 输 出 : void
* 说 明 : none
*******************************************************************************/
void Clock_Show()
{
DS1302_Return();
LCD_ShowNum(1,1,20,2);
LCD_ShowNum(1,3,time[0],2);
LCD_ShowString(1,5,"-");
LCD_ShowNum(1,6,time[1],2);
LCD_ShowString(1,8,"-");
LCD_ShowNum(1,9,time[2],2);
switch(time[6])
{
case 1:LCD_ShowString(1,13,"MON");break;
case 2:LCD_ShowString(1,13,"TUE");break;
case 3:LCD_ShowString(1,13,"WED");break;
case 4:LCD_ShowString(1,13,"THU");break;
case 5:LCD_ShowString(1,13,"FRI");break;
case 6:LCD_ShowString(1,13,"SAT");break;
case 7:LCD_ShowString(1,13,"SUN");break;
}
LCD_ShowNum(2,1,time[3],2);
LCD_ShowString(2,3,":");
LCD_ShowNum(2,4,time[4],2);
LCD_ShowString(2,6,":");
LCD_ShowNum(2,7,time[5],2);
if(alarm_flag==1){LCD_ShowString(2,13," # "); } //闹钟开启主页面显示#
else{LCD_ShowString(2,13," "); }
}
/*******************************************************************************
* 函 数 名 : Clock_Set
* 函数功能 : 按键设置时钟时间
* 输 入 : none
* 输 出 : void
* 说 明 : none
*******************************************************************************/
void Clock_Set()
{
if(run1==0&&buzzer==0&&keynum == 4)
{
beep=0;Beep_Delay(20);beep=1; //蜂鸣器模块
mode1++;
if(mode1>7)
{
mode1=0;
DS1302_Set(); //发送调节后的时间
}
}
if(run1==0&&buzzer==0&&keynum == 2)
{
beep=0;Beep_Delay(20);beep=1; //蜂鸣器模块
time[mode1-1]++;
if(time[0]>99){time[0]=0;} //年越界判断
if(time[1]>12){time[1]=1;} //月越界判断
if( time[1]==1 || time[1]==3 || time[1]==5 || time[1]==7 ||
time[1]==8 || time[1]==10 || time[1]==12)//日越界判断
{
if(time[2]>31){time[2]=1;}//大月
}
else if(time[1]==4 || time[1]==6 || time[1]==9 || time[1]==11)
{
if(time[2]>30){time[2]=1;}//小月
}
else if(time[1]==2)
{
if(time[0]%4==0)
{
if(time[2]>29){time[2]=1;}//闰年2月
}
else
{
if(time[2]>28){time[2]=1;}//平年2月
}
}
if(time[3]>23){time[3]=0;} //时越界判断
if(time[4]>59){time[4]=0;} //分越界判断
if(time[5]>59){time[5]=0;} //秒越界判断
if(time[6]>8){time[6]=1;} //星期越界判断
}
if(run1==0&&buzzer==0&&keynum == 3)
{
beep=0;Beep_Delay(20);beep=1; //蜂鸣器模块
time[mode1-1]--;
if(time[0]<0){time[0]=99;} //年越界判断
if(time[1]<1){time[1]=12;} //月越界判断
if( time[1]==1 || time[1]==3 || time[1]==5 || time[1]==7 ||
time[1]==8 || time[1]==10 || time[1]==12)//日越界判断
{
if(time[2]<1){time[2]=31;}//大月
if(time[2]>31){time[2]=1;}//大月
}
else if(time[1]==4 || time[1]==6 || time[1]==9 || time[1]==11)
{
if(time[2]<1){time[2]=30;}//小月
if(time[2]>30){time[2]=1;}//小月
}
else if(time[1]==2)
{
if(time[0]%4==0)
{
if(time[2]<1){time[2]=29;}//闰年2月
if(time[2]>29){time[2]=1;}//闰年2月
}
else
{
if(time[2]<1){time[2]=28;}//平年2月
if(time[2]>28){time[2]=1;}//平年2月
}
}
if(time[3]<0){time[3]=23;} //时越界判断
if(time[4]<0){time[4]=59;} //分越界判断
if(time[5]<0){time[5]=59;} //秒越界判断
if(time[6]<1){time[6]=7;} //星期越界判断
}
//更新显示,根据mode和flash判断可完成闪烁功能
if(mode1==1 && flash==1){LCD_ShowString(1,3," ");}
else {LCD_ShowNum(1,3,time[0],2);}
if(mode1==2 && flash==1){LCD_ShowString(1,6," ");}
else {LCD_ShowNum(1,6,time[1],2);}
if(mode1==3 && flash==1){LCD_ShowString(1,9," ");}
else {LCD_ShowNum(1,9,time[2],2);}
if(mode1==7 && flash==1){LCD_ShowString(1,13," ");}
else
{
switch(time[6])
{
case 1:LCD_ShowString(1,13,"MON");break;
case 2:LCD_ShowString(1,13,"TUE");break;
case 3:LCD_ShowString(1,13,"WED");break;
case 4:LCD_ShowString(1,13,"THU");break;
case 5:LCD_ShowString(1,13,"FRI");break;
case 6:LCD_ShowString(1,13,"SAT");break;
case 7:LCD_ShowString(1,13,"SUN");break;
}
}
if(mode1==4 && flash==1){LCD_ShowString(2,1," ");}
else {LCD_ShowNum(2,1,time[3],2);}
if(mode1==5 && flash==1){LCD_ShowString(2,4," ");}
else {LCD_ShowNum(2,4,time[4],2);}
if(mode1==6 && flash==1){LCD_ShowString(2,7," ");}
else {LCD_ShowNum(2,7,time[5],2);}
}
/*******************************************************************************
* 函 数 名 : Uart_Change
* 函数功能 : 电脑通过串口设置时钟时间
* 输 入 : none
* 输 出 : void
* 说 明 : 第一个发送的数据指定修改的内容(1~7对应为时钟修改,8~9对应为闹钟修改,10~12为计时器修改),
第二次发送的数据为要修改的数据
*******************************************************************************/
void Uart_Change()
{
switch(uart[0])
{
case 1:time[0]=uart[1];break;
case 2:time[1]=uart[1];break;
case 3:time[2]=uart[1];break;
case 4:time[3]=uart[1];break;
case 5:time[4]=uart[1];break;
case 6:time[5]=uart[1];break;
case 7:time[6]=uart[1];break;
case 8:alarm_time[3]=uart[1];break;
case 9:alarm_time[4]=uart[1];break;
case 10:timer_time[3]=uart[1];break;
case 11:timer_time[4]=uart[1];break;
case 12:timer_time[5]=uart[1];break;
default: break;
}
}
/*******************************************************************************
*主函数
*******************************************************************************/
void main()
{
LCD_Init(); //LCD屏幕初始化
Timer0_Init(); //定时器初始化
DS1302_Init(); //DS1302初始化
DS1302_Set(); //DS1302初始时间设定
UART_Init(); //串口初始化
while(1)
{
keynum = Key(); //读取按键键码
if(run1==0&&keynum == 1)
{
beep=0;Beep_Delay(20);beep=1; //蜂鸣器模块
menu++; //调整菜单
if(menu>6)
{
menu=0;DS1302_Set();
}
}
switch(menu)
{
case 0:
Clock_Show();break; //显示时间
case 1:
Uart_Change();break; //串口调整模式
case 2:
Clock_Set();break; //串口调整时间
case 3:
Alarm_Init(); break; //显示闹钟调节页面
case 4:
Alarm_Set();break; //调节闹钟
case 5:
Timer_Init();break; //显示计时器调节页面
case 6:
Timer_Set();break; //调节计时器
}
if(run1==1) //定时器中断程序
{
if(keynum==1||keynum==2||keynum==3||keynum==4) //任意一个按键按下
{
beep=0;Beep_Delay(20);beep=1; //蜂鸣器模块
timer_flag=!timer_flag;
// run1=!run1;
if(timer_flag==0&&beep==1&&timer_time[5]!=0)
{
LCD_ShowString(2,13,"STOP");
}else{LCD_ShowString(2,13,"ON ");}
}
}
if(buzzer==1&&temp==0) //闹钟响铃程序
{
beep=0; //蜂鸣器响
if(keynum==1||keynum==2||keynum==3||keynum==4) //任意一个按键按下
{
beep=1;
temp=1;
buzzer=0;
}
}
}
}
/*******************************************************************************
*定时器0中断函数
*******************************************************************************/
void Timer0_Routine() interrupt 1
{
static unsigned int cnt;
TL0 = 0x18;
TH0 = 0xFC;
cnt++;
if(cnt>=1000) //1s
{
cnt=0;
/*计时器*/
if(timer_flag==1)
{
run1=1;
if(timer_time[5]>0) timer_time[5]--;
else
{
if(timer_time[4]>0){timer_time[4]--;timer_time[5]=59;}
else
{
if(timer_time[3]>0){timer_time[3]--;timer_time[4]=59;}
}
}
if(timer_time[3]==0&&timer_time[4]==0&&timer_time[5]==0)
{
timer_flag=0; //标志位 置零
run1=0; //运行位 置零
if(timer_flag == 0)
{
LCD_ShowString(2,13,"OFF ");
}else{
LCD_ShowString(2,13,"ON ");
}
beep=0;
Beep_Delay(500);
beep=1;
Beep_Delay(500);
beep=0;
Beep_Delay(500);
beep=1;
}
}
/*闹钟检测*/
if(time[3]==alarm_time[3]&&time[4]==alarm_time[4]&&alarm_flag==1)
{
buzzer=1;
}else {buzzer=0;temp=0;}
}else if(cnt==249||cnt==499||cnt==749||cnt==999){flash=!flash;} //实现闪烁显示0.5s
}
/*******************************************************************************
*串口定时器1中断函数
*******************************************************************************/
void UART_Routine() interrupt 4
{
static int i;
if(RI==1) //如果接收标志位为1,接收到了数据
{
uart[i]=SBUF; //将接收到的数据存入数组中
i++;
if(i==2)
{
i=0;
UART_Send(0xFF); //设置一次后返回值做参考
}
RI=0; //接收标志位清0
}
}
头文件
/*******************************************************************************
*Hardware.h
*******************************************************************************/
#ifndef __HARDWARE_H__
#define __HARDWARE_H__
char Key(void);
void Timer0_Init(void);
void UART_Init(void);
void UART_Send(char Data);
#endif
/*******************************************************************************
*LCD1602.h
*******************************************************************************/
#ifndef __LCD1602_H__
#define __LCD1602_H__
void LCD_Init(void);
void LCD_ShowString(unsigned char row,unsigned char col,unsigned char String[]);
void LCD_ShowNum(unsigned char row,unsigned char col,unsigned int Number,unsigned char Length);
void LCD_Clean(void);
#endif
/*******************************************************************************
*DS1302.h
*******************************************************************************/
#ifndef __DS1302_H__
#define __DS1302_H__
extern int time[7];
void DS1302_Init();
void DS1302_Write(char Command,Data);
char DS1302_Read(char Command);
void DS1302_Set();
void DS1302_Return();
#endif
LCD1602驱动函数
#include <at89c51RC2.h>
//引脚定义
sbit LCD_RS=P2^6;
sbit LCD_RW=P2^5;
sbit LCD_E=P2^7;
void LCD_Delay() //@12.000MHz 1ms
{
unsigned char i, j;
i = 2;
j = 239;
do
{
while (--j);
} while (--i);
}
/*******************************************************************************
* 函 数 名 : LCD_WriteCommand
* 函数功能 : 写命令字
* 输 入 : Command
* 输 出 : void
* 说 明 : none
*******************************************************************************/
void LCD_WriteCommand(unsigned char Command)
{
LCD_RS=0;
LCD_RW=0;
P0=Command;
LCD_E=1;
LCD_Delay();
LCD_E=0;
LCD_Delay();
}
/*******************************************************************************
* 函 数 名 : LCD_SetCursor
* 函数功能 : 设置光标范围
* 输 入 : 行(1~2),列(1~16)
* 输 出 : void
* 说 明 : none
*******************************************************************************/
void LCD_SetCursor(unsigned char row,unsigned char col)
{
if(row==1)
{
LCD_WriteCommand(0x80|(col-1));
}
else
{
LCD_WriteCommand(0x80|(col-1)+0x40);
}
}
/*******************************************************************************
* 函 数 名 : LCD_WriteData
* 函数功能 : 写数据
* 输 入 : Data
* 输 出 : void
* 说 明 : none
*******************************************************************************/
void LCD_WriteData(unsigned char Data)
{
LCD_RS=1;
LCD_RW=0;
P0=Data;
LCD_E=1;
LCD_Delay();
LCD_E=0;
LCD_Delay();
}
/*******************************************************************************
* 函 数 名 : LCD_Init
* 函数功能 : 初始化
* 输 入 : none
* 输 出 : void
* 说 明 : none
*******************************************************************************/
void LCD_Init(void)
{
LCD_WriteCommand(0x38); //模式:八位数据
LCD_WriteCommand(0x0C); //显示开,光标关,闪烁关
LCD_WriteCommand(0x06); //读写操作后,光标自动加一
LCD_WriteCommand(0x01); //清屏
}
/*******************************************************************************
* 函 数 名 : LCD_Clean
* 函数功能 : 清屏
* 输 入 : none
* 输 出 : void
* 说 明 : none
*******************************************************************************/
void LCD_Clean(void)
{
LCD_WriteCommand(0x01);
}
/*******************************************************************************
* 函 数 名 : LCD_ShowString
* 函数功能 : 显示字符串
* 输 入 : 行(1~2),列(1~16),字符串
* 输 出 : void
* 说 明 : none
*******************************************************************************/
void LCD_ShowString(unsigned char row,unsigned char col,unsigned char String[])
{
unsigned char i;
LCD_SetCursor(row,col); //设置光标位置
for(i=0;String[i]!='\0';i++)
{
LCD_WriteData(String[i]); //依次取出字符串的每一位
}
}
int LCD_Pow(int X,int Y) //X的Y次方代码实现
{
unsigned char i;
int Result=1;
for(i=0;i<Y;i++)
{
Result*=X;
}
return Result;
}
/*******************************************************************************
* 函 数 名 : LCD_ShowNum
* 函数功能 : 显示数字
* 输 入 : 行(1~2),列(1~16),字符串,位数
* 输 出 : void
* 说 明 : none
*******************************************************************************/
void LCD_ShowNum(unsigned char row,unsigned char col,unsigned int Number,unsigned char Length)
{
unsigned char i;
LCD_SetCursor(row,col); //设置光标位置
for(i=Length;i>0;i--)
{
LCD_WriteData('0'+Number/LCD_Pow(10,i-1)%10); //依次取出数字的每一位
}
}
DS1302驱动函数
#include <at89c51RC2.h>
//引脚定义
sbit DS1302_SCLK = P3^6;
sbit DS1302_IO = P3^4;
sbit DS1302_CE = P3^5;
//命令字定义
#define SECOND 0x80
#define MINUTE 0x82
#define HOUR 0x84
#define DATE 0x86
#define MONTH 0x88
#define DAY 0x8A
#define YEAR 0x8C
#define WP 0x8E
//默认上电时间
int time[7]={24,1,1,8,0,0,1};
/*******************************************************************************
* 函 数 名 : DS1302_Init
* 函数功能 : 芯片初始化
* 输 入 : void
* 输 出 : void
* 说 明 : none
*******************************************************************************/
void DS1302_Init(void)
{
DS1302_CE = 0;
DS1302_SCLK = 0;
}
/*******************************************************************************
* 函 数 名 : DS1302_Write
* 函数功能 : 芯片写入
* 输 入 : command(命令字),Data(数据帧)
* 输 出 : void
* 说 明 : none
*******************************************************************************/
void DS1302_Write(unsigned char Command,Data)
{
int i=0;
DS1302_CE = 1; //开启
for(i;i<8;i++)
{
DS1302_IO = Command&(0x01<<i); //顺序取出命令的每一位
DS1302_SCLK = 1; //时钟上升沿读取
DS1302_SCLK = 0; //时钟恢复低电平
}
for(i=0;i<8;i++)
{
DS1302_IO = Data&(0x01<<i); //顺序取出数据的每一位
DS1302_SCLK = 1; //时钟上升沿读取
DS1302_SCLK = 0; //时钟恢复低电平
}
DS1302_CE = 0; //关闭
}
/*******************************************************************************
* 函 数 名 : DS1302_Read
* 函数功能 : 芯片读出
* 输 入 : command
* 输 出 : Data
* 说 明 : none
*******************************************************************************/
char DS1302_Read(char Command)
{
int i = 0;
char Data = 0x00;
Command|=0x01; //末位置一,转为读的命令
DS1302_CE = 1; //根据芯片手册开启
for(i = 0;i<8;i++)
{
DS1302_IO = Command&(0x01<<i); //顺序取出命令的每一位
DS1302_SCLK = 0;
DS1302_SCLK = 1;
}
for(i = 0;i<8;i++)
{
DS1302_SCLK = 1;
DS1302_SCLK = 0;
if(DS1302_IO)
{
Data|=(0x01<<i);
}
}
DS1302_CE = 0; //根据芯片手册关闭
DS1302_IO = 0;
return Data;
}
/*******************************************************************************
* 函 数 名 : DS1302_Set
* 函数功能 : 设置时间
* 输 入 : none
* 输 出 : none
* 说 明 : none
*******************************************************************************/
void DS1302_Set(void)
{
DS1302_Write(WP,0x00); //关闭写保护
DS1302_Write(YEAR,time[0]/10*16+time[0]%10); //十进制转BCD
DS1302_Write(MONTH,time[1]/10*16+time[1]%10);
DS1302_Write(DATE,time[2]/10*16+time[2]%10);
DS1302_Write(HOUR,time[3]/10*16+time[3]%10);
DS1302_Write(MINUTE,time[4]/10*16+time[4]%10);
DS1302_Write(SECOND,time[5]/10*16+time[5]%10);
DS1302_Write(DAY,time[6]/10*16+time[6]%10);
DS1302_Write(WP,0x80); //打开写保护
}
/*******************************************************************************
* 函 数 名 : DS1302_Return
* 函数功能 : DS1302读取时间,调用之后,DS1302中的数据会被读取到time数组中
* 输 入 : none
* 输 出 : none
* 说 明 : none
*******************************************************************************/
void DS1302_Return()
{
int temp = 0;
temp = DS1302_Read(YEAR);
time[0] = temp/16*10+temp%16; //BCD转十进制
temp = DS1302_Read(MONTH);
time[1] = temp/16*10+temp%16; //BCD转十进制
temp = DS1302_Read(DATE);
time[2] = temp/16*10+temp%16; //BCD转十进制
temp = DS1302_Read(HOUR);
time[3] = temp/16*10+temp%16; //BCD转十进制
temp = DS1302_Read(MINUTE);
time[4] = temp/16*10+temp%16; //BCD转十进制
temp = DS1302_Read(SECOND);
time[5] = temp/16*10+temp%16; //BCD转十进制
temp = DS1302_Read(DAY);
time[6] = temp/16*10+temp%16; //BCD转十进制
}
单片机自带外设驱动
#include <at89c51RC2.h>
/*******************************************************************************
* 功 能 : 定义本芯片所用的定时器相关地址
* 说 明 : 地址定义来自芯片手册
*******************************************************************************/
Sfr ( IPH , 0xB7);
Sfr ( XICON , 0xC0);
Sfr ( IP , 0xB8);
Sbit (PT2, 0xB8, 5);
Sbit (PS , 0xB8, 4);
Sbit (PT1 , 0xB8, 3);
Sbit (PX1 , 0xB8, 2);
Sbit (PT0 , 0xB8, 1);
Sbit (PX0 , 0xB8, 0);
/*******************************************************************************
* 函 数 名 : Hardware_Delay
* 函数功能 : 延时函数
* 输 入 : x(ms)
* 输 出 : void
* 说 明 : @12.000MHz 1ms
*******************************************************************************/
void Hardware_Delay(int x)
{
unsigned char a, b;
a = 2;
b = 239;
while(x--)
{
while (--a);
while (--b);
}
}
/*******************************************************************************
* 函 数 名 : Key
* 函数功能 : 读取按键键码
* 输 入 : none
* 输 出 : void
* 说 明 : Delay与while的作用为延时消抖
*******************************************************************************/
char Key()
{
char key=0;
if(P3_1==0){Hardware_Delay(20);while(P3_1==0);Hardware_Delay(20);key=1;}
if(P3_0==0){Hardware_Delay(20);while(P3_0==0);Hardware_Delay(20);key=2;}
if(P3_2==0){Hardware_Delay(20);while(P3_2==0);Hardware_Delay(20);key=3;}
if(P3_3==0){Hardware_Delay(20);while(P3_3==0);Hardware_Delay(20);key=4;}
return key;
}
/*******************************************************************************
* 函 数 名 : Timer0_Init
* 函数功能 : 定时器0初始化
* 输 入 : none
* 输 出 : void
* 说 明 : 中断函数模板
void Timer0_Routine() interrupt 1
{
static int cnt;
TL0 = 0x18; //设置定时初值
TH0 = 0xFC; //设置定时初值
cnt++;
if(T0Count>=1000)
{
cnt=0;
}
}
*******************************************************************************/
void Timer0_Init(void)
{
/*TMOD&=0xF0
TMOD|=0x01*/
TMOD=0x01; //设置定时器模式
TF0=0; //开启定时器0
TR0=1; //开启定时器0
// TH0=64535/256;
// TL0=64535%256;
TH0=0xFC; //初始化计数值
TL0=0x18; //初始化计数值
EA=1; //打开全部中断
ET0=1; //打开计时器0中断
IPH=0x00; //设置中断优先级
PT0=0; //设置中断优先级
}
/*******************************************************************************
* 函 数 名 : UART_Init
* 函数功能 : 初始化串口通信
* 输 入 : none
* 输 出 : void
* 说 明 : 通过软件生成——9600bps
*******************************************************************************/
void UART_Init(void)
{
/*串口设置*/
PCON &= 0x7F; //波特率不倍速
SCON = 0x50; //8位数据,接收模式
/*定时器设置*/
AUXR &= 0xBF; //定时器1时钟为Fosc/12,即12T
AUXR &= 0xFE; //串口1选择定时器1为波特率发生器
TMOD &= 0x0F; //清除定时器1模式位
TMOD |= 0x20; //设定定时器1为8位自动重装方式
TL1 = 0xFD; //设定定时初值
TH1 = 0xFD; //设定定时器重装值
ET1 = 0; //禁止定时器1中断
TR1 = 1; //启动定时器1
/*中断设置*/
EA=1; //打开全部中断
ES=1; //允许串行口中断
PS=1; //中断优先级设置为1
IPH=0x00;
}
/*******************************************************************************
* 函 数 名 : UART_Send
* 函数功能 : 单片机向电脑发送字节
* 输 入 : Data:数据帧
* 输 出 : void
* 说 明 : SBUF为串口数据缓存器,TI为发送标志位,RI为接收标志位
* 中断接收函数模板
void UART_Routine() interrupt 4
{
if(RI==1)
{
P2=SBUF;
UART_Send(SBUF);
RI=0; //复位清零
}
}
*******************************************************************************/
void UART_Send(char Data)
{
SBUF=Data;
while(TI==0); //标志位检测
TI=0; //复位
}