kerecs 发表于 2017-2-28 15:09:34

【51单片机】时光钟 - 一寸光阴一寸光

时间就像光一样,匆匆一撇却已远去,离去的时光怕是连光也望尘莫及。

1.概要:有别于传统石英钟,内部不使用任何机械结构,而是全部使用电子电路。通过单片机控制发光二极管所形成的光束来指示时间。因为指针全部使用光束代替,所以在深夜也能看得很清楚,也因此可以当作“壁灯”使用。

2.原理:51单片机作为主控芯片,从DS3231时钟得到时间数据,再通过74ls38译码器输出低电平控制60个Led灯的开关。Led发光二极管安装于全透明的聚光杯中,形成的光束作为指针,通过单片机的PWM控制Led的形成长短不一的光束来区分时针、分针和秒针。HC06作为通信芯片,可连接手机的蓝牙实现对本时钟时间的修改,以及指定Led灯的亮灭(作为壁灯使用时),或者显示一些预设的动画效果,比如流水灯等。

PS:楼主由于工具所限(自己在家无聊时做的,纯手工请不要嫌弃),这里只使用12个Led做了个原型,没加蓝牙模块,只实现最核心的时间功能。

3.材料:
1. STC89C52RC
2. DS3231时钟模块
3. 12个高亮5mmLED
4. 3.7v锂电池
5. TP4056锂电池充电模块
6. 奶茶店的透明吸管(套在Led上聚光可形成光束,选择适合自己Led 的吸管即可)

PS:根据自己的喜好选择led的颜色即可,但是注意不同波长的led形成的光束有别,有些会比较不明显。

4.下载代码:

#include <reg52.h>
#include <intrins.h>
#define uchar unsigned char
#define uint unsigned int

#define DS3231_WriteAddress 0xD0   
#define DS3231_ReadAddress0xD1   
#define DS3231_SECOND       0x00   
#define DS3231_MINUTE       0x01   
#define DS3231_HOUR         0x02   
#define DS3231_WEEK         0x03   
#define DS3231_DAY          0x04   
#define DS3231_MONTH      0x05   
#define DS3231_YEAR         0x06   

bitack;         //ó|′e±ê־λ
sbit SDA = P0^6;   //Ä£ÄaI2Cêy¾Y′«ËíλSDA      
sbit SCL = P0^7;   //Ä£ÄaI2Cê±Öó¿ØÖÆÎ»SCL

sbit c1 = P2^6;   //Ã룬¸öλ
sbit c2 = P2^5;   //·Ö£¬¸öλ
sbit c3 = P2^7;   //Ã룬¸öλ
sbit c4 = P2^3;   //Ã룬¸öλ
sbit c5 = P2^1;   //Ã룬ê®Î»
sbit c6 = P2^0;   //Ã룬¸öλ
sbit c7 = P3^7;   //Ã룬¸öλ
sbit c8 = P3^6;   //Ã룬¸öλ
sbit c9 = P3^2;   //Ã룬ê®Î»
sbit c10 = P1^5;   //·Ö£¬ê®Î»
sbit c11 = P1^3;   //ê±£¬¸öλ
sbit c12 = P1^2;   //ê±£¬ê®Î»

unsigned int flag1, flag2, flag3, flag4, flag5, flag6, flag7, flag8, flag9, flag10, flag11, flag12;
unsigned char hour, minute, second;
unsigned char lastHour = 24, lastMinute = 60, lastSecond = 60;

void TM1637_start();
void TM1637_stop();
void TM1637_write1Bit(unsigned char mBit);
void TM1637_write1Byte(unsigned char mByte);
void TM1637_writeCammand(unsigned char mData);
void TM1637_writeData(unsigned char addr, unsigned char mData);
void time_set(char hour, char min);
void time_display();
void timer0_init();

void setZero();
void delay_140us();
void delayus(uint us);

uchar BCD2HEX(uchar val)    //BCDÂë×a»»ÎaByte
{
    uchar temp;
    temp = val & 0x0f;
    val >>= 4;
    val &= 0x0f;
    val *= 10;
    temp += val;
    return temp;
}

