矿石收音机论坛

 找回密码
 加入会员

QQ登录

只需一步,快速开始

搜索
查看: 6810|回复: 14

【参赛】省电的“星光"LED时钟

[复制链接]
     
发表于 2016-2-9 17:35:52 | 显示全部楼层 |阅读模式
本帖最后由 d3b7 于 2016-2-9 17:55 编辑

    我曾经有个烂尾工程 旷日持久的制作开始了——家用时钟,快5年过去了,仍旧没有投入实用。
    但卧室确实缺少一个夜里能轻松看清的时钟,于是正儿八经再重做这个项目吧。
    PCB就在厂家做了,当年用感光膜只能做单面工艺,还费时间。改版后,LED仍然在正面,单片机和升压电路就在背面了。这样一块板子搞定。
sch.png

    上面这个图只带了两个数字的显示,一个钟需要两套显示板,就复制一份好了。控制电路只需要一份公用,所以左右两边的单片机部分只需要装一个。那么为什么我的PCB还布上两份同样的控制呢?这样可以分割成两块用,做99秒倒计时器啥的。
top.PNG
bottom.PNG

      这个电路不复杂,就是用三只超高亮度的LED来组成数码显示的一个笔段,用4片74HC164作为串-并转换和锁存,构成显示驱动。单片机ATMEGA48作为主控,SPI输出串行显示驱动信号,平时也就半秒种唤醒一次,刷新显示;其余时间单片机都在休眠状态,几乎没有功耗。而用于LED发光的显示耗电情况,取决于LED的性能和电流。

       PCB元旦后收到。
pcb1.jpg
pcb2.jpg

       焊接正面的LED,74HC164等,主要是LED手工焊接很消耗时间……
c1.jpg
c2.jpg

       焊接MCU主控,调试程序
c4.jpg
c3.jpg

       基本的程序(完成了走时和时钟调节)
  1. #include <avr/io.h>
  2. #include <avr/interrupt.h>
  3. #include <avr/sleep.h>
  4. #include <stdlib.h>
  5. #include <string.h>

  6. /* Current time */
  7. uint8_t hh=12, mm=0, ss=0;
  8. char half=0;

  9. /* Clock parameters */
  10. uint8_t flag=0;
  11. uint8_t mode;

  12. static char brt1, brt2; // button release time

  13. ISR (TIMER2_COMPA_vect)
  14. {
  15.     if(half)
  16.     {
  17.         half=0;
  18. //      PORTD |= _BV(5);
  19.         ss++;
  20.         if(ss>59)
  21.         {
  22.             ss=0;
  23.             mm++;
  24.             if(mm>59)
  25.             {
  26.                 mm=0;
  27.                 hh++;
  28.                 if(hh>23)
  29.                     hh=0;
  30.             }
  31.         }
  32.     }
  33.     else
  34.     {
  35.         half=1;
  36. //      PORTD &= ~_BV(5);
  37.     }
  38.     if(brt1>-16)
  39.         brt1-=16;
  40.     if(brt2>-16)
  41.         brt2-=16;
  42. }

  43. ISR (PCINT0_vect)
  44. {
  45. }

  46. uint8_t getbutton()
  47. {
  48.     static char bs1, bs2;   // button state
  49.     static char bh1, bh2;   // button hold time
  50.     char button=PINB;
  51.     char tick=TCNT2;
  52.     char state=0;
  53.    
  54.     if(!bs1)
  55.     {
  56.         if(button&1)    // button 1 release
  57.         {
  58.             bs1=1;
  59.             brt1=tick;
  60.             bh1=0;
  61.         }
  62.         else
  63.         {
  64.             if(tick==0)
  65.                 bh1++;
  66.         }
  67.         if(bh1>5)
  68.             state|=4;
  69.     }
  70.     else
  71.     {
  72.         if(!(button&1)) // button 1 press
  73.         {
  74.             bs1=0;
  75.             if(tick-brt1>3) // valid key
  76.                 state|=1;
  77.         }
  78.     }

  79.     if(!bs2)
  80.     {
  81.         if(button&2)    // button 2 release
  82.         {
  83.             bs2=1;
  84.             brt2=tick;
  85.         }   
  86.         else
  87.         {
  88.             if(tick==0)
  89.                 bh2++;
  90.         }
  91.         if(bh2>5)
  92.             state|=8;

  93.     }
  94.     else
  95.     {
  96.         if(!(button&2)) // button 2 press
  97.         {
  98.             bs2=0;
  99.             if(tick-brt2>3) // valid key
  100.                 state|=2;
  101.         }
  102.     }
  103.     return state;
  104. }

  105. const char digdisp[16]=
  106. {
  107.     0x02,   //0 xxxx xx.h
  108.     0x7a,   //1 x... .x.h
  109.     0x90,   //2 .xx. xxxh
  110.     0x30,   //3 xx.. xxxh
  111.     0x68,   //4 x..x .xxh
  112.     0x24,   //5 xx.x x.xh
  113.     0x04,   //6 xxxx x.xh
  114.     0x72,   //7 x... xx.h
  115.     0x00,   //8 xxxx xxxh
  116.     0x20,   //9 xx.x xxxh
  117.     0xfc,   // '-' symbol
  118.     0xfe    // blank
  119. /*  0x40,   //A x.xx xxxh
  120.     0x0c,   //b xxxx ..xh
  121.     0x86,   //C .xxx x..h
  122.     0x18,   //d xxx. .xxh
  123.     0x84,   //E .xxx x.xh
  124.     0xc4    //F ..xx x.xh  */
  125. };

  126. inline void nop(void)
  127. {
  128.     __asm__ volatile("nop");
  129. }

  130. #define HHMM 8
  131. #define MMSS 9


  132. void display()
  133. {   
  134.     uint8_t l,h;
  135.     uint8_t colon;
  136.     uint8_t b4,b3,b2,b1;

  137.     if(flag & 0x01)
  138.         colon=0;
  139.     else
  140.         colon=1;
  141.     if(flag & 0x02)
  142.     {
  143.         switch(mode)
  144.         {
  145.             case HHMM:
  146.                 h=(mm*26)>>8;
  147.                 l=mm-10*h;
  148.                 break;
  149.             case MMSS:
  150.                 h=(ss*26)>>8;
  151.                 l=ss-10*h;
  152.                 break;
  153.             default:
  154.                 h=10;
  155.                 l=10;
  156.                 break;
  157.         }
  158.     }
  159.     else
  160.     {
  161.         h=11;
  162.         l=11;
  163.     }
  164.     b4=digdisp[l];
  165.     b3=digdisp[h]|colon;
  166.     if(flag & 0x04)
  167.     {
  168.         switch(mode)
  169.         {
  170.             case HHMM:
  171.                 if(hh<10)
  172.                 {
  173.                     h=11;
  174.                     l=hh;
  175.                 }
  176.                 else
  177.                 {
  178.                     h=(hh*26)>>8;
  179.                     l=hh-10*h;
  180.                 }
  181.                 break;
  182.             case MMSS:
  183.                 h=(mm*26)>>8;
  184.                 l=mm-10*h;
  185.                 break;
  186.             default:
  187.                 h=10;
  188.                 l=10;
  189.                 break;
  190.         }
  191.     }
  192.     else
  193.     {
  194.         h=11;
  195.         l=11;
  196.     }
  197.     b2=digdisp[l];
  198.     b1=digdisp[h];

  199.     SPDR=b4;
  200.     while(!(SPSR & _BV(SPIF)));
  201.     SPDR=b3|colon;
  202.     while(!(SPSR & _BV(SPIF)));
  203.     SPDR=b2;
  204.     while(!(SPSR & _BV(SPIF)));
  205.     SPDR=b1;
  206.     while(!(SPSR & _BV(SPIF)));
  207. }

  208. int main()
  209. {
  210.     int i;
  211.     // set sysclk prescaler
  212.     CLKPR=_BV(CLKPCE);
  213.     CLKPR=0;    // no div
  214.     nop();
  215.     nop();
  216.     nop();
  217.     nop();
  218.     nop();
  219.    
  220.    
  221.     // configure Timer 2        
  222.     ASSR=_BV(AS2);  // asynchronous clock osc
  223.     TCCR2A=_BV(WGM21);  // Timer2 CTC mode, TOP as OCRA
  224.     OCR2A=15;
  225.     TCCR2B=_BV(CS22)|_BV(CS21)|_BV(CS20);   // enable, clk/1024
  226.     TIFR2=_BV(OCF2A);   // clear flag
  227.     TIMSK2=_BV(OCIE2A); // enable interrupt
  228.     sei();
  229.    
  230.     // configure SPI
  231.     DDRB=_BV(2)|_BV(3)|_BV(5);  // SPI output pin, SS must be output
  232.     SPSR=_BV(SPI2X);
  233.     SPCR=_BV(SPE)|_BV(MSTR)|_BV(CPHA);  // Fastest SPI
  234.    
  235.     set_sleep_mode(SLEEP_MODE_IDLE);
  236.    
  237.     DDRD=_BV(5)|_BV(2); //PD5: Status (BLUE), PD5: DC-DC EN
  238.     PORTD=_BV(2);   // DC-DC on
  239.     PORTB |= _BV(0)|_BV(1); // button 1, 2
  240.    
  241.     flag=7;
  242.     display();
  243.     sleep_mode();   // wait until RTC oscillator is stable
  244.     set_sleep_mode(SLEEP_MODE_PWR_SAVE);

  245.     PCICR=_BV(PCIE0);   // Pin-change interrupt 0
  246.     PCMSK0=_BV(PCINT0)|_BV(PCINT1);
  247.     PCIFR=_BV(PCIF0);
  248.    
  249.     mode=HHMM;
  250.     for(;;)
  251.     {
  252.         static char phalf=3;
  253.         char b;
  254.         char show=0;
  255.         static char adjust=0;
  256.         char update=0;

  257.         if(phalf!=half)
  258.         {
  259.             show=1;
  260.             phalf=half;
  261.         }

  262.         b=getbutton();
  263.         if(adjust==0)
  264.         {
  265.             if(b&2)
  266.             {
  267.                 if(mode==HHMM)
  268.                     mode=MMSS;
  269.                 else
  270.                     mode=HHMM;
  271.                 show=1;
  272.             }
  273.             else
  274.             {
  275.                 if((b&12)==4)   // button 1 Hold
  276.                 {
  277.                     set_sleep_mode(SLEEP_MODE_IDLE);    // change back later
  278.                     if(mode==HHMM)
  279.                         adjust=1;
  280.                     else
  281.                         adjust=3;
  282.                     show=1;
  283.                 }
  284.             }
  285.         }
  286.         else
  287.         {
  288.             switch(adjust)
  289.             {
  290.                 case 1:     // adjust Minute
  291.                 if(b&2)
  292.                 {
  293.                     mm++;
  294.                     if(mm>59)
  295.                         mm=0;
  296.                     update=1;
  297.                 }
  298.                 else
  299.                     if(b&1)
  300.                     {
  301.                         adjust=2;
  302.                         show=1;
  303.                     }
  304.                 break;
  305.                 case 2:     // adjust Hour
  306.                 if(b&2)
  307.                 {
  308.                     hh++;
  309.                     if(hh>23)
  310.                         hh=0;
  311.                     update=1;
  312.                 }
  313.                 else
  314.                     if(b&1)
  315.                     {
  316.                         adjust=0;
  317.                         set_sleep_mode(SLEEP_MODE_PWR_SAVE);
  318.                         show=1;

  319.                     }
  320.                 break;
  321.                 case 3:     // adjust Second
  322.                 if(b&2)
  323.                 {
  324.                     ss=0;
  325.                     TCNT2=0;
  326.                     half=0;
  327.                     update=1;
  328.                 }
  329.                 else
  330.                     if(b&1)
  331.                     {
  332.                         adjust=0;
  333.                         set_sleep_mode(SLEEP_MODE_PWR_SAVE);
  334.                         show=1;
  335.                     }
  336.                 break;
  337.             }
  338.             if(update)
  339.                 show=1;
  340.         }
  341.         
  342.                
  343.         if(mode==HHMM && half==0)
  344.         {
  345.             flag |= 0x01;
  346.         }
  347.         else
  348.         {
  349.             flag &= ~0x01;
  350.         }
  351.         
  352.         if(half==0 || update)
  353.         {
  354.             flag |= 0x06;
  355.         }
  356.         else
  357.         {
  358.             if(adjust==1 || adjust==3)
  359.                 flag &= ~0x02;
  360.             if(adjust==2)
  361.                 flag &= ~0x04;
  362.         }
  363.         
  364.         if(show)
  365.             display();

  366.         sleep_mode();

  367.     }
  368.    

  369. }
复制代码
相对于传统的LED钟来说,这个是相当省电:1节3.2V的磷酸铁锂电池供电时,总电流大约1mA~1.1mA之间
current.jpg

       当然,这个电流下不可能觉得亮,强光下就很难看出来了。台灯下勉强能识别。
bright.jpg

        做这个钟我是给卧室用的,暗光环境下足够亮了,关了灯就觉得很亮了。
dark.jpg

       其实我还设计了亚克力的面板,只是没有做绿色亚克力的,所以颜色不搭,暂时没安装。

补充内容 (2016-2-16 20:56):
又做了一个蓝色LED的,加上亚克力面板。
[attachimg]6101171[/attachimg]
发表于 2016-2-9 17:45:58 | 显示全部楼层
不错不错,比我的大很多,可以考虑加入授时系统哦,有单片机就比较简单了。
回复 支持 反对

使用道具 举报

     
发表于 2016-2-9 19:42:29 | 显示全部楼层
牛!比我用数码管做的好看,而且经济
回复 支持 反对

使用道具 举报

     
发表于 2016-2-9 20:27:10 | 显示全部楼层
佩服动手能力强,我一直都想做一个可编程不熟悉
回复 支持 反对

使用道具 举报

     
 楼主| 发表于 2016-2-16 20:55:14 | 显示全部楼层
