时钟目前能正常走时,大概1天快12秒
鄙人愚昧,部分问题未能解决,
还望各位高手出手相救,出谋划策
【按键扫描问题】:
调时间时:1,调小时分钟 加键不是按一次加一,是乱加,
小时能调到24时,退出设置显示0时
2,调小时分钟 减键不是按一次减一,是乱减
[size=13.63636302948px] 3,调秒时,加键减键乱加减,秒能调到8*,9*秒
[size=13.63636302948px] 4,退出设置秒清零,设置的秒未能保存,时和分能保存
[size=13.63636302948px] 5,时间能调到24时,退出设置显示0时
[size=13.63636302948px] 当有按键按下时数码管全灭不显示,按键松开数码管显示
[size=13.63636302948px] 6,启动定时器中断,能轻微看见数码管闪烁
[size=13.63636302948px] //7,闹钟有问题,麻烦增加闹钟函数,
[size=13.63636302948px] // 闹钟开指示灯亮,闹钟关指示灯灭
[size=13.63636302948px] 8,如何提高走时精度[size=13.63636302948px] 这里是源工程文件
加按键测试01.zip
(33.2 KB, 下载次数: 22)
[size=13.63636302948px]源程序:
- /************************
- ds1302数码管显示时间
- ************************/
- /*****头文件*****/
- #include<reg52.h>
- #include<intrins.h>
- #define uchar unsigned char
- #define uint unsigned int
- /*****DS1302引脚定义*****/
- sbit rst = P0^7; /*实时时钟复位线引脚*///(所有的数据传输在rst置1时进行,rst为0时终止传输)
- sbit io = P0^6; /*实时时钟数据线引脚*/
- sbit clk = P0^5; /*实时时钟时钟线引脚*/
- sbit ACC0 = ACC^0; /*累加寄存器的第0位*/
- sbit ACC7 = ACC^7; /*累加寄存器的第7位*/
- sbit LED1 = P3^0; /*未定义(高电平亮)(3mm红发红光)*/
- sbit LED2 = P3^1; /*闹钟指示灯(低电平亮)(亮:闹钟开;灭:闹钟关)(alarm clock)(3mm白发绿光)*/
- sbit tele = P3^2; /*红外遥控数据线引脚(telecontrol)*/
- sbit motor = P3^3; /*振子,马达,震动(低电平转)(vibration,motor)*/
- sbit beep = P3^4; /*蜂鸣器(低电平响)*/
- /*****按键定义*****/
- sbit key1 = P3^7; /*设置键*/
- sbit key2 = P3^6; /*加键*/
- sbit key3 = P3^5; /*减键*/
- uchar keynum; /*按键计数*/
-
- /*****数码管数组*****/
- uchar code smg_du[]= /*共阳数码管段码表*//*P2引脚*/
- {0xc0,0xf9,0xa4,0xb0,0x99, /*0-9*/
- 0x92,0x82,0xf8,0x80,0x90,0xbf};
- uchar code smg_we[]= /*数码管位码*//*P1引脚*/
- {0xC1,0xC2,0xC4, /*从左到右*/
- 0xC8,0xD0,0xE0}; /*位置1,2,3,4,5,6*/
- /*****时间初值*****/
- uchar table_shijian[7]={15,7,12,30,23,59,55}; /*年周月日时分秒*/
- uchar write_add[7]={0x8c,0x8a,0x88,0x86,0x84,0x82,0x80}; /*定义写寄存器(年周月日时分秒)*/
- uchar read_add[7]={0x8d,0x8b,0x89,0x87,0x85,0x83,0x81}; /*定义读寄存器(年周月日时分秒)*/
- uchar disp[6]; //存放转换成十进制后并分离出个位十位的数/*6个显示元素(6个数码管)*/
-
- /******函数声明*****/
- void write_ds1302byte(uchar com); /*写一个字节*/
- void write_ds1302(uchar com,uchar dat); /*写一个字节命令和一个字节数据*/
- uchar read_ds1302(uchar com); /*读一字节数据*/
- void ds1302_init(void); /*初始化ds1302*/
- void read_rtc(void); /*读取时间*/
- void display(void); /*显示处理函数*/
- void display_shijian(void); /*显示函数*/
- void delay(uchar z); /*延时*/
- void tiaoshi(void); /*按键扫描*/
- void Timer0Init(); /*定时器初始化*/
- void Timer0zd(); /*定时器中断*/
- /************************************************************************/
- /************主函数***************/
- void main(void)
- {
- delay(200); //等待系统稳定
- LED1=0; //关闭未定义LED (P3.0)
- // Timer0Init(); //初始化定时器0
- ds1302_init(); //初始化ds1302/*一次即可*/
- while(1) /*大循环*/
- {
- tiaoshi(); /*调用按键扫描函数*/
- display(); /*调用显示处理函数*/
- display_shijian(); /*调用显示时间函数*/
- if(keynum==0) /*如果按键没有动作则执行以下指令*/
- {
- read_rtc(); /*调用读时间函数*/
- }
- }
- }
- /*****定时器*****/
- //void Timer0Init() //20毫秒@11.0592MHz
- //{
- // TMOD |= 0x01; //定时器0模式1定时器时钟12T模式
- // TL0 = 0x00; //设置定时初值
- // TH0 = 0xb8; //设置定时初值
- // TF0 = 0; //清除TF0标志
- // TR0 = 1; //开定时器0
- // ET0 = 1; //开定时器中断
- // EA = 1; //开总中断
- //}
- ////
- //void Timer0zd() interrupt 1
- //{
- // TL0 = 0x00; //设置定时初值
- // TH0 = 0xb8; //设置定时初值
- //
- // display();
- ////display_shijian(); /*调用显示时间函数*/
- //// read_rtc(); /*调用读时间函数*/
- // if(keynum==0) /*如果按键没有动作则执行以下指令*/
- // {
- // read_rtc(); /*调用读时间函数*/
- // }
- //}
- /*****延时函数*****/
- void delay(uchar z) /*延时≈1毫秒*/
- {
- uint x,y;
- for(x=z;x>0;x--)
- for(y=115;y>0;y--);
- }
- /*****按键扫描模块*****/
- void tiaoshi(void)
- {
- if(key1==0) //如果设置键按下
- {
- delay(10); //延时消抖
- if(key1==0) //判断,防误操作
- {
- while(!key1); //松手检测
- write_ds1302(0x8e,0x00); //关闭写保护(可以写操作)
- write_ds1302(0x80,0x80); //晶振停振时钟停止秒停
- keynum++; //设置键按键计数自动加1*/
- switch(keynum) //设置键按键次数统计*/
- {
- case 1:P2=smg_du[disp[1]];P1=smg_we[1];delay(100);break; /*按1次*//*调小时*//*数码管第二位闪烁*//*时个位*/
- case 2:P2=smg_du[disp[3]];P1=smg_we[3];delay(100);break; /*按2次*//*调分钟*//*数码管第四位闪烁*//*分个位*/
- case 3:P2=smg_du[disp[5]];P1=smg_we[5];delay(100);break; /*按3次*//*调秒钟*//*数码管第六位闪烁*//*秒个位*/
- case 4:keynum=0;write_ds1302(0x80,0x00);write_ds1302(0x8e,0x80);break; /*按4次*//*退出设置*//*启动晶振开始走时*//*开写保护*/
- default:break;
- }
- }
- }
- if(keynum!=0) //如果keynum不是0说明设置键有动作
- { //则执行以下指令
- if(key2==0) //如果加键被按下
- { //则执行以下指令
- delay(10); //延时消抖
- while(!key2) //松手检测
- switch(keynum) /*设置键按键计数*/
- {
- case 1: /*加键按一次*//*时加1*/
- table_shijian[4]=read_ds1302(read_add[4]); //读出当前的小时
- table_shijian[4]=((((table_shijian[4]&0xf0)>>4)*10)+(table_shijian[4]&0x0f)); //将当前的时转换成十进制数
- table_shijian[4]++;
- if(table_shijian[4]==24) table_shijian[4]=0;
- table_shijian[4]=(((table_shijian[4]/10)<<4)|table_shijian[4]%10); //将时部分十进制数转换为十六进制数
- write_ds1302(write_add[4],table_shijian[4]);break; //写入ds1302时位置
-
- case 2: /*加键按一次*//*分加1*/
- table_shijian[5]=read_ds1302(read_add[5]); //读出当前的分钟
- table_shijian[5]=((((table_shijian[5]&0xf0)>>4)*10)+(table_shijian[5]&0x0f)); //将当前的分钟转换成十进制数
- table_shijian[5]++;
- if(table_shijian[5]==60) table_shijian[5]=0;
- table_shijian[5]=(((table_shijian[5]/10)<<4)|table_shijian[5]%10); //将分钟部分十进制数转换为十六进制数
- write_ds1302(write_add[5],table_shijian[5]);break; //写入ds1302分位置
-
- case 3: /*加键按一次*//*秒加1*/
- table_shijian[6]=read_ds1302(read_add[6]); //读出当前的秒
- table_shijian[6]=((((table_shijian[6]&0xf0)>>4)*10)+(table_shijian[6]&0x0f)); //将当前的秒转换成十进制数
- table_shijian[6]++;
- if(table_shijian[6]==60) table_shijian[6]=0;
- table_shijian[6]=(((table_shijian[6]/10)<<4)|table_shijian[6]%10); //将秒部分十进制数转换为十六进制数
- write_ds1302(write_add[6],table_shijian[6]);break; //写入ds1302秒位置
- }
- }
- }
- if(keynum!=0) //如果keynum不是0说明设置键有动作
- { //则执行以下指令
- if(key3==0) //如果减键被按下
- { //则执行以下指令
- delay(10); //延时消抖
- while(!key3) //松手检测
- switch(keynum) /*设置键按键计数*/
- {
- case 1: /*减键按一次*//*时减1*/
- table_shijian[4]=read_ds1302(read_add[4]); //读出当前的时
- table_shijian[4]=((((table_shijian[4]&0xf0)>>4)*10)+(table_shijian[4]&0x0f)); //将当前的时转换成十进制数
- table_shijian[4]--;
- if(table_shijian[4]==-1) table_shijian[4]=23;
- table_shijian[4]=(((table_shijian[4]/10)<<4)|table_shijian[4]%10); //将时部分十进制数转换为十六进制数
- write_ds1302(write_add[4],table_shijian[4]);break; //写入ds1302时位置
-
- case 2: /*减键按一次*//*分减1*/
- table_shijian[5]=read_ds1302(read_add[5]); //读出当前的分
- table_shijian[5]=((((table_shijian[4]&0xf0)>>4)*10)+(table_shijian[5]&0x0f)); //将当前的分转换成十进制数
- table_shijian[5]--;
- if(table_shijian[5]==-1) table_shijian[5]=59;
- table_shijian[5]=(((table_shijian[5]/10)<<4)|table_shijian[5]%10); //将分部分十进制数转换为十六进制数
- write_ds1302(write_add[5],table_shijian[5]);break; //写入ds1302分位置
-
- case 3: /*减键按一次*//*秒减1*/
- table_shijian[6]=read_ds1302(read_add[6]); //读出当前的秒
- table_shijian[6]=((((table_shijian[6]&0xf0)>>4)*10)+(table_shijian[6]&0x0f)); //将当前的秒转换成十进制数
- table_shijian[6]--;
- if(table_shijian[6]==-1) table_shijian[6]=59;
- table_shijian[6]=(((table_shijian[6]/10)<<4)|table_shijian[6]%10); //将秒部分十进制数转换为十六进制数
- write_ds1302(write_add[6],table_shijian[6]);break; //写入ds1302秒位置
- }
- }
- }
- }
- /*****ds1302模块*****/
- /*****写一个字节*****/
- void write_ds1302byte(uchar com)
- {
- uchar i; //定义一个变量i
- for(i=0;i<8;i++) //连续写8个二进制位数据
- {
- clk=0; //拉低时钟线,为脉冲上升沿写入数据做好准备
- io=com&0x01; //取出com的第0位数据写入1302//(数据和0x01与)每次传输低字节
- com=com>>1; //将com的数据位右移1位
- clk=1; //时钟线上升沿写入数据
- }
- }
- /*****写一个字节命令和一个字节数据*****/
- void write_ds1302(uchar com,uchar dat)
- {
- rst=0; _nop_(); //禁止数据传输//空操作(相当于短暂延时)
- clk=0; _nop_(); //确保写数据前时钟线被拉低//空操作
- rst=1; _nop_(); //启动数据传输//空操作
- write_ds1302byte(com); //写命令地址
- write_ds1302byte(dat); //写数据
- rst=0; _nop_(); //禁止数据传递(操作完赶紧拉低防止误操作)//空操作
- io=0; _nop_(); //释放io
- clk=1; _nop_(); //将时钟线电平置于已知状态
- }
- /*****读一个字节命令读一个字节数据*****/
- uchar read_ds1302(uchar com)
- {
- uchar i,value;
- clk=1; _nop_(); //确保写数据前时钟线被拉高//空操作
- io=1; _nop_(); //数据线拉高
- rst=1; _nop_(); //启动数据传输//空操作
- write_ds1302byte(com); //写入命令字后/进行读操作之前要进行写命令(地址),以确定是读那个
- for(i=0;i<8;i++) //连续读8个二进制位数据
- {
- clk=0; //拉低时钟线,形成脉冲下降沿读数据
- value=value>>1; //将value的各数据位右移1位,先读出的是字节的最低位
- if(io) //如果读出的数据是1
- value=value|0x80; //将1取出,写在value的最高位
- clk=1; //将clk拉高,为下次下降沿读出数据做好准备
- }
- rst=0; //禁止数据传输
- return(value); //将读出的数据返回
- }
- /*****初始化DS1302*****/
- void ds1302_init(void)
- {
- uchar i,a,b;
- // uchar CH;
- write_ds1302(0x8e,0x00); //关闭写保护(可以写操作)
- // write_ds1302(0x80,0x80); //装初值前晶振停止,秒停
- for(i=0;i<7;i++)
- {
- a=table_shijian[i]%10; //个位
- b=table_shijian[i]/10; //十位
- table_shijian[i]=a+b*16; //转换为十六进制
- }
- // CH=read_ds1302(0x81); //先对ds1302进行读回秒寄存器,
- //
- // if(CH&0x80) //判断秒寄存器最高位(CH)是否为1
- // { //如为1,说明晶振停止工作,ds1302处于低功耗待命状态,对它写入初值
- // //如为0,说明晶振开始振动,ds1302处于工作状态,(说明在断电时还起用了备用电池,所以ds1302还处于工作状态)
- // //如果每次上电要求都写入初值,就无需这步操作,
- // for(i=0;i<7;i++) //写入数据(年周月日时分秒)
- // {
- // write_ds1302(write_add[i],table_shijian[i]); //写入命令,写数据
- // }
- // }
- for(i=0;i<7;i++) //连续写7个数据(年周月日时分秒)
- {
- write_ds1302(write_add[i],table_shijian[i]); //写入命令,写数据//对号入座
- }
-
- // write_ds1302(0x80,0x00); //启动晶振开始走时,秒走
- write_ds1302(0x90,0xa5); //使能充电,1个二极管,2K电阻
- write_ds1302(0x8e,0x80); //打开写保护(禁止写操作)
- }
- //*****读取时间*****/
- void read_rtc(void)
- {
- uchar i;
- for(i=0;i<7;i++) //连续读7个数据(年周月日时分秒)
- {
- table_shijian[i]=read_ds1302(read_add[i]); //数据对应寄存器的地址
- }
- }
- /************显示处理**************/
- void display(void)
- {
- disp[0]=table_shijian[4]/16; /*时的十位*/
- disp[1]=table_shijian[4]%16; /*时的个位*/
- /*disp[2]=10;*/
- disp[2]=table_shijian[5]/16; /*分的十位*/
- disp[3]=table_shijian[5]%16; /*分的个位*/
- /*disp[5]=10; */
- disp[4]=table_shijian[6]/16; /*秒的十位*/
- disp[5]=table_shijian[6]%16; /*秒的个位*/
- }
- /*****显示时间*****/
- void display_shijian(void)
- {
- uchar i;
- for(i=0;i<6;i++) /*连续写入6位,时时分分秒秒*/
- {
- P1=smg_we[i]; /*数码管位选*/
- P2=smg_du[disp[i]]; /*数码管段选*/
- delay(2); /*延时*/
- P2=0xff; /*消隐*/
- // delay(2); /*延时*///这个延时影响数码管闪烁
- }
- }
复制代码
|