//PIC16F73
//UPS power source measurer
//Defines
#define CHARGING PORTC.F0
#define POW_SW PORTC.F1
#define POW_CONT PORTC.F3
#define BUTTON PORTC.F4
#define FAN PORTC.F5
#define TEMP_LO 3592.0 // Resistance for low temp, 50'C
#define TEMP_AL_OFF 1735 // Resistance for alarm off, 70'C
#define TEMP_HI 1243.0 // Resistance for high temp, 80'C
#define TEMP_AL_ON 782 // Resistance for alarm on, 95'C
#define INITIAL_FAN_SPEED 50 // Minimal PWM for proper fan operate, 20%
#define CHARGE_FAN_SPEED 75 // PWM for fan if charging, 30%
#define DPH_COOLING_FAN_SPEED 180 // PWM for fan if DPH fan is on, 70%
//Variables
char *digittext = "00000";
int battery_ADC, T_bat_ADC, T_coil_ADC, T_mos_ADC, T_rec_ADC;
unsigned long T_bat_res, T_coil_res, T_mos_res, T_rec_res;
char ADC_channel;
char count_resistance;
float flt_val;
long int fan_task, fan_speed;
bit bat_overH, coil_overH, mos_overH, rec_overH, overheat;
bit bat_hot, coil_hot, mos_hot, rec_hot;
bit batt_ok;
bit blink;
bit send_uart;
bit alarm_off;
char alarm_timer;
bit blink_long;
char blink_long_timer;
char display_mode;
char display_data;
bit button_pressed;
//*************************************************************************************
//battery charge
//Level 0 1 2 3 4 5 6 7 8
//voltage 3.1 3.2 3.4 3.5 3.6 3.7 3.8 3.9 4
//voltage 12.4 12.8 13.6 14 14.4 14.8 15.2 15.6 16
//ADC 182 190 202 208 214 220 226 233 239
const char battery_levels[9] = {182, 190, 202, 208, 214, 220, 226, 233, 239};
//*************************************************************************************
//temperature resistances
//level 0 1 2 3 4 5 6 7
//deg 55 60 65 70 75 80 85 95
//resist 2972 2472 2066 1735 1465 1243 1059 782
const int temper_resistances[8] = {2972, 2472, 2066, 1735, 1465, 1243, 1059, 782};
void WriteInt(long number){
digittext[0] = (number/10000)%10 + 48;
digittext[1] = (number/1000)%10 + 48;
digittext[2] = (number/100)%10 + 48;
digittext[3] = (number/10)%10 + 48;
digittext[4] = number%10 + 48;
UART1_Write_Text(digittext);
}
void Display() {
if (display_mode == 0)
{
WriteInt(Battery_ADC);
UART1_Write_Text("; ");
WriteInt(fan_speed);
if (~(batt_OK)) UART1_Write_Text(" B");
if (overheat) UART1_Write_Text(" H");
}
if (display_mode == 1) WriteInt(T_mos_res);
if (display_mode == 2) WriteInt(T_rec_res);
if (display_mode == 3) WriteInt(T_coil_res);
if (display_mode == 4) WriteInt(T_bat_res);
UART1_Write('\r');
}
void TemperatureGauge(long value) {
display_data.F1 = (value < temper_resistances[0]);
display_data.F0 = (value < temper_resistances[1]);
display_data.F3 = (value < temper_resistances[2]);
display_data.F2 = (value < temper_resistances[3]);
display_data.F5 = (value < temper_resistances[4]);
display_data.F4 = (value < temper_resistances[5]);
display_data.F7 = (value < temper_resistances[6]);
display_data.F6 = (value < temper_resistances[7]);
}
int Fan_power(unsigned long resistanse) {
int result = (((INITIAL_FAN_SPEED - 255)*(resistanse - TEMP_HI))/(TEMP_LO - TEMP_HI)) + 255;
return result;
}
unsigned long Get_resistanse(int value) {
unsigned long result;
{flt_val = 255.0 / value; flt_val = flt_val + (-1); result = 10000.0 / flt_val;}
return result;
}
void interrupt() {
if (INTCON.TMR0IF) {
if (ADC_channel == 0) Battery_ADC = ADRES;
if (ADC_channel == 1) T_mos_ADC = ADRES;
if (ADC_channel == 2) T_rec_ADC = ADRES;
if (ADC_channel == 3) T_coil_ADC = ADRES;
if (ADC_channel == 4) T_bat_ADC = ADRES;
count_resistance = ADC_channel;
ADC_channel ++;
if (ADC_channel > 4) ADC_channel = 0;
if (ADC_channel == 0) ADCON0 = 0b01000001;
if (ADC_channel == 1) ADCON0 = 0b01001001;
if (ADC_channel == 2) ADCON0 = 0b01010001;
if (ADC_channel == 3) ADCON0 = 0b01011001;
if (ADC_channel == 4) ADCON0 = 0b01100001;
//ADCON0 = 0b10000001 + (ADC_channel << 3);
//ADCON0.GO = 1;
Delay_ms(2);
ADCON0 = ADCON0 + 0b00000100;
INTCON.TMR0IF = 0;
}
if (PIR1.TMR1IF) {
//Test = ~(Test);
if ( (batt_OK) && (~(overheat)) ) alarm_timer = 0; else {if (alarm_timer < 100) alarm_timer++;}
if (alarm_timer > 38) alarm_off = 1; // 10 000 / 262 (mS)
blink = ~(blink);
blink_long_timer++;
if (blink_long_timer > 4) // 4
{
blink_long_timer = 0;
//blink_long = 0;
//blink_long = 1;
blink_long = ~(blink_long);
}
send_uart = 1; //Display();
PIR1.TMR1IF = 0;
}
}
void main() {
//OPTION_REG = 0b10000101; //pull_ups off, TMR0 = 1*64*256=16384mkS
OPTION_REG = 0b10000110; //pull_ups off, TMR0 = 1*128*256=32768mkS
T1CON = 0b00100001; //Enable timer 1, ovf = 1*4*65535 = 262140 mS
ADCON0 = 0; //0b10000001; //Fosc/32, ADC enable
ADCON1 = 0b00000000; //All for ADC, left alligment
//CMCON = 0b00000111;
TRISA = 0b11111111;
TRISB = 0b00000000;
TRISC = 0b10110011;
// INTCON = 0; //interrupt stop
INTCON = 0b11100000; //interrupt on periphery and TMR0
PIE1 = 0b00000001; // TMR1 ovf interrupt enable
CCP1CON = 0b00001100; //CCP1 as PWM mode
PR2 = 255; //4096 mks
CCPR1L = 0;
T2CON = 0b00000110; //Tmr2 on, prescale 16, for 244Hz PWM
PortA = 0;
PortB = 0;
PortC = 0;
UART1_Init(9600);
// UART1_Write_Text("Hello !");
alarm_off = 0;
alarm_timer = 0;
ADC_channel = 0;
display_mode = 0;
while(1)
{
batt_ok = (Battery_ADC >= battery_levels[0]);
//**************************************************************************************
if (display_mode == 0)
{
if (~(batt_ok)) display_data.F1 = blink;
else {if (~(CHARGING)) display_data.F1 = blink_long; else display_data.F1 = (Battery_ADC >= battery_levels[1]);}
display_data.F0 = (Battery_ADC >= battery_levels[2]);
display_data.F3 = (Battery_ADC >= battery_levels[3]);
if ((mos_hot)|(T_mos_res>80000)) display_data.F2 = blink; else display_data.F2 = (Battery_ADC >= battery_levels[4]);
if ((rec_hot)|(T_rec_res>80000)) display_data.F5 = blink; else display_data.F5 = (Battery_ADC >= battery_levels[5]);
if ((coil_hot)|(T_coil_res>80000)) display_data.F4 = blink; else display_data.F4 = (Battery_ADC >= battery_levels[6]);
if ((bat_hot)|(T_bat_res>80000)) display_data.F7 = blink; else display_data.F7 = (Battery_ADC >= battery_levels[7]);
if (~(FAN)) display_data.F6 = blink; else display_data.F6 = (Battery_ADC >= battery_levels[8]);
}
if (display_mode == 1)
{
if (blink_long) display_data = 0b00000100; else TemperatureGauge(T_mos_res);
}
if (display_mode == 2)
{
if (blink_long) display_data = 0b00100000; else TemperatureGauge(T_rec_res);
}
if (display_mode == 3)
{
if (blink_long) display_data = 0b00010000; else TemperatureGauge(T_coil_res);
}
if (display_mode == 4)
{
if (blink_long) display_data = 0b10000000; else TemperatureGauge(T_bat_res);
}
//**************************************************************************************
PORTB = display_data;
//**************************************************************************************
if ( (~(BUTTON)) && (~(button_pressed)) )
{
Delay_ms(10);
if (~(BUTTON))
{
display_mode ++;
if (display_mode > 4) display_mode = 0;
blink_long = 1;
blink_long_timer = 0;
button_pressed = 1;
}
}
if (BUTTON) button_pressed = 0;
//**************************************************************************************
if (count_resistance > 0)
{
if (count_resistance == 1)
{
//if (T_mos_ADC > 228) T_mos_res = 0; else
//{flt_val = 255.0 / T_mos_ADC; flt_val = flt_val + (-1); T_mos_res = 10000.0 / flt_val;}
T_mos_res = Get_resistanse(T_mos_ADC);
}
if (count_resistance == 2)
{
//if (T_rec_ADC > 228) T_rec_res = 0; else
//{flt_val = 255.0 / T_rec_ADC; flt_val = flt_val + (-1); T_rec_res = 10000.0 / flt_val;}
T_rec_res = Get_resistanse(T_rec_ADC);
}
if (count_resistance == 3)
{
//if (T_coil_ADC > 228) T_coil_res = 0; else
//{flt_val = 255.0 / T_coil_ADC; flt_val = flt_val + (-1); T_coil_res = 10000.0 / flt_val;}
T_coil_res = Get_resistanse(T_coil_ADC);
}
if (count_resistance == 4)
{
//if (T_bat_ADC > 228) T_bat_res = 0; else
//{flt_val = 255.0 / T_bat_ADC; flt_val = flt_val + (-1); T_bat_res = 10000.0 / flt_val;}
T_bat_res = Get_resistanse(T_bat_ADC);
}
count_resistance = 0;
}
//**************************************************************************************
fan_speed = 0;
if (T_mos_res > TEMP_LO) fan_task = 0;
else if (T_mos_res < TEMP_HI) fan_task = 255;
else fan_task = Fan_power(T_mos_res);//(((INITIAL_FAN_SPEED - 255)*(T_mos_res - TEMP_HI))/(TEMP_LO - TEMP_HI)) + 255;
if (fan_task > fan_speed) fan_speed = fan_task;
if (T_rec_res > TEMP_LO) fan_task = 0;
else if (T_rec_res < TEMP_HI) fan_task = 255;
else fan_task = Fan_power(T_rec_res);//(((INITIAL_FAN_SPEED - 255)*(T_rec_res - TEMP_HI))/(TEMP_LO - TEMP_HI)) + 255;
if (fan_task > fan_speed) fan_speed = fan_task;
if (T_coil_res > TEMP_LO) fan_task = 0;
else if (T_coil_res < TEMP_HI) fan_task = 255;
else fan_task = Fan_power(T_coil_res);//(((INITIAL_FAN_SPEED - 255)*(T_coil_res - TEMP_HI))/(TEMP_LO - TEMP_HI)) + 255;
if (fan_task > fan_speed) fan_speed = fan_task;
if (T_bat_res > TEMP_LO) fan_task = 0;
else if (T_bat_res < TEMP_HI) fan_task = 255;
else fan_task = Fan_power(T_bat_res);//(((INITIAL_FAN_SPEED - 255)*(T_bat_res - TEMP_HI))/(TEMP_LO - TEMP_HI)) + 255;
if (fan_task > fan_speed) fan_speed = fan_task;
if (~(CHARGING)) fan_task = CHARGE_FAN_SPEED; else fan_task = 0;
if (fan_task > fan_speed) fan_speed = fan_task;
if (~(FAN)) fan_task = DPH_COOLING_FAN_SPEED; else fan_task = 0;
if (fan_task > fan_speed) fan_speed = fan_task;
CCPR1L = fan_speed;
//***************************************************************************************
if (T_mos_res < TEMP_AL_ON) mos_overH = 1;
if (T_mos_res < TEMP_HI) mos_hot = 1;
if (T_mos_res > TEMP_AL_OFF) { mos_overH = 0; mos_hot = 0;}
if (T_rec_res < TEMP_AL_ON) rec_overH = 1;
if (T_rec_res < TEMP_HI) rec_hot = 1;
if (T_rec_res > TEMP_AL_OFF) { rec_overH = 0; rec_hot = 0;}
if (T_coil_res < TEMP_AL_ON) coil_overH = 1;
if (T_coil_res < TEMP_HI) coil_hot = 1;
if (T_coil_res > TEMP_AL_OFF) { coil_overH = 0; coil_hot = 0;}
if (T_bat_res < TEMP_AL_ON) bat_overH = 1;
if (T_bat_res < TEMP_HI) bat_hot = 1;
if (T_bat_res > TEMP_AL_OFF) { bat_overH = 0; bat_hot = 0;}
overheat = mos_overH | rec_overH | coil_overH | bat_overH;
//***************************************************************************************
POW_CONT = ( (POW_SW) && (~(alarm_off)) );
if ( (~(POW_SW)) && (batt_OK) && (~(overheat)) ) alarm_off = 0;
//***************************************************************************************
if (send_uart)
{
send_uart = 0;
//{WriteInt(T_mos_res); UART1_Write_Text("; "); WriteInt(fan_speed); UART1_Write('\r');}
Display();
}
}
}
+23 |
1888
52
|
+47 |
2506
89
|
+165 |
3923
48
|
+24 |
1965
26
|
1.Такие аккумы нельзя тулить в легковоспламеняющийся корпус в целях безопасности;
2.Я так понял контроллер управляет обдувом.Эта функция легко реализуется по подобию
БП АТХ при помощи терморезистора(ов) и одного (двух, трех и т д по количеству банок)
транзистора для упрвления работой кулера.
3. Вместо стеклотекстолита лучше бы воздушные промежутки для охлаждения и
возможного надувания.
Я бы такие пакеты даже дома не хранил.
На выезды «без розетки» себе тоже собрал, только карманный вариант.
Скрутил из мелкого модуля с алихи и пары 18650 шоколадок.
Месяц пользуюсь, за исключением изначально дурного управления, одни плюсы. Удобная штукенция!
Только немного смущают надписи на передней панели на трёх языках :)
Это конечно мелочи по сравнению со всем остальным, но наверное надо было выбрать «наш родной» и единственный англицкий.
Может я и не прав. Не могу судить, так как сам бы такой агрегат не собрал бы точно. Ну и до надписей у меня тем более дело и не дошло бы…
Просто это первое, что «бросилось в глаза» при первом беглом просмотре статьи.
На двух — украинском и английском, русского (если вьі имели его ввиду как третий) — там нет
Но вот к реализации есть вопросы, как по мне то слишком плотная компоновка, ухудшает тепловой режим и усложняет обдув, хотя я сам так иногда делаю :)
Аккумуляторы в устройстве это интересно, но опять же, как они поведут себя со временем, лучше бы классические цилиндрические, безопасность была бы повыше, у них в крайнем случае просто клапан разомкнется. Кстати заряжать их лучше в режиме, когда блок наименее нагружен, аккумуляторы плохо относятся к перегреву во время заряда.
Функционал. Здесь фактически его обеспечивает сам преобразователь, остальное выполняет больше сервисные функции, так что вопросов нет
Управление вентилятором это хорошо, но индикация как по мне, излишня, хотя это дело вкуса. Я бы наверное делал так, чтобы оно «само работало», не отвлекая внимание. Либо как вариант, под надписями контролируемых узлов поставил по двухцветному светодиоды и выводил в режиме зеленый-оранжевый-красный :)
Насчет передней панели поддержу комментатора victorz, лучше при оформлении придерживаться какого-то одного языка, смотрелось бы гармоничнее.
Также вопрос к размещению выходных клемм, почему не поставили слева, Вам они не мешают при регулировке энкодером?
Если в общем, то интересно и необычно, автору плюс, видно что старался, да и оформил все красиво и аккуратно, а до этого этапа далеко не у всех доходит.
P.S. Чтобы фотка на заглавной смотрелась аккуратно, она должна быть квадратной, т.е. с одинаковым соотношением сторон, иначе муська искажает изображение.
Крутой комбайн. Реально — крутой.
Но повторить его, уверен, никто не захочет.
Я поступил проще, тот же DPH5005, в стандартном корпусе, а к нему хвостик с ХТ60, на который и блок питания от ноута 19В 3.5А можно, и блок LiPo 3S, и коробочку с 4S 18650, и крокодилы, и прикуриватель.
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.