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