/*
程序名(program name) : 時鐘芯片控制程序;
概述 : 基于本程序的開發(fā)板是本人自主研發(fā)的YF-A1 AVR MEGA16單片機芯片開發(fā)板,信號
輔助硬件工具有一部8通道的24兆赫茲的邏輯分析儀和一部萬用表,通俗的講,此程序就
是開發(fā)板的操作系統(tǒng),以MEGA16A為中央控制芯片,來控制DS1302時鐘芯片,使其時間數(shù)據(jù)
顯示在1602液晶屏上;
我用業(yè)余時間大概寫了三天左右....得以完善,這次我寫的比較順利,錯誤只有兩點,
一是將寫好的程序下載入芯片后,時間不走,錯誤在于寫錯了時序,用邏輯分析儀捕捉信號
后,修正,KO! 二是時間可以走,但是跑秒?yún)^(qū)并非從0走到59,問題在于顯示時,直接顯示
BCD碼,并未將BCD碼轉(zhuǎn)換為十進制數(shù),修正后OK!
此程序還用到了定時器模塊,定時每100毫秒讀一次時間數(shù)據(jù),并顯示在液晶屏上;
心得: 此次又突破了以往的程序量,這是我寫的目前最大的一個程序,由于AVR芯片IO口
控制比較復(fù)雜,所以程序語句比較多,但是此程序還有精簡的空間,IO口的初始化很重
要!
finish time: 2014年3月7日13:16:14
作者: 肖邦;
QQ: 14-545-07665 ;
TEL: SORRY 保密;
地址: 新疆昌吉回族自治州昌吉市;
夢想: 將 托尼*斯塔克成為現(xiàn)實;
*/
#include <avr/io.h>
#include <avr/interrupt.h>//此頭文件用于中斷服務(wù),本程序中可以省略;
typedef unsigned char uint8;
typedef unsigned int uint16;
void init_io(void) //====初始化所有io口;
{
DDRA=0XFF;
PORTA=0XFF;
DDRB=0XFF;
PORTB=0X00;
DDRC=0XFF;
PORTC=0X00;
DDRD=0XFF;
PORTD=0X00;
}
//================IO口的位操作==================
void rs(uint8 a) //指令/數(shù)據(jù)位/ ===========DS1302時鐘位;
{
if(a) { PORTB|=1<<3; }
else { PORTB&=~(1<<3); }
}
void rw(uint8 a) //讀/寫位/ ================DS1302數(shù)據(jù)位;
{
if(a) { PORTB|=1<<4; }
else { PORTB&=~(1<<4); }
}
void e(uint8 a) //1602傳輸時能位;
{
if(a) { PORTB|=1<<5; }
else { PORTB&=~(1<<5); }
}
void ds(uint8 a) //=========================DS1302傳輸使能位;
{
if(a) { PORTC|=1<<4; }
else { PORTC&=~(1<<4); }
}
//==============================================
/*/======================================================
模塊名: 1602LCD液晶屏函數(shù)
功能: 負責(zé)將視覺需要的數(shù)據(jù)顯示在屏幕上;
*///=====================================================
void pa7(uint8 a) //繁忙檢測位=================
{
if(a) { DDRA|=0X80; PORTA|=0X80 ;} //輸出高電平狀態(tài);
else { DDRA&=~(0X80); PORTA|=0X80; }//輸入內(nèi)部有上拉電阻;
}
void busy(void) //繁忙檢測函數(shù)
{
pa7(0); // PA7引腳輸入狀態(tài)內(nèi)部有上拉;
do
{
e(0);
rs(0);
rw(1);
e(1); //注意!此處和讀寫數(shù)據(jù)指令不同,要置1傳輸使能位,再讀取,讀取完成后再清零此位;
}
while(PINA&0X80);//讀取PA7引腳是否是0;如果是0,表示液晶屏處于空閑狀態(tài),可以進行操作;
e(0);
pa7(1); //PA7引腳輸出狀態(tài),輸出1;
}
void pa(uint8 a) //====向PA口裝載數(shù)據(jù);
{
PORTA=a;
}
void lcd_dat(uint8 dat)//=========寫數(shù)據(jù)==============
{
busy(); //繁忙檢測;
rs(1); //數(shù)據(jù);
rw(0); //寫入;
e(1); //傳輸開始;
pa(dat); //裝載數(shù)據(jù);
e(0) ; //傳輸結(jié)束;
}
void lcd_cmd(uint8 cmd) //=============寫指令=============
{
busy(); //繁忙檢測;
rs(0); //指令;
rw(0); //寫入;
e(1); //傳輸開始;
pa(cmd); //裝載數(shù)據(jù);
e(0); //傳輸結(jié)束;
}
void init_lcd() //初始化液晶屏指令;
{
lcd_cmd(0x3c); //顯示數(shù)據(jù),8位數(shù)據(jù), 兩行,5X10顯示;
lcd_cmd(0x0c); //整屏顯示光標不閃,字符不閃.
lcd_cmd(0x06); //寫入一個數(shù)據(jù)時地址加一,整屏不移動;
lcd_cmd(0x01); //清屏指令;
}
void play(uint8 add,uint8 dat)//=======最終顯示函數(shù)===================
{
lcd_cmd(add);
lcd_dat(dat);
}
void delay1(uint8 j,uint8 i)//====可編程延時函數(shù)========
{
uint16 a=0,s=10000;
s=s*j;
while(i--)
{
for(a=0;a<s;a++);
}
}
void buzz(void) //蜂鳴器=============
{
PORTC|=0X80;
delay1(3,4);
PORTC&=~(0X80);
}
//==========================================================
//==================DS1302模塊===========
void reset_1302()
{
ds(0);
rs(0);
rw(0);
}
void delay2(void) //用于DS1302小延時函數(shù);
{
uint8 j=0;
for(j=0;j<200;j++);
}
void ds_write(uint8 dat) //DS1302寫數(shù)據(jù)函數(shù);
{
uint8 j=0;
for(j=0;j<8;j++)
{
rw(dat&0x01);
rs(0);
rs(1);
dat>>=1;
}
}
uint8 ds_read(void) // DS1302讀取函數(shù);
{
uint8 j=0,temp=0;
DDRB&=~(1<<4); //rw引腳輸入狀態(tài);
PORTB|=1<<4; //內(nèi)部有上拉電阻;
rs(0);
for(j=0;j<8;j++)
{
temp>>=1;
if((PINB&0X10)==0X10)//如果PB4口讀到1;
{
temp|=0x80;//裝載數(shù)據(jù);
}
rs(1); //下降沿有效;
delay2(); //時鐘脈寬延時;
rs(0);
}
DDRB|=1<<4; // rw引腳輸出狀態(tài);
PORTB|=1<<4; //rw引腳輸出1;
rs(0);
rw(0);
return (temp);
}
void w_1302(uint8 addr,uint8 dat) //寫一個地址,寫一個數(shù)據(jù);
{
ds_write(addr);
ds_write(dat);
}
void ds_wp(uint8 j) //j==1:不能夠?qū)懭霐?shù)據(jù),j==0:可以寫入數(shù)據(jù);
{
reset_1302(); //初始化時鐘,數(shù)據(jù),片選線;
ds(1);
w_1302(0x8e,j?0x80:0); //三目運算;
ds(0);
}
void set_time(uint8 * dat) //設(shè)置時間;
{
uint8 r=0 ,t=0, ad=0x80;
for(r=0;r<7;r++) //BCD碼的轉(zhuǎn)換.
{
t=dat[r]%10;
dat[r]=dat[r]/10;
dat[r]=(dat[r]*16)+t;
}
ds_wp(0);//可以寫入數(shù)據(jù);
for(r=0;r<7;r++)
{
reset_1302(); //初始化1302;
ds(1); //傳輸使能開;
ds_write(ad); //寫入"寫"操作地址;
ds_write(dat[r]);//寫入時間數(shù)據(jù);
ds(0);
ad+=2;//地址加2;
}
ds_wp(1);//禁止寫入數(shù)據(jù);
}
void read_time(uint8 * dat)
{
uint8 j=0,addr=0x81 ;
for(j=0;j<7;j++)
{
reset_1302();
ds(1); //傳輸使能開;
ds_write(addr); //發(fā)送讀取地址;
dat[j]=ds_read(); //接收讀到的數(shù)據(jù);
ds(0); //傳輸使能關(guān);
addr+=2; //讀取地址加2;
}
}
void timer0(void) //定時器模塊函數(shù);
{
TCNT0=22; //每5毫秒溢出一次;
TCCR0=0X04; //256分頻;
}
int main(void)
{
uint8 j=0;
uint8 sj[]={20,23,13,7,3,5,14};
init_io(); //初始化所有io口;
init_lcd(); //初始化1602液晶屏;
play(0x82,'2');
delay1(3,2);
play(0x83,'0');
delay1(3,2);
play(0x86,'-');
delay1(3,2);
play(0x89,'-');
delay1(3,2);
play(0x8d,'(');
delay1(3,2);
play(0x8f,')');
delay1(3,2);
play(0xc4,':');
delay1(3,2);
play(0xc7,':');
delay1(3,2);
buzz(); //蜂鳴器叫;
delay1(3,2);
set_time(sj); //設(shè)置時間;
timer0(); //運行定時器;
while(1)
{
if(TIFR&0X01) //定時器溢出了;
{
j++;
TCNT0=22;
TIFR|=0X01;//溢出位置一清零;
}
if(j==20)
{
j=0;
read_time(sj);
play(0xc9,sj[0]%16+'0'); //秒個位;
play(0xc8,sj[0]/16+'0'); //秒十位;
play(0xc6,sj[1]%16+'0'); //分個位;
play(0xc5,sj[1]/16+'0'); //分十位;
play(0xc3,sj[2]%16+'0'); //時個位;
play(0xc2,sj[2]/16+'0'); //時十位;
play(0x8b,sj[3]%16+'0'); //號個位;
play(0x8a,sj[3]/16+'0'); //號十位;
play(0x88,sj[4]%16+'0'); //月個位;
play(0x87,sj[4]/16+'0'); //月十位;
play(0x8e,sj[5]+'0'); //星期;
play(0x85,sj[6]%16+'0'); //秒個位;
play(0x84,sj[6]/16+'0'); //秒十位;
}
}
}