求助,一个时钟程序,时间不走,调了两天仍无进展。。。

2019-07-15 19:21发布

ds1302+lcd1602的电子时钟程序附带闹钟功能,本人亲调了两天仍无法找出bug,求大神指导.
以下是程序:
#include <reg52.h>
#include <intrins.h>
#define MSB 0x80 //读忙位
#define HIGH 1
#define LOW 0
//*****************************************
#define DATA_MODE 0x38 //LCD模式设置,0x28位四位数据线模式
#define OPEN_SCREEN 0x0C //打开LCD显示
#define DISPLAY_ADDRESS 0x80 //写地址指令
#define CLEARSCREEN LCD_en_com(0x01) //清屏
//***********//LCD1602的接线//*****************************
#define LCDIO P0 //LCD1602的高四位接在P0口的高四位
sbit LCD1602_RS=P2^6; //RS为寄存器选择,高电平时选择数据寄存器、低电平时选择指令寄存器。
sbit LCD1602_RW=P2^5; //RW为读写信号线,高电平时进行读操作,低电平时进行写操作。
sbit LCD1602_EN=P2^7; //E端为使能端,当E端由高电平跳变成低电平时,液晶模块执行命令。
//*********************************************************//
sbit alARM_speaker=P1^5; //蜂鸣器的接线
//sbit DS18B20=P3^7; //自已定义的ds18b20口
sbit SCLK=P3^6; //ds1302的接线
sbit IO=P3^4;
sbit RST=P3^5;
sbit ACC7=ACC^7; //累加器
sbit ACC0=ACC^0;
//unsigned char L_18B20,H_18B20; //分别存放低八位高八位的数据;
//unsigned char fg=0,zhengshu,xiaoshu1,xiaoshu2; //fg为负数标志位,zhengshu是温度的整数部分,xiaoshu1是十分位,xiaoshu2是百分位
unsigned char times[7]={55,39,16,7,11,3,7}; //存放时间
unsigned char key=16; //存放健值
unsigned char alarm_clock[3]={0}; //用于存放闹钟的时间:时分和闹钟的标志位
//void Reset_18B20(void); //ds18b20复位程序
//void Wait_18B20(); //等待程序,等待ds18b20应答
//bit Readbit_18B20(void); //读取一个bit的数据
//unsigned char Readbyte_18B20(void); //读取一个字节的数据
//void Writebyte_18B20(unsigned char b); //写一个字节(控制字)
//void Convert(void); //开始转换
//void Read_18B20(void); //读取ds18b20
void write_1302_byte(unsigned char d); //向1302写入一字节数据d
unsigned char read_1302_byte(void); //从1302读出一字节数据并返回
void write_1302_reg(unsigned char add,unsigned char d); //向1302地址add处写入数据d
unsigned char read_1302_reg(unsigned char add); //从1302地址add处读出数据并返回
void on_off_1302(unsigned char ch); //启动/停止计时,gate=0时启动计时,gate!=0时停止计时
void hour_mode_1302(unsigned char ch); //时间显示方式设置,ch=0时为24小时格式,ch!=0时为12小时格式
void write_1302_time(unsigned char *time); //设置时间
void read_1302_time(unsigned char time[]); //读出时间
//**********************************************************************
void LCD_en_com(unsigned char command); //写命令指令
void LCD_en_dat(unsigned char temp); //写数据指令
void LCD_set_xy(unsigned char x, unsigned char y); //设置显示地址:X为横轴(0-15),Y为纵轴(0-1).
void LCD_write_char(unsigned x,unsigned char y,unsigned char dat); //写一个字符
void LCD_write_string(unsigned char x,unsigned char y,unsigned char *s);//写一个字符串
void LCD_write_int(unsigned char x,unsigned char y,unsigned int intdat); //写无字符型整形数
void LCD_init(void); //lcd初始化
void LCD_Read_BF(void); //LCD读忙信号
//**********************************************************************
/*
LCD1602.c

*/
void LCD_Read_BF(void)
{
LCD1602_RW=1; //RW 1
LCD1602_RS=0; //RS 0
LCD1602_EN=1; //EN 1 读忙信号
LCDIO=LCDIO&0x0F|0xf0;
while(LCDIO&MSB);
LCD1602_EN=LOW;
}

