本人初學單片機,想用8位數碼管和ds1302做個簡單的時鐘,折騰了很久,死活讀取不了ds1302的時間,時分秒都一直顯示0,請各位高手不吝賜教,謝謝!
51hei圖片_20200613204435.jpg (69.9 KB, 下載次數: 49)
下載附件
時分秒一直是0
2020-6-13 20:45 上傳
單片機源程序如下:
/*******************************************************************************
* 標題: 8位數碼管顯示時鐘 *
* *
* *
********************************************************************************/
#include<reg51.h>
#include <intrins.h>
#define uchar unsigned char
sbit SCK=P3^6; //時鐘
sbit SDA=P3^4; //數據
sbit RST = P3^5;// DS1302復位
void main (void); // 主函數
void LED4_Display (void); // LED顯示
void LED_OUT(uchar X); // LED單字節串行移位函數
unsigned char code LED_0F[]; // LED字模表
sbit DIO = P1^0; //串行數據輸入
sbit RCLK = P1^1; //時鐘脈沖信號——上升沿有效
sbit SCLK = P1^2; //打入信號————上升沿有效
//-----------------------------------------------------------------------------
// 全局變量
unsigned char LED[8] = {0,0,12,15,5,3,8}; //用于LED的8位顯示緩存
bit ReadRTC_Flag;//定義讀DS1302標志
unsigned char l_tmpdate[7]= {0,0,12,15,5,3,8}; //秒分時日月周年08-05-15 12:00:00
unsigned char l_tmpdisplay[8];
code unsigned char write_rtc_address[7]= {0x80,0x82,0x84,0x86,0x88,0x8a,0x8c}; //秒分時日月周年 最低位讀寫位
code unsigned char read_rtc_address[7]= {0x81,0x83,0x85,0x87,0x89,0x8b,0x8d};
//碼表
unsigned char code LED_0F[] =
{ // 0 1 2 3 4 5 6 7 8 9 A b C d E F -
0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0x8C,0xBF,0xC6,0xA1,0x86,0xFF,0xbf
};
code unsigned char table[]= {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xbf,0xff};
//共陽數碼管
/******************************************************************/
/* 函數聲明 */
/******************************************************************/
void Write_Ds1302_byte(unsigned char temp);
void Write_Ds1302( unsigned char address,unsigned char dat );
unsigned char Read_Ds1302 ( unsigned char address );
void Read_RTC(void);//read RTC
void Set_RTC(void); //set RTC
void InitTIMER0(void);//inital timer0
/******************************************************************/
/* 主函數 */
/******************************************************************/
void main(void)
{
InitTIMER0(); //初始化定時器0
//Set_RTC(); //寫入時鐘值,如果使用備用電池時候,不需要沒每次上電寫入,此程序應該屏蔽
while(1)
{
if(ReadRTC_Flag)
{
ReadRTC_Flag=0;
Read_RTC();
LED[0]=l_tmpdate[2]/16; //數據的轉換,因我們采用數碼管0~9的顯示,將數據分開
LED[1]=l_tmpdate[2]&0x0f;
LED[2]=16; //加入"-"
LED[3]=l_tmpdate[1]/16;
LED[4]=l_tmpdate[1]&0x0f;
LED[5]=16;
LED[6]=l_tmpdate[0]/16;
LED[7]=l_tmpdate[0]&0x0f;
}
}
}
/******************************************************************/
/* 定時器0初始化 */
/******************************************************************/
void InitTIMER0(void)
{
TMOD|=0x01;//定時器設置 16位
TH0=0xef;//初始化值
TL0=0xf0;
ET0=1;
TR0=1;
EA=1;
}
/******************************************************************/
/* 寫一個字節 */
/******************************************************************/
void Write_Ds1302_Byte(unsigned char temp)
{
unsigned char i;
for (i=0; i<8; i++) //循環8次 寫入數據
{
SCK=0;
SDA=temp&0x01; //每次傳輸低字節
temp>>=1; //右移一位
SCK=1;
}
}
/******************************************************************/
/* 寫入DS1302 */
/******************************************************************/
void Write_Ds1302( unsigned char address,unsigned char dat )
{
RST=0;
_nop_();
SCK=0;
_nop_();
RST=1;
_nop_(); //啟動
Write_Ds1302_Byte(address); //發送地址
Write_Ds1302_Byte(dat); //發送數據
RST=0; //恢復
}
/******************************************************************/
/* 讀出DS1302數據 */
/******************************************************************/
unsigned char Read_Ds1302 ( unsigned char address )
{
unsigned char i,temp=0x00;
RST=0;
_nop_();
_nop_();
SCK=0;
_nop_();
_nop_();
RST=1;
_nop_();
_nop_();
Write_Ds1302_Byte(address);
for (i=0; i<8; i++) //循環8次 讀取數據
{
if(SDA)
temp|=0x80; //每次傳輸低字節
SCK=0;
temp>>=1; //右移一位
_nop_();
_nop_();
_nop_();
SCK=1;
}
RST=0;
_nop_(); //以下為DS1302復位的穩定時間
_nop_();
RST=0;
SCK=0;
_nop_();
_nop_();
_nop_();
_nop_();
SCK=1;
_nop_();
_nop_();
SDA=0;
_nop_();
_nop_();
SDA=1;
_nop_();
_nop_();
return (temp); //返回
}
/******************************************************************/
/* 讀時鐘數據 */
/******************************************************************/
void Read_RTC(void) //讀取 日歷
{
unsigned char i,*p;
p=read_rtc_address; //地址傳遞
for(i=0; i<7; i++) //分7次讀取 秒分時日月周年
{
l_tmpdate[ i]=Read_Ds1302(*p);
p++;
}
}
/******************************************************************/
/* 設定時鐘數據 */
/******************************************************************/
void Set_RTC(void) //設定 日歷
{
unsigned char i,*p,tmp;
for(i=0; i<7; i++) { //BCD處理
tmp=l_tmpdate[ i]/10;
l_tmpdate[ i]=l_tmpdate[ i]%10;
l_tmpdate[ i]=l_tmpdate[ i]+tmp*16;
}
Write_Ds1302(0x8E,0X00);
p=write_rtc_address; //傳地址
for(i=0; i<7; i++) //7次寫入 秒分時日月周年
{
Write_Ds1302(*p,l_tmpdate[ i]);
p++;
}
Write_Ds1302(0x8E,0x80);
}
/******************************************************************/
/* 定時器中斷函數 */
/******************************************************************/
void tim(void) interrupt 1 using 1
//中斷,用于數碼管掃描
{
static unsigned char i,num;
uchar code *led_table; // 查表指針
TH0=0xf5;
TL0=0xe0;
//uchar i;
//顯示第1位
LED4_Display();
i++;
if(i==8)
{
i=0;
num++;
if(10==num) //隔段時間讀取1302的數據。時間間隔可以調整
{
ReadRTC_Flag=1; //使用標志位判斷
num=0;
}
}
}
void LED4_Display (void)
{
uchar code *led_table; // 查表指針
uchar i;
//顯示第1位
led_table = LED_0F + LED[0];
i = *led_table;
LED_OUT(i);
LED_OUT(0x01);
RCLK = 0;
RCLK = 1;
//顯示第2位
led_table = LED_0F + LED[1];
i = *led_table;
LED_OUT(i);
LED_OUT(0x02);
RCLK = 0;
RCLK = 1;
//顯示第3位
led_table = LED_0F + LED[2];
i = *led_table;
LED_OUT(i);
LED_OUT(0x04);
RCLK = 0;
RCLK = 1;
//顯示第4位
led_table = LED_0F + LED[3];
i = *led_table;
LED_OUT(i);
LED_OUT(0x08);
RCLK = 0;
RCLK = 1;
//顯示第5位
led_table = LED_0F + LED[4];
i = *led_table;
LED_OUT(i);
LED_OUT(0x10);
RCLK = 0;
RCLK = 1;
//顯示第6位
led_table = LED_0F + LED[5];
i = *led_table;
LED_OUT(i);
LED_OUT(0x20);
RCLK = 0;
RCLK = 1;
//顯示第7位
led_table = LED_0F + LED[6];
i = *led_table;
LED_OUT(i);
LED_OUT(0x40);
RCLK = 0;
RCLK = 1;
//顯示第8位
led_table = LED_0F + LED[7];
i = *led_table;
LED_OUT(i);
LED_OUT(0x80);
RCLK = 0;
RCLK = 1;
}
void LED_OUT(uchar X)
{
uchar i;
for(i=8; i>=1; i--)
{
if (X&0x80) DIO=1;
else DIO=0;
X<<=1;
SCLK = 0;
SCLK = 1;
}
}
|