uchar HEX2BCD(uchar val)    //BÂë×a»»ÎaBCDÂë
{
   return (((val % 100) / 10) << 4) | (val % 10);
}

void delayus(uint us)
{
    while(us--);
}

void Start_I2C()
{
    SDA = 1;               
    delayus(1);
    SCL = 1;
    delayus(5);            

    SDA = 0;            
    delayus(5);         

    SCL = 0;               
    delayus(2);
}

void Stop_I2C()
{
    SDA = 0;               
    delayus(1);            
    SCL = 1;               
    delayus(5);

    SDA = 1;               
    delayus(4);
}

void SendByte(uchar c)
{
    uchar BitCnt;

    for(BitCnt = 0;BitCnt < 8;BitCnt++)      
    {
      if((c << BitCnt) & 0x80)
            SDA = 1;                     
      else
            SDA = 0;               
          delayus(1);
          SCL = 1;                           
          delayus(5);                     
          SCL = 0;
    }

    delayus(2);
    SDA = 1;                              
    delayus(2);
    SCL = 1;
    delayus(3);
    if(SDA == 1)
                        ack = 0;   
    else
                        ack = 1;                           
    SCL = 0;
    delayus(2);
}

uchar RcvByte()
{
   uchar retc;
   uchar BitCnt;

   retc = 0;
   SDA = 1;
   for(BitCnt = 0;BitCnt < 8;BitCnt++)
   {
      delayus(1);
      SCL = 0;                     
      delayus(5);         
      SCL = 1;
      delayus(3);
      retc = retc << 1;
      if(SDA == 1)
            retc = retc + 1;         
      delayus(2);
   }
   SCL = 0;
   delayus(2);
   return(retc);
}

void Ack_I2C(bit a)
{
    if(a == 0)
                        SDA = 0;            
    else
                        SDA = 1;
               
    delayus(3);   
    SCL = 1;
    delayus(5);         
    SCL = 0;         
    delayus(2);   
}


uchar write_byte(uchar addr, uchar write_data)
{
    Start_I2C();
    SendByte(DS3231_WriteAddress);
    if (ack == 0)
                        return 0;

    SendByte(addr);   
    if (ack == 0)
                        return 0;

    SendByte(write_data);
    if (ack == 0)
                        return 0;

    Stop_I2C();
    delayus(10);
                        return 1;
}


uchar read_current()
{
    uchar read_data;
    Start_I2C();
    SendByte(DS3231_ReadAddress);
    if(ack == 0)
                        return(0);

    read_data = RcvByte();
    Ack_I2C(1);
    Stop_I2C();
               
    return read_data;
}


uchar read_random(uchar random_addr)
{
    Start_I2C();
    SendByte(DS3231_WriteAddress);
    if(ack == 0)
                        return(0);

    SendByte(random_addr);
    if(ack == 0)
                        return(0);

    return(read_current());
}

