📄 clock.c
字号:
//
// I2C操作函数库
// I2C有关概念参见《MCS-51系列单片机应用及接口技术》P289
//
// idata=14
#include "Global.h"
///////////////////////////////////////////////////////////////////////////////
// 内部存储区变量 0~128字节 直接寻址
// 全局变量定义
extern data uchar cur_time[15]; // 系统当前时间显示存储区 XXXX年XX月XX日XX时XX分XX秒星期X
extern data uchar time[10]; // 读取时钟存储区
extern bdata bit ack; // 时钟I2C总线通信应答状态
//
// 在I2C总线数据传送过程中,定义了一种开始和结束信号(有时也称启动和停止信号),
// 开始和结束信号的定义在I2C协议中具有十分重要的意义。当SCL为高电平时,SDA发生
// 高到低跳变定义为开始信号;当SCL为高电平时,SDA发生低到高跳变定义为结束信号,
// 开始和结束信号的定义参见《MCS-51系列单片机应用及接口技术》P291所示。开始和
// 结束信号都是由主器件(这里是8051单片机)发出的。在开始信号以后,总线被认为
// 是忙的。在结束信号后过一定时间,总线被认为是空闲的。如果连接在总线上的器件
// 具有相应的硬件接口电路,开始和结束信号的检测还比较容易,但是没有这种硬件接
// 口电路的微处理器必须在一个时钟周期内至少2次采样,SDA才能检测到这种跳变。
//
//
// 启动I2C总线
// 函数原型:void Start_I2c8563();
// 功能:
// 启动I2C时钟8563总线,即发送I2C起始条件
//
void Start_I2c8563()
{
SDA=1; // SDA维持高电平,准备发送起始信号
SCL=1; // SCL为高电平,SDA由高变低,表明通信起始信号
Some_NOP; // SCL信号高电平维持至少4us,等待电平稳定
SDA=0; // 发送起始信号,SDA下跳
Some_NOP; // 起始信号至少维持4.7us
SCL=0; // 时钟信号跳变
Some_NOP; // 等待一段时间
}
//
// 结束I2C总线
// 函数原型: void Stop_I2c8563();
// 功能:
// 结束I2C总线,即发送I2C结束条件.
//
void Stop_I2c8563()
{
SDA=0; // SDA维持低电平,准备发送停止信号
_Nop();
SCL=1; // SCL信号高电平,SDA由低变高,表明通信停止信号
Some_NOP; // SCL信号高电平维持至少4us
SDA=1; // 发送停止信号
Some_NOP; // 停止信号至少维持4us
}
//
// 送到SDA线上的每个字节必须为8位长度,每次传送的字节数是不受限制的,每个字节后
// 面必须跟随一个响应位。数据传送时先传送最高位。如果接收器不能接收下一个字节(
// 例如正在处理一个内部中断,在这个中断处理完之前不能接收I2C总线上的数据字节),
// 可以使时钟保持低电平,迫使主处理器处于等待状态。当从器件准备好接收下一个数据
// 字节时就释放SCL,以便数据继续传送。
//
// 接收器必须确认数据的接收,确认位相对于主器件产生一个时钟在这个时钟内发送器件
// 释放SDA线。接收器件在这个时钟内必须将SDA拉成低电平,使SDA在该时钟的高电平期间
// 为稳定的低电平。
// 通常,被寻址的接收器件必须在收到每个字节后发出响应信息。若一个从器件在处理一
// 个实时事件不能接收数据时,从器件必须使SDA保持高电平。此时,主器件产生一个结
// 束信号使传送异常结束。
// 在主器件接收的传送中,主器件对最后一个数据字节不予确认,以对从发送器指出数据
// 传送的结束,从发送器释放SDA线,使主器件能产生一个结束信号。
//
// 字节数据传送函数,,向从器件写一个字节
// 函数原型: void SendByte8563(uchar c);
// 功能:
// 将数据c发送出去,可以是地址,也可以是数据,发完后等待应答,并对
// 此状态位进行操作.(不应答或非应答都使ack=0 假)
// 发送数据正常,ack=1; ack=0表示被控器无应答或损坏。
//
void SendByte8563(uchar c)
{
idata uchar i;
for(i=0;i<8;i++)// 每字节必须8位长度
{
if((c<<i)&0x80)
{
SDA=1; // 数据最高位先发送,数据1
}
else
{
SDA=0; // 数据0
}
_Nop();
SCL=1; // 每个主器件在SCL线上产生时钟,数据仅在
// 时钟的高电平期间有效,锁存数据。
Some_NOP; // 保证SCL时钟高电平至少为4us
SCL=0; // 时钟低电平,准备写入下一个字节
_Nop(); // 等待
_Nop();
}
_Nop();
_Nop();
SDA=1; // 8位数据发送完毕,检测从器件响应
_Nop();
_Nop();
SCL=1; // SCL为高电平,发送第9时钟作为应答信号
_Nop();
_Nop();
_Nop();
if(SDA==1)
ack=0; // 从器件保持SDA为高电平,发送异常
else
ack=1; // 从器件拉低SDA为低电平,发送正常
SCL=0; // SCL为低电平,清除时钟
_Nop();
_Nop();
}
//
// 字节数据传送函数,读出从器件一个字节
// 函数原型: uchar RcvByte();
// 功能:
// 用来接收从器件传来的数据,并判断总线错误(不发应答信号),
// 发完后请用应答函数。
//
uchar RcvByte8563()
{
idata uchar temp=0;
idata uchar i;
SDA=1; // 准备接收数据
for(i=0;i<8;i++)
{
_Nop();
SCL=0; // SCL时钟下跳准备接收数据
Some_NOP; // SCL时钟信号,最小低电平为4.7us
SCL=1; // 时钟上跳
_Nop(); // 等待数据出现
_Nop();
temp=temp<<1; // 数据移位
if(SDA==1)
temp=temp+1;// 接收数据位
_Nop(); // 接收下一位数据
_Nop();
}
SCL=0; // 准备发送结束信号
_Nop();
_Nop();
return temp; // 返回接收到的字节
}
//
// 应答子函数
// 原型: void Ack_I2c8563(bit a);
// 功能:
// 主控器进行应答信号,(可以是应答或非应答信号)
//
void Ack_I2c8563(bit a)
{
if(a==0)
SDA=0; // 发应答信号
else
SDA=1; // 发非应答信号
_Nop(); // 等待
_Nop();
_Nop();
SCL=1; // SCL时钟上跳
Some_NOP; // SCL时钟高电平最小4.7us
SCL=0; // 钳住I2C总线,继续接收下一个字节
_Nop(); // 等待
_Nop();
}
//
// 向有子地址器件8563时钟芯片发送多字节数据函数
// 函数原型: bit ISendStr8563(uchar sla,uchar suba,ucahr *s,uchar no);
// 功能:
// 从启动总线到发送地址,子地址,数据,结束总线的全过程,从器件
// 地址sla,子地址suba,发送内容是s指向的内容,发送no个字节。
// 如果返回1表示操作成功,否则操作有误。
// 注意:
// 使用前必须已结束总线。
//
bit ISendStr8563(uchar sla,uchar suba,uchar *s,uchar no)
{
idata uchar i;
Start_I2c8563(); // 启动I2C总线
SendByte8563(sla&0xfe); // 发送主地址
if(ack==FALSE)
return ERROR; // 发送数据错误
SendByte8563(suba); // 发送子地址
if(ack==FALSE)
return ERROR; // 发送数据错误
for(i=0;i<no;i++)
{
SendByte8563(s[i]); // 发送一个字节
if(ack==FALSE)
return ERROR; // 发送数据错误
}
Stop_I2c8563(); // 停止I2C总线
return OK; // 成功返回
}
//
// 子地址器件8563时钟芯片读取多字节数据函数
// 函数原型: bit IRcvStr8563(uchar sla,uchar suba,ucahr *s,uchar no);
// 功能:
// 从启动总线到发送地址,子地址,读数据,结束总线的全过程,从器件
// 地址sla,子地址suba,读出的内容放入s指向的存储区,读no个字节。
// 如果返回1表示操作成功,否则操作有误。
// 注意?
// 使用前必须已结束总线。
//
bit IRcvStr8563(uchar sla,uchar suba,uchar *s,uchar no)
{
idata uchar i;
Start_I2c8563(); // 启动8563时钟芯片I2C总线
SendByte8563(sla&0xfe); // 向8563发送主地址
if(ack==FALSE)
return ERROR; // 发送数据错误
SendByte8563(suba); // 向8563发送子地址
if(ack==FALSE)
return ERROR; // 发送数据错误
Start_I2c8563(); // 启动8563时钟芯片I2C总线
SendByte8563(sla|0x01); // 向8563发送主地址
if(ack==FALSE)
return ERROR; // 发送数据错误
for(i=0;i<no-1;i++)
{
s[i]=RcvByte8563(); // 读8563一个字节
Ack_I2c8563(0); // 发送I2C应答位
}
s[i]=RcvByte8563(); // 读8563一个字节
Ack_I2c8563(1); // 发送I2C非应答位
Stop_I2c8563(); // 停止I2C总线
return OK; // 成功返回
}
///////////////////////////////////////////////////////////////////////////////
// 读取时间
///////////////////////////////////////////////////////////////////////////////
void read_time()
{
idata uchar i;
DISABLE;
IRcvStr8563(0xa2,0x02,time,0x07); // 读时间
ENABLE;
for(i=0;i<7;i++)
{
switch(i) // 时间格式化
{
case 0:time[i]=time[i]&0x7f;break;
case 1:time[i]=time[i]&0x7f;break;
case 2:time[i]=time[i]&0x3f;break;
case 3:time[i]=time[i]&0x3f;break;
case 4:time[i]=time[i]&0x07;break;
case 5:time[i]=time[i]&0x9f;break;
case 6:time[i]=time[i]&0xff;break;
default:break;
}
}
if(time[5]&0x80) // 世纪
{
cur_time[0]='1';cur_time[1]='9';
}
else
{
cur_time[0]='2';cur_time[1]='0';
}
cur_time[2]=((time[6]>>4)&0x0f)+0x30; // 年
cur_time[3]=(time[6]&0x0f)+0x30;
cur_time[4]=((time[5]>>4)&0x01)+0x30; // 月
cur_time[5]=(time[5]&0x0f)+0x30;
cur_time[6]=((time[3]>>4)&0x03)+0x30; // 日
cur_time[7]=(time[3]&0x0f)+0x30;
cur_time[8]=((time[2]>>4)&0x03)+0x30; // 时
cur_time[9]=(time[2]&0x0f)+0x30;
cur_time[10]=((time[1]>>4)&0x07)+0x30; // 分
cur_time[11]=(time[1]&0x0f)+0x30;
cur_time[12]=((time[0]>>4)&0x07)+0x30; // 秒
cur_time[13]=(time[0]&0x0f)+0x30;
cur_time[14]=(time[4]&0x07)+0x30;
}
///////////////////////////////////////////////////////////////////////////////
// 设置时间
///////////////////////////////////////////////////////////////////////////////
void set_time()
{
time[0]=0x08;
time[1]=0x00;
time[2]=((cur_time[12]-0x30)<<4)|((cur_time[13]-0x30)&0x0f);
time[3]=((cur_time[10]-0x30)<<4)|((cur_time[11]-0x30)&0x0f);
time[4]=((cur_time[8]-0x30)<<4)|((cur_time[9]-0x30)&0x0f);
time[5]=((cur_time[6]-0x30)<<4)|((cur_time[7]-0x30)&0x0f);
time[6]=(cur_time[14]-0x30)&0x07;
time[7]=((cur_time[4]-0x30)<<4)|((cur_time[5]-0x30)&0x0f);
time[8]=((cur_time[2]-0x30)<<4)|((cur_time[3]-0x30)&0x0f);
DISABLE;
ISendStr8563(0xa2,0x00,time,0x09);
ENABLE;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -