專注電子技術(shù)學(xué)習(xí)與研究
當(dāng)前位置:單片機(jī)教程網(wǎng) >> MCU設(shè)計(jì)實(shí)例 >> 瀏覽文章

avr MEGA16單片機(jī)控制DS1302時(shí)鐘芯片1602液晶顯示

作者:肖邦   來(lái)源:本站原創(chuàng)   點(diǎn)擊數(shù):  更新時(shí)間:2014年03月08日   【字體:
/*
 
          程序名(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'); //秒十位;

 

 

 
      
   
 }

 

 

 
  }

 

 

 

 
 

 

 
}
關(guān)閉窗口

相關(guān)文章