【蓝桥杯单片机组】| DS1302(官方驱动)+ 矩阵按键 + 数码管(改,解决数码管跳动的问题)

DS1302这个芯片给我的印象就是不同种类的寄存器真的很多,比如秒寄存器的bit7(时间暂停位)可以在时间计数的时候控制停止与启动,再比如写保护寄存器的bit7(写保护位)可以控制写操作,诸如此类的还有很多,在初学阶段比较容易混淆,不过只要多翻翻芯片手册,弄明白各个寄存器的功能就不会晕头转向了。

对该芯片的学习过程中,最郁闷的一件事就是中文资料有时候真的很会误导人,错把VCC1翻译成主电源,如下图所示。

【蓝桥杯单片机组】| DS1302(官方驱动)+ 矩阵按键 + 数码管(改,解决数码管跳动的问题)_第1张图片

而原版英文资料如下。

【蓝桥杯单片机组】| DS1302(官方驱动)+ 矩阵按键 + 数码管(改,解决数码管跳动的问题)_第2张图片


接下来进入正题!我想通过 DS1302(官方给的时序代码) + 矩阵按键 + 数码管 来实现电子钟的时间暂停时间启动时间重置的功能。


头文件

/*
  程序说明: DS1302驱动程序
  软件环境: Keil uVision 4.10 
  硬件环境: CT107单片机综合实训平台 8051,12MHz
  日    期: 2011-8-9
*/

#include 
#include 

sbit SCK=P1^7;		
sbit SDA=P2^3;		
sbit RST = P1^3;   // DS1302复位												

void Write_Ds1302_Byte(unsigned  char temp) 
{
	unsigned char i;
	for (i=0;i<8;i++)     	
	{ 
		SCK=0;
		SDA=temp&0x01;
		temp>>=1; 
		SCK=1;
	}
}   

void Write_Ds1302( unsigned char address,unsigned char dat )     
{
 	RST=0;
	_nop_();
 	SCK=0;
	_nop_();
 	RST=1;	
   	_nop_();  
 	Write_Ds1302_Byte(address);	
 	Write_Ds1302_Byte(dat);		
 	RST=0; 
}

unsigned char Read_Ds1302 ( unsigned char address )
{
 	unsigned char i,temp=0x00;
 	RST=0;
	_nop_();
 	SCK=0;
	_nop_();
 	RST=1;
	_nop_();
 	Write_Ds1302_Byte(address);
 	for (i=0;i<8;i++) 	
 	{		
		SCK=0;
		temp>>=1;	
 		if(SDA)
 		temp|=0x80;	
 		SCK=1;
	} 
 	RST=0;
	_nop_();
 	RST=0;
	SCK=0;
	_nop_();
	SCK=1;
	_nop_();
	SDA=0;
	_nop_();
	SDA=1;
	_nop_();
	return (temp);			
}

void delay(int n)/*延时函数*/  		  
{  
    char z=110;  
    while(n--)  
    for(z=0;z<110;z++);  
}  

主程序


#include "reg52.h"  
#include "ds1302.h"      //上文中的头文件
#define uchar unsigned char;  
#define uint  unsigned int; 

sfr P4=0XC0;

sbit KO1=P3^0;
sbit KO2=P3^1;

sbit KI1=P3^4;
sbit KI2=P3^5;
sbit KI3=P4^2;
sbit KI4=P4^4;

unsigned char KeyCodeMap[2][4]={
{0x31,0x32,0x33,0x26},			   	//<-  ->  +  -
{0x34,0x35,0x36,0x25}				//RST C   NON NON
};
unsigned char  KeySta[2][4]={                   //按键状态缓冲区
{1,1,1,1},{1,1,1,1}
};


uchar code LedChar[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xff,0xbf};  	 //数码管真值表
uchar dsbuff[]={10,10,10,10,10,10,10,10};   
uchar s_time[7]={0x00,0x2,0x10,0x05,0x03,0x04,0x18};                                                          //设置时间数组  
uchar g_time[7]={0};                                                                                                                //保存时间数组  
  
void init_smg();
void LedScan();
  
void show_time();  
void get_time(); 
void set_time();

void KeyDriver();                                                                                                                     //按键驱动程序
void KeyAction(unsigned char keycode);                                                                               //按键操作程序

void main()  
{  


      init_smg();                                                                                                                         //初始化数码管  
      set_time();                                                                                                                         //设置时间  
      while(1)  
      {  
        show_time();                                                                                                                   //显示时间
        get_time();                                                                                                                      //获取时间  
        KeyDriver();                                                                                                                    //按键驱动程序
          
      }  
  

}    

					     

void init_smg()             /*配置定时器0*/ 
{  
    TMOD|=0x01;  
    TH0=(65536-1000)/256;  
    TL0=(65536-1000)%256;  
    EA=1;  
    ET0=1;  
    TR0=1;  
}  

