×
单片机 > 单片机程序设计 > 详情

51单片机+带字库液晶12864+DS1302数字时钟C源程序

发布时间:2020-06-05 发布时间:
|
经过两天的搜索与调试,在别人程序的基础上,不断修改,终于调试成功了这个程序。

目前还不能修改时间与日期,只是以预定时间以始。

适用于开发板:51单片机(AT89S52)+带字库液晶12864(ST7920)+DS1302(实时时钟)

实现功能:简单,数字时钟+日期(以后会不断完美)。

C语言源程序如下:

 

#include
#include
#define uchar unsigned char
#define uint unsigned int

/*DS1302 端口设置 */
sbit SCK=P3^6;        //DS1302时钟
sbit SDA=P3^4;      //DS1302 IO
sbit RST = P3^5;   // DS1302复位

bit ReadRTC_Flag;      //读DS1302全局变量

/* 12864端口定义*/
#define LCD_data P0             //带字库液晶12864数据口
sbit LCD_RS = P2^4;            //寄存器选择输入 
sbit LCD_RW = P2^5;            //液晶读/写控制
sbit LCD_EN = P2^6;     //液晶使能控制
sbit    PSB=P2^1;          //并口控制
sbit    RES=P2^3;

 


uchar code dis1[] = {" 电子设计天地"};        //液晶显示的汉字

uchar code dis2[] = {"有志者,事竟成!"};
uchar code dis4[] = {'0','1','2','3','4','5','6','7','8','9'};
unsigned char temp;
#define delayNOP(); {_nop_();_nop_();_nop_();_nop_();};
void lcd_pos(uchar X,uchar Y); //确定显示位置

 

unsigned char l_tmpdate[7]={0,7,16,19,10,1,9};//秒分时日月周年09-10-19 16:07:00

code unsigned char write_rtc_address[7]={0x80,0x82,0x84,0x86,0x88,0x8a,0x8c}; //秒分时日月周年 最低位读写位
code unsigned char read_rtc_address[7]={0x81,0x83,0x85,0x87,0x89,0x8b,0x8d}; 
void Write_Ds1302_byte(unsigned char temp); 
void Write_Ds1302( unsigned char address,unsigned char dat );
unsigned char Read_Ds1302 ( unsigned char address );
void Read_RTC(void);//read RTC 
void Set_RTC(void); //set RTC 
void InitTIMER0(void);//inital timer0

 


/*******************************************************************/
/*                                                                 */
/* 延时函数                                                       */
/*                                                                 */
/*******************************************************************/

void    delay(unsigned int m)            //延时程序
                   {
                      unsigned int i,j;
                      for(i=0;i                          for(j=0;j<10;j++);
                   }

/*******************************************************************/
/*                                                                 */
/*检查LCD忙状态                                                    */
/*lcd_busy为1时,忙,等待。lcd-busy为0时,闲,可写指令与数据。      */
/*                                                                 */
/*******************************************************************/
bit lcd_busy()
{                          
    bit result;
    LCD_RS = 0;
    LCD_RW = 1;
    LCD_EN = 1;
    delayNOP();
    result = (bit)(P0&0x80);
    LCD_EN = 0;
    return(result); 
}
/*******************************************************************/
/*                                                                 */
/*写指令数据到LCD                                                  */
/*RS=L,RW=L,E=高脉冲,D0-D7=指令码。                             */
/*                                                                 */
/*******************************************************************/
void lcd_wcmd(uchar cmd)
{                          
   while(lcd_busy());
    LCD_RS = 0;
    LCD_RW = 0;
    LCD_EN = 0;
    _nop_();
    _nop_(); 
    P0 = cmd;
    delay(1);
    LCD_EN = 1;
    delay(1);
    LCD_EN = 0; 
}
/*******************************************************************/
/*                                                                 */
/*写显示数据到LCD                                                  */
/*RS=H,RW=L,E=高脉冲,D0-D7=数据。                               */
/*                                                                 */
/*******************************************************************/
void lcd_wdat(uchar dat)
{                          
   while(lcd_busy());
    LCD_RS = 1;
    LCD_RW = 0;
    LCD_EN = 0;
    P0 = dat;
    delayNOP();
    LCD_EN = 1;
    delay(1);
    LCD_EN = 0; 
}
/*******************************************************************/
/*                                                                 */
/* LCD初始化设定                                                  */
/*                                                                 */
/*******************************************************************/
void lcd_init()

P0=0xFF;
P2=0xFF;

delay(40);
PSB=1;             //并口方式。
delay(1);
RES=0;
delay(1);
RES=1;

delay(10);
lcd_wcmd(0x30);
delay(100);
lcd_wcmd(0x30);
delay(37);
lcd_wcmd(0x08);
delay(100);
lcd_wcmd(0x10);
delay(100);
lcd_wcmd(0x0C);      //显示开,关光标
    delay(100);
    lcd_wcmd(0x01);      //清除LCD的显示内容
    delay(100);
lcd_wcmd(0x06);
delay(100);

}


