【参赛】省电的“星光"LED时钟
本帖最后由 d3b7 于 2016-2-9 17:55 编辑我曾经有个烂尾工程 旷日持久的制作开始了——家用时钟,快5年过去了,仍旧没有投入实用。
但卧室确实缺少一个夜里能轻松看清的时钟,于是正儿八经再重做这个项目吧。
PCB就在厂家做了,当年用感光膜只能做单面工艺,还费时间。改版后,LED仍然在正面,单片机和升压电路就在背面了。这样一块板子搞定。
上面这个图只带了两个数字的显示,一个钟需要两套显示板,就复制一份好了。控制电路只需要一份公用,所以左右两边的单片机部分只需要装一个。那么为什么我的PCB还布上两份同样的控制呢?这样可以分割成两块用,做99秒倒计时器啥的。
这个电路不复杂,就是用三只超高亮度的LED来组成数码显示的一个笔段,用4片74HC164作为串-并转换和锁存,构成显示驱动。单片机ATMEGA48作为主控,SPI输出串行显示驱动信号,平时也就半秒种唤醒一次,刷新显示;其余时间单片机都在休眠状态,几乎没有功耗。而用于LED发光的显示耗电情况,取决于LED的性能和电流。
PCB元旦后收到。
焊接正面的LED,74HC164等,主要是LED手工焊接很消耗时间……
焊接MCU主控,调试程序
基本的程序(完成了走时和时钟调节)#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>
#include <stdlib.h>
#include <string.h>
/* Current time */
uint8_t hh=12, mm=0, ss=0;
char half=0;
/* Clock parameters */
uint8_t flag=0;
uint8_t mode;
static char brt1, brt2; // button release time
ISR (TIMER2_COMPA_vect)
{
if(half)
{
half=0;
// PORTD |= _BV(5);
ss++;
if(ss>59)
{
ss=0;
mm++;
if(mm>59)
{
mm=0;
hh++;
if(hh>23)
hh=0;
}
}
}
else
{
half=1;
// PORTD &= ~_BV(5);
}
if(brt1>-16)
brt1-=16;
if(brt2>-16)
brt2-=16;
}
ISR (PCINT0_vect)
{
}
uint8_t getbutton()
{
static char bs1, bs2; // button state
static char bh1, bh2; // button hold time
char button=PINB;
char tick=TCNT2;
char state=0;
if(!bs1)
{
if(button&1) // button 1 release
{
bs1=1;
brt1=tick;
bh1=0;
}
else
{
if(tick==0)
bh1++;
}
if(bh1>5)
state|=4;
}
else
{
if(!(button&1)) // button 1 press
{
bs1=0;
if(tick-brt1>3) // valid key
state|=1;
}
}
if(!bs2)
{
if(button&2) // button 2 release
{
bs2=1;
brt2=tick;
}
else
{
if(tick==0)
bh2++;
}
if(bh2>5)
state|=8;
}
else
{
if(!(button&2)) // button 2 press
{
bs2=0;
if(tick-brt2>3) // valid key
state|=2;
}
}
return state;
}
const char digdisp=
{
0x02, //0 xxxx xx.h
0x7a, //1 x... .x.h
0x90, //2 .xx. xxxh
0x30, //3 xx.. xxxh
0x68, //4 x..x .xxh
0x24, //5 xx.x x.xh
0x04, //6 xxxx x.xh
0x72, //7 x... xx.h
0x00, //8 xxxx xxxh
0x20, //9 xx.x xxxh
0xfc, // '-' symbol
0xfe // blank
/*0x40, //A x.xx xxxh
0x0c, //b xxxx ..xh
0x86, //C .xxx x..h
0x18, //d xxx. .xxh
0x84, //E .xxx x.xh
0xc4 //F ..xx x.xh*/
};
inline void nop(void)
{
__asm__ volatile("nop");
}
#define HHMM 8
#define MMSS 9
void display()
{
uint8_t l,h;
uint8_t colon;
uint8_t b4,b3,b2,b1;
if(flag & 0x01)
colon=0;
else
colon=1;
if(flag & 0x02)
{
switch(mode)
{
case HHMM:
h=(mm*26)>>8;
l=mm-10*h;
break;
case MMSS:
h=(ss*26)>>8;
l=ss-10*h;
break;
default:
h=10;
l=10;
break;
}
}
else
{
h=11;
l=11;
}
b4=digdisp;
b3=digdisp|colon;
if(flag & 0x04)
{
switch(mode)
{
case HHMM:
if(hh<10)
{
h=11;
l=hh;
}
else
{
h=(hh*26)>>8;
l=hh-10*h;
}
break;
case MMSS:
h=(mm*26)>>8;
l=mm-10*h;
break;
default:
h=10;
l=10;
break;
}
}
else
{
h=11;
l=11;
}
b2=digdisp;
b1=digdisp;
SPDR=b4;
while(!(SPSR & _BV(SPIF)));
SPDR=b3|colon;
while(!(SPSR & _BV(SPIF)));
SPDR=b2;
while(!(SPSR & _BV(SPIF)));
SPDR=b1;
while(!(SPSR & _BV(SPIF)));
}
int main()
{
int i;
// set sysclk prescaler
CLKPR=_BV(CLKPCE);
CLKPR=0; // no div
nop();
nop();
nop();
nop();
nop();
// configure Timer 2
ASSR=_BV(AS2);// asynchronous clock osc
TCCR2A=_BV(WGM21);// Timer2 CTC mode, TOP as OCRA
OCR2A=15;
TCCR2B=_BV(CS22)|_BV(CS21)|_BV(CS20); // enable, clk/1024
TIFR2=_BV(OCF2A); // clear flag
TIMSK2=_BV(OCIE2A); // enable interrupt
sei();
// configure SPI
DDRB=_BV(2)|_BV(3)|_BV(5);// SPI output pin, SS must be output
SPSR=_BV(SPI2X);
SPCR=_BV(SPE)|_BV(MSTR)|_BV(CPHA);// Fastest SPI
set_sleep_mode(SLEEP_MODE_IDLE);
DDRD=_BV(5)|_BV(2); //PD5: Status (BLUE), PD5: DC-DC EN
PORTD=_BV(2); // DC-DC on
PORTB |= _BV(0)|_BV(1); // button 1, 2
flag=7;
display();
sleep_mode(); // wait until RTC oscillator is stable
set_sleep_mode(SLEEP_MODE_PWR_SAVE);
PCICR=_BV(PCIE0); // Pin-change interrupt 0
PCMSK0=_BV(PCINT0)|_BV(PCINT1);
PCIFR=_BV(PCIF0);
mode=HHMM;
for(;;)
{
static char phalf=3;
char b;
char show=0;
static char adjust=0;
char update=0;
if(phalf!=half)
{
show=1;
phalf=half;
}
b=getbutton();
if(adjust==0)
{
if(b&2)
{
if(mode==HHMM)
mode=MMSS;
else
mode=HHMM;
show=1;
}
else
{
if((b&12)==4) // button 1 Hold
{
set_sleep_mode(SLEEP_MODE_IDLE); // change back later
if(mode==HHMM)
adjust=1;
else
adjust=3;
show=1;
}
}
}
else
{
switch(adjust)
{
case 1: // adjust Minute
if(b&2)
{
mm++;
if(mm>59)
mm=0;
update=1;
}
else
if(b&1)
{
adjust=2;
show=1;
}
break;
case 2: // adjust Hour
if(b&2)
{
hh++;
if(hh>23)
hh=0;
update=1;
}
else
if(b&1)
{
adjust=0;
set_sleep_mode(SLEEP_MODE_PWR_SAVE);
show=1;
}
break;
case 3: // adjust Second
if(b&2)
{
ss=0;
TCNT2=0;
half=0;
update=1;
}
else
if(b&1)
{
adjust=0;
set_sleep_mode(SLEEP_MODE_PWR_SAVE);
show=1;
}
break;
}
if(update)
show=1;
}
if(mode==HHMM && half==0)
{
flag |= 0x01;
}
else
{
flag &= ~0x01;
}
if(half==0 || update)
{
flag |= 0x06;
}
else
{
if(adjust==1 || adjust==3)
flag &= ~0x02;
if(adjust==2)
flag &= ~0x04;
}
if(show)
display();
sleep_mode();
}
}
相对于传统的LED钟来说,这个是相当省电:1节3.2V的磷酸铁锂电池供电时,总电流大约1mA~1.1mA之间
当然,这个电流下不可能觉得亮,强光下就很难看出来了。台灯下勉强能识别。
做这个钟我是给卧室用的,暗光环境下足够亮了,关了灯就觉得很亮了。
其实我还设计了亚克力的面板,只是没有做绿色亚克力的,所以颜色不搭,暂时没安装。
补充内容 (2016-2-16 20:56):
又做了一个蓝色LED的,加上亚克力面板。
6101171 不错不错,比我的大很多,可以考虑加入授时系统哦,有单片机就比较简单了。 牛!比我用数码管做的好看,而且经济 佩服动手能力强,我一直都想做一个可编程不熟悉:lol:lol:lol
本帖最后由 d3b7 于 2016-2-16 20:58 编辑
今天又焊了一块,使用蓝色LED。 同等电流下蓝色的亮度不及如翠绿色的。
白天不能用吗? 很漂亮!
亮度有些差异,美中不足。
总电流这么小?才1mA多点? szshly 发表于 2016-2-17 08:08 static/image/common/back.gif
白天不能用吗?
LED电流需要根据环境光线强度设定(可以加光敏元件自动调节)
白天室内很亮的话,需要把电流调大,就不那么省电了。 ckc 发表于 2016-2-17 12:03 static/image/common/back.gif
很漂亮!
亮度有些差异,美中不足。
总电流这么小?才1mA多点?
亮度和颜色不均匀是因为LED的离散性,如果买来先筛选一下的话可以做得好些。
没错,总电流1mA多晚上足够亮了。翠绿色LED效率很高,每只LED的电流数十微安级就够了。 我也一直有这个想法。
不过要加入授时 哦 ,不加授时的话要用 ds3231这类高精度的 d3b7 发表于 2016-2-17 15:09 static/image/common/back.gif
亮度和颜色不均匀是因为LED的离散性,如果买来先筛选一下的话可以做得好些。
没错,总电流1mA多晚上足够 ...
还是用数码管效果好
我做的是白光的可以当照明用的.每段6个LED.
PCB画好了还没做板.等有空了做出来也来晒一下. 做的不错,以前也做过不少LED/LCD的电子时钟,但是精度是个不好解决的问题,都成了摆设 楼主,可以卖了,我们需要
页:
[1]