迷你智能电源
2015-07-14 by Stavros做了个简单的小电源,用一节18650供电,可以输出1.26V、1.8V、2.5V、2.85V、3.3V、5.0V和6.0V,共7种电压,可以通过USB给18650充电,如图:
原理图:
充电使用TP4056,充电电流为1200/1.5k = 800mA。LM3478接成SEPIC电路,既能升压也能降压。单片机ATtiny13输出一路PWM信号,经滤波后控制LM3478的反馈端,从而控制输出电压。三只LED用于指示输出电压。
源程序:
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <avr/sleep.h>
#include "misc.h"
vu8 g_status;
vu32 g_key;
// 0, 1.2x, 1.8, 2.5, 2.85, 3.3, 5.0, 6.0
vu8 g_pwm[] = {200, 105, 90, 77, 70, 62, 29, 0}; // 8种状态下的PWM值
void port_init(void)
{
PORTB = 0x0e;
DDRB = 0x1f; // PB0~4作为输出
}
void timer0_init(void)
{
TCCR0B = 0x00;
TCCR0A = 0x83; // 快速PWM,1分频
TCCR0B = 0x01; // 启动定时器
TIMSK0 |= _BV(TOIE0);
}
ISR(TIM0_OVF_vect)
{
// 读键
u8 tmp;
g_key <<= 1;
tmp = PORTB & _BV(PB3);
PORTB |= _BV(PB3);
DDRB &= ~_BV(PB3);
if( !(PINB & _BV(PB3) ) )
g_key |= 1;
else
g_key &= ~1;
DDRB |= _BV(PB3);
if(tmp) // 恢复PB3的旧状态
PORTB |= _BV(PB3);
else
PORTB &= ~_BV(PB3);
if( (g_key & 0xffffffff) == 0xffffff00 ) { // 判断按键
g_status++;
g_status %= 8;
OCR0A = g_pwm[g_status];
if( g_status == 0 ) { // 状态0时调慢主频,省电
CLKPR = 0x80;
CLKPR = 0x08;
PORTB &= ~_BV(PB4);
}
else {
CLKPR = 0x80;
CLKPR = 0x03; // 正常状态为8分频,9.6M / 8 = 1.2M
PORTB |= _BV(PB4);
}
}
}
void init_devices(void)
{
port_init();
timer0_init();
set_sleep_mode(SLEEP_MODE_IDLE);
sleep_enable();
CLKPR = 0x80;
CLKPR = 0x08;
ACSR |= _BV(ACD); // 关闭模拟比较器,也是为了省电
sei();
PORTB &= ~_BV(PB4); // 禁用LM3478
}
int main()
{
init_devices();
while(1) {
PORTB = (PORTB & 0xf1) | ((~(g_status<<1)) & 0x0e); // LED输出
sleep_cpu();
}
return 0;
}