void main()
{
uchar i;
InitTIMER0();
   Set_RTC();
   lcd_init();


    
              //初始化LCD             
while(1)
{
if(ReadRTC_Flag)
{
   ReadRTC_Flag=0;
Read_RTC();
lcd_pos(0,0);             //设置显示位置为第一行的第1个字符
     i = 0;
    while(dis1[i] != '\0')
     {                         //显示字符
       lcd_wdat(dis1[i]);
       i++;
     }
    lcd_pos(1,0);             //设置显示位置为第二行的第1个字符
     i = 0;
    while(dis2[i] != '\0')
     {
       lcd_wdat(dis2[i]);      //显示字符
       i++;
     }

lcd_pos(2,0); 
lcd_wdat(dis4[l_tmpdate[6]/16]);          //DS1302是BCD码,进行处理得到十位与个位数。
lcd_pos(2,1);             
     lcd_wdat(dis4[l_tmpdate[6]%16]);
lcd_pos(2,2);             
     lcd_wdat('-');
lcd_pos(2,3);             
     lcd_wdat(dis4[l_tmpdate[4]/16]);
lcd_pos(2,4);             
     lcd_wdat(dis4[l_tmpdate[4]%16]);
lcd_pos(2,5);             
     lcd_wdat('-');
lcd_pos(2,6);             
     lcd_wdat(dis4[l_tmpdate[3]/16]);
lcd_pos(2,7);             
     lcd_wdat(dis4[l_tmpdate[3]%16]);           //设置显示位置为第三行的第1个字符
    
lcd_pos(3,0);             //设置显示位置为第四行的第1个字符
     lcd_wdat(dis4[l_tmpdate[2]/16]);
lcd_pos(3,1);             
     lcd_wdat(dis4[l_tmpdate[2]%16]);
lcd_pos(3,2);             
     lcd_wdat(':');
lcd_pos(3,3);             
     lcd_wdat(dis4[l_tmpdate[1]/16]);
lcd_pos(3,4);             
     lcd_wdat(dis4[l_tmpdate[1]%16]);
lcd_pos(3,5);             
     lcd_wdat(':');
lcd_pos(3,6);             
     lcd_wdat(dis4[l_tmpdate[0]/16]);
lcd_pos(3,7);             
     lcd_wdat(dis4[l_tmpdate[0]%16]);
  
}
}
}
/*********************************************************/
/*                                                       */
/* 设定显示位置                                          */
/*                                                       */
/*********************************************************/
void lcd_pos(uchar X,uchar Y)
{                          
   uchar pos;
   if (X==0)
     {X=0x80;}
   else if (X==1)
     {X=0x90;}
   else if (X==2)
     {X=0x88;}
   else if (X==3)
     {X=0x98;}
   pos = X+Y ; 
   lcd_wcmd(pos);     //显示地址
}

 


void InitTIMER0(void)
{
TMOD|=0x01;//定时器设置 16位
TH0=0xef;//初始化值
TL0=0xf0;
ET0=1;
TR0=1;
EA=1;
}

 

void Write_Ds1302_Byte(unsigned char temp) 
{
unsigned char i;
for (i=0;i<8;i++)     //循环8次 写入数据

   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++)    //循环8次 读取数据
   {  
    if(SDA)
    temp|=0x80;    //每次传输低字节
   SCK=0;
   temp>>=1;    //右移一位
    SCK=1;

   RST=0;
_nop_();   //以下为DS1302复位的稳定时间
   RST=0;
SCK=0;
_nop_();
SCK=1;
_nop_();
SDA=0;
_nop_();
SDA=1;
_nop_();
return (temp);    //返回
}
/****************************************************************************/
void Read_RTC(void)   //读取 日历
{
unsigned char i,*p;
p=read_rtc_address; //地址传递
for(i=0;i<7;i++)   //分7次读取 秒分时日月周年
{
l_tmpdate[i]=Read_Ds1302(*p);
p++;
}
}
/***********************************************************************/
void Set_RTC(void)   //设定 日历
{
unsigned char i,*p,tmp;
for(i=0;i<7;i++){           //BCD处理
   tmp=l_tmpdate[i]/10;
   l_tmpdate[i]=l_tmpdate[i]%10;
   l_tmpdate[i]=l_tmpdate[i]+tmp*16;
}
   Write_Ds1302(0x8E,0X00);

   p=write_rtc_address; //传地址 
   for(i=0;i<7;i++)   //7次写入 秒分时日月周年
   {
    Write_Ds1302(*p,l_tmpdate[i]);
    p++; 
}
Write_Ds1302(0x8E,0x80);
}

void tim(void) interrupt 1 using 1//中断,用于数码管扫描
{

    static unsigned char i,num;
    TH0=0xf5;
    TL0=0xe0;

   //P0=table[l_tmpdisplay[i]];   //查表法得到要显示数字的数码段
//P2=table1[i];
i++;
if(i==8)
   {
    i=0;
    num++;
    if(20==num)       //隔段时间读取1302的数据。时间间隔可以调整
      {
   ReadRTC_Flag=1; //使用标志位判断
   num=0;
   }
    
    }
}

/*****END ************/

 

以上经过在开发板上调试OK。

下面讲一下调试经验与大家分享。

首先用液晶显示DS1302分三步走。

第一步:搞清楚液晶12864(带字库,方便使用),也就是怎样让其显示汉字及字符。

第二步:搞清楚DS1302怎样用,怎样写入与显示出时间数据。

第三步:把上面两步程序合在一起进行调试,当然要注意各端口的定义与连接。

这里并不能修改时间日期,以后会进一步研究。

总之,在液晶显示学习上又进一步了。

路要一步步走。




『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
STM32单片机的复用端口初始化的步骤及方法