A. 我的DS1302秒大於60請問如何解決啊 下面有代碼
顯然是晶元問題,也許可以通過合適的外電路設計和軟體操作解決,但本質上應換用真貨,否則長期可靠性仍無法保證。
B. DS1302晶元如何進行12/24 制顯示時間轉換的編程(C語言)
修改DS1302晶元的(85h、84h)寄存的BIT7進行12/24小時模式切換,BIT7=1是12小時模式,BIT7=0是24小時模式。
C. 從ds1302中讀到的時間是BCD碼,那調整ds1302的時間,寫進去的是BCD碼嗎
對的 需要將所寫的時間寫成bcd碼的形式,也就是如果是56那就是0x56h
D. ds1302 寫時鍾程序 怎麼實現掉電後1302繼續計時,下次上電後時間和實際時間一樣,給個具體的程序寫法
ds_rd(0x81); //讀取秒
ds_data=ds_data&0x80;
if(ds_data==0x80) //判斷是否在運行 沒有運行執行
{
ds_write(0x8e,0x00);//關閉防寫
ds_write(0x8c,0x11);//年 年月日什麼的專當10進制數看
ds_write(0x88,0x10);//月
ds_write(0x86,0x20);//日
ds_write(0x84,0x01);//時屬
ds_write(0x82,0x18);//分
ds_write(0x80,0x00);//秒
ds_write(0x8a,0x05);//星期
ds_write(0x8f,0x80);//打開防寫
}
E. 用12C5A60S2單片機和ds1302做了一個萬年歷 ,其他的都好,就是一天有35(2*16+3)個小時,求解……急啊
ds1302用的是16進製表示時間的
所以到10點的時候就變成了0x10 在十進制中表示16了 20點的時候0x20變成32小時了
轉換方法是
(獲取到的時間/16)*10+獲取到的時間%16
例如在23點的時候,讀出來的數據是0x23 也就是十進制的 35
35/16 = 2
35%16=3
2再乘以10+3就是23點了
F. 有木有大佬幫我解釋一下這段ds1302時鍾晶元程序是什麼意思
在前面的課程中我們已經了解到了不少關於時鍾的概念,比如我們用的單片機的主時鍾是11.0592M、I2C匯流排有一條時鍾信號線SCL等,這些時鍾本質上都是一個某一頻率的方波信號。那麼除了這些在前面新學到的時鍾概念外,還有一個我們早已熟悉的不能再熟悉的時鍾概念——年-月-日 時:分:秒,就是我們的鍾表和日歷給出的時間,它的重要程度我想就不需要多說了吧,在單片機系統里我們把它稱作實時時鍾,以區別於前面提到的幾種方波時鍾信號。實時時鍾,有時也被稱作牆上時鍾,很形象的一個名詞,對吧,大家知道他們講的一回事就行了。本章,我們將學習實時時鍾的應用,有了它,你的單片機系統就能在漫漫歷史長河中找到自己的時間定位啦,可以在指定時間干某件事,或者記錄下某事發生的具體時間,等等。除此之外,本章還會學習到C語言的結構體,它也是C語言的精華部分,我們通過本章先來了解它的基礎,後面再逐漸達到熟練、靈活運用它,你的編程水平會提高一個檔次哦。 15.1 BCD碼的學習 在我們日常生產生活中用的最多的數字是十進制數字,而單片機系統的所有數據本質上都是二進制的,所以聰明的前輩們就給我們創造了BCD碼。
BCD碼(Binary-Coded Decimal)亦稱二進碼十進制數或二-十進制代碼。用4位二進制數來表示1位十進制數中的0~9這10個數字。是一種二進制的數字編碼形式,用二進制編碼的十進制代碼。BCD碼這種編碼形式利用了四個位元來儲存一個十進制的數碼,使二進制和十進制之間的轉換得以快捷的進行。我們前邊講過十六進制和二進制本質上是一回事,十六進制僅僅是二進制的一種縮寫形式而已。而十進制的一位數字,從0到9,最大的數字就是9,再加1就要進位,所以用4位二進製表示十進制,就是從0000到1001,不存在1010、1011、1100、1101、1110、1111這6個數字。BCD碼如果到了1001,再加1的話,數字就變成了0001 0000這樣的數字了,相當於用了8位的二進制數字表示了2位的十進制數字。關於BCD碼更詳細的介紹請點擊 www.51hei.com 的基礎教程欄目裡面有很多相關文章.
BCD碼的應用還是非常廣泛的,比如我們這節課要學的實時時鍾,日期時間在時鍾晶元中的存儲格式就是BCD碼,當我們需要把它記錄的時間轉換成可以直觀顯示的ASCII碼時(比如在液晶上顯示),就可以省去一步由二進制的整型數到ASCII的轉換過程,而直接取出表示十進制1位數字的4個二進制位然後再加上0x30就可組成一個ASCII碼位元組了,這樣就會方便的多,在後面的實際常式中將看到這個簡單的轉換。
15.2 SPI時序初步認識 UART、I2C和SPI是單片機通信中最常用的三種通信協議。前邊我們已經學了UART和I2C通信協議,這節課我們來學習剩下的SPI通信協議。SPI是英語Serial Peripheral Interface的縮寫,顧名思義就是串列外圍設備介面。SPI是一種高速的、全雙工、同步通信匯流排,標準的SPI也僅僅使用4個引腳,常用於單片機和EEPROM、FLASH、實時時鍾、數字信號處理器等器件的通信。SPI通信原理比I2C要簡單,它主要是主從方式通信,這種模式通常只有一個主機和一個或者多個從機,標準的SPI是4根線,分別是SSEL(片選,也寫作SCS)、SCLK(時鍾,也寫作SCK)、MOSI(主機輸出從機輸入Master Output/Slave Input)和MISO(主機輸入從機輸出Master Input/Slave Output)。
SSEL:從設備片選使能信號。如果從設備是低電平使能的話,當拉低這個引腳後,從設備就會被選中,主機和這個被選中的從機進行通信。
SCLK:時鍾信號,由主機產生,和I2C通信的SCL有點類似。
MOSI:主機給從機發送指令或者數據的通道。
MISO:主機讀取從機的狀態或者數據的通道。
在某些情況下,我們也可以用3根線的SPI或者2根線的SPI進行通信。比如主機只給從機發送命令,從機不需要回復數據的時候,那MISO就可以不要;而在主機只讀取從機的數據,不需要給從機發送指令的時候,那MOSI可以不要;當一個主機一個從機的時候,從機的片選有時可以固定為有效電平而一直處於使能狀態,那麼SSEL可以不要;此時如果再加上主機只給從機發送數據,那麼SSEL和MISO都可以不要;如果主機只讀取從機送來的數據,SSEL和MOSI都可以不要。 3線和2線的SPI大家要知道怎麼回事,實際使用也是有應用的,但是當我們提及SPI的時候,一般都是指標准SPI,都是指4根線的這種形式。
SPI通信的主機也是我們的單片機,在讀寫數據時序的過程中,有四種模式,要了解這四種模式,首先我們得學習一下2個名詞。
CPOL:Clock Polarity,就是時鍾的極性。
時鍾的極性是什麼概念呢?通信的整個過程分為空閑時刻和通信時刻,SCLK在數據發送之前和之後的空閑狀態是高電平那麼CPOL=1,如果空閑狀態SCLK是低電平,那麼CPOL=0。
CPHA:Clock Phase,就是時鍾的相位。
主機和從機要交換數據,就牽涉到一個問題,即主機在什麼時刻輸出數據到MOSI上而從機在什麼時刻采樣這個數據,或者從機在什麼時刻輸出數據到MISO上而主機什麼時刻采樣這個數據。同步通信的一個特點就是所有數據的變化和采樣都是伴隨著時鍾沿進行的,也就是說數據總是在時鍾的邊沿附近變化或被采樣。而一個時鍾周期必定包含了一個上升沿和一個下降沿,這是周期的定義所決定的,只是這兩個沿的先後並無規定。又因為數據從產生的時刻到它的穩定是需要一定時間的,那麼,如果主機在上升沿輸出數據到MOSI上,從機就只能在下降沿去采樣這個數據了。反之如果一方在下降沿輸出數據,那麼另一方就必須在上升沿采樣這個數據。
CPHA=1,就表示數據的輸出是在一個時鍾周期的第一個沿上,至於這個沿是上升沿還是下降沿,這要是CPOL的值而定,CPOL=1那就是下降沿,反之就是上升沿。那麼數據的采樣自然就是在第二個沿上了。
CPHA=0,就表示數據的采樣是在一個時鍾周期的第一個沿上,同樣它是什麼沿由CPOL決定。那麼數據的輸出自然就在第二個沿上了。仔細想一下,這里會有一個問題:就是當一幀數據開始傳輸第一bit時,在第一個時鍾沿上就采樣該數據了,那麼它是在什麼時候輸出來的呢?有兩種情況:一是SSEL使能的邊沿,二是上一幀數據的最後一個時鍾沿,有時兩種情況還會同時生效。
我們以CPOL=1/CPHA=1為例,把時序圖畫出來給大家看一下,如圖15-1所示,。
G. 麻煩老師們大俠們注釋一下下面這段51c語言,ds1302時間讀取代碼。越詳細越好,感激不盡啊~
你是在學習嗎? 這段代碼很簡單啊,看不懂證明你還差得很遠。基礎很重要,要會二進制數學,要有一定的英語基礎,能看懂晶元手冊,要會C語言,如果會匯編就更好了。
大概給你說一下吧,上半段是讀時分秒的,從寄存器讀出來以後,根據寄存器的定義進行了處理,把每個數字都分成了兩部分存儲,下半段類似,是讀年月日的。
和0x70相與並右移,意思是只要第6、5、4位,和0x0f相與,意思是只要第3、2、1、0位。
看不到Time數組的定義和用法,所以這里只能猜,與操作和右移操作是為了將數字在什麼地方顯示出來,比如數碼管之類的。
H. 誰有ds1302 oled液晶顯示時間的程序代碼。謝謝了
我給你一份,我之前寫過的程序。
/*
* LCD1602 時鍾
*
* author:
* date:2011.2.22
*/
#include "main.h"
#include "ds1302.h"
#include "LCD1602.h"
sbit delua = P2^6;
sbit welua = P2^7;
uint8 Time[7]={55,59,11,22,2,2,11};//秒分時日月周年10-08-15 11:59:55
uint8 T_tmp[7];
uint8 Num, T_n=0;
void delay(uint16 n)
{
while (n--);
}
/*
* 初始化系統定時器
*/
void systimer_init(void)
{
TMOD &= 0x0F;
TMOD |= 0x10;
TH1 = 0xDC; // 定時10ms
TL1 = 0x00;
TR1 = 0;
ET1 = 0;
EA = 1;
}
/*
* 判斷鍵值
*/
/*
uint8 scan_key(void)
{
uint8 val=0;
KeyOut1 = 0;
KeyOut2 = 1;
KeyOut3 = 1;
KeyOut4 = 1;
if(KeyIn4 == 0)
{
delay(KEY_DELAY);
if (KeyIn4 == 0)
{
val = K_ADD;
}
}
while((KeyIn1 == 0)||(KeyIn2 == 0)||(KeyIn3 == 0)||(KeyIn4 == 0));
KeyOut1 = 1;
KeyOut2 = 0;
KeyOut3 = 1;
KeyOut4 = 1;
if(KeyIn4 == 0)
{
delay(KEY_DELAY);
if(KeyIn4 == 0)
val = K_LEFT;
}
while ((KeyIn1 == 0)||(KeyIn2 == 0)||(KeyIn3 == 0)||(KeyIn4 == 0));
KeyOut1 = 1;
KeyOut2 = 1;
KeyOut3 = 0;
KeyOut4 = 1;
if (KeyIn4 == 0)
{
delay(KEY_DELAY);
if (KeyIn4 == 0)
val = K_SUB;
}
while ((KeyIn1 == 0)||(KeyIn2 == 0)||(KeyIn3 == 0)||(KeyIn4 == 0));
KeyOut1 = 1;
KeyOut2 = 1;
KeyOut3 = 1;
KeyOut4 = 0;
if (KeyIn2 == 0)
{
delay(KEY_DELAY);
if (KeyIn2 == 0)
val = K_SET;
}
if (KeyIn3 == 0)
{
delay(KEY_DELAY);
if (KeyIn3 == 0)
val = K_ENTER;
}
if (KeyIn4 == 0)
{
delay(KEY_DELAY);
if (KeyIn4 == 0)
val = K_RIGHT;
}
while ((KeyIn1 == 0)||(KeyIn2 == 0)||(KeyIn3 == 0)||(KeyIn4 == 0));
return val;
}
*/
/*
* 啟動clock數字閃爍
*/
void start_flash(void)
{
T_n = 0;
switch (Num)
{
case 0: w_data(6, Time[0]); break;
case 1: w_data(3, Time[1]); break;
case 2: w_data(0, Time[2]); break;
default: break;
}
TH1 = 0xDC; // 定時10ms
TL1 = 0x00;
TR1 = 1;
ET1 = 1;
}
/*
* 停止clock數字閃爍
*/
void stop_flash(void)
{
ET1 = 0;
TR1 = 0;
switch (Num)
{
case 0: w_data(6, Time[0]); break;
case 1: w_data(3, Time[1]); break;
case 2: w_data(0, Time[2]); break;
default: break;
}
}
/*
* 更新LCD時間
*/
void refresh_clock(void)
{
if (Time[0] != T_tmp[0]) // 更新秒
{
T_tmp[0] = Time[0];
w_data(6, Time[0]);
}
if (Time[1] != T_tmp[1]) // 更新分
{
T_tmp[1] = Time[1];
w_data(3, Time[1]);
}
if (Time[2] != T_tmp[2]) // 更新時
{
T_tmp[2] = Time[2];
w_data(0, Time[2]);
}
}
/*
* 時鍾設置
*/
void set_clock(void)
{
uint8 k_val, flag=0;
Num = 0;
while (1)
{
// k_val = scan_key();
if (k_val == 0)
{
if (flag == 0)
{
start_flash();
flag = 1;
}
continue;
}
flag = 0;
stop_flash();
if (k_val == K_ENTER)
{
set_time(Time);
break;
}
switch (k_val)
{
case K_ADD:
if (Num == 2)
{
if (Time[Num] >= 23)
Time[Num] = 0;
else
Time[Num]++;
}
else
{
if (Time[Num] >= 59)
Time[Num] = 0;
else
Time[Num]++;
}
break;
case K_SUB:
if (Num == 2)
{
if (Time[Num] == 0)
Time[Num] = 23;
else
Time[Num]--;
}
else
{
if (Time[Num] == 0)
Time[Num] = 59;
else
Time[Num]--;
}
break;
case K_LEFT:
if (Num >= 2)
Num = 0;
else
Num++;
break;
case K_RIGHT:
if (Num == 0)
Num = 2;
else
Num--;
break;
default: break;
}
refresh_clock();
}
}
main()
{
uint8 k_val;
delua = 0;
welua = 0;
systimer_init();
LCD1602_init();
set_time(Time); //初始時間設定
w_string(0, " : : ");
w_data(0, Time[2]); // 時
w_data(3, Time[1]); // 分
w_data(6, Time[0]); // 秒
while (1)
{
read_time(Time);
refresh_clock();
// k_val = scan_key();
if (k_val == K_SET)
set_clock();
}
}
void time1_isr() interrupt 3
{
ET1 = 0;
TH1 = 0xDC; // 定時10ms
TL1 = 0x00;
T_n++;
if (T_n == 50) // 0.5s
{
switch (Num)
{
case 0: clear_data(6); break;
case 1: clear_data(3); break;
case 2: clear_data(0); break;
default: break;
}
}
else if (T_n >= 100) // 1s
{
T_n = 0;
switch (Num)
{
case 0: w_data(6, Time[0]); break;
case 1: w_data(3, Time[1]); break;
case 2: w_data(0, Time[2]); break;
default: break;
}
}
ET1 = 1;
}
/*
* LCD1602顯示
*
*/
#include "main.h"
#include "LCD1602.h"
/**
* 等待繁忙標志
*/
/*
void wait(void)
{
P0 = 0xFF;
do
{
RS = 0;
RW = 1;
EN = 0;
EN = 1;
}while (BUSY == 1);
EN = 0;
}
*/
void Delay_1ms(unsigned int Time)
{
unsigned int x, y;
for(x = Time; x > 0; x--)
for(y = 120; y > 0; y--);
}
/**
* 寫數據
*/
void w_dat(uint8 dat)
{
RS = 1;
P0 = dat;
Delay_1ms(5);
EN = 1;
Delay_1ms(5);
EN = 0;
}
/**
* 寫命令
*/
void w_cmd(uint8 cmd)
{
RS = 0;
P0 = cmd;
Delay_1ms(5);
EN = 1;
Delay_1ms(5);
EN = 0;
}
/**
* 發送字元串到LCD
*/
void w_string(uint8 addr_start, uint8 *p)
{
w_cmd(addr_start | 0x80);
while (*p != '\0')
{
w_dat(*p++);
}
}
/**
* 發送數字到LCD(00~99)
*/
void w_data(uint8 addr_start, uint8 dat)
{
w_cmd(addr_start | 0x80);
w_dat(dat%100/10 + '0');
w_dat(dat%10 + '0');
}
/**
* 顯示兩位空白
*/
void clear_data(uint8 addr_start)
{
w_cmd(addr_start | 0x80);
w_dat(' ');
w_dat(' ');
}
/**
* 初始化1602
*/
void LCD1602_init(void)
{
w_cmd(0x38); // 16*2顯示,5*7點陣,8位數據介面
w_cmd(0x0C); // 顯示器開、游標開、游標允許閃爍
w_cmd(0x06); // 文字不動,游標自動右移
w_cmd(0x01); // 清屏
}
/*
* DS1302 突發方式,連讀,連寫
*
*/
#include "main.h"
#include "ds1302.h"
/**
* 寫一個位元組
*/
void write_ds1302_byte(uint8 dat)
{
uint8 i;
for (i=0;i<8;i++)
{
SDA = dat & 0x01;
SCK = 1;
dat >>= 1;
SCK = 0;
}
}
/**
* 讀一個位元組
*/
uint8 read_ds1302_byte(void)
{
uint8 i, dat=0;
for (i=0;i<8;i++)
{
dat >>= 1;
if (SDA)
dat |= 0x80;
SCK = 1;
SCK = 0;
}
return dat;
}
void reset_ds1302(void)
{
RST = 0;
SCK = 0;
RST = 1;
}
/**
* 清除防寫
*/
void clear_ds1302_WP(void)
{
reset_ds1302();
RST = 1;
write_ds1302_byte(0x8E);
write_ds1302_byte(0);
SDA = 0;
RST = 0;
}
/**
* 設置防寫
*/
void set_ds1302_WP(void)
{
reset_ds1302();
RST = 1;
write_ds1302_byte(0x8E);
write_ds1302_byte(0x80);
SDA = 0;
RST = 0;
}
/**
* 設定時鍾數據
*/
void set_time(uint8 *timedata)
{
uint8 i, tmp;
for (i=0; i<7; i++) // 轉化為BCD格式
{
tmp = timedata[i] / 10;
timedata[i] = timedata[i] % 10;
timedata[i] = timedata[i] + tmp*16;
}
clear_ds1302_WP(); //清除防寫
reset_ds1302(); //初始化端
RST = 1; //使能拉高
write_ds1302_byte(DS1302_W_ADDR); //時鍾突發寄存器寫寄存器
for (i=0; i<7; i++)
{
write_ds1302_byte(timedata[i]);
delay(10);
}
write_ds1302_byte(0);
SDA = 0;
RST = 0;
set_ds1302_WP(); //設置防寫
}
/**
* 讀時鍾數據
*/
void read_time(uint8 *timedata)
{
uint8 i, tmp;
clear_ds1302_WP();
reset_ds1302();
RST = 1;
write_ds1302_byte(DS1302_R_ADDR);
for (i=0; i<7; i++)
{
timedata[i] = read_ds1302_byte();
delay(10);
}
SDA = 0;
RST = 0;
set_ds1302_WP();
for (i=0; i<7; i++) // 轉化為正常格式
{
tmp = timedata[i] / 16;
timedata[i] = timedata[i] % 16;
timedata[i] = timedata[i] + tmp*10;
}
}
I. 利用字元型LCD1602和時鍾晶元DS1302,顯示年月日星期時分秒信息。求解啊。求解。大家多多幫忙啊。。
#include"DS1302.h"
#include <at89x52.h>
/*DS1302
寄存器命令字(讀,寫)取值范圍各位內容(7~0)
讀寫
秒80H81H00~59CH(7)10SEC(6~4)SEC(3~0)
分82H83H00~590(7)10MIN(6~4)MIN(3~0)
時84H85H 00~12 00~2412/24(7)0(6)10/AP(5~4) HR(3~0)
日86H87H01~28,29,39,310(7),0(6),10DATE(5~4)DATE(3~0)
月88H89H01~120(7),0(6),0(5),10M(4),MONTH(3~0)
星期8AH8BH01~070(7),0(6),0(5),0(4),DAY(3~0)
年8CH8DH01~9919YEAE(7~4)YEAR(3~0)
防寫8EH8FHWP(7),0(6),0(5),0(4),0(3~0)
慢充電90H91HTCS(7),TCS(6),TCS(5),TCS(4),DS(3),DS(2),RS(1),RS(0)
時鍾突發BEHBFH//讀寫秒,分,時,日,月,周,年,防寫,8位元組一個
RAM突發FEHFFH//讀寫31B的RAM,可以不以8位元組為單位
CH時鍾開關,0開1關
12/241先12小時,2選24小時,12小時下,位5為AM/PM選擇位,此位1表PM,24小時下,位5是第二個小時位(20~23)
WP防寫位,0,允許,1,禁止
TCS1010才允許充電
DS二極體選擇位 01 一個10兩個00,11禁止
RS選擇連接在VCC1,VCC2之間的電阻,00禁止01 2K104K118K
*/
uchar DateTime[8]={0x05,0x02,0x04,0x13,0x06,0x02,0x99,0x00};
//分別為 秒,分,時,日,月,周,年,防寫
//uchar DateTime[8]={0x05,0x03,0x04,0x
/*
函數名稱:DS1302寫入命令函數
功能描述:將命令寫入DS1302
全局變數:無
參數說明:Command為要寫入的命令
返回說明:
版本:1.0
說明:
*/
void WriteCommand(uchar Command)
{
uchar i;
RST=0;CLK=0;RST=1;
for(i=8;i>0;i--)//發送命令字
{
CLK=0;
DP=Command&0x01;//取一位送數據口
CLK=1;//產生一個上升沿
Command>>=1;
}
}
/*
函數名稱:DS1302寫入數據函數
功能描述:將數據寫入DS1302
全局變數:無
參數說明:SendDat為要寫入的命令
返回說明:
版本:1.0
說明:
*/
void WriteData(uchar SendDat)
{
uchar i;
for(i=8;i>0;i--)//發送數值
{
CLK=0;
DP=SendDat&0x01;
CLK=1;
SendDat>>=1;
}
}
/*
函數名稱:DS1302讀取數據函數
功能描述:從DS1302讀取數據
全局變數:無
參數說明:
返回說明:返回讀取的一個位元組數據
版本:1.0
說明:
*/
uchar ReadData(void)
{
uchar i,RecDat=0;
for(i=0;i<8;i++)//讀入數值
{
CLK=1;CLK=0;//產生一個下降沿
if(DP)RecDat|=0x01<<i;//讀入數據
}
return RecDat;
}
/*
函數名稱:DS1302向某地址單字寫函數
功能描述:向某地址寫入數據
全局變數:無
參數說明:Command為地址變數,SendDat為所送的數據
返回說明:
版本:1.0
說明:
*/
void WriteByte(uchar Command,uchar SendDat)
{
WriteCommand(Command);
WriteCommand(SendDat);
RST=0;
}
/*
函數名稱:DS1302單位元組讀取某地址數據函數
功能描述:讀取某一地址的數據
全局變數:無
參數說明:Command為地址變數
返回說明:返回讀取的指定地址數據
版本:1.0
說明:
*/
uchar ReadByte(uchar Command)//讀位元組子程序,入口參數,命令字
{
uchar RecDat=0;
WriteCommand(Command);
RecDat=ReadData();
RST=0;
return RecDat;
}
/*
讀防寫操作,不能在多位元組寫模式下寫入
SendByte(0x8EH,0x80)//向8EH地址寫入0x80H數據,實現禁止寫入操作
SendByte(0x8EH,0x00)//向8EH地址寫入0x00H數據,實現允許寫入操作
*/
//允許時鍾啟動,CH變為0
void OscCtrl(bit CtrlDat)//振盪起動和停止控制,入口參數1起動或0停止
{
if(CtrlDat)WriteByte(0x80,0x00);
elseWriteByte(0x80,0x80);
}
/*
//單位元組傳送
SendByte(0x80H,0x85);//啟動時鍾,秒為5
SendByte(0x81H);//讀取時間中的秒數據
SendByte(0x82H,0x06);//寫入分鍾數據為6
SendByte(0x83H);//讀取分鍾數據
*/
/*
函數名稱:DS1302連續寫入數據函數
功能描述:
全局變數:無
參數說明:Command為命令,p發送的數據,longth為位元組數據
返回說明:
版本:1.0
說明:當寫入時間數據時,長度必須為8才可以,當寫入RAM數據時數據長度為0~31
*/
void DS1302_BustWrite(uchar Command,uchar longth,uchar *p)
{
uchar i;
WriteCommand(Command);
for(i=longth;i>0;i--)
{
WriteData(*p);
p++;
}
RST=0;
}
/*
函數名稱:DS1302連續讀數據函數
功能描述:
全局變數:無
參數說明:Command為命令,longth為讀取的數據長度,p讀出後寫入的數組指針
返回說明:
版本:1.0
說明:當讀取RAM數據的時候數據長度為0~31
*/
void DS1302_BustReadByte(uchar Command,uchar longth,uchar *p)
{
uchar i;
WriteCommand(Command);
for(i=longth;i>0;i--)
{
//*p=0;
*p=ReadData();
p++;
}
RST=0;
}
J. 利用單片機DS1302晶元編制數字時鍾程序:能計算2100之前的秒,分,時,日,星期,月和年的能力,能進行閏
我也是用ds1302晶元來做電子鍾的
#include<reg51.h>
#include<string.h>
#define uchar unsigned char
#define uint unsigned int
sbit sda=P1^0;
sbit clk=P1^1;
sbit rst=P1^2;
sbit rs=P2^0;
sbit rw=P2^1;
sbit en=P2^2;
sbit k1=P3^4; //選擇
sbit k2=P3^5; //加
sbit k3=P3^6; //減
sbit k4=P3^7; //確定
uchar tcount=0;
uchar monthsdays[]={0,31,0,31,30,31,30,31,31,30,31,30,31}; //一年中每月的天數
uchar *week[]={"SUN","MON","TUS","WEN","THU","FRI","SAT"}; //每一周
uchar lcd_dsy_buffer1[]={"DATA 00-00-00"}; //lcd 顯示
uchar lcd_dsy_buffer2[]={"TIME 00:00:00"};
uchar datetime[7]; //所讀取的日期時間
char adjust_index=-1; //當前調節的時間對象
uchar change_flag[]="-MHDM-Y"; //調節分、時、日、月 、年
void delayms(uint x)
{
uchar i;
while(x--)
for(i=0;i<120;i++);
}
// 向ds1302寫入一個位元組
void write_a_byte_to_ds1302(uchar x)
{
uchar i;
for(i=0;i<8;i++)
{
sda=x&1;
clk=1;
clk=0;
x>>=1;
}
}
//向ds1302讀取一個位元組
uchar get_a_byte_from_ds1302()
{
uchar i,b,t;
for(i=0;i<8;i++)
{
b>>=1;
t=sda;
b|=t<<7;
clk=1;
clk=0;
}
return b/16*10+b%16;
}
//從ds1302 指定位置讀數據
uchar read_data(uchar addr)
{
uchar dat;
rst=0;
clk=0;
rst=1;
write_a_byte_to_ds1302(addr);
dat=get_a_byte_from_ds1302();
clk=1;
rst=0;
return dat;
}
//向第三302某地址寫入數據
void write_ds1302(uchar adder,uchar dat)
{
clk=0;
rst=1;
write_a_byte_to_ds1302(adder);
write_a_byte_to_ds1302(dat);
clk=0;
rst=0;
}
//設置時間
void set_ds1302()
{
uchar i;
write_ds1302(0x8e,0x00);
for(i=1;i<7;i++) //寫入分、時、日、月、年、
{
write_ds1302(0x80+2*i,(datetime[i]/10<<4)|(datetime[i]%10));
}
write_ds1302(0x8e,0x80);
}
//讀取當前日期時間
void gettime()
{
uchar i;
for(i=0;i<7;i++)
{
datetime[i]=read_data(0x81+2*i);
}
}
//讀lcd狀態
uchar read_lcd_state()
{
uchar state;
rs=0;
rw=1;
en=1;
delayms(1);
state=P0;
en=0;
delayms(1);
return state ;
}
//忙等待
void lcd_busy_wait()
{
while ((read_lcd_state()&0x80)==0x80);
delayms(5);
}
//向lcd寫數據
void write_lcd_data(uchar dat)
{
lcd_busy_wait();
rs=1;
rw=0;
en=0;
P0=dat;
en=1;
delayms(1);
en=0;
}
//寫lcd指令
void write_lcd_command(uchar cmd)
{
lcd_busy_wait();
rs=0;
rw=0;
en=0;
P0=cmd;
en=1;
delayms(1);
en=0;
}
//lcd初始化
void init_lcd()
{
write_lcd_command(0x38);delayms(1);
write_lcd_command(0x01);delayms(1);
write_lcd_command(0x06);delayms(1);
write_lcd_command(0x0c);delayms(1);
}
//設置液晶顯示位置
void set_lcd_pos(uchar p)
{
write_lcd_command(p|0x80);
}
//在lcd上顯示字元
void display_lcd_string(uchar p,uchar *s)
{
uchar i;
set_lcd_pos(p);
for(i=0;i<16;i++)
{
write_lcd_data(s[i]);
delayms(1);
}
}
//日期和時間轉為數字字元
void format_datetime (uchar d, uchar *a)
{
a[0]=d/10+'0';
a[1]=d%10+'0';
}
//判斷是否為閏年
uchar isleapyear(uint y)
{
return (y%4==0&&y%100!=0)||(y%400==0);
}
void refreshweekday()
{
uint i,d,w=5;
for(i=2000;i<2000+ datetime[6];i++)
{
d=isleapyear(i) ? 366:365;
w=(w+d) % 7;
}
d=0;
for(i=1;i<datetime[4];i++)
d+=monthsdays[i];
d+=datetime[3];
datetime[5]=(w+d)%7+1;
}
//年、月、日、時、分
void datetime_adjust(char x)
{
switch (adjust_index)
{
case 6: //年 00-99
if (x==1 && datetime[6]<99) datetime[6]++;
if(x==-1 && datetime[6]>0) datetime[6]--;
monthsdays[2]=isleapyear(2000+datetime[6])?29:28; //2月份天數
if(datetime[3]>monthsdays[datetime[4]])
datetime[3]=monthsdays[datetime[4]];
refreshweekday(); //刷新星期
break;
case 4: //月01-12
if((x==1) && (datetime[4]<12)) datetime[4]++;
if((x==-1) && (datetime[4]>1)) datetime[4]--;
monthsdays[2]=isleapyear(2000+datetime[6])? 29:28; //2月份天數
if(datetime[3]>monthsdays[datetime[4]])
datetime[3]=monthsdays[datetime[4]];
refreshweekday(); //刷新星期
break;
case 3: //日00-28/29/30/31
monthsdays[2]=isleapyear(2000+datetime[6])? 29:28; //2月份天數
if((1==x)&&(datetime[3]<monthsdays[datetime[4]])) datetime[3]++;
if((-1==x)&&(datetime[3]>0)) datetime[3]--;
refreshweekday(); //刷新星期
break;
case 2: //時
if (x==1&&datetime[2]<23) datetime[2]++;
if(x==-1&&datetime[2]>0) datetime[2]--;
break;
case 1: //分
if((x==1) && (datetime[1]<59)) datetime[1]++;
if((x==-1) && (datetime[1]>0)) datetime[1]--;
break;
default:break;
}
}
//定時器0每秒刷新lcd顯示
void T0_INT() interrupt 1
{
TH0=-50000/256;
TL0=-50000%256;
if(++tcount!=2) return;
tcount=0;
//按指定格式生成待顯示的日期時間串
format_datetime(datetime[6],lcd_dsy_buffer1+5);
format_datetime(datetime[4],lcd_dsy_buffer1+8);
format_datetime(datetime[3],lcd_dsy_buffer1+11);
//星期
strcpy(lcd_dsy_buffer1+13,week[datetime[5]-1]);
//時分秒
format_datetime(datetime[2],lcd_dsy_buffer2+5);
format_datetime(datetime[1],lcd_dsy_buffer2+8);
format_datetime(datetime[0],lcd_dsy_buffer2+11);
//顯示年月日、星期、時分秒
display_lcd_string(0x00,lcd_dsy_buffer1);
display_lcd_string(0x40,lcd_dsy_buffer2);
}
//鍵盤中斷
void EX_INT0() interrupt 0
{
if(k1==0)
{
while(k1==0) ;
if(adjust_index==-1||adjust_index==1) adjust_index=7;
adjust_index--;
if(adjust_index==5) adjust_index=4; //跳過對星期的調節
lcd_dsy_buffer2[13]='[';
lcd_dsy_buffer2[14]=change_flag[adjust_index];
lcd_dsy_buffer2[15]=']';
}
else if(k2==0)
{
while(k2==0);
datetime_adjust(1);
}
else if(k3==0)
{
while(k3==0) ;
datetime_adjust(-1);
}
else if(k4==0)
{
while(k4==0) ;
set_ds1302();
lcd_dsy_buffer2[13] = "";
lcd_dsy_buffer2[14] = "";
lcd_dsy_buffer2[15] = "";
adjust_index=-1; //時間繼續正常顯示
}
}
//主程序
void main()
{
init_lcd();
IE=0x83; //允許INTO,T0中斷
IP=0x01;
IT0=0x01;
TMOD=0x01;
TH0=-50000/256;
TL0=-50000%256;
TR0=1;
while(1)
{
if(adjust_index==-1)
gettime();
}
}
我的這個是有做成實物的,成功了