?? time-1302._c
字號:
//******************************************************************************
// *
// FileName : 實驗板time_1302.c ICCAVR V6.31A編譯 *
// Function : 實時時鐘DS1302的讀寫操作應(yīng)用 *
// Date : 2007-01-16 *
// Version : 1.0 *
// *
// Author : 開關(guān)電源 hongtusy@163.com *
// Company : 電子信息技術(shù)咨詢網(wǎng) http://www.itsn.cn *
// *
//***************************描述與記事*****************************************
//實驗板的AVR程序,實時時鐘DS1302應(yīng)用,將實時時間通過串口打印到PC機上,并通過1602LCD
//顯示出來。只要不在主電源掉電下拆除電池,LCD將可以一直顯示當前的實時時間。
//接線定義:PD0-RXD PD1-TXD即開關(guān)SW6-7/8。
// SW5-1=PA3時鐘CLK,SW5-2=PA4數(shù)據(jù)DAT,SW5-3=PA5復(fù)位RET。
//PC(SW1-1~8)為LCD數(shù)據(jù)端,PD4(SW2-1),5(SW2-2),6(SW2-3) 為RS,R/W,EA腳 SW2-5為背光開關(guān)。
//記事:本程序旨在對1302驅(qū)動的理解與演示,程序適合初學者使用.
// 使用串口調(diào)試器可觀察到時間變換后顯示在PC上的數(shù)據(jù)。
//使用片內(nèi)8MHz晶體。
//秒寄存器的最高位在開機時默認是1,代表時鐘振蕩器停止,必須將其改為0后方可啟動時鐘。
//******************************************************************************
#include <iom8535v.h> //頭文件,ATmega8535單片機的寄存器定義
#include <macros.h> //包含有SEI()、CLI()、NOP()、WDR()、等宏定義.
typedef unsigned char uchar; //數(shù)據(jù)類型說明
typedef unsigned int uint; //數(shù)據(jù)類型說明
uchar buf_time[]=" Day:2007-01-16 Time: 00:00:00 "; //LCD顯示用的數(shù)組
uchar buf_read[8]; //從DS1302讀出的時間數(shù)據(jù),數(shù)據(jù)格式為:秒 分 時 日 月 星期 年 寫保護字節(jié)
uchar buf_write[8]={0x01,0x20,0x01,0x16,0x01,0x02,0x07,0x00}; //往DS1302寫入的時間數(shù)據(jù)
// 數(shù)據(jù)格式為:01秒 20分 01時 16日 01月 02星期 07年 00寫保護字節(jié)
/************************************************
函 數(shù) 名: DelaymS()
功 能: 毫秒級延時函數(shù)
輸入?yún)?shù): 延遲時間/系統(tǒng)晶體
輸出參數(shù): 做相應(yīng)的延遲處理
描 述: /
***********************************************/
void DelaymS (uint i) //延時函數(shù),參數(shù)i為延時時間
{
uint j,k; //雙重延時
for (j=0;j<i;j++)
{
for (k=0;k<=500;k++);
}
}
/********************************************************
子程序名: write_data()
功 能: 寫入一字節(jié)LCD數(shù)據(jù)
輸入?yún)?shù): /
輸出參數(shù): /
描 述: /
********************************************************/
void write_data(uchar h)
{
PORTC = h; //先將數(shù)據(jù)送出
PORTD |= (1<<PD4); //RS=1,數(shù)據(jù)
PORTD &= ~(1<<PD5); //R/W=0,寫
PORTD &= ~(1<<PD6); //EN=0 ,使能,產(chǎn)生一個下降沿。
DelaymS (1);
PORTD |= (1<<PD6); //EN=1 ,除能
}
/********************************************************
子程序名: write_code()
功 能: 寫入一字節(jié)LCD指令/地址
輸入?yún)?shù): /
輸出參數(shù): /
描 述: /
********************************************************/
void write_code(uchar h)
{
PORTC = h; //先將地址送出
PORTD &= ~(1<<PD4); //RS=0,命令或數(shù)據(jù)
PORTD &= ~(1<<PD5); //R/W=0,寫
PORTD &= ~(1<<PD6); //EN=0 ,使能,產(chǎn)生一個下降沿。
DelaymS (1);
PORTD |= (1<<PD6); //EN=1 ,除能
}
/********************************************************
子程序名: init_lcd()
功 能: 初始化LCD
輸入?yún)?shù): /
輸出參數(shù): /
描 述: /
********************************************************/
void init_lcd(void)
{
write_code(0x01); //清除屏幕
write_code(0x38); //功能設(shè)定,8位數(shù)據(jù)口/2行/5*7的點陣
write_code(0b00001111); //顯示幕ON,光標ON,閃爍ON
write_code(0x06); //模式,加1,顯示幕ON。
write_code(0b00000011); //光標回到原點
}
/********************************************************
子程序名: display_lcd()
功 能: 刷新顯示一屏數(shù)據(jù),獨立的LCD顯示程序,用戶將顯存內(nèi)容更新后,只要調(diào)用此程序即可更新顯示。
輸入?yún)?shù): /
輸出參數(shù): /
描 述: 在寫一個字符前,先設(shè)定顯示的位置地址,然后再寫數(shù)據(jù)。系統(tǒng)可以自動地址加一。
********************************************************/
void display_lcd(uchar *p)
{
uchar i;
write_code(0x80); //第一行起始地址,0b10000000B=0x80.
for(i=0;i<16;i++)
{
write_data(p[i]);
}
write_code(0xc0); //第二行起始地址,0b11000000B=0xc0.
for(i=16;i<32;i++)
{
write_data(p[i]);
}
}
/************************************************
函 數(shù) 名: InputByte()
功 能: 串行寫入1字節(jié)的數(shù)據(jù)函數(shù)
輸入?yún)?shù): /
輸出參數(shù): /
描 述: PA4為數(shù)據(jù)端,PA3為時鐘端,bit0在先,時鐘上升沿寫入。
***********************************************/
void InputByte (uchar CD)
{
uchar i;
for(i=0;i<8;i++)
{
if((CD & (1<<i))==0)
PORTA &= ~(1<<PA4); //數(shù)據(jù)端輸出0
else
PORTA |= (1<<PA4); //否則輸出1
PORTA |= (1<<PA3); //時鐘置高,產(chǎn)生上升沿。
PORTA &= ~(1<<PA3); //時鐘置低
}
}
/************************************************
函 數(shù) 名: OutputByte
功 能: 從DS1302串行讀出1字節(jié)的數(shù)據(jù)函數(shù)
輸入?yún)?shù): /
輸出參數(shù): /
描 述: PA4為數(shù)據(jù)端,PA3為時鐘端,bit0在先,時鐘下降沿讀出。
***********************************************/
uchar OutputByte (void)
{
uchar i,mid=0;
for(i=0;i<8;i++)
{
if((PINA & 0x10)==0) //操作的是PA4
{
mid &= ~(1<<i); //讀取0
}
else
{
mid |= (1<<i); //讀取1
}
PORTA |= (1<<PA3); //時鐘置高
PORTA &= ~(1<<PA3); //時鐘置低,產(chǎn)生下降沿
}
return (mid);
}
/************************************************
函 數(shù) 名: write_DS1302
功 能: 給DS1302寫入上電數(shù)據(jù),置需要設(shè)定的時鐘值
輸入?yún)?shù): /
輸出參數(shù): /
描 述: 單字節(jié)和多字節(jié)操作模式都用了。
數(shù)據(jù)格式為:秒 分 時 日 月 星期 年 寫保護字節(jié)
***********************************************/
void write_DS1302 (void)
{
uchar i;
DDRA |= (1<<DDA5)|(1<<DDA4)|(1<<DDA3); //復(fù)位,數(shù)據(jù)和時鐘腳都為輸出
PORTA &= ~(1<<PA5); //RST=0
PORTA &= ~(1<<PA3); //CLK=0
PORTA |= (1<<PA5); //RST=1
NOP();
InputByte(0x8e); //寫保護命令字節(jié)的地址
InputByte(0x00); //解除寫保護命令
PORTA &= ~(1<<PA5); //RST=0
PORTA &= ~(1<<PA3); //CLK=0
PORTA |= (1<<PA5); //RST=1
NOP();
InputByte(0b10010000); //涓流充電寄存器的地址
InputByte(0b10101010); //設(shè)置涓流充電
PORTA &= ~(1<<PA5); //RST=0
PORTA &= ~(1<<PA3); //CLK=0
PORTA |= (1<<PA5); //RST=1
NOP();
InputByte(0xbe); //多字節(jié)寫操作命令
for (i=0;i<8;i++)
{
InputByte(buf_write[i]);
}
PORTA &= ~(1<<PA5); //RST=0
}
/************************************************
函 數(shù) 名: read_DS1302
功 能: 讀取DS1302的所有時間數(shù)據(jù)
輸入?yún)?shù): /
輸出參數(shù): /
描 述: 使用多字節(jié)方式。
數(shù)據(jù)格式為:秒 分 時 日 月 星期 年
***********************************************/
void read_DS1302 (void)
{
uchar i;
DDRA |= (1<<DDA5)|(1<<DDA3); //復(fù)位和時鐘腳都為輸出
PORTA &= ~(1<<PA5); //RST=0
PORTA &= ~(1<<PA3); //CLK=0
PORTA |= (1<<PA5); //RST=1
DDRA |= (1<<DDA4); //數(shù)據(jù)腳為輸出
NOP();
InputByte(0xbf); //多字節(jié)讀命令
DDRA &= ~(1<<DDA4); //數(shù)據(jù)腳改為輸入
NOP();
for (i=0;i<8;i++)
{
buf_read[i]=OutputByte();
}
PORTA &= ~(1<<PA5); //RST=0
}
/********************************************************
子程序名: write_pc232()
功 能: 串口發(fā)送一個字節(jié)
輸入?yún)?shù): /
輸出參數(shù): /
描 述: 把數(shù)據(jù)發(fā)送出去先發(fā)送再檢測,發(fā)完后,才離開
********************************************************/
void write_pc232(uchar i)
{
while(!(UCSRA&(1<<UDRE))); //1字節(jié)發(fā)送完畢?
UDR = i; //發(fā)送一個字符數(shù)據(jù)
DelaymS (10);
}
/************************************************
函 數(shù) 名: mcu_Init()
功 能: 單片機初始化函數(shù)
輸入?yún)?shù): /
輸出參數(shù): /
描 述: 相關(guān)口方向的設(shè)置等
***********************************************/
void mcu_Init(void)
{
DDRC = 0xff; //PC口為推挽1輸出,段碼
DDRD = 0xff; //PD口為推挽1輸出,位碼,PD7為485DE腳。
DDRA = 0xff; //PA口接DS1302
}
/********************************************************
子程序名: usart_Init()
功 能: 串口初始化
輸入?yún)?shù): /
輸出參數(shù): /
描 述: /
********************************************************/
void usart_Init (void)
{
UBRRL=51; //波特率寄存器,UART:9600bps,8.000MHz
UCSRB = (1<<RXEN)|(1<<TXEN); //UART控制寄存器,RXD&TXD使能
}
/************************************************
函 數(shù) 名: spk()
功 能: 蜂鳴器鳴叫一聲函數(shù)
輸入?yún)?shù):
輸出參數(shù):
描 述: /
***********************************************/
void spk (uchar i)
{
DDRA |= (1<<2); //DDRA2為輸出。
PORTA &= ~(1<<PA2); //蜂鳴器響
DelaymS (i); //延遲
PORTA |= (1<<PA2); //蜂鳴器關(guān)閉
}
/********************************************************
子程序名: data_conversion()
輸入?yún)?shù): 數(shù)據(jù)轉(zhuǎn)換程序
輸出參數(shù): /
描 述: /1302讀出的數(shù)據(jù)是BCD碼形式,必須進行數(shù)制轉(zhuǎn)換。
數(shù)據(jù)格式: 秒 分 時 日 月 星期 年 寫保護字節(jié)
顯示格式: 秒秒 分分 時時 日日 月月 年年 輔助
********************************************************/
void data_conversion (void)
{
buf_time[29] = (buf_read[0] & 0x0f) + '0'; //秒的低位
buf_time[28] = (buf_read[0] >> 4 ) + '0'; //秒的高位
buf_time[26] = (buf_read[1] & 0x0f) + '0'; //分的低位
buf_time[25] = (buf_read[1] >> 4 ) + '0'; //分的高位
buf_time[23] = (buf_read[2] & 0x0f) + '0'; //時的低位
buf_time[22] = (buf_read[2] >> 4 ) + '0'; //時的高位
buf_time[14] = (buf_read[3] & 0x0f) + '0'; //日的低位
buf_time[13] = (buf_read[3] >> 4 ) + '0'; //日的高位
buf_time[11] = (buf_read[4] & 0x0f) + '0'; //月的高位
buf_time[10] = (buf_read[4] >> 4 ) + '0'; //月的高位
buf_time[8] = (buf_read[6] & 0x0f) + '0'; //年的高位
buf_time[7] = (buf_read[6] >> 4 ) + '0'; //年的高位
}
/********************************************************
子程序名: out_data_pc232()
功 能: 串口發(fā)送時間數(shù)據(jù)到PC,
輸入?yún)?shù): /
輸出參數(shù): /
描 述: 包括"當前的溫度是:xxx.xx攝氏度",此程序借助LCD的顯示緩沖區(qū)
********************************************************/
void out_data_pc232(void)
{
uchar i;
uchar time1[16]=" 今天的日期是:";
uchar time2[16]=" 當前的時間是:";
for(i=0;i<16;i++) //向串口發(fā)送數(shù)據(jù)
{
write_pc232(time1[i]);
}
write_pc232('2'); //年
write_pc232('0');
write_pc232(buf_time[7]);
write_pc232(buf_time[8]);
write_pc232('-');
write_pc232(buf_time[10]); //月
write_pc232(buf_time[11]);
write_pc232('-');
write_pc232(buf_time[13]); //日
write_pc232(buf_time[14]);
for(i=0;i<16;i++) //向串口發(fā)送數(shù)據(jù)
{
write_pc232(time2[i]);
}
write_pc232(buf_time[22]); //時
write_pc232(buf_time[23]);
write_pc232(':');
write_pc232(buf_time[25]); //分
write_pc232(buf_time[26]);
write_pc232(':');
write_pc232(buf_time[28]); //秒
write_pc232(buf_time[29]);
write_pc232('\n');
write_pc232('\r'); //顯示回車換行
}
//*****************主程序**********************************
void main (void)
{
uchar data_old;
uchar buf_logo[]=" welcome! www.itsn.cn! ";
mcu_Init(); //單片機初始化
usart_Init(); //串口初始化
init_lcd(); //lcd初始化
write_pc232('o'); //測試串口
write_pc232('k'); //測試串口
write_pc232('\n');
write_pc232('\r'); //顯示回車換行
display_lcd(buf_logo); //顯示LOGO
spk (1000); //上電蜂鳴器長響
DelaymS(2000); //長延遲
display_lcd(buf_time); //開始工作,LCD刷新顯示一屏
spk (100); //開始工作,蜂鳴器短響
//---------此段測試1302是否已經(jīng)寫過內(nèi)容了,若寫過就不再重新寫。
read_DS1302(); //讀時間
if(buf_read[0] & 0x80)
{
write_DS1302(); //寫入需要的初始時間值,
}
//------------------
DelaymS(1); //延遲
read_DS1302(); //讀時間
data_old = buf_read[0]; //提取舊時鐘的秒數(shù)值
while(1) //無限循環(huán)執(zhí)行,此程序保證了一秒鐘更新一次串口數(shù)據(jù),更新一次LCD顯示。
{
DelaymS(10); //延遲
read_DS1302(); //讀時間
if (data_old == buf_read[0])
{
DelaymS(10); //延遲
}
else
{
data_conversion(); //將讀出的數(shù)據(jù)分開,分別裝入顯存
display_lcd(buf_time); //刷新顯示一屏
out_data_pc232(); //串口將時間數(shù)據(jù)送PC
data_old = buf_read[0]; //更新時鐘的秒數(shù)值
}
}
}
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -