基于51单片机的万年历设计

关于设计单片机万年历的收获
1.在改程序中的错误的过程中,知道了许多错误类型,增加了经验,而且我深刻的体会到了做任何事都要有耐心~
2.在结合模块的过程中,我知道了扎实基础很重要,不然这个过程会很混乱…
3.不能半途而废,程序中有些错误改不出来时,有些内容不理解时,我想过换一些模块联动,但是我相信坚持就是胜利~
4.虚心求教的重要性,问过CSDN上的其他博主,B站上的老师等等,他们都给我提供了有力的帮助~
!!万年历具有读取方便,显示直观,功能多样,电路简洁等优点
功能:
1.显示年,月,日,时,分,秒
2.显示温度
3.显示星期
4.按键调节各参数,分别为设置键,加键,减键设置闹钟键
一. 电路组成
1.单片机最小系统
2.LCD1602液晶显示屏电路
3.四路独立按键
4.DS1302时钟电路
5.DS18B20温度传感器
6.系统电源
二.lcd1602介绍
1.引脚定义
VL引脚:为液晶显示器对比度调整端
RS引脚:RS为寄存器选择,高电平时选择数据寄存器、低电平时选择指令寄存器
R/W引脚:R/W为读写信号线,高电平时进行读操作,低电平时进行写操作。当RS和R/W共同为低电平时可以写入指令或者显示地址,当RS为低电平R/W为高电平时可以读忙信号,当RS为高电平R/W为低电平时可以写入数据。
EN引脚:E端为使能端,当E端由高电平跳变成低电平时,液晶模块执行命令。
基于51单片机的万年历设计_第1张图片
2.控制程序:写数据、写指令、初始化
读状态:输入:RS=L,RW=H,E=H----输出:D0~D7=状态字
写指令:输入:RS=L,RW=L,D0~D7=指令码----输出:无
读数据:输入:RS=H,RW=H,E=H----输出:D0~D7=数据
写数据:输入:RS=H,RW=L,D0~D7=数据,E=高脉冲----输出:无
(1)写数据函数
(2)写指令函数
(3)初始化函数
a.设置写操作:R/W设为低电平;
b.屏幕设置模式:写指令38H;
c.打开显示,关闭光标:写指令0CH;
d.设置显示光标移动位置:写指令06H;
e.设置字符显示位置:写指令(字符显示的起始位置);
由于对LCD1602进行控制时不需要实现读操作,所以R/W在初始化后恒为低电平;对控制器每次进行读写操作前,都必须进行读写检测,确保STA7为0
三.DS18B20介绍
1.初始化
在操作时序的时候,为了防止中断干扰总线时序,先关闭总中断。拉低 DS18B20 这个引脚,持续 500us;延时 60us;读取存在脉冲,并且等待存在脉冲结束。
2.ROM 操作指令
3.RAM 存储器操作指令
4.DS18B20的位读写时序
四.ds1302介绍
本系统的时间读取主要来源于单片机对ds1302的操作
引脚功能
基于51单片机的万年历设计_第2张图片
内部结构基于51单片机的万年历设计_第3张图片
寄存器基于51单片机的万年历设计_第4张图片
操作方法:启动传送,发送命令字节,传送数据

ds18b20

uchar ds18b20_read()
{
                   //读一个字节
      uchar i=0;
      uchar dat = 0;
      for (i=8;i>0;i--)
      {
     
           dq = 0; // 给脉冲信号
           dat>>=1;
           dq = 1; // 给脉冲信号
           if(dq)
           dat|=0x80;
           delay1(4);
      }
        return(dat);
}
void ds18b20_write(char dat)
{
                  //写一个字节
     uchar i=0;
     for (i=8; i>0; i--)
     {
     
          dq = 0;
          dq = dat&0x01;
          delay1(5);
          dq = 1;
          dat>>=1;
      }
}
int ds18b20_read_temp()
{
              //读取温度
         uchar low;
         uchar high;
         unsigned long tmp;
         float value;
         int t;//温度
ds18b20_init();
ds18b20_write(0xCC); //跳过读序列号的操作
ds18b20_write(0x44); //启动温度转换
ds18b20_init();
ds18b20_write(0xCC); //跳过读序列号的操作
ds18b20_write(0xBE); //读取温度寄存器
low=ds18b20_read();//低八位数据
high=ds18b20_read();//高八位数据
tmp=high;
tmp<<=8;
tmp=tmp|low;//此处有正负之分
if(tmp>=63488)
{
               //ffff f000 0000 0000-->(f800)
    temp_flag=0;//8位全为1时,加1才进位
   if((~low)==0xff)
   {
              //判断low取反加1之后是否进位
      high=(~high)+1;
      low=0;
   }
  else
  {
     
      high=~high;
      low=(~low)+1;
  }
     tmp=high*256+low;
}
   else
  {
     
        temp_flag=1;
  }
     value=tmp*0.0625;
     t=value*10+((temp_flag==1)?+0.5:-0.5);//放大十倍输出并四舍五入
     return t;
}

