>

迷你智能电源

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;
}