本帖最后由 d3b7 于 2016-2-16 20:58 编辑

今天又焊了一块,使用蓝色LED。 同等电流下蓝色的亮度不及如翠绿色的。
IMGP5928.jpg
回复 支持 反对

使用道具 举报

发表于 2016-2-16 21:23:10 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽
回复 支持 反对

使用道具 举报

     
发表于 2016-2-17 08:08:03 | 显示全部楼层
白天不能用吗?
回复 支持 反对

使用道具 举报

     
发表于 2016-2-17 12:03:51 | 显示全部楼层
很漂亮!
亮度有些差异,美中不足。
总电流这么小?才1mA多点?
回复 支持 反对

使用道具 举报

     
 楼主| 发表于 2016-2-17 15:04:43 | 显示全部楼层
szshly 发表于 2016-2-17 08:08
白天不能用吗?

LED电流需要根据环境光线强度设定(可以加光敏元件自动调节)
白天室内很亮的话,需要把电流调大,就不那么省电了。
回复 支持 反对

使用道具 举报

     
 楼主| 发表于 2016-2-17 15:09:33 | 显示全部楼层
ckc 发表于 2016-2-17 12:03
很漂亮!
亮度有些差异,美中不足。
总电流这么小?才1mA多点?

亮度和颜色不均匀是因为LED的离散性,如果买来先筛选一下的话可以做得好些。
没错,总电流1mA多晚上足够亮了。翠绿色LED效率很高,每只LED的电流数十微安级就够了。
回复 支持 反对

使用道具 举报

     
发表于 2016-2-17 17:36:59 | 显示全部楼层
我也一直有这个想法。


不过要加入授时 哦 ,不加授时的话  要用 ds3231这类高精度的
回复 支持 反对

使用道具 举报

     
发表于 2016-3-6 21:40:36 | 显示全部楼层
d3b7 发表于 2016-2-17 15:09
亮度和颜色不均匀是因为LED的离散性,如果买来先筛选一下的话可以做得好些。
没错,总电流1mA多晚上足够 ...

还是用数码管效果好

老年数字钟完工图.jpg
回复 支持 反对

使用道具 举报

     
发表于 2016-3-18 22:40:10 | 显示全部楼层
我做的是白光的可以当照明用的.每段6个LED.
PCB画好了还没做板.等有空了做出来也来晒一下.
回复 支持 反对

使用道具 举报

     
发表于 2016-3-23 08:49:42 | 显示全部楼层
做的不错,以前也做过不少LED/LCD的电子时钟,但是精度是个不好解决的问题,都成了摆设
回复 支持 反对

使用道具 举报

     
发表于 2016-3-25 20:23:41 来自手机 | 显示全部楼层
楼主,可以卖了,我们需要
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 加入会员

本版积分规则

小黑屋|手机版|矿石收音机 ( 蒙ICP备05000029号-1 )

蒙公网安备 15040402000005号

GMT+8, 2024-5-5 08:43

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表