LCD1602

void write_1602com(uchar com)
{
                   //1602写指令
    rs=0;
    lcden=0;
    P2=com;
    delay(5);
    lcden=1;
    delay(5);
    lcden=0;
}
void write_1602data(uchar dat)
{
           //1602写数据
	  rs=1;
	  lcden=0;
      P2=dat;
      delay(5);
      lcden=1;
      delay(5);
      lcden=0;
}
void init_1602()
{
          //初始化1602液晶
rw=0;
lcden=0;
write_1602com(0x38);//设置显示模式
write_1602com(0x0c);//显示开关及光标是否显示和闪动
write_1602com(0x06);//光标移动方向
write_1602com(0x01);//清屏
}

ds1302

void write_ds1302_byte(uchar temp)
{
               //ds1302写一个字节数据
    uchar i;
    for(i=0;i<8;i++)
    {
     
        io=temp&0x01;//将数据放到IO口上
        scl=0;//scl为低时准备数据
        scl=1;//上升沿写入
        temp>>=1;
     }
}
void write_ds1302(uchar add,uchar dat)
{
              //向地址add写入数据dat
     rst=0;
     scl=0;
     rst=1;
     write_ds1302_byte(add);
     write_ds1302_byte(dat);
     scl=1;
     rst=0;
}
uchar read_ds1302(uchar add)
{
           //ds1302读数据
     uchar i,dat;
     rst=0;
     scl=0;
     rst=1;
     write_ds1302_byte(add);//首先写入要读的数据处的地址
     for(i=0;i<8;i++)
     {
     
         if(io==1)
         {
     
             dat|=0x80;
         }
           scl=1;
           scl=0;//下降沿读取数据
           dat>>=1;
      }
           scl=1;
           rst=0;
           return dat;
}
void read_time(uchar curr_time[])
{
     
       uchar i;
       uchar ucAddr = 0x81;
       for (i=0;i<7;i++)
       {
     
       curr_time[i] = read_ds1302(ucAddr);//格式为: 秒 分 时 日 月 星期 年
       ucAddr += 2;
       }
}
void set_time(uchar *pSecDa)
{
             //设定时间
      uchar i;
      uchar ucAddr = 0x80;
      write_ds1302(0x8e,0x00);
      for(i =7;i>0;i--)
      {
     
      write_ds1302(ucAddr,*pSecDa); //秒 分 时 日 月 星期 年
      pSecDa++;
      ucAddr+=2;
      }
      write_ds1302(0x8e,0x80);
}
void init_ds1302()
{
          //ds1302初始化
    isInit_1302=read_ds1302(0x81);//读出时钟状态
    if(isInit_1302&0x80)
    {
          //说明没有初始化
    write_ds1302(0x8e,0x00);//关闭写保护
    write_ds1302(0x90,0xa5); //辅助电源充电命令 一个二极管一个2K电阻
    write_ds1302(0x80,0x00);//秒 CH置0 开启时钟
    write_ds1302(0x82,0x59);//分
    write_ds1302(0x84,0x10);//时
    write_ds1302(0x86,0x07);//日
    write_ds1302(0x88,0x05);//月
    write_ds1302(0x8a,0x04);//星期
    write_ds1302(0x8c,0x14);//年
    write_ds1302(0x8e,0x80);
    }
}

闹钟设置

void init_alarm()
{
         //闹钟设置界面 只有首次进入才执行
   uchar code x[]="SET ALARM";
   uchar i;
   if(alarm==0)
   {
     
         write_1602com(0x01);//清屏
         write_1602com(0x80+3);//设置数据指针
         for(i=0;i<9;i++)
         {
     
              write_1602data(x[i]);
         }
              display_alarm(0x80+0x40+5,shi);//载入闹钟的时分
              write_1602com(0x80+0x40+7);
              write_1602data(':');
              display_alarm(0x80+0x40+8,fen);
              if(isOpen)
              {
             //初始化的时候如果已经设定闹钟则显示ON
                   write_1602com(0x80+0x40+13);
                   write_1602data(' ');
                   write_1602data('O');
                   write_1602data('N');
               }
              else 
             {
     
                   write_1602com(0x80+0x40+13);
                   write_1602data('O');
                   write_1602data('F');
                   write_1602data('F');
            } 
   }
}

你可能感兴趣的:(笔记)