?? 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 + -