Электромагнитные гитики...
Dec. 4th, 2019 01:47 amНамедни тут развлекался программуя свой фонарик с микроконтроллером.
Он питается от NiMH аккумулятора. (Ну потому, что их некуда девать
и они более безопасны и не боятся переразряда и хреновой погоды,
чем литиевые)
Интересный и неожиданный эффект обнаружил. Там есть индуктор
типа ферритоавой катушки для зарядки аккумулятора от USB.
DC-DC buck конвертер для понтов и эффективности.
Так вот работает хорошо, а вот как завинчиваю рядом крепежный болтик, начинает свистеть...
Я подумал, что это пьезоффект керамических конденсаторов.
Но оказалось, что железный болтик идет слишком близко к индуктору
и начинает свистеть, как маленький телефончик.
Не очень громко, но в тишине ночью слышно.
Конечно ничего особенного, этого надо было ожидать,
но все же удивительно. И урок для дизайна таких штук.
По серьезному надо торроид, а лучше закрытый.
Кстати вспомнил, что в советской военной аппаратуре на свалке
видел такие. Люди понимали и знали что делают. Респект!
Под катом программа - просто так, для самых любопытных...
Он питается от NiMH аккумулятора. (Ну потому, что их некуда девать
и они более безопасны и не боятся переразряда и хреновой погоды,
чем литиевые)
Интересный и неожиданный эффект обнаружил. Там есть индуктор
типа ферритоавой катушки для зарядки аккумулятора от USB.
DC-DC buck конвертер для понтов и эффективности.
Так вот работает хорошо, а вот как завинчиваю рядом крепежный болтик, начинает свистеть...
Я подумал, что это пьезоффект керамических конденсаторов.
Но оказалось, что железный болтик идет слишком близко к индуктору
и начинает свистеть, как маленький телефончик.
Не очень громко, но в тишине ночью слышно.
Конечно ничего особенного, этого надо было ожидать,
но все же удивительно. И урок для дизайна таких штук.
По серьезному надо торроид, а лучше закрытый.
Кстати вспомнил, что в советской военной аппаратуре на свалке
видел такие. Люди понимали и знали что делают. Респект!
Под катом программа - просто так, для самых любопытных...
/*
* File: FlashLight3.c
* Author:
*
* Created on May 8, 2017, 9:22 PM
*/
// 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 Functions as MCLR)
#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
//==============================================================================
static const char _copyright[] = "(C) Alex " __DATE__;
#define FUNC static void
typedef unsigned char byte;
typedef unsigned int uint;
#define ON 1u
#define OFF 0
#define TMR_SEC 31u // timer counts per second
// ------------------- I/O CONFIGURATION ---------------------------------------
#define BUT_TIMER_BOUNCE 4u
#define BUT_TIMER_DBLCLICK 30u
#define BUT_TIMER_IDLE 127u
#define BUT_TIMER_LONG 64u
#define LED_TIMER 16u
#define BAT_TIMER 255u
#define PIN_LED 0b00000001u
#define PIN_POWER 0b00000010u
#define PIN_VBAT 0b00000100u
#define PIN_BUT 0b00001000u
#define PIN_DRIVE 0b00010000u
#define PIN_CHARGE 0b00100000u
#define BIT_LED GPIObits.GP0
#define BIT_POWER GPIObits.GP1
#define BIT_VBAT GPIObits.GP2
#define BIT_BUT !GPIObits.GP3
#define BIT_DRIVE GPIObits.GP4
#define BIT_CHARGE GPIObits.GP5
//============================ ADC ===========================================
#define ADC_WAIT while(ADCON0 & 2u);
#define ADC_OFF ADCON0 = 0b00101100u;
#define ADC_VREF ADCON0 = 0b01101111u;
#define ADC_VBAT ADCON0 = 0b01101011u;
#define ADC_POWER ADCON0 = 0b11100111u;
#define CMP_OFF 0b01010001u
#define CMP_BEAM_BIT 0b10000000u
//---------------------------- timer functions ---------------------------------
#define SYS_TIMER TMR0
typedef unsigned char timer_t;
typedef unsigned char sys_timer_t;
static timer_t but_timer_bounce, but_timer_dblclick, idle_timer, Timer1, Timer2, led_timer,
but_timer_long;
FUNC reset_timers()
{
Timer1 = 0;
Timer2 = 0;
but_timer_bounce = 0;
but_timer_dblclick = 0;
led_timer = 0;
SYS_TIMER = 0;
idle_timer = 0;
but_timer_long = 0;
}
#define UPDATE_TIMER(val) if(val) --val;
FUNC UpdateTimers()
{
static sys_timer_t timer;
timer_t t = SYS_TIMER;
if (t < timer) // roll over
{
// Update all timers:
UPDATE_TIMER(but_timer_bounce)
UPDATE_TIMER(but_timer_dblclick)
UPDATE_TIMER(but_timer_long)
UPDATE_TIMER(Timer1)
UPDATE_TIMER(Timer2)
UPDATE_TIMER(led_timer)
UPDATE_TIMER(idle_timer)
}
timer = t;
}
//void timer_delay(timer_t del)
//{
// timer_t t = Timer;
// while (Timer - t < del)
// UpdateTimer();
//}
// ------------------------------ ADC ------------------------------------------
enum StateEnum
{
STATE_NORMAL,
STATE_CHARGE,
};
static byte State = STATE_NORMAL;
static byte CheckState()
{
ADC_POWER
ADC_WAIT
ADC_POWER
ADC_WAIT
if (ADRES > 240u) //
{
ADC_VREF
return STATE_CHARGE;
}
ADC_VREF
return STATE_NORMAL;
}
enum BatteryEnums
{
BAT_LOW,
BAT_NORMAL,
BAT_CHARGE,
BAT_FULL,
BAT_MAX
};
byte CheckBattery()
{
// return BAT_CHARGE; //debug
ADC_VREF
ADC_WAIT
ADC_VREF
ADC_WAIT
byte vref = ADRES;
ADC_VBAT
byte v = (vref << 1) - (vref >> 2); // 1.05V
ADC_WAIT
ADC_VBAT
ADC_WAIT
if (ADRES < v)
return BAT_LOW;
v += vref >> 1; // 1.35V
if (ADRES <= v)
return BAT_NORMAL;
v += (vref >> 2); //1.5V
if (ADRES < v)
return BAT_CHARGE;
return BAT_FULL;
}
//-----------------------------------------------------------------------
enum ButtonEnums
{
BUT_OFF,
BUT_ON,
BUT_CLICK,
BUT_CLICK_LONG,
BUT_DBLCLICK
};
static byte Button = BUT_OFF;
void CheckButton()
{
switch (Button)
{
case BUT_OFF:
if(BIT_BUT)
{
Button = BUT_ON;
but_timer_bounce = BUT_TIMER_BOUNCE;
but_timer_long = BUT_TIMER_LONG;
}
break;
case BUT_ON:
if (BIT_BUT)
break;
if (but_timer_dblclick)
{
Button = BUT_DBLCLICK;
but_timer_dblclick = 0;
}
else
{
if(but_timer_bounce)
{
Button = BUT_OFF;
but_timer_bounce = 0;
}
else
{
if(but_timer_long)
{
Button = BUT_CLICK;
but_timer_dblclick = BUT_TIMER_DBLCLICK;
but_timer_long = 0;
}
else
{
Button = BUT_CLICK_LONG;
but_timer_dblclick = 0;
}
}
}
break;
default:
if (BIT_BUT)
Button = BUT_ON;
else
Button = BUT_OFF;
}//switch (ButtonState)
}//void CheckButton()
static bit bitLight, bitLightSet, bitBeam, bitCharge, bitChargeSet, bitChargeLow,
bitNightMode;
//------------------------------------- LOOPS ----------------------------------'
#define RUN_LOOPS(loop) \
{ \
loop; \
loop; \
loop; \
loop; \
loop; \
loop; \
}
FUNC DEL()
{
}
FUNC RunIdle()
{
BIT_DRIVE = ON;
NOP();
BIT_CHARGE = OFF;
NOP();
BIT_CHARGE = ON;
BIT_DRIVE = OFF;
}//static void IdleLoop()
FUNC RunLight()
{
BIT_DRIVE = ON;
if(bitBeam)
{
DEL();
DEL();
DEL();
DEL();
DEL();
BIT_DRIVE = OFF;
NOP();
NOP();
}
else
{
DEL();
NOP();
NOP();
BIT_DRIVE = OFF;
NOP();
NOP();
}
}
FUNC RunCharge()
{
BIT_CHARGE = OFF;
NOP();
NOP();
if(!bitChargeLow)
{
DEL();
}
BIT_CHARGE = ON;
DEL();
}
FUNC RunChargeLight()
{
BIT_CHARGE = OFF;
BIT_DRIVE = ON;
if(bitChargeLow)
{
if(bitBeam)
{
NOP();
NOP();
NOP();
NOP();
NOP();
NOP();
NOP();
NOP();
NOP();
BIT_CHARGE = ON;
NOP();
NOP();
NOP();
NOP();
}
else
BIT_CHARGE = ON;
BIT_DRIVE = OFF;
}
else
{
if(bitBeam)
{
DEL();
NOP();
NOP();
BIT_CHARGE = ON;
NOP();
BIT_DRIVE = OFF;
NOP();
}
else
{
NOP();
BIT_DRIVE = OFF;
NOP();
NOP();
BIT_CHARGE = ON;
}
}
}
//00000000000000000000000000000000000000000000000000000000000000000000000000000
FUNC InitMCU()
{
OPTION = 0b01000110; // 64 timer prescale, no pullups
TRIS = PIN_VBAT | PIN_BUT | PIN_POWER;
GPIO = PIN_CHARGE;
ADC_POWER
CM1CON0 = CMP_OFF;
}//static void InitMCU()
FUNC Sleep()
{
ADC_OFF
GPIO;
SLEEP();
}
//========================== MAIN =============================================
void main()
{
InitMCU();
byte oldState = STATE_NORMAL;
for (;;) // ----- MAIN LOOP -------
{
CLRWDT();
State = CheckState();
if(State != oldState)
{
BIT_LED = OFF;
bitCharge = OFF;
bitLight = OFF;
bitLightSet = bitLight;
bitNightMode = OFF;
reset_timers();
if(State == STATE_CHARGE)
{
bitChargeSet = bitCharge = ON;
bitChargeLow = ON;
led_timer = LED_TIMER;
Timer1 = 0;
Timer2 = BAT_TIMER;
BIT_LED = ON;
}
oldState = State;
}
UpdateTimers();
CheckButton();
switch(Button)
{
case BUT_OFF:
break;
case BUT_ON:
idle_timer = BUT_TIMER_IDLE;
break;
case BUT_CLICK:
if(bitLight)
bitBeam = !bitBeam;
if(bitNightMode)
{
bitNightMode = OFF;
idle_timer = 0;
}
break;
case BUT_DBLCLICK:
bitLight = !bitLight;
bitLightSet = bitLight;
if(bitLight)
bitBeam = ON;
else
idle_timer = 0;
break;
case BUT_CLICK_LONG:
bitNightMode = ON;
bitLight = OFF;
idle_timer = 0;
break;
}//switch(Button)
switch(State)
{
case STATE_NORMAL:
if(bitLight)
RUN_LOOPS(RunLight())
else
{
RunIdle();
if(bitNightMode)
RunIdle();
else
if(idle_timer == 0)
{
RunIdle();
Sleep();
}
}
break;
case STATE_CHARGE:
if(led_timer == 0)
{
led_timer = LED_TIMER;
if(BIT_LED)
{
if(bitCharge)
BIT_LED = OFF;
if(Timer2 == 0)
{
bitCharge = OFF;
bitLight = OFF;
BIT_LED = OFF;
}
}
else
{
if(Timer2 == 0 && bitCharge == 0)
{
Timer2 = BAT_TIMER;
byte bat = CheckBattery();
if(bitChargeSet)
bitCharge = bat != BAT_FULL;
else
bitCharge = bat == BAT_LOW || bat == BAT_NORMAL;
bitChargeSet = bitCharge;
bitLight = bitLightSet;
bitChargeLow = bat == BAT_LOW;
}
BIT_LED = ON;
}
}//if(led_timer == 0)
CLRWDT();
if(bitLight)
if(bitCharge)
RUN_LOOPS(RunChargeLight())
else
RUN_LOOPS(RunLight())
else
if(bitCharge)
RUN_LOOPS(RunCharge())
if(Timer1 == 0)
{
RunIdle();
RunIdle();
RunIdle();
Timer1 = 1u;
}
if(idle_timer)
RunIdle();
if(bitNightMode)
{
RunIdle();
RunIdle();
}
break;
}//switch(State)
// ------ CHARGE STATE --------
}//for(;;) // MAIN LOOP
}//void main(void)