专注电子技术学习与研究
当前位置:单片机教程网 >> MCU设计实例 >> 浏览文章

avr MEGA16单片机控制DS1302时钟芯片1602液晶显示

作者:肖邦   来源:本站原创   点击数:  更新时间:2014年03月08日   【字体:
/*
 
          程序名(program name) :  时钟芯片控制程序;

 
          概述 :  基于本程序的开发板是本人自主研发的YF-A1 AVR MEGA16单片机芯片开发板,信号
     辅助硬件工具有一部8通道的24兆赫兹的逻辑分析仪和一部万用表,通俗的讲,此程序就
              是开发板的操作系统,以MEGA16A为中央控制芯片,来控制DS1302时钟芯片,使其时间数据
 显示在1602液晶屏上;
     我用业余时间大概写了三天左右....得以完善,这次我写的比较顺利,错误只有两点,
              一是将写好的程序下载入芯片后,时间不走,错误在于写错了时序,用逻辑分析仪捕捉信号
              后,修正,KO! 二是时间可以走,但是跑秒区并非从0走到59,问题在于显示时,直接显示
 BCD码,并未将BCD码转换为十进制数,修正后OK!
                   此程序还用到了定时器模块,定时每100毫秒读一次时间数据,并显示在液晶屏上;

 

 
            心得:    此次又突破了以往的程序量,这是我写的目前最大的一个程序,由于AVR芯片IO口
    控制比较复杂,所以程序语句比较多,但是此程序还有精简的空间,IO口的初始化很重
要!
 

 

 
                 finish time:   2014年3月7日13:16:14
                        作者: 肖邦;
                          QQ: 14-545-07665 ;
                         TEL:  SORRY 保密;
       地址:  新疆昌吉回族自治州昌吉市; 
                        梦想:  将 托尼*斯塔克成为现实;

 
*/

 

 
#include <avr/io.h>
#include <avr/interrupt.h>//此头文件用于中断服务,本程序中可以省略;

 
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)    //指令/数据位/ ===========DS1302时钟位;
{
  if(a) { PORTB|=1<<3; }

 
  else  { PORTB&=~(1<<3); }
}

 
void rw(uint8 a)  //读/写位/   ================DS1302数据位;
{
  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液晶屏函数 
     功能:  负责将视觉需要的数据显示在屏幕上;
     
*///=====================================================
void pa7(uint8 a)  //繁忙检测位=================
{
  if(a) { DDRA|=0X80; PORTA|=0X80 ;} //输出高电平状态;
  else  { DDRA&=~(0X80); PORTA|=0X80; }//输入内部有上拉电阻;
}

 
void busy(void)    //繁忙检测函数
{
   pa7(0);  // PA7引脚输入状态内部有上拉;
   do
   {
    e(0);
    rs(0);
    rw(1);
    e(1);   //注意!此处和读写数据指令不同,要置1传输使能位,再读取,读取完成后再清零此位;
   }

 
   while(PINA&0X80);//读取PA7引脚是否是0;如果是0,表示液晶屏处于空闲状态,可以进行操作;
   e(0);

 
   pa7(1);   //PA7引脚输出状态,输出1;
}

 
void pa(uint8 a) //====向PA口装载数据;
{

 
  PORTA=a;

 
}
void lcd_dat(uint8 dat)//=========写数据==============
{
   busy();  //繁忙检测;
    rs(1);  //数据;
    rw(0);  //写入;
e(1);   //传输开始;
    pa(dat);  //装载数据;
    e(0) ;   //传输结束;
  
}

 
void lcd_cmd(uint8 cmd)  //=============写指令=============
{
   busy();  //繁忙检测;
    rs(0);  //指令;
    rw(0);  //写入;
e(1);   //传输开始;
    pa(cmd);  //装载数据;
    e(0);    //传输结束;
  
}

 
void init_lcd()  //初始化液晶屏指令;
{
   lcd_cmd(0x3c);  //显示数据,8位数据, 两行,5X10显示;
   lcd_cmd(0x0c);  //整屏显示光标不闪,字符不闪.
   lcd_cmd(0x06);  //写入一个数据时地址加一,整屏不移动;
   lcd_cmd(0x01);  //清屏指令;

 
}

 
void play(uint8 add,uint8 dat)//=======最终显示函数===================
{
  lcd_cmd(add);
  lcd_dat(dat);

 
}

 
void delay1(uint8 j,uint8 i)//====可编程延时函数========
{
   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小延时函数;
{
  uint8 j=0;
  for(j=0;j<200;j++);

 

 
}

 
void ds_write(uint8 dat)   //DS1302写数据函数;
{
   uint8 j=0;

 
   for(j=0;j<8;j++)
     {
    rw(dat&0x01);
         
rs(0);
rs(1);
dat>>=1;
}
   
    
  
}

 
uint8 ds_read(void) // DS1302读取函数;
{
    uint8 j=0,temp=0;

 
    DDRB&=~(1<<4); //rw引脚输入状态;
    PORTB|=1<<4;   //内部有上拉电阻;
     rs(0);

 

 
    for(j=0;j<8;j++)
{         
        temp>>=1;

 

 
   if((PINB&0X10)==0X10)//如果PB4口读到1;
 {   
     temp|=0x80;//装载数据;
 }
 
 
      rs(1);       //下降沿有效;
 delay2();    //时钟脉宽延时;
      rs(0);        
}
 
    DDRB|=1<<4; //  rw引脚输出状态;
    PORTB|=1<<4;   //rw引脚输出1;
        rs(0);
rw(0);

 
return (temp);

 

 
}

 
void w_1302(uint8 addr,uint8 dat) //写一个地址,写一个数据;
{
   ds_write(addr);
   ds_write(dat);

 
}

 

 
void ds_wp(uint8 j)  //j==1:不能够写入数据,j==0:可以写入数据;
{  
   reset_1302(); //初始化时钟,数据,片选线;
   ds(1);
   w_1302(0x8e,j?0x80:0);  //三目运算;
   ds(0);
}

 

 
void set_time(uint8 * dat)   //设置时间;
 { 
  uint8 r=0 ,t=0, ad=0x80;
   for(r=0;r<7;r++)    //BCD码的转换.
     {
  t=dat[r]%10;
  dat[r]=dat[r]/10;
  dat[r]=(dat[r]*16)+t;
 
}
      ds_wp(0);//可以写入数据;
      for(r=0;r<7;r++)
  {     
     reset_1302();  //初始化1302;
        ds(1);    //传输使能开;
        ds_write(ad); //写入"写"操作地址;
        ds_write(dat[r]);//写入时间数据;
ds(0);
         ad+=2;//地址加2;
       }
       ds_wp(1);//禁止写入数据;  

 
}

 
void read_time(uint8 * dat)
{
   uint8 j=0,addr=0x81 ;

 
   for(j=0;j<7;j++)
    {
      reset_1302();
 ds(1);          //传输使能开;
      ds_write(addr);  //发送读取地址;
 dat[j]=ds_read(); //接收读到的数据;
 ds(0);          //传输使能关;

 
 addr+=2;   //读取地址加2;
}

 
}

 
void timer0(void)  //定时器模块函数;
{

 
  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);  //设置时间;
  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'); //秒十位;

 

 

 
      
   
 }

 

 

 
  }

 

 

 

 
 

 

 
}
关闭窗口

相关文章