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

时钟及温度用74hc164+74ls145数码管显示单片机程序

作者:huqin   来源:本站原创   点击数:  更新时间:2014年03月15日   【字体:

下面是实物图:



电路图很简单我就不画了 数码管用74hc164串行转并行芯片+74ls145这2个芯片驱动一个负责段选一个负责位选,具体看程序顶部的引脚定义.完整的keil工程文件下载地址: http://www.51hei.com/f/164smg.rar   下面是程序源码.

#include<reg52.h>
#include <intrins.h>
#define uchar unsigned char
#define uint unsigned int
sbit iicclk=P1^0;////总线存储时钟引脚定义
sbit iicdat=P1^1;////总线存储数据引脚定义
sbit hc164dat=P1^2;//段显串行数据引脚定义
sbit hc164clk=P1^3;//段显串行时钟引脚定义
/*sbit hc164clr=P1^4;*///段显芯片清零引脚,低电平时,全部输出引脚清零,即低电平
sbit ls145p0=P1^5;///位选译码芯片P0
sbit ls145p1=P1^6;///位选译码芯片P1
sbit ls145p2=P1^7;///位选译码芯片P2
sbit ls145p3=P3^7;///位选译码芯片P2,用于在74HC164移入数据时P0~P3全置高,关闭所有数码管
sbit DS1820DQ=P0^0;
sbit ADD=P0^4;///////加一
sbit MINUS=P0^5;/////减一
sbit ENTER=P0^6;/////确定
sbit SET=P0^7;///////设定键
uchar code tabledu[]={0xed,0x21,0x8f,0xab,0x63,0xea,0xee,0xa1,0xef,0xeb,0x0};//垃圾显示板0~~9段显数据
uchar code tablewe[]={0x0,0x20,0x40,0x60,0x80,0xa0,0xc0,0xe0,0x10};//位选编码,P2口高八位产生编码值,0x10为关闭所有位选
char dateshu[8];
uchar tim,sec,ming,mins,hourg,hours,min,hour,setflag,seta,dqflag,temperl,temperh,dat;
void delay1ms(uint x)//0.5毫秒延时函数
 {
  uint y,z;
   for(y=x;y>0;y--)
    for(z=60;z>0;z--);
 }
void delayns()
 {
  _nop_();
  _nop_();
 
 }
void delay10us(uchar z)//z为3是定时10微秒
{
  while(z)
  z--;
}
void DelayX0us(uchar n)
{
    while (n--)
    {
        _nop_();
        _nop_();
    }
}
void dqrsr()//1820初始化函数
    {
   
         dqflag=0;
         DS1820DQ=1;
         delayns();
         DS1820DQ=0;
         DelayX0us(48);//时序延时500US
         DS1820DQ=1;
         delay10us(6);//时序延时20us
          if(DS1820DQ==0)dqflag=1;
         DelayX0us(42);
       
   
    }
void dqwrite(uchar a)
   {
     uchar i;
    dqflag=0;
    DS1820DQ=1; //to释放总线
    delayns();//时序延时
   
     for(i=8;i>0;i--)//写一个字节的数据
      {
       DS1820DQ=0;//总线置低
       _nop_();
       _nop_();
      
       a=a>>1;//右移时,逸出位保存到CY中
       DS1820DQ=CY;//发送送据
       DelayX0us(6);//延时70us
       DS1820DQ=1; //to释放总线
              
      }
   }
uchar dqread(void)//1820读函数
   {
    uchar i;
    DS1820DQ=1; //to释放总线
   
    delayns();//时序延时
        for(i=0;i<8;i++)
      {
       dat>>=1;
       DS1820DQ=0;
       _nop_();
       _nop_();
       DS1820DQ=1;       
       delayns();
      
       if(DS1820DQ)dat|=0x80; //如果读回的数据为1则作与处理移入DAT变量
      
       DelayX0us(6);//延时70us
      }
   
    return dat;
   
   }
void write164(uchar x)
   {
     uchar y;
     hc164clk=0;//时钟置低
     _nop_();
     _nop_();
       for(y=0;y<8;y++)
        {
    hc164dat=(x&0x80);
    delayns();
    hc164clk=1;
    delayns();
    hc164clk=0;
    delayns();
    x<<=1;
     }
  
   }
void init()
 {
  P0=0xff;//输入接口P0全置一,让按键读回输入信息
  P2=tablewe[8];//关闭所有数码管的位选
  hc164clk=0;//时钟置低,以产生上升沿移入数据
  IE=0X82;  //EA=1开总中断ET0=1定时器零中断允许
  TCON=0X10;//TR0=1定时零中断启动
  TMOD=0X01;//M1M0=01 T0 工作方式1,16位定时器
  TH0=(65636-50000)/256;
  TL0=(65636-50000)%256;//50ms定时初值
  DS1820DQ=1;
 
 }
void iicstart()//暂未使用
 {
 
 }
void iicstop()//暂未使用
 {
 
 }