/********************************************************************
* Ãû3Æ : delay_140us()
* 1|Äü : Ñóê±
* êäèë : void
* êä3ö : ÎT
**************************************************************/
void delay_140us()
{
    int i;
    for(i = 0; i < 20; i++)
      _nop_();
}
/********************************************************************
* Ãû3Æ : void ModifyTime(uchar hou,uchar min,uchar sec)
* 1|Äü : DT¸Ä걼䣨諣©
* êäèë : void
* êä3ö : ÎT
**************************************************************/
void ModifyTime(uchar hou, uchar min,uchar sec)
{
    uchar temp = 0;

    temp = HEX2BCD(hou);
    write_byte(DS3231_HOUR, temp);   //éèÖÃê±

    temp = HEX2BCD(min);
    write_byte(DS3231_MINUTE, temp); //éèÖ÷Ö

    temp = HEX2BCD(sec);
    write_byte(DS3231_SECOND, temp); //éèÖÃÃë
}
/********************************************************************
* Ãû3Æ : void ModifyTime(uchar hou,uchar min,uchar sec)
* 1|Äü : DT¸Ä걼䣨걣©
* êäèë : void
* êä3ö : ÎT
**************************************************************/
void ModifyHour(hour)
{
          uchar temp = HEX2BCD(hour);
    write_byte(DS3231_HOUR, temp);   //éèÖÃê±
}
/********************************************************************
* Ãû3Æ : void Modifymin(minute)
* 1|Äü : DT¸Ä걼䣨·Ö£©
* êäèë : void
* êä3ö : ÎT
**************************************************************/
void ModifyMinute(minute)
{   
          uchar temp = HEX2BCD(minute);
    write_byte(DS3231_MINUTE, temp); //éèÖ÷Ö
}
/********************************************************************
* Ãû3Æ : void ModifyTime(uchar hou,uchar min,uchar sec)
* 1|Äü : DT¸Ä걼䣨Ã룩
* êäèë : void
* êä3ö : ÎT
**************************************************************/
void ModifySecond(second)
{
          uchar temp = HEX2BCD(second);
    write_byte(DS3231_SECOND, temp); //éèÖÃÃë
}
/********************************************************************
* Ãû3Æ : void init()
* 1|Äü : 3ìDò3õê¼»ˉ
* êäèë : void
* êä3ö : ÎT
**************************************************************/
void init()
{
                TMOD = 0x02;
                TH0 = 0x06;
                TL0 = 0x06;
                TR0 = 1;
                ET0 = 1;
                EA = 1;
}
/********************************************************************
* Ãû3Æ : void setZero()
* 1|Äü : è«2¿Çåá㣬ËùóDμÆ¶¼2»áá
* êäèë : void
* êä3ö : ÎT
**************************************************************/
void setZero()
{
        flag1 = 0;
        flag2 = 0;
        flag3 = 0;
        flag4 = 0;
        flag5 = 0;
        flag6 = 0;
        flag7 = 0;
        flag8 = 0;
        flag9 = 0;
        flag10 = 0;
        flag11 = 0;
        flag12 = 0;
}
/********************************************************************
* Ãû3Æ : void light(uint number, uint level)
* 1|Äü : Ö¸¶¨μÆáá
* êäèë : uint number, uint level
* êä3ö : ÎT
**************************************************************/
void light(uint number, uint level)
{
                switch(number)
                {
                        case 0:
                                        flag12 = level;
                        break;
                        case 1:
                                        flag1 = level;
                        break;
                        case 2:
                                        flag2 = level;
                        break;
                        case 3:
                                        flag3 = level;
                        break;
                        case 4:
                                        flag4 = level;
                        break;
                        case 5:
                                        flag5 = level;
                        break;
                        case 6:
                                        flag6 = level;
                        break;
                        case 7:
                                        flag7 = level;
                        break;
                        case 8:
                                        flag8 = level;
                        break;
                        case 9:
                                        flag9 = level;
                        break;
                        case 10:
                                        flag10 = level;
                        break;
                        case 11:
                                        flag11 = level;
                        break;
                        default:break;
                }
}
/********************************************************************
* Ãû3Æ : void computer_and_display_time()
* 1|Äü : ÏÔê¾ê±¼ä
* êäèë : void
* êä3ö : ÎT
**************************************************************/
void compute_and_display_time()
{
                //¼ÆËãê±¼ä
    uchar Htemp1, Htemp2, Mtemp1, Mtemp2, Stemp1, Stemp2;
    Htemp1 = read_random(DS3231_HOUR);    //»ñè¡ê±
    Htemp1&=0x3f;                  
    Htemp2 = BCD2HEX(Htemp1);
       
    Mtemp1 = read_random(DS3231_MINUTE);//»ñè¡·Ö
    Mtemp2 = BCD2HEX(Mtemp1);
                       
          Stemp1 = read_random(DS3231_SECOND);//»ñè¡Ãë
    Stemp2 = BCD2HEX(Stemp1);
       
                hour = Htemp2 % 12;
                minute = Mtemp2 / 5;
                second = Stemp2 / 5;

                //update hour
                if(hour != lastHour){
                        light(hour, 40);
                }
                //update minute
                if(minute != lastMinute){
                        if(minute != hour)
                                light(minute, 30);
                }
                //update second
                if(second != lastSecond){
                        if(second != hour && second != minute)
                                light(second, 1);
                }
                if(lastHour != hour && lastHour != minute && lastHour != second)
                        light(lastHour, 0);
                if(lastMinute != hour && lastMinute != minute && lastMinute != second)
                        light(lastMinute, 0);
                if(lastSecond != hour && lastSecond != minute && lastSecond != second)
                        light(lastSecond, 0);
               
                lastHour = hour;
                lastMinute = minute;
                lastSecond = second;
}
/********************************************************************
* Ãû3Æ : timer0()
* 1|Äü : PWMμ÷ÕûÕ¼¿Õ±è,0~10, áá¶èμY¼õ
* êäèë : void
* êä3ö : ÎT
**************************************************************/
void timer0() interrupt 1
{
        static unsigned int count;
        count++;
        if(count == 50)
        {
                count = 0;
                c1 = 1;
                c2 = 1;
                c3 = 1;
                c4 = 1;
                c5 = 1;
                c6 = 1;
                c7 = 1;
                c8 = 1;
                c9 = 1;
                c10 = 1;
                c11 = 1;
                c12 = 1;
        }

        if(flag12 != 0 && flag12 == count)
                c12 = 0;
        else if(flag1 != 0 && flag1 == count)
                c1 = 0;
        else if(flag2 != 0 && flag2 == count)
                c2 = 0;
        else if(flag3 != 0 && flag3 == count)
                c3 = 0;
        else if(flag4 != 0 && flag4 == count)
                c4 = 0;
        else if(flag5 != 0 && flag5 == count)
                c5 = 0;
        else if(flag6 != 0 && flag6 == count)
                c6 = 0;
        else if(flag7 != 0 && flag7 == count)
                c7 = 0;
        else if(flag8 != 0 && flag8 == count)
                c8 = 0;
        else if(flag9 != 0 && flag9 == count)
                c9 = 0;
        else if(flag10 != 0 && flag10 == count)
                c10 = 0;
        else if(flag11 != 0 && flag11 == count)
                c11 = 0;
}
/***********************************************************
*****
***** Ö÷oˉêy
*****
***********************************************************/
void main()
{
        init();
        setZero();
//        ModifyHour(16);
//        ModifyMinute(24);
        while(1)
        {
                        compute_and_display_time();
        }
}