void LCD_en_write(void) //EN端产生一个高电平脉冲,写LCD
{
LCD1602_EN=HIGH;
_nop_();
LCD1602_EN=LOW;
}
//*************************************
void LCD_en_com(unsigned char command)
{
LCD_Read_BF();
LCD1602_RS=LOW; //RS 0 写命令
LCD1602_RW=LOW; //RW 0
//LCDIO&=0x0F;
LCDIO=command;//&0xf0 | LCDIO&0x0f; //先发送高四位数据
LCD_en_write();
//command=command<<4;
//LCDIO&=0x0F;
//LCDIO=command&0xf0 | LCDIO&0x0f; //发送低四位数据
//LCD_en_write();
}
//*********************************
void LCD_en_dat(unsigned char dat)
{
LCD_Read_BF();
LCD1602_RS=HIGH; //RS 1 写数据
LCD1602_RW=LOW; //RW 0
//LCDIO &=0x0F;
LCDIO=dat;//&0xf0 | LCDIO&0x0f; //先发送高四位数据
LCD_en_write();
//dat=dat<<4;
//LCDIO &=0x0F;
//LCDIO=dat&0xf0 | LCDIO&0x0f; //发送低四位数据
//LCD_en_write();
}
//**************设置显示地址:X为横轴(0-15),Y为纵轴(0-1)********************
void LCD_set_xy(unsigned char x,unsigned char y)
{
unsigned char address;
x&=0x0f;
if(!y)
address=0x80+x;
else
address=(0x80+0x40)+x;
LCD_en_com(address);
}
//***************写一个字符:X为横轴(0-15),Y为纵轴(0-1)**********
void LCD_write_char(unsigned x,unsigned char y,unsigned char dat)
{
LCD_set_xy(x,y);
LCD_en_dat(dat);
}
//****************写一个字符串***************************************
void LCD_write_string(unsigned char x,unsigned char y,const unsigned char *s)
{
LCD_set_xy(x,y);
while(*s)                 //字符串以'0'结束
{
LCD_en_dat(*s);
s++;
}
}
//****************写一个无字符整数***************************************
void LCD_write_int(unsigned char x,unsigned char y,unsigned int intdat)
{
unsigned char i=0,temp[5];
LCD_set_xy(x,y);
if(intdat==0)
{
LCD_en_dat(0x30);                //?
return;
}
while(intdat/10 || intdat%10)
{
temp[i]=intdat%10;
intdat/=10;
i++;
}
while(i)
{
i--;
LCD_en_dat(temp[i]+0x30);
}
}
//*****//LCD的初始化函数(刚上电的时候一定要调用一次)//*********************
void LCD_init(void)
{
LCD_en_com(DATA_MODE); //设计四位数据线模式
LCD_en_com(OPEN_SCREEN); //打开LCD显示
LCD_en_com(DISPLAY_ADDRESS);//设计首地址
CLEARSCREEN; //清屏
}
/*void Reset_18B20(void)//ds18b20复位程序
{
unsigned char i;
DS18B20=0;
i=110;
while(i>0)i--;
DS18B20=1;
i=6;
while(i>0)i--;
}
void Wait_18B20()//等待程序,等待ds18b20应答
{
unsigned char i;
while(DS18B20);
while(~DS18B20);
i=6;
while(i>0)i--;
}
bit Readbit_18B20(void) //读取一个bit的数据
{
unsigned char i;
bit b;
DS18B20=0;
i++;i++;
DS18B20=1;
i++;i++;i++;i++;i++;
b=DS18B20;
i=13;
while(i>0)i--;
return b;
}
unsigned char Readbyte_18B20(void) //读取一个字节的数据
{
unsigned char i,j,b;
b=0;
for(i=1;i<=8;i++)
{
j=Readbit_18B20();
b=(j<<7)|(b>>1); //又玩野
}
return b;
}
void Writebyte_18B20(unsigned char b)//写一个字节(控制字)
{
unsigned char j,i;
bit temp;
for(j=1;j<=8;j++)
{
temp=b&0x01;
b=b>>1;
if(temp) // 写"1"
{
DS18B20=0;
i++;i++;i++;i++;i++;
DS18B20=1;
i=13;
while(i>0)i--;
}
else //写"0"
{
DS18B20=0;
i=13;
while(i>0)i--;
DS18B20=1;
i++;i++;i++;i++;i++;
}
}
}
void Convert(void) //开始转换
{
Reset_18B20();
Wait_18B20(); //等待应答脉冲
Writebyte_18B20(0xcc); //跳过序列号脉冲
Writebyte_18B20(0x44); //转换命令
}
void Read_18B20(void) //读取ds18b20
{
Convert();
Reset_18B20();
Wait_18B20();
Writebyte_18B20(0xcc); //跳过ROM
Writebyte_18B20(0xbe); //发送读取命令
L_18B20=Readbyte_18B20(); //读取低八位数据
H_18B20=Readbyte_18B20(); //读取高八位数据
if(H_18B20>0x7f) //最高位为1时温度是负
{
L_18B20=~L_18B20; //补码转换,取反加一
H_18B20=~H_18B20+1;
fg=1; //读取温度为负时fg=1
}
zhengshu=L_18B20/16+H_18B20*16; //整数部分
xiaoshu1=(L_18B20&0x0f)*10/16; //小数第一位
xiaoshu2=(L_18B20&0x0f)*100/16%10;//小数第二位
}
/*================================================================*/
/* 向1302当前地址处写入1字节数据 */
/*================================================================*/
void write_1302_byte(unsigned char d)
{
unsigned char i;
ACC=d; //将8位数据写入ACC
for(i=8;i>0;i--) //循环8次将ACC8位数据从低位到高位写入1302
{
IO=ACC0; //将ACC的最低位转送到IO口
SCLK=1; //上升沿写入1位数据
SCLK=0;
ACC=ACC>>1; //将ACC次低位变为最低位
}
}
/*=================================================================*/
/*=================================================================*/
/* 从1302的当前地址处读出1字节数据 */
/*=================================================================*/
unsigned char read_1302_byte(void)
{
unsigned char i;
for(i=8;i>0;i--)
{
ACC=ACC>>1;
ACC7=IO;
SCLK=1; //时钟下降沿读1位数据
SCLK=0;
}
return (ACC);
}
/*=================================================================*/
/* 将数据Data写入1302寄存器add处 */
/*================================================================*/
void write_1302_reg(unsigned char add,unsigned char d)
{
RST= 0;
SCLK=0;          //只有sclk为低电平是RST才能被置为高电平
RST= 1;          //只有RST为高电平是才允许数据传输
write_1302_byte(add); //将1302的指针移到add处
write_1302_byte(d); //往add处写入数据
SCLK=1;
RST=0; //停止写数据
}
/*=================================================================*/
/* 读寄存器add处的值 */
/*==================================================================*/
unsigned char read_1302_reg(unsigned char add)
{
unsigned char d;
RST=0;
SCLK=0;
RST=1;
write_1302_byte(add);
d=read_1302_byte();
SCLK=1;
RST=0;
return (d);
}
/*=================================================================*/
/* 设置时间,time[0]-time[6]数据存放顺序为:秒,分,时,日,月,星期,年 */
/*===================================================================*/
void write_1302_time(unsigned char *time)
{
unsigned char add=0x80; //地址add初值(秒),偶数地址为只写
unsigned char i;
unsigned char timeBCD[7]; //用以存放time数据的BCD码值
bdata unsigned char l,h; //单位变量,分别存放时间数据(8421BCD码)的低4位和高4位
for(i=0;i<7;i++) //将时间数据转为BCD码放入timeBCD中
{
l=time[i]%10;
h=time[i]/10;
timeBCD[i]=h*16+l;
}
write_1302_reg(0x8e,0x00); //禁止写                                                                                                 //?
for(i=0;i<7;i++)
{
write_1302_reg(add,timeBCD[i]); //将时间数据写入1302对应的寄存器
add+=2; //地址移动,确保地址为偶数
}
write_1302_reg(0x8e,0x80); //允许写
}
/*================================================================= =*/
/* 读取当前时间 */
/*======================= ===========================================*/
void read_1302_time(unsigned char time[])
{
unsigned char i;
unsigned char add=0x81; //设置地址add初值(秒),奇数为只读
bdata unsigned char l,h; //单位变量,分别存放时间数据(8421BCD码)的低4位和高4位,用以进行十进制转换
write_1302_reg(0x8e,0x00); //禁止写
for(i=0;i<7;i++)
{
time[i]=read_1302_reg(add); //将时间数据(8421BCD码)从1302对应的寄存器中读出
l=time[i]&0x0f; //l存放time的低4位,即个位
h=(time[i]>>4)&0x0f; //h存放time的高4位,即十位
time[i]=h*10+l; //时间数据以十进制形式放进time[i]中
add+=2; //地址移动,确保地址为奇数
}
}
/*======================================================================================*/
/*=====================================================================================*/
/* 启动/停止计时,gate=0时启动计时,gate!=0时停止计时 */
/*=====================================================================================*/
void on_off_1302(unsigned char ch)
{
unsigned char temp;
if(ch)
{
temp=read_1302_reg(0x80); //将秒当前值读入temp暂存
temp=temp|0x80; //将秒数据最高位置1          ,允许写入??
write_1302_reg(0x80,temp); //将置1后的秒数据写入秒寄存器,以定止计时
}
else
{
temp=read_1302_reg(0x80); //将秒当前值读入temp暂存
temp=temp&0x80; //将秒数据最高位置0                禁止写入??
write_1302_reg(0x80,temp); //将最高位置0后的秒数据写入秒寄存器,以启动计时
}
}
/*=====================================================================================*/
/*=========================================================================================*/
/* 时间显示方式设置,ch=0时为24小时格式,ch!=0时为12小时格式
*/
/*=========================================================================================*/
void hour_mode_1302(unsigned char ch)
{
unsigned char temp;
if(ch)
{
temp=read_1302_reg(0x85); //将小时当前值读入temp暂存
temp=temp|0x80; //将小时数据最高位置1
write_1302_reg(0x84,temp); //将置1后的小时数据写入小时寄存器,变为12小时格式
}
else
{
temp=read_1302_reg(0x85); //将小时当前值读入temp暂存
temp=temp&0x80; //将小时数据最高位置0
write_1302_reg(0x84,temp); //将最高位置0后的小时数据写入小时寄存器,变为24小时格式
}
}
/*=========================================================================================*/
void delay(unsigned char i) //延时函数
{
unsigned char j;
while(i--)
for(j=101;j>1;j--);
}

