标题:
有大神可以解释下单片机ds1302实时显示时间的流程,数码管显示流程,按键扫描工作流程?
[打印本页]
作者:
LTLIGHT
时间:
2022-1-12 18:57
标题:
有大神可以解释下单片机ds1302实时显示时间的流程,数码管显示流程,按键扫描工作流程?
#include<reg51.h>
#include<intrins.h>
typedef unsigned char uchar;
typedef unsigned int uint;
sbit T_CLK=P1^2;
sbit T_IO=P1^1;
sbit T_RST=P1^0;
sbit ACC0=ACC^0;
sbit ACC7=ACC^7;
sbit W1=P2^0;
sbit W2=P2^1;
sbit W3=P2^3;
sbit W4=P2^4;
sbit W5=P2^6;
sbit W6=P2^7;
sbit p22=P2^2;
sbit p25=P2^5;
uchar code table1[]={ //共阴数码管
63,6,91,79,102,
109,125,7,127,
111,119,124,57,
94,121,113,118,
56,115,49,62,
110,64,128,0
};
#define sec 128//1302秒寄存器地址
#define min 130//1302分寄存器地址
#define hou 132//1302时寄存器地址
#define read 1//读操作,因为读的时候地址要加1,使最低位为1
sbit SET=P3^5;
sbit UP=P3^6;
sbit DOWN=P3^7;
//函数声明
void display();
void Scan_Key();
void id_case1_key();
void Set_id(uchar,uchar);
//变量定义
uchar id=0,timecount,re_disp=0;//定义用到的变量,id为调整模式用,不为0时表示调整模式,调整哪个量由id值确定 //timecount用于500ms定时记数,时间到取反flag标志位,re_disp记数200次共10s,调整状态下按键无操作10s自动返回正常显示状态
bit hour,minute,second,flag; //定义位变量,hour,minute,second分别为调整时闪烁标志位,flag 500ms取反一次,调整位闪烁及冒号闪烁用
uchar inittime[7]={0,0,18,22,17,6,4}; //初始化1302时用到的初始化数据
//秒 分钟 小时 日 月 年 星期
//DS1302读写程序
/********************************************************************
函 数名:RTInputByte()
功 能:实时时钟写入一字节
说 明:往DS1302写入1Byte数据 (内部函数)
入口参数:d 写入的数据
返 回值:无
***********************************************************************/
void RTInputByte(uchar d)
{
uchar i;
ACC=d;
for(i=8;i>0;i--)
{
T_IO=ACC0; //相当于汇编中的 RRC
T_CLK=1;
T_CLK=0;
ACC=ACC>>1;
}
}
/********************************************************************
函 数名:RTOutputByte()
功 能:实时时钟读取一字节
说 明:从DS1302读取1Byte数据 (内部函数)
入口参数:无
返 回值:ACC
设 计:欣辉电子 日 期:2015-01-01
修 改: 日 期:
***********************************************************************/
uchar RTOutputByte()
{
uchar i;
for(i=8;i>0;i--)
{
ACC=ACC>>1; //相当于汇编中的 RRC
ACC7=T_IO;
T_CLK=1;
T_CLK=0;
}
return(ACC);
}
/********************************************************************
函 数名:Write1302()
功 能:往DS1302写入数据
说 明:先写地址,后写命令/数据 (内部函数)
调 用:RTInputByte() , RTOutputByte()
入口参数:ucAddr:DS1302地址, ucData: 要写的数据
返 回值:无
***********************************************************************/
void Write1302(uchar ucAddr,uchar ucDa)
{
T_RST=0;
T_CLK=0;
T_RST=1;
RTInputByte(ucAddr); // 地址,命令
RTInputByte(ucDa); // 写1Byte数据
T_CLK=1;
T_RST=0;
}
/********************************************************************
函 数名:Read1302()
功 能:读取DS1302某地址的数据
说 明:先写地址,后读命令/数据 (内部函数)
调 用:RTInputByte() , RTOutputByte()
入口参数:ucAddr:DS1302地址
返 回值:ucData :读取的数据
***********************************************************************/
uchar Read1302(uchar ucAddr)
{
uchar ucData;
T_RST=0;
T_CLK=0;
T_RST=1;
RTInputByte(ucAddr); // 地址,命令
ucData=RTOutputByte(); // 读1Byte数据
T_CLK=1;
T_RST=0;
return(ucData);
}
/********************************************************************
函 数名:Set1302()
功 能:设置初始时间
说 明:先写地址,后读命令/数据(寄存器多字节方式)
调 用:Write1302()
入口参数:pClock: 设置时钟数据地址 格式为: 秒 分时 日 月 星期 年
7Byte (BCD码)1B 1B 1B 1B 1B 1B 1B
返 回值:无
***********************************************************************/
void Set1302(uchar *pClock)
{
uchar i;
uchar ucAddr=128;
Write1302(142,0); // 控制命令,WP=0,写操作
for(i=7;i>0;i--)
{
Write1302(ucAddr,*pClock); // 秒分 时 日 月 星期 年
pClock++;
ucAddr+=2;
}
Write1302(142,128); // 控制命令,WP=1,写保护
}
void delay(uint z)
{
uintx,y;
for(x=z;x>0;x--)
for(y=110;y>0;y--);
}
void display() //显示函数
{
if(flag&hour) //如hour为1表示调整时,flag为1时不显示
{
P0=(0); //再传段码
W1=0;
delay(1); //延迟时间2ms以内
W1=1;
P0=(0&~((uchar)~flag<<8)); //再传段码
W2=0;
delay(1); //延迟时间2ms以内
W2=1;
}
else //flag为0时显示,产生闪烁效果,下同
{
P0=(table1[Read1302(hou|read)/16]); //再传段码
W1=0;
delay(1); //延迟时间2ms以内
W1=1;
P0=(table1[Read1302(hou|read)%16]&~((uchar)~flag<<8)); //再传段码
W2=0;
delay(1); //延迟时间2ms以内
W2=1;
}
P0=64; //再传段码
p22=0;
delay(1); //延迟时间2ms以内
p22=1;
if(flag&minute)
{
P0=(0&~((uchar)~flag<<8)); //再传段码
W3=0;
delay(1); //延迟时间2ms以内
W3=1;
P0=(0&~((uchar)~flag<<8)); //再传段码
W4=0;
delay(1); //延迟时间2ms以内
W4=1;
}
else
{
P0=(table1[Read1302(min|read)/16]&~((uchar)~flag<<8)); //再传段码
W3=0;
delay(1); //延迟时间2ms以内
W3=1;
P0=(table1[Read1302(min|read)%16]&~((uchar)~flag<<8)); //再传段码
W4=0;
delay(1); //延迟时间2ms以内
W4=1;
}
P0=64; //再传段码
p25=0;
delay(1); //延迟时间2ms以内
p25=1;
if(flag&second)
{
P0=(0&~((uchar)~flag<<8)); //再传段码
W5=0;
delay(1); //延迟时间2ms以内
W5=1;
P0=(0); //再传段码
W6=0;
delay(1); //延迟时间2ms以内
W6=1;
}
else
{
P0=(table1[Read1302(sec|read)/16]&~((uchar)~flag<<8)); //再传段码
W5=0;
delay(1); //延迟时间2ms以内
W5=1;
P0=(table1[Read1302(sec|read)%16]); //再传段码
W6=0;
delay(1); //延迟时间2ms以内
W6=1;
}
}
void Scan_Key() //键盘检测函数
{
display(); //程序开头调用显示函数
if(!SET)
{
while(!SET)
display(); //等待按键释放,如一直按下一直调用显示函数,防止显示中断
re_disp=0; //清除记数,重新开始10s定时
id++;
if(id>3)
id=0; //id加1,后面根据id值对应调整项目
}
if(id==0)
{
hour=0;
minute=0;
second=0;
} //根据id值跳到相应处理函数
if(id==1)
{
hour=1;
id_case1_key();
} //id为1,选择调整小时位,闪烁标志位置1,然后跳到键盘处理函数,下同
if(id==2)
{
hour=0;
minute=1;
id_case1_key();
}
if(id==3)
{
minute=0;
second=1;
id_case1_key();
}
}
void id_case1_key() //键盘处理函数,只有按下set键时才会进入,
{
display();
if(!DOWN) //减少
{
while(!DOWN)
display(); //等待按键释放,如一直按下一直调用显示函数,防止显示中断
re_disp=0; //清除记数,重新开始10s定时
Set_id(id,0); //跳到加减判断函数,下同,
}
if(!UP) //增加
{
while(!UP)
display();
re_disp=0;
Set_id(id,1);
}
}
//根据选择调整相应项目并写入DS1302
void Set_id(uchar sel,uchar sel_1) //执行调整项目的函数
{
signed char max,mini,address,item;
if(sel==1)
{
address=hou;
max=23;
mini=0;
} //小时 //根据id值确定要调整的项,并确定调整上下限,下同
if(sel==2)
{
address=min;
max=59;
mini=0;
} //分钟
if(sel==3)
{
address=sec;
max=0;
mini=0;
} //秒
item=Read1302(address|read)/16*10+Read1302(address|read)%16; //从相应的地址读取当前数据并转换为十进制
if(sel_1==0)
item--;
else
item++; //确定是对项目加还是减,并对越限处理
if(item>max)
item=mini;
if(item<mini)
item=max;
Write1302(142,0);//允许写操作
Write1302(address,item/10*16+item%10); //将调整结果转换成压缩BCD码重新写入1302
Write1302(142,128);//写保护,禁止写操作
}
//主函数
void main()
{
TMOD=1;//初始化定时器
TH0=60;
TL0=176;
EA=1;
ET0=1;
TR0=1;
P2=255;
Write1302(144,160);//关闭充电二级管,不能对后备电池进行充电,防止发胀,原来的程序是打开的请关闭
Write1302(142,128);//写保护,禁止写操作
if(!UP&!DOWN)
Set1302(inittime); //如果同时按下UP和DOWN键则初始化1302,该语句在while(1)前,只执行一次,需要复位,防止误操作
while(1)
{
Scan_Key(); //主程序一直调用键盘检测函数即可
}
}
//中断处理程序,主要用于取反标志位,返回正常显示状态
void t0() interrupt 1 using 0
{
TH0=60; //50ms定时
TL0=176;
timecount++;
re_disp++;
if(timecount>9)
{
timecount=0;
flag=~flag;
}
if(re_disp>200)
{
re_disp=0;
if(id)
id=0;
}
}
复制代码
作者:
man1234567
时间:
2022-1-13 08:43
顺着语句住下捋,就可以画出全部的流程。
作者:
罗斯德隆
时间:
2022-1-13 09:20
1.开机,上下两个按键同时按时进行时间初始化1302,只进行一次。
2.键盘扫描。设置按键按下后,循环切换时、分、秒设置,up键是增加,down是减少。
3.定时器设置50ms时标,每500ms数码管时间显示产生闪烁效果,应该是时钟每秒更新显示。10s超时,如果10s后无操作还有设置动作,退出。
这个程序可以理解成一个只有时分秒的时钟设置程序。
作者:
LTLIGHT
时间:
2022-1-13 14:59
罗斯德隆 发表于 2022-1-13 09:20
1.开机,上下两个按键同时按时进行时间初始化1302,只进行一次。
2.键盘扫描。设置按键按下后,循环切换时 ...
老哥可否再详细点
欢迎光临 (http://www.51hei.com/bbs/)
Powered by Discuz! X3.1