febb: (Default)
febb ([personal profile] febb) wrote2018-12-13 11:29 pm

Фонарик-2...

Сделал еще такой светодиодный фонарик из хлама с микропроцессором...
У нас на работе, в небоскребе выдают, а потом выкидывают такие одноразовые emergency фонарики.
Я переделал, на крутой манер: с микроконтроллером, DC-DC преобразователями для светодиода
и зарядки аккумулятора от USB. А питается от одного Ni-MH элемента (чуть побольше AA).
Причем микроконтроллер подкачивает все время для себя необходимые 2-3V из батареечных 1.2V.
Светодиод (LED 1W) светится чуть-чуть и фонарик всегда можно найти в темноте.
Процессор просыпается от Watch Dog Timer-а, следит за напряжениями, переключателем и засыпает.
Переключателем можно выбрать яркий и экономный режим. Мне было интересно это попрограммировать.
Для любителей языка Си, под катом программа, между прочим 300 строк! :) Enjoy! :)
1.jpg

/*
 * File:   FlashLight2.c
 * Author:
 *
 * Created on December 8, 2018, 8:06 AM
 */

 // PIC12F510 Configuration Bit Settings
 // 'C' source line config statements
 // CONFIG
#pragma config OSC = IntRC      // Oscillator Select (INTOSC with 1.125 ms DRT)
#pragma config WDT = ON         // Watchdog Timer Enable bit (WDT enabled)
#pragma config CP = OFF         // Code Protect (Code protection off)
#pragma config MCLRE = OFF      // Master Clear Enable bit (GP3/MCLR pin functions as GP3, MCLR internally tied to VDD)
#pragma config IOSCFS = OFF     // Internal Oscillator Frequency Select bit (4 MHz INTOSC Speed)

// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.

#include xc.h

typedef unsigned char byte;

#define INIT_GPIO   0b010000
#define INIT_TRIS   0b001101
#define INIT_CM1CON0    0b11110001

#define PIN_LED     GPIObits.GP1

#define PIN_SWITCH  GPIObits.GP3
#define PIN_FLASH   GPIObits.GP5
#define PIN_CHARGE  GPIObits.GP4
#define BIT_BAT     0b100


#define ADC_OFF         0b00111100
#define ADC_VREF        0b00111111
#define ADC_BAT         0b01111011

#define ADC_SET(set)    ADCON0 = set;
#define ADC_WAIT        while(ADCON0 & 2u);


static bit bit_wake, bit_power, bit_switch, bit_beam, bit_charge, bit_charge_fast;
static volatile byte timer1, timer2;
//--------------------------------------------------------------------------
inline void InitMCU()
{
	OPTION = 0b11000111;
	TRIS = INIT_TRIS;
	GPIO = INIT_GPIO;
	ADC_SET(ADC_VREF)
	bit_beam = CM1CON0 & 1;
	CM1CON0 = INIT_CM1CON0;
}

static void ADC(byte adc)
{
	byte t = 10;
	while (--t)
	{
		ADC_SET(adc);
		ADC_WAIT
	}
}

inline void FlashPump()
{
	byte t = 3;
	CLRWDT();
	while (--t)
	{
		PIN_FLASH = 1;
		NOP();
		if (bit_beam)
		{
			NOP();
			NOP();
			NOP();
			NOP();
			NOP();
			NOP();
			NOP();
			NOP();
			NOP();
			NOP();
		}
		PIN_FLASH = 0;
		NOP();
	}
}//void FlashPump()

inline void FlashIdle()
{
	byte t = 3u;
	while (--t)
	{
		PIN_FLASH = 1;
		NOP();
		PIN_FLASH = 0;
	}
}

#define TIMER_SEC(sec)  sec << 4 
// OSC 4 MHz
inline void UpdateTimer()
{
	static byte timer;

	byte t = TMR0;
	if (t < timer)
	{
		if (timer1)
			--timer1;
		if (timer2)
			--timer2;
	}
	timer = t;
}

inline void CheckPower()
{
	if (ADRES < 39u) // V > 4.1V
	{
		ADC_SET(ADC_VREF)
		bit_power = 1;
	}
	else
	{
		ADC_SET(ADC_VREF)
		if (bit_power)
		{
			PIN_LED = 0;
			bit_power = 0;
		}
	}
}

inline void CheckBattery()
{
	if (timer1 == 0)
	{
		if (bit_charge)
		{
			timer2 = 7;
			bit_charge = 0;
			return;
		}
		if (timer2)
			return;
		ADC(ADC_VREF);
		byte vref = ADRES;
		ADC(ADC_BAT);
		byte t = vref << 1;
		if (ADRES >= t + (vref >> 1)) // 1.5V
			bit_charge = 0;
		else
		{
			if (ADRES < (t - (vref >> 2))) // 1.05V
				bit_charge_fast = 0;
			else
				bit_charge_fast = 1;
			bit_charge = 1;
		}
		ADC(ADC_VREF);
		PIN_LED = 1;
		timer1 = 255u;
	}
	if (!bit_charge)
		return;

	if (timer2 == 0)
	{
		PIN_LED = !PIN_LED;
		timer2 = 7u;
	}

	//    bit_charge_fast = 0;
	byte t = 3;
	CLRWDT();
	while (--t)
	{
		PIN_CHARGE = 0;
		if (bit_charge_fast)
		{
			NOP();
			NOP();
			NOP();
			NOP();
			NOP();
			NOP();
		}
		PIN_CHARGE = 1;
		NOP();
		NOP();
		NOP();
		NOP();
		NOP();
		NOP();
		NOP();
		NOP();
		NOP();
		NOP();
	}
}

inline void Sleep()
{
	ADC_SET(ADC_OFF)
	if (bit_beam)
		CM1CON0 = INIT_CM1CON0 | 1u;
	else
		CM1CON0 = INIT_CM1CON0 & 0b11111110u;
	SLEEP();
}


#define SWITCH_BEAM_COUNTER 120u

inline void CheckSwitch()
{
	if (PIN_SWITCH)
	{
		if (bit_switch)
		{
			bit_switch = 0;
			TMR0 = 0;
		}
		else
			if (++TMR0 > SWITCH_BEAM_COUNTER)
				TMR0 = SWITCH_BEAM_COUNTER;
	}
	else
	{
		if (bit_switch == 0)
		{
			if (TMR0 < SWITCH_BEAM_COUNTER)
				bit_beam = !bit_beam;
			bit_switch = 1;
		}
	}
}

//================================== MAIN ======================================
void main(void)
{
	InitMCU();
	FlashIdle();
	for(;;)
	{
		UpdateTimer();
		CheckPower();
		CLRWDT();
		if (bit_power)
		{
			CheckBattery();
			continue;
		}
		CheckSwitch();
		if (bit_switch)
			FlashPump();
		else
			Sleep();
		}
	}
}