5.焊接:(从代码里可以看出怎么接线,所以就不再废话了。)
http://image.geek-workshop.com/album/201702/28/144346w7ddqqwzeqz2d5w0.jpg
http://image.geek-workshop.com/album/201702/28/144426k854ggxam44p88ko.jpg
http://image.geek-workshop.com/album/201702/28/144442v83zs20tkzfkfqpj.jpg
http://image.geek-workshop.com/album/201702/28/144457abjwzjbttwjddgkb.jpg

拆了个旧风扇,搞定外壳。有没有外壳其实无所谓。
http://image.geek-workshop.com/album/201702/28/144512g7zyzxo8oo28ooeu.jpg
http://image.geek-workshop.com/album/201702/28/144903umiwf22l7ls9v9id.jpg
http://image.geek-workshop.com/album/201702/28/144917ikwd8kdn1khh1khw.jpg

6.半成品:
http://image.geek-workshop.com/album/201702/28/144935t1v1qjfpz9jdj322.jpg

7.成品图:(没有工具制作合适的外壳所以只能PS假装一下)
http://image.geek-workshop.com/album/201702/28/144948i977mwlyrlkkmyay.jpg

galaxy 发表于 2017-2-28 15:31:54

讚 讚 讚 , 頂一個

slotg 发表于 2017-3-1 08:43:00

不错的 DIY

独行者 发表于 2017-3-1 09:29:05

很有创意,谢谢分享!

小猪会轮滑 发表于 2017-3-1 17:28:49

666666666666666

zlucas 发表于 2017-3-2 21:25:22

很有想象力

ianon 发表于 2017-3-3 17:15:17

:lol:lol:lol:lol

Daming 发表于 2017-4-21 15:31:39

厉害了,楼主好人
页: [1]
查看完整版本: 【51单片机】时光钟 - 一寸光阴一寸光