void LedScan()              /*数码管动态刷新*/  
{  
	static unsigned char i=0;
        P2=(P2&0X1F)|0XE0;
	P0=0XFF;	
	P2&=0X1F; 
	P2|=0XC0;
	P0=0x80>>i;
	P2&=0X1F;
        P2|=0XE0;
	P0=LedChar[dsbuff[i]];          
	P2&=0X1F;
        if(++i==8) i=0;  
}  
 
void set_time()              /*初始化时间*/  
{  
    char i=0;  
    char adr=0x80;                           
    Ds1302_Single_Byte_Write(0x8e,0x00);                                                                      //清除写保护位  
    for(i=0;i<7;i++)  						                                                               //将设置好的时间写入Register
    Ds1302_Single_Byte_Write(adr+i*2,s_time[i]);                                                           //将设置好的时间数组写入DS1302
    Ds1302_Single_Byte_Write(0x8e,0x80);                                                                     //启动写保护
  
}  



void get_time()                              /*获取时间*/  
{  
    char i=0;  
    for(i=0;i<7;i++)  
    {  
    g_time[i]=Ds1302_Single_Byte_Read(0x81+i*2);  
    delay(30);  
    }  
}  



void show_time()                             /*显示时间*/  
{  

    dsbuff[1]=(g_time[0]&0x70)>>4;           //秒十位  
    dsbuff[0]=g_time[0]&0x0f;                    //秒各位  
  
    dsbuff[5]=11;                                         //-  
  
    dsbuff[4]=(g_time[1]&0x70)>>4;          //分十位  
    dsbuff[3]=g_time[1]&0x0f;                    //分各位  
  
    dsbuff[2]=11;                                        //-  
  
    dsbuff[7]=(g_time[2]&0x30)>>4;         //时十位  
    dsbuff[6]=g_time[2]&0x0f;                   //时各位  
  
}  

void KeyDriver()
{
  unsigned char i,j;
  static unsigned char backup[2][4]={       //按键状态区
  {1,1,1,1},{1,1,1,1}
};
   for(i=0;i<2;i++)
   {
	 for(j=0;j<4;j++)
	 {
		if(backup[i][j]!=KeySta[i][j])
		{
			if(backup[i][j]==0)
			{
			   KeyAction(KeyCodeMap[i][j]);
			}
			backup[i][j]=KeySta[i][j];
		}
	 }
   }
}

void KeyAction(unsigned char keycode)                   //按键行动
{
  if(keycode==0x34)                                                  //重置时间
  {
	set_time();  
  }
  else if(keycode==0x31)                                           //时间暂停
  {
	Ds1302_Single_Byte_Write(0x80,g_time[0]|0x80);     
  }
  else if(keycode==0x32)                                           //时间启动
  {
  	Ds1302_Single_Byte_Write(0x80,g_time[0]&0x7f); 
  }
 
}

void KeyScan()                                                               //按键刷新函数
{
  unsigned char i;
  static unsigned char keyout=0;						 
  static unsigned char keybuf[4][4]={
  {0XFF,0XFF,0XFF,0XFF},{0XFF,0XFF,0XFF,0XFF}
  };
  

 /*低4位全为0,认为按键按下,耗时4毫秒*/

  keybuf[keyout][0]=(keybuf[keyout][0]<<1)|KI4;
  keybuf[keyout][1]=(keybuf[keyout][1]<<1)|KI3;
  keybuf[keyout][2]=(keybuf[keyout][2]<<1)|KI2;
  keybuf[keyout][3]=(keybuf[keyout][3]<<1)|KI1;


  for(i=0;i<4;i++)
  {
      if((keybuf[keyout][i] & 0X0F)==0X00)
	  {
		 KeySta[keyout][i]=0;
      }
	  else if((keybuf[keyout][i] & 0X0F)==0X0F)
	  {
		 KeySta[keyout][i]=1;
      }
  }


  keyout++;
  if(keyout>=2) keyout=0;

/*矩阵按键的一个局限性,因为一次只能控制一行的低电平,矩阵按键行的动态刷新*/

  switch(keyout)
  {
         case 0: KO2=1;KO1=0;break;
	 case 1: KO1=1;KO2=0;break;
	 default: break;
  }
}

void smg_time() interrupt 1                     /*定时器0中断,1毫秒进入一次中断*/  
{  
   
    TH0=(65536-1000)/256;  
    TL0=(65536-1000)%256;       
    LedScan(); 				                  //数码管刷新
   KeyScan();                                              //按键刷新
}

其实上述代码遗留了一些问题,其体现在数码管跳动的问题上,通过200ms检测(读取)一次时间数据可解决此问题,以下是改动的三个地方


①。先定义一个全局变量 int flag=0;                //200ms标志位

②。主函数改为如下:

void main()  
{  


      init_smg();          
      set_time();           
      while(1)  
      {  
            show_time();
   if(flag>=200)
{   
flag=0;
                get_time();       
               }  
      }    

③。中断函数

void smg_time()interrupt 1                   /*定时器0中断*/  
{  
   
    TH0=(65536-1000)/256;  
    TL0=(65536-1000)%256;       
    LedScan();                 //数码管刷新
flag++;

你可能感兴趣的:(蓝桥杯,单片机)