void display(uchar a,uchar b,uchar c,uchar d,uchar e,uchar f,uchar g,uchar h)//显示函数
   {
    P2=tablewe[8];
    write164(tabledu[a]);
    P2=tablewe[0];
    delay1ms(2);
    
    P2=tablewe[8];
    write164(tabledu[b]);
    P2=tablewe[1];
    delay1ms(2);
    P2=tablewe[8];
    write164(tabledu[c]);
    P2=tablewe[2];
    delay1ms(2);
    P2=tablewe[8];
    write164(tabledu[d]);
    P2=tablewe[3];
    delay1ms(2);
    P2=tablewe[8];
    write164(tabledu[e]);
    P2=tablewe[4];
    delay1ms(2);
    P2=tablewe[8];
    write164(tabledu[f]);
    P2=tablewe[5];
    delay1ms(2);
    P2=tablewe[8];
    write164(tabledu[g]);
    P2=tablewe[6];
    delay1ms(2);
    P2=tablewe[8];
    write164(tabledu[h]);
    P2=tablewe[7];
    delay1ms(2);
   }
void timer()//24小时时间计算函数
   {
    
    if(sec>59)
     {
     
     
      sec=0;
      min++;
         if(min>59)
        {
         min=0;
         hour++;
          if(hour>23)
         {
           hour=0;
         }
        }
     
     }
   dateshu[0]=sec%10;
   dateshu[1]=sec/10;
   dateshu[2]=min%10;
   dateshu[3]=min/10;
   dateshu[4]=hour%10;
   dateshu[5]=hour/10;
   
  
   }
void key()//设定程序入口
   {
       if(SET==0)
        {
         setflag=1;
        }
    
    
  
  
   }
void keyshu()//设定键函数
   {
   
    bit b,d,e;
    b=MINUS;d=ADD;//变量B,D,E分别读回P0。4~P0。6的状态。分别为加一,减一,确认键
    e=ENTER;
    if(b==0)//减一按键按下
     {
      dateshu[seta]--;
       if(dateshu[seta]<0)dateshu[seta]=9;//减到零时自动循环回九
       b=MINUS;//再读回键值,做松手查检测
      while(b==0){b=MINUS;display(dateshu[0],dateshu[1],10,seta+1,dateshu[2],dateshu[3],dateshu[4],dateshu[5]);}//松手检测
     
     }
    else if(d==0)//加一按键按下
     {
      dateshu[seta]++;
       if(dateshu[seta]>9)dateshu[seta]=0;//加到九时自动循环回零
       d=ADD;//做松手检测
      while(d==0){d=ADD;display(dateshu[0],dateshu[1],10,seta+1,dateshu[2],dateshu[3],dateshu[4],dateshu[5]);}//松手检测
    
     }
       else if(e==0)//确认键按下
     {
      seta++;
      e=ENTER;
      while(e==0){e=ENTER;display(dateshu[0],dateshu[1],10,seta+1,dateshu[2],dateshu[3],dateshu[4],dateshu[5]);}
      if(seta>5)//如果六位数值已设定完毕,测退出设定状态
{
 seta=0;sec=0;setflag=0;
 sec=dateshu[1]*10+dateshu[0];//分别将设定好的值,赋给时秒变量,设定生效
 min=dateshu[3]*10+dateshu[2];//分别将设定好的值,赋给分变量,设定生效
 hour=dateshu[5]*10+dateshu[4];//分别将设定好的值,赋给时变量,设定生效
 
}
     }
   
}  
void main()

 {
   init();//各外围元件及CPU初始化
   delay10us(150);//进入大循环时的延时
   while(1)
 
     {
     
       key();//检测功能键有无按下
          if(setflag==0)//如果设定功能未进入,则显示实时时钟
         {
        timer();//时间运算函数
        display(dateshu[0],dateshu[1],10,10,dateshu[2],dateshu[3],dateshu[4],dateshu[5]);//显示实时时钟
         }
       else//如果进入了功能设定函数
         {
        keyshu();//读取键值
        display(dateshu[0],dateshu[1],10,seta+1,dateshu[2],dateshu[3],dateshu[4],dateshu[5]);//显示实时设定
         }
        if((dateshu[0]==3)&&(dateshu[1]%2==0))//每隔十秒温度读取显示一次
         {uchar i;//显示延时用
          dqrsr();//初始化
           if(dqflag==1)//检测存在脉冲
            {
            
             dqwrite(0xcc);//跳过ROM操作
            
             dqwrite(0x44);//开始温度转换
             while(!DS1820DQ);//延时等待温度转换完毕
              dqrsr();//初始化
               if(dqflag==1)
                 {
                  uchar temper;//温度变量
                  dqwrite(0xcc);//跳过ROM操作
                  dqwrite(0xbe);//读取数据指令
                 
                  temperl=dqread();//读取低字节温度值
                  temperh=dqread();//读取高字节温度值
                  temperl=temperl>>4;//移去低四位的温度值
                  temperh=temperh<<4;//移去读回的符号号
                  temper=temperl+temperh;//将处理后的高字节温度和低字节温度值相加
            for(i=250;i>0;i--)display(temper%10,temper/10,temper/100,10,10,10,10,10);//延时显示实时温度
                                  

                 }
            }   
 
   
         }
     }
 
 
 
 
 
 
 
 
 }
void time0(void) interrupt 1
  {
 
   TH0=(65536-50000)/256;
   TL0=(65536-50000)%256;//定时器零重赋初值
    tim++;
     if(tim==20)
       {
        tim=0;//tim==20时,为50MS*20=1S
        sec++;
       }
 
  }

 


关闭窗口

相关文章