void key_scan()
{ unsigned char X,Y,Z,k=key;
P1=0x0f;
P1=0x0f; //先对P1置数行扫描
if(P1!=0x0f) //判断是否有键按下
{ delay(5); //延时,软件去干扰
if(P1!=0x0f) //确认按键按下X = P1;
{
X=P1; //保存行扫描时有键按下时状态
P1=0xf0; //列扫描
delay(5);
Y=P1; //保存列扫描时有键按下时状态
Z=X|Y; //取出键值
switch ( Z ) //判断键值(那一个键按下)
{case 0xe7: k=13;break; //对键值赋值
case 0xd7: k=9;break;
case 0xb7: k=5;break;
case 0x77: k=1;break;
case 0xeb: k=14;break;
case 0xdb: k=10;break;
case 0xbb: k=6;break;
case 0x7b: k=2;break;
case 0xed: k=15;break;
case 0xdd: k=11;break;
case 0xbd: k=7;break;
case 0x7d: k=3;break;
case 0xee: k=16;break;
case 0xde: k=12;break;
case 0xbe: k=8;break;
case 0x7e: k=4;break;
}
key=k-1;
}
}
P1=0xff;
}
void display_dat() //显示时间和温度的函数
{
CLEARSCREEN;
LCD_write_string(0,0,"DAT:");
LCD_write_int(4,0,2000+times[6]); //显示年份
LCD_en_dat('-');
LCD_write_int(9,0,times[4]/10); //显示月份
LCD_write_int(10,0,times[4]%10);
LCD_en_dat('-');
LCD_write_int(12,0,times[3]/10); //显示日期
LCD_write_int(13,0,times[3]%10);
LCD_write_int(15,0,times[5]); //显示星期
LCD_write_int(0,1,times[2]/10); //显示小时
LCD_write_int(1,1,times[2]%10);
LCD_en_dat(':');
LCD_write_int(3,1,times[1]/10); //显示分钟
LCD_write_int(4,1,times[1]%10);
LCD_en_dat(':');
LCD_write_int(6,1,times[0]/10); //显示秒
LCD_write_int(7,1,times[0]%10);
//LCD_write_int(10,1,zhengshu); //显示温度的整数部分
//LCD_en_dat('.');
//LCD_en_dat(xiaoshu1+0x30); //显示温度的小数部分
//LCD_en_dat(0x27); //显示'号
//LCD_en_dat('C'); //显示C
}
void chang_time(unsigned char i)
{
unsigned char tem=0,temp_time=0,clock=0,temp_clock;
CLEARSCREEN;
if(i<=7)
{
if(i==0) LCD_write_string(0,0,"Change second:"); //修改秒
if(i==1) LCD_write_string(0,0,"Change minute:"); //修改分
if(i==2) LCD_write_string(0,0,"Change hour:"); //修改时
if(i==3) LCD_write_string(0,0,"Change day:"); //修改日
if(i==4) LCD_write_string(0,0,"Change month:"); //修改月
if(i==5) LCD_write_string(0,0,"Change week:"); //修改星期
if(i==6) LCD_write_string(0,0,"Change year:"); //修改年
if(i==7 && alarm_clock[2]==0) LCD_write_string(0,0,"Open AlarmClock");//修改闹钟
if(i==7 && alarm_clock[2]!=0) LCD_write_string(0,0,"AlarmClock:");
key=16;
delay(250);
while(1)
{
key_scan();
if(key<10)
{
tem=(tem*10)+key;
if((i==0 || i==1 || clock==1) && tem>59) tem=59;//确保修改的数据不超出限制,
if((i==2 || (clock==0 && i==7)) && tem>23) tem=23; //比如分不能超过60,月不能超过12等。
if(i==3 && tem>31) tem=31; //如超过限制,则定为最大
if(i==4 && tem>12) tem=12;
if(i==5 && tem>7)
{if(key<=7 && key!=0)tem=key;
else tem=7;
}
delay(200);
key=16;
}
if(key==14)
{
tem/=10;
key=16;
delay(200);
}
if(key==15 && i!=7)break; //确定闹钟之外的数据
if(key==15 && i==7)
{
if(clock==0)
{
temp_clock=tem; //确定闹钟的时
key=16;
tem=0;
clock=1;
delay(200);
}
else //确定闹钟的分
{
alarm_clock[0]=temp_clock;
alarm_clock[1]=tem;
alarm_clock[2]=1;
return;
}
}
if(key==12)return;
if(key==13)
{
alarm_clock[2]=0; //取消闹钟功能
CLEARSCREEN;
LCD_write_string(0,0,"Close AlarmClock");
delay(250);
delay(250);
delay(250);
delay(250);
delay(250);
delay(250);
return;
}
if(temp_time!=tem)
{
LCD_write_char(8,1,' '); //实时显示修改的数据
if(i==6)
{
LCD_write_int(9,1,20);
LCD_en_dat(tem/10+0x30);
LCD_en_dat(tem%10+0x30);
}
else if(clock==0)
{
LCD_write_int(7,1,tem);
if(i==7)
{
LCD_en_dat(':'); //实时显示修改闹钟的数据
LCD_en_dat(0x30);
LCD_en_dat(0x30);
}
}
else
{
LCD_write_int(7,1,temp_clock/10);
LCD_write_int(8,1,temp_clock%10);
LCD_en_dat(':');
LCD_write_int(10,1,tem/10);
LCD_write_int(11,1,tem%10);
}
temp_time=tem;
}
delay(100);
read_1302_time(times);
LCD_write_string(0,1,"Now: ");
if(i<6)LCD_write_int(4,1,times[i]); //实时显示当前的数据
else if(i==6)LCD_write_int(4,1,times[i]+2000);
else if(i==7)
{
LCD_write_int(0,1,alarm_clock[0]/10); //显示当前闹钟的时间
LCD_write_int(1,1,alarm_clock[0]%10);
LCD_en_dat(':');
LCD_write_int(3,1,alarm_clock[1]/10);
LCD_write_int(4,1,alarm_clock[1]%10);
}
}
read_1302_time(times);
times[i]=tem;
write_1302_time(times); //把数据写进1302
}
}
void main() //主函数
{
unsigned char temp=0;
LCD_init();
write_1302_time(times); //把数据写进1302
while(1)
{
read_1302_time(times); //读ds1302的时间
key_scan(); //扫描键盘
if(key<8) //如果键盘值小于8则进入修改界面
{
chang_time(key);
key=16;
}
if(times[1]==alarm_clock[1] && times[2]==alarm_clock[0] && alarm_clock[2]==1)//如时间到,闹钟响
{
if(key==16)alarm_speaker=0;
}
delay(30);
alarm_speaker=1;
delay(170);
display_dat();//显示时间和温度
//Read_18B20();
}
}


友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。