📄 main_c.c
字号:
/*/////////////////////////////////////////////////////
文件名 : main.c
功 能 : Time helper 主模块
控制器 : AT89S52
时钟 : 11.0592
编译器 : Keil C51 7.0
*/////////////////////////////////////////////////////
#include "common.h"
sbit LED = P3^5;
sbit BEEP = P1^4;
sbit BEEP_EX= P0^0;
sbit RADIO = P3^7;
#define SETLED LED=0
#define CLRLED LED=1
#define SETBEEP BEEP_EX=BEEP=0
#define CLRBEEP BEEP_EX=BEEP=1
#define SETRADIO RADIO=0;
#define CLRRADIO RADIO=1;
uchar g_time[3]; //时间计数器 存储格式:h,m,s
uchar g_alarm_time[3]; //报警时间缓冲 存储格式:h,m,alarm index
uchar g_minflag=0; //过分钟标记
//延时
void DelayMs(uint n)
{
uint i;
uchar j;
for(i=0;i<n;i++)
for(j=0;j<150;j++);
}
//初始化
void Initial(void)
{
CLRLED;
CLRBEEP;
CLRRADIO;
lcd_initial();
lcd_clear();
eep_init();
RTC_Enable();
Uart_Enable();
EA=1;//总中断允许
}
/********计数模块*****************/
//time1-time2 返回分钟
//从TIME1到TIME2的时间
uint GetTimeDefference(uchar *time1,uchar *time2)
{
uchar tmp=time2[0];
uint ret=0;
if(time2[0]<time1[0])
tmp+=24;
else if(time2[0]==time1[0])
{
if(time2[1]<=time1[1])
tmp+=24;
}
ret=(tmp-time1[0])*60;
ret+=time2[1];
ret-=time1[1];
return ret;
}
//计数模块要检测报警时间
//获取下一次报警时间
void GetNextAlarmTime(void)
{
uchar i,tmpbuf[2];
uchar index=0;//记录最小时差的报警索引
uint minval=24*60,tmp;
for(i=0;i<5;i++)//找出在EEPROM五个记录中时间距离最近的一项
{
eep_readstring(i*24,tmpbuf,2);
tmp=GetTimeDefference(g_time,tmpbuf);
if(tmp<minval)
{
minval=tmp;
index=i;
}
}
eep_readstring(index*24,g_alarm_time,2);
g_alarm_time[2]=index;//报警信息在EEPROM里存的索引
}
//在计时模式时格式化显示时间
void BeginDisplayTime(uchar *p)
{
//将年月日、星期、时分显示到LCD
uchar disbuf[6];
lcd_clear();
disbuf[0]=(p[6]>>4)+48;//年高
disbuf[1]=(p[6]&0x0f)+48;//年低
disbuf[2]='-';
disbuf[3]=(p[5]>>4)+48;//月高
disbuf[4]=0;
lcd_displaystring(disbuf,0);
disbuf[0]=(p[5]&0x0f)+48;//月低
disbuf[1]='-';
disbuf[2]=(p[4]>>4)+48;//日高
disbuf[3]=(p[4]&0x0f)+48;//日低
disbuf[4]=0;
lcd_displaystring(disbuf,2);
disbuf[0]=32;
disbuf[1]=p[3]+48;
disbuf[2]='d';
disbuf[3]='a';
disbuf[4]='y';
disbuf[5]=0;
lcd_displaystring(disbuf,4);
disbuf[0]=((p[2]&0x3f)>>4)+48;//小时
disbuf[1]=(p[2]&0x0f)+48;
disbuf[2]=':';
disbuf[3]=' ';
disbuf[4]=0;
lcd_displaystring(disbuf,7);
disbuf[0]=(p[1]>>4)+48;
disbuf[1]=(p[1]&0x0f)+48;
disbuf[2]=0;
lcd_displaystring(disbuf,9);
}
//进入计时模式功能函数
void EnterClockMode(void)
{
uchar *p=RTC_GetBuffer();
while(1)
{
RTC_ClearError();
RTC_UpdateData(1);
if(RTC_GetError())
{
lcd_displaystring("RTC error! retry...",0);
SETLED;
DelayMs(500);
CLRLED;
DelayMs(500);
}
else
break;
}
g_time[0]=((p[2]&0x3f)>>4)*10+(p[2]&0x0f);//h
g_time[1]=(p[1]>>4)*10+(p[1]&0x0f);//m
g_time[2]=0;//s
BeginDisplayTime(p);
GetNextAlarmTime();
RTC_SetSQWOutput(1,1);//1Hz output
IT1=1;//外部中断1边沿触发
EX1=1;//外部中断1允许
}
//离开计时模式
void LeaveClockMode(void)
{
EX1=0;//外部中断1禁止
RTC_SetSQWOutput(0,0);//1Hz output disable
}
//外部中断1,信号来自DS1307 1Hz 输出
void IntSQW1Hz() interrupt 2
{
g_time[2]++;
if(g_time[2]==60)
{
g_time[2]=0;
g_minflag=1;
}
}
////////////////////////////////////////////////////
/*为串口操作存储器提供的6个函数*/
void WriteEeprom(void)
{
uchar i,addr;
uchar *p=Uart_GetBuffer();
p[0]=0xaa;
Uart_Send(1);//回应
Uart_Recv(10,UART_WAIT);
addr=p[0]*24;
eep_writestring(addr,p+1,4);
addr+=4;
for(i=0;i<2;i++)
{
p[0]=0xaa;
Uart_Send(1);//回应
Uart_Recv(10,UART_WAIT);
eep_writestring(addr,p,10);
addr+=10;
}
p[0]=0xaa;
Uart_Send(1);//回应
}
void ReadEeprom(void)
{
uchar i;
uchar *p=Uart_GetBuffer();
for(i=0;i<120;)
{
eep_readstring(i,p,2);
Uart_Send(2);
i+=2;
}
}
//写DS1307 ram
void WriteRTCRam(void)
{
uchar i;
uchar *p=Uart_GetBuffer();
for(i=0;i<5;i++)
{
p[0]=0xaa;
Uart_Send(1);
Uart_Recv(10,UART_WAIT);
RTC_WriteRAM(i*10,p,10);
}
p[0]=0xaa;
Uart_Send(1);
}
//读DS1307 ram
void ReadRTCRam(void)
{
uchar i;
uchar *p=Uart_GetBuffer();
for(i=0;i<5;i++)
{
RTC_ReadRAM(i*10,p,10);
Uart_Send(10);
}
}
//设置当前时间
void SetCurrentTime()
{
uchar i;
uchar *p=Uart_GetBuffer();
uchar *p1=RTC_GetBuffer();
p[0]=0xaa;
Uart_Send(1);//确认准备好
Uart_Recv(7,UART_WAIT);//读时间数据
for(i=0;i<7;i++)
p1[i]=p[i];
RTC_UpdateData(0);//写ds1307
p[0]=0xaa;//确认操作成功
Uart_Send(1);
}
//获取当前时间
void GetCurrentTime()
{
uchar i;
uchar *p=Uart_GetBuffer();
uchar *p1=RTC_GetBuffer();
RTC_UpdateData(1);//从DS1307读时间数据
for(i=0;i<7;i++)
p[i]=p1[i];
Uart_Send(7);
}
///////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////
//报警功能函数////////////////////////////////////////////
void Alarm(uchar index)
{
uchar temp[5],i;
uint *p=(uint *)temp;
//显示报警字符
lcd_clear();
for(i=0;i<5;i++)
{
eep_readstring(index*24+4+i*4,temp,4);
temp[4]=0;
lcd_displaystring(temp,i*2);
}
//读报警类型及持续时间
eep_readstring(index*24+2,temp,2);
if(temp[0]==1)//led alarm
{
for(i=0;i<temp[1];i++)
{
SETLED;
DelayMs(800);
CLRLED;
DelayMs(800);
}
}
else if(temp[0]>1 &&temp[0]<6)//play music
{
for(i=0;i<temp[1];i++)
MusicPlay(temp[0]-2);
}
else if(temp[0]==6)//beep
{
for(i=0;i<temp[1];i++)
{
SETBEEP;
DelayMs(500);
CLRBEEP;
DelayMs(800);
}
}
else if(temp[0]==7)//radio alarm
{
SETRADIO;
for(i=0;i<temp[1];i++)
DelayMs(1200);
CLRRADIO;
}
}
//主入口////////////////////////////////////////////////////
int main(void)
{
uchar *p;
//等待系统稳定
DelayMs(2000);
//初始化各功能
Initial();
//串行口异步接收一字节
Uart_Recv(1,UART_NO_WAIT);
//进入计时模式
EnterClockMode();
//主循环
while(1)
{
//根据分钟标记更新计数器并更新显示
if(g_minflag)
{
if(++g_time[1]==60)
{
if(++g_time[0]==24)
{
g_time[0]=0;
}
lcd_displaynum(g_time[0],7);
g_time[1]=0;
}
lcd_displaynum(g_time[1],9);
g_minflag=0;
}
//报警检测、如果满足条件进入报警状态
if((g_time[1]==g_alarm_time[1]) && (g_time[0]==g_alarm_time[0]))
{
LeaveClockMode();
Uart_Disable();
Alarm(g_alarm_time[2]);
Uart_Enable();
EnterClockMode();
}
//串口是否有数据//////////////////////////////////////
if(!Uart_IsWaitRecv())
{
p=Uart_GetBuffer();
LeaveClockMode();
//lcd_clear();
switch(p[0])
{
case 0xAA: //写EEPROM
//lcd_displaystring("write eeprom...",0);
WriteEeprom();
break;
case 0xAB://读EEPROM
//lcd_displaystring("read eeprom...",0);
ReadEeprom();
break;
case 0xac://写DS1307 RAM
//lcd_displaystring("write ram...",0);
WriteRTCRam();
break;
case 0xad://读DS1307 RAM
//lcd_displaystring("read ram...",0);
ReadRTCRam();
break;
case 0xae:
//lcd_displaystring("set time...",0);
SetCurrentTime();
break;
case 0xaf:
//lcd_displaystring("get time...",0);
GetCurrentTime();
break;
case 1:
//p[0]=g_alarm_time[0];
//p[1]=g_alarm_time[1];
//Uart_Send(2);
break;
default:
//lcd_displaystring("Recved:",0);
//p[0]%=100;
//lcd_displaynum(p[0],9);
break;
}
Uart_Recv(1,UART_NO_WAIT);//异步接收下一命令字节
EnterClockMode();
}//switch (uart)
//////////////////////////////////////////////////////
}//while
}//main
//////////////////////////////////////////////////////////////
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -