Климат контроль для автомобиля

Kompaniets86
Offline
Зарегистрирован: 07.02.2015

Всем привет.

Хочу сделать проэкт климат конроля для автомобиля.

Задумка такая:

На потолке в авто поставить датчик температуры/влажности, на печку присобащить сервопривод.

Хочу чтоб можно было задавать необходимую температуру с помощью вращения потенциометра, а сервопривод будет управлять заслонкой печки добиваясь тем самым необходимой температуры в салоне.

Все параметры заданной и фактической температуры должны отображатся на цветном oled дисплее.

Подскажите с чего начать , т.к опыта нету.

 

arter
Offline
Зарегистрирован: 16.01.2015

я тоже думал об этом, только вот в чем вопрос, при сильном холоде, надо быстро нагреть машину, то есть надо на максимум ветер и на максимум тепло, ладно как то нагрели... при ззапотевании лобового надо переключиться на лобовое стекло, допустим переключили в ручную, а дует то слабо или не с той температурой, может в твоей по другому будет, просто у меня 3 переключатель (крутилки), одна заслонки, лобовое, ноги; вторая это 4 скорости вентилятора; и тепло холод: И как то у меня нет пока надумок как сделать что бы и в ручную можно было переключать и автоматически. и еще на сколько я помню сервопривод крутится только на 180градусов, а ручка тепло холод где то на 290-300 градусов

buba
buba аватар
Offline
Зарегистрирован: 08.02.2015

мне кажется только на потолке датчика недостаточно,на предыдущем автомобиле у меня точно знаю были в полу,в панели,может и ещё где,но то был климат контроль в комплекте)с авто,и вот боги смилостивелись и послали мне русскую машину ваз09,скажу даже рад что могу поэксперементировать ,хочу покрайней мере начать управлять через шим вентелятором печки,дальше по необходимости,такую вот задачу себе поставил минимум)

сервы сейчас есть и на 350град крутят,тут вопрос в другом ,сразу всё в кучу и серво,и темп.контроль,запутаешься,это моё мнение,я бы начал с шим регулирования,но так как програмировал в основном производственное оборудование контроллеры сименс и т.п.с этим не сталкивался ,а к ардуино так сказать по наводке начал присматриваться,что-то уже получается но мне гораздо проще програмировать через FLprog ,схожая с step S7 среда,но вот теперь возникла необходимость в написании отдельных блоков в среде ардуино ,учусь вот.

по примеру современного холодильника,вентилятор один ,зон две (в холодильном отделении)био фреш 0град,и остальная 2-9 град,чем не повод задуматься,и взять за прообраз например,а когда уже будет понятно как распостраняется тепло,тогда уже и с заслонками можно поиграться,для написания управления регулировкой вентилятора можно использовать следующий алгоритм-так было на хонде,на холодном двигателе (соответственно нужен датчик охл.жидкости)вентилятор работает на мин.,с прогревом обороты растут но не более 3/4 от мах.,при достижении заданной температуры падают ,но не меньше мин.как-то так 

SU-27-16
SU-27-16 аватар
Offline
Зарегистрирован: 13.08.2012

Kompaniets86 пишет:

На потолке в авто поставить датчик температуры/влажности, на печку присобащить сервопривод.

Хочу чтоб можно было задавать необходимую температуру с помощью вращения потенциометра, а сервопривод будет управлять заслонкой печки добиваясь тем самым необходимой температуры в салоне.

Все параметры заданной и фактической температуры должны отображатся на цветном oled дисплее.

Подскажите с чего начать , т.к опыта нету.

- считывать данные с потенциометра

- считывать показания с датчиков температуры и влажности

- управлять сервой

- выводить данные на LCD_20_4 ( он проще цветного oled дисплея )

- изучить ПИД-регулятор ( ПропорциональноИнтегральноДифференциальный регулятор ) ( это пока рано )

машинка какая ?

SU-27-16
SU-27-16 аватар
Offline
Зарегистрирован: 13.08.2012

Kompaniets86, знаете кого-либо из выпуска КВИРТУ-87 ?

Kompaniets86
Offline
Зарегистрирован: 07.02.2015

Не не знаю.

Kompaniets86
Offline
Зарегистрирован: 07.02.2015

Вобщем пока жду ве барахло из поднебесной, все уже заказал.

А сервопривод и не нужно чтоб на 360, град, я его подключу к тросику, а там всего да 100 град.

SU-27-16
SU-27-16 аватар
Offline
Зарегистрирован: 13.08.2012

чем больше рычаг сервы, тем меньше угол

DenVik
Offline
Зарегистрирован: 03.03.2016

Скажите, чем закончился проект? Удалось ли его воплотить в жизнь?

AndreyFly
Offline
Зарегистрирован: 26.03.2016

У меня в Матизе стоит управление климатом, собранное на микрочиповском контроллере. Сейчас собираюсь переделать на ардуино уно с сенсорным дисплеем 2,8 дюйма. Проблем при переделке было много. Вот немногие. Сервомашинки цифровые с 10кг момента на валу не справляются с заслонками, когда напор воздуха на них давит. Сейчас заказал с моментом в 20 кг (3 сервомашинки 40$). Сервомашинка лежащая на столе  имеющая небольшой джиттер практически бесшумна, при фиксации ее жестко к кузову - становится как музыкальная шкатулка - крепить надо будет через демпфер резиновый. В первой моей конструкции небыло поддержания температуры, просто выбираем любой режим вручную, и все работает. Целью было уйти от крутилок, которые занимали много места, а перенести в другое место (ниже или выше) - тросики не давали. Все это было сделано, чтобы поставить 2ДИН магнитолу. Из моего мнения - обороты вентилятора выбирать самому, положение обдува (ноги, стекло, центр) выбирать самому. Температуру в салоне регулировать по двум датчикам температуры управлением заслонкой. Также у меня реализованно плавный старт мотора печки и плавная смена оборотов.

Short Circuit
Short Circuit аватар
Offline
Зарегистрирован: 17.05.2015

скажите, разбирать торпеду для смены заслонок на матизе - сильно пришлось?

AndreyFly
Offline
Зарегистрирован: 26.03.2016

Нет, только передний фартук, в котором климат стоит. и бардачек 2 шурупа. Там ко всем узлам печки можно подлезть без проблем. Я просто делал все за одно, и снимал полностью всю панель приборов, всю торпеду, и печку. Делал обесшумку, и всю машину зафлокировал (она у меня теперь бархатная внутри вся), заодно и климат перебрал...

axill
Offline
Зарегистрирован: 05.09.2011

 из того что я видел в конструкции климат контроля на японке могу рекомендовать следующее:

- датчиков нужно ставить несколько, чтобы контролировать температуру в нескольких точках салона

- просто поставить датчик мало, нужно обеспечить около него циркуляцию воздуха, иначе комфорта не получить - замер датчиком около потолка/панели/пола будет сильно отличаться от температуры воздуха в середине салона. Можно или маленький вентилятор поставить или еще что то придумать. В японке датчик на консоли был хитро установлен перед тонкой трубочкой которая была дальше где то подсоеденена к воздуховоду так, что вентилятор печки в ней обеспечивал разряжение и воздух в эту трубочку засасывался в микроскопических объемах, но достаточно, чтобы постоянно обдувать датчик

- управлять заслонкой мало, как минимум еще нужно управлять оборотами вентилятора, а еще лучше и возможность менять направление тока воздуха. С тем, чтобы создать не просто какую то среднюю температуру в салоне, а обеспечить комфорт и в ногах, и на уровне груди и на уровне лица.

AndreyFly
Offline
Зарегистрирован: 26.03.2016

Я с Вами полностью согласен, но у меня не лексус 2016 года, а малолитражка с низкопроизводительным мотором вентилятора, и в пасмурный день у меня чтобы не потели стекла на выбор 2 варианта. Обдув на стекло, обдув на стекло и ноги. И ни в одном из вариантов нету, чтобы убавить обороты вентилятора, только на максимум. При этом стекла задних пассажиров и стекло заднее будет запотевшее. Ни о каком температурном комфорте у меня даже мыслей нет. Мне кажется, что переделывать печку начинают те, кого не устраивает штатная, а это машины среднего класса, где есть и сквозняки, и либо передние пассажиры сгорают от жары, а задние пассажиры едут комфортно, либо передние едут комфортно, а задние мерзнут. Чтобы исправить положение - требуется не только много датчиков по всей машине, но и много воздуховодов, во все точки авто с независимой регулировкой температуры воздуха в каждом. Возможно я и ошибаюсь, но это мое личное мнение. Проблема многих машин не в управлении печкой, а в ее возможностях физически прогревать салон равномерно и комфортно для всех одинаково.

DenVik
Offline
Зарегистрирован: 03.03.2016

Так то оно да, но ведь можно дополнительные печки поставить, воздуховоды провести.

AndreyFly
Offline
Зарегистрирован: 26.03.2016

На каждую печку и воздуховод надо отдельное управление температурой потока и скоростью потока воздуха. Цена девайса растет, сервомашинки только стоят недешего, а надо 2 на воздуховод (объем и температура). Думаю ардуино стоит 8 длолларов, экран 5 долларов, сервомашинки в стандартную систему поставить 13х3 = 39 долларов. Датчики температуры 2 доллара за штуку. Стабилизатор питания 5 вольт (BEC) около 7 долларов. Шимка на мосфете пару долларов для управления мотором печки, и мосфет для обогрева заднего стекла. Вот и считайте бюджет самоделки. Каждый воздуховод будет удорожать стоимость минимум на 40 долларов. Может это кому и надо, я так вкладываться не хочу :) 

AndreyFly
Offline
Зарегистрирован: 26.03.2016

Вот мой код под Pic18f452, схема в голове, печатка была в спринтлайоуте, но найти не могу. Хотя по программе итак понятно на какой ноге кнопка, на какой светодиод, на какой сервомашинка, на какой ноге ШИМ вентилятора, и ШИМ яркости подсветки климата.

#include <htc.h>

// PIC 18F452 fuse configuration:
// Config word 1 (Oscillator configuration)
// 4Mhz crystal
__CONFIG(1, OSCSDIS & HS);
// Config word 2
__CONFIG(2, BORDIS & PWRTDIS & WDTDIS);
// Config word 3
__CONFIG(3, CCP2RC1);
// Config word 4
__CONFIG(4, DEBUGDIS & LVPDIS & STVREN);
// Config word 5, 6 and 7 (protection configuration)
__CONFIG(5, UNPROTECT);
__CONFIG(6, WRTEN);
__CONFIG(7, TRU);

// Bank 0
__EEPROM_DATA( 0x00,0x0f,0x19,0x23,0x2E,0x00,0x04,0x00 ); // speedmotor[5] = 0 , 15 , 25 , 35 , 46   по адресу 6,7 хранится последняя настройка отопителя
__EEPROM_DATA( 0x00,0x00,0x03,0x84,0x04,0xC9,0x06,0x0E ); // PPM1[6] = 0, 900, 1225, 1550, 1875, 2200
__EEPROM_DATA( 0x07,0x53,0x08,0x98,0x00,0x00,0x00,0x00 ); // 2х байтовые константы, сначала старший, потом младший байты
__EEPROM_DATA( 0x00,0x00,0x03,0x84,0x08,0x98,0x00,0x00 ); // PPM2[3] = 0, 900, 2200
// Bank 1
__EEPROM_DATA( 0x0A,0x2E,0x03,0x84,0x08,0x98,0x00,0x00 ); // PWMMin, PWMMax, PPMMin - 2 байта, PPMMax - 2 байта
__EEPROM_DATA( 0x0A,0x05,0x00,0x00,0x00,0x00,0x00,0x00 ); // DayLight, NightLight
__EEPROM_DATA( 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 );
__EEPROM_DATA( 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 );

#define KeyCount 1
#define KeyLong  100
#define KeyLong2 250

volatile unsigned char PinPress[8];
volatile unsigned char KeyLongPress[8];
volatile unsigned char KeyLongPress2[8];
volatile unsigned char Status1;
volatile unsigned char Status2;
volatile unsigned char Status3;
volatile unsigned int ObogrevTime;
volatile unsigned char Vvod;
volatile unsigned char Obogrev;
volatile unsigned char PWMMotorSel;
volatile unsigned int ADCResult;
volatile unsigned char KeyPressed[8];
volatile unsigned int Servos[4];
volatile unsigned int PWM;
volatile unsigned char Setup;
volatile unsigned char Start;
volatile unsigned char Ticks;
volatile unsigned char speedmotor[5];
volatile unsigned int PPM1[6];
volatile unsigned int PPM2[3];
volatile unsigned char NeedWriteEeprom;
volatile unsigned char Menu;
volatile signed char Correct;
volatile unsigned char PWMMax;
volatile unsigned char PWMMin;
volatile unsigned int PPMMax;
volatile unsigned int PPMMin;
volatile unsigned char DayLight;
volatile unsigned char NightLight;
volatile unsigned char ServoWorks;
volatile unsigned int PauseWrite;
volatile unsigned int Temp;

void InitADC(void);
void InitServo(void);
void InitButton(void);
void InitLED(void);
void KeyScan(void);
unsigned int GetADCValue(void);
void InitPWM(void);
void SetPWMDutyCycle(unsigned char, unsigned int);
void WorkKey(void);
void ADCMotor(void);
void RefreshPWMMotor(void);
void InitParametrs(void);
void SetupKey(void);
void SaveParametrs(void);


void InitADC(void)
{
    ADCS1  	= 0; // 8 tosc
    ADCS0	= 1; // 8 tosc
    ADON	= 1; // включить АЦП
    
    ADFM	= 1; // правое выравнивание
    ADCS2	= 0; // 8 tosc
    PCFG3	= 0; // AN0, AN1, AN3
    PCFG2	= 1;
    PCFG1	= 0;
    PCFG0	= 0;
    LVDEN = 0;
    SSPEN = 0;
    
    ADIE = 0;

    TRISA = 0b00011111; //RA2 вход габаритов, RA5 выход обогрева
    LATA5 = 0;
    TRISA5 = 0;
}

void InitServo(void)
{
    LATE0 = 0;
    LATE1 = 0;
    LATE2 = 0;
    TRISE0 = 0;
    TRISE1 = 0;
    TRISE2 = 0;
    RD16 = 0;
    T1CKPS0 =0;
    T1CKPS1 =0;
    TMR1CS = 0;
    T1OSCEN = 0;
    TMR1H = 0xB1;
    TMR1L = 0xE1;
    TMR1IF=0; 
    TMR1IE=1;
    PEIE=1;
    GIE=1;
    TMR1ON = 1;
    PSPMODE = 0;
}

void InitButton(void)
{
    RBIE = 0;
    TRISB = 255;
    RBPU = 0;
}

void SaveParametrs(void) //только после настройки используется
{
  
    EEPROM_WRITE(0, 0);
    EEPROM_WRITE(1, speedmotor[1]);    
    EEPROM_WRITE(2, speedmotor[2]);  
    EEPROM_WRITE(3, speedmotor[3]);  
    EEPROM_WRITE(4, PWMMax);  
  
    EEPROM_WRITE(8, (PPM1[0] >> 8)); 
    EEPROM_WRITE(9, PPM1[0]);
    
    EEPROM_WRITE(10, (PPM1[1] >> 8)); 
    EEPROM_WRITE(11, PPM1[1]);
    
    EEPROM_WRITE(12, (PPM1[2] >> 8)); 
    EEPROM_WRITE(13, PPM1[2]);
    
    EEPROM_WRITE(14, (PPM1[3] >> 8)); 
    EEPROM_WRITE(15, PPM1[3]);
    
    EEPROM_WRITE(16, (PPM1[4] >> 8)); 
    EEPROM_WRITE(17, PPM1[4]);
    
    EEPROM_WRITE(18, (PPM1[5] >> 8)); 
    EEPROM_WRITE(19, PPM1[5]);  
    
    EEPROM_WRITE(24, (PPM2[0] >> 8)); 
    EEPROM_WRITE(25, PPM2[0]);  
    
    EEPROM_WRITE(26, (PPM2[1] >> 8)); 
    EEPROM_WRITE(27, PPM2[1]);  
    
    EEPROM_WRITE(28, (PPM2[2] >> 8)); 
    EEPROM_WRITE(29, PPM2[2]);  

    EEPROM_WRITE(32, PWMMin);
    EEPROM_WRITE(33, PWMMax);    
                    
    EEPROM_WRITE(40, DayLight);
    EEPROM_WRITE(41, NightLight);    

    EEPROM_WRITE(34, (PPMMin >> 8)); 
    EEPROM_WRITE(35, PPMMin); 
    
    EEPROM_WRITE(36, (PPMMax >> 8)); 
    EEPROM_WRITE(37, PPMMax); 

}

void InitParametrs(void)
{
    NeedWriteEeprom = 0;
    Ticks = 0;
    Start = 1;
    Setup = 0; 
    Menu = 1;     
    
    speedmotor[0]          = eeprom_read( 0 )  ;
    speedmotor[1]          = eeprom_read( 1 )  ;
    speedmotor[2]          = eeprom_read( 2 )  ;
    speedmotor[3]          = eeprom_read( 3 )  ;
    speedmotor[4]          = eeprom_read( 4 )  ;
  
    PPM1[0]                = (((eeprom_read( 8 ))<<8) + (eeprom_read( 9 )))  ;
    PPM1[1]                = (((eeprom_read( 10 ))<<8) + (eeprom_read( 11 )))  ;
    PPM1[2]                = (((eeprom_read( 12 ))<<8) + (eeprom_read( 13 )))  ;
    PPM1[3]                = (((eeprom_read( 14 ))<<8) + (eeprom_read( 15 )))  ;
    PPM1[4]                = (((eeprom_read( 16 ))<<8) + (eeprom_read( 17 )))  ;
    PPM1[5]                = (((eeprom_read( 18 ))<<8) + (eeprom_read( 19 )))  ;
      

    PPM2[0]                = (((eeprom_read( 24 ))<<8) + (eeprom_read( 25 )))  ;
    PPM2[1]                = (((eeprom_read( 26 ))<<8) + (eeprom_read( 27 )))  ;
    PPM2[2]                = (((eeprom_read( 28 ))<<8) + (eeprom_read( 29 )))  ;

    Status1                 = eeprom_read( 6 )  ;
    Status2                 = eeprom_read( 7 )  ;

    PWMMin                 = eeprom_read( 32 )  ;
    PWMMax                 = eeprom_read( 33 )  ;

    PPMMin                 = (((eeprom_read( 34 ))<<8) + (eeprom_read( 35 )))  ;
    PPMMax                 = (((eeprom_read( 36 ))<<8) + (eeprom_read( 37 )))  ;
    
    DayLight               = eeprom_read( 40 )  ;
    NightLight             = eeprom_read( 41 )  ;
    
    if (Status1 == 1)
    { 
        Servos[1] = PPM1[1];
        LATD5 = 1;
        LATD6 = 0;
        LATD7 = 0;
        LATD4 = 0;
        LATD2 = 0;
    }    
     if (Status1 == 2)
    { 
        Servos[1] = PPM1[2];
        LATD6 = 1;
        LATD5 = 0;
        LATD7 = 0;
        LATD4 = 0;
        LATD2 = 0;
    }    
    if (Status1 == 3)
    { 
        Servos[1] = PPM1[3];
        LATD7 = 1;
        LATD5 = 0;
        LATD6 = 0;
        LATD4 = 0;
        LATD2 = 0;
    }    
    if (Status1 == 4)
    { 
        Servos[1] = PPM1[4];
        LATD4 = 1;
        LATD5 = 0;
        LATD6 = 0;
        LATD7 = 0;
        LATD2 = 0;
    }    
    if (Status1 == 5)
    { 
        Servos[1] = PPM1[5];
        LATD2 = 1;
        LATD5 = 0;
        LATD6 = 0;
        LATD7 = 0;
        LATD4 = 0;
    }    


    if (Status2 == 1)
    {
        Servos[2] = PPM2[2];
        LATD1 = 1;
        Vvod = 1;
    }
    else
    {
        Servos[2] = PPM2[1];
        LATD1 = 0;
        Vvod = 0;
    }    
    Obogrev = 0;
    LATD0 = 0;
    NOP();
    NOP();
    LATA5 = 0; 
    NOP();
    NOP();    
    ObogrevTime = 0;
    Status3 = 0;

  
}


void InitLed(void)
{
 
    TRISD = 0;
    LATD = 0;
    
}


void KeyScan(void)
{
    if (RB0 == 0)
    {
        PinPress[1] = PinPress[1] + 1;
        if (PinPress[1] > KeyLong)     // если кнопка удерживается дольше 2 секунд (для функции настройки)
        {
            KeyLongPress[1] = 1;
        }
        if (PinPress[1] > KeyLong2)     // если кнопка удерживается дольше 16 секунд (для входа в настройки  и корректировки серво)
        {
            KeyLongPress2[1] = 1;
            PinPress[1] = KeyLong2;    // не даем выйти за предел 255
        }
    }    
    else                                   // если отпущена или не нажата
    {
        if ((PinPress[1] > KeyCount) && (PinPress[1] <= KeyLong2))      // до  отпускания кнопка удерживалась более 0.1 сек но меньше 2х секунд
        {
            KeyPressed[1] = 1;
        }
        else
        {
            KeyPressed[1] = 0;
            KeyLongPress[1] = 0;
            KeyLongPress2[1] = 0;
        }
        PinPress[1]=0;                    // после отпускания обнуляем счетчик


    }
     if (RB1 == 0)
    {
        PinPress[2] = PinPress[2] + 1;
        if (PinPress[2] > KeyLong)     // если кнопка удерживается дольше 2 секунд (для функции настройки)
        {
            KeyLongPress[2] = 1;
        }
        if (PinPress[2] > KeyLong2)     // если кнопка удерживается дольше 16 секунд (для входа в настройки  и корректировки серво)
        {
            KeyLongPress2[2] = 1;
            PinPress[2] = KeyLong2;    // не даем выйти за предел 255
        }
    }    
    else                                   // если отпущена или не нажата
    {
        if ((PinPress[2] > KeyCount) && (PinPress[2] <= KeyLong2))      // до  отпускания кнопка удерживалась более 0.1 сек но меньше 2х секунд
        {
            KeyPressed[2] = 1;
        }
        else
        {
            KeyPressed[2] = 0;
            KeyLongPress[2] = 0;
            KeyLongPress2[2] = 0;
        }
        PinPress[2]=0;                    // после отпускания обнуляем счетчик


    }
    if (RB2 == 0)
    {
        PinPress[3] = PinPress[3] + 1;
        if (PinPress[3] > KeyLong)     // если кнопка удерживается дольше 2 секунд (для функции настройки)
        {
            KeyLongPress[3] = 1;
        }
        if (PinPress[3] > KeyLong2)     // если кнопка удерживается дольше 16 секунд (для входа в настройки  и корректировки серво)
        {
            KeyLongPress2[3] = 1;
            PinPress[3] = KeyLong2;    // не даем выйти за предел 255
        }
    }    
    else                                   // если отпущена или не нажата
    {
        if ((PinPress[3] > KeyCount) && (PinPress[3] <= KeyLong2))      // до  отпускания кнопка удерживалась более 0.1 сек но меньше 2х секунд
        {
            KeyPressed[3] = 1;
        }
        else
        {
            KeyPressed[3] = 0;
            KeyLongPress[3] = 0;
            KeyLongPress2[3] = 0;
        }
        PinPress[3]=0;                    // после отпускания обнуляем счетчик


    }
    if (RB3 == 0)
    {
        PinPress[4] = PinPress[4] + 1;
        if (PinPress[4] > KeyLong)     // если кнопка удерживается дольше 2 секунд (для функции настройки)
        {
            KeyLongPress[4] = 1;
        }
        if (PinPress[4] > KeyLong2)     // если кнопка удерживается дольше 16 секунд (для входа в настройки  и корректировки серво)
        {
            KeyLongPress2[4] = 1;
            PinPress[4] = KeyLong2;    // не даем выйти за предел 255
        }
    }    
    else                                   // если отпущена или не нажата
    {
        if ((PinPress[4] > KeyCount) && (PinPress[4] <= KeyLong2))      // до  отпускания кнопка удерживалась более 0.1 сек но меньше 2х секунд
        {
            KeyPressed[4] = 1;
        }
        else
        {
            KeyPressed[4] = 0;
            KeyLongPress[4] = 0;
            KeyLongPress2[4] = 0;
        }
        PinPress[4]=0;                    // после отпускания обнуляем счетчик


    }
    if (RB4 == 0)
    {
        PinPress[5] = PinPress[5] + 1;
        if (PinPress[5] > KeyLong)     // если кнопка удерживается дольше 2 секунд (для функции настройки)
        {
            KeyLongPress[5] = 1;
        }
        if (PinPress[5] > KeyLong2)     // если кнопка удерживается дольше 16 секунд (для входа в настройки  и корректировки серво)
        {
            KeyLongPress2[5] = 1;
            PinPress[5] = KeyLong2;    // не даем выйти за предел 255
        }
    }    
    else                                   // если отпущена или не нажата
    {
        if ((PinPress[5] > KeyCount) && (PinPress[5] <= KeyLong2))      // до  отпускания кнопка удерживалась более 0.1 сек но меньше 2х секунд
        {
            KeyPressed[5] = 1;
        }
        else
        {
            KeyPressed[5] = 0;
            KeyLongPress[5] = 0;
            KeyLongPress2[5] = 0;
        }
        PinPress[5]=0;                    // после отпускания обнуляем счетчик


    }
    if (RB5 == 0)
    {
        PinPress[6] = PinPress[6] + 1;
        if (PinPress[6] > KeyLong)     // если кнопка удерживается дольше 2 секунд (для функции настройки)
        {
            KeyLongPress[6] = 1;
        }
        if (PinPress[6] > KeyLong2)     // если кнопка удерживается дольше 16 секунд (для входа в настройки  и корректировки серво)
        {
            KeyLongPress2[6] = 1;
            PinPress[6] = KeyLong2;    // не даем выйти за предел 255
        }
    }    
    else                                   // если отпущена или не нажата
    {
        if ((PinPress[6] > KeyCount) && (PinPress[6] <= KeyLong2))      // до  отпускания кнопка удерживалась более 0.1 сек но меньше 2х секунд
        {
            KeyPressed[6] = 1;
        }
        else
        {
            KeyPressed[6] = 0;
            KeyLongPress[6] = 0;
            KeyLongPress2[6] = 0;
        }
        PinPress[6]=0;                    // после отпускания обнуляем счетчик


    }
    if (RB6 == 0)
    {
        PinPress[7] = PinPress[7] + 1;
        if (PinPress[7] > KeyLong)     // если кнопка удерживается дольше 2 секунд (для функции настройки)
        {
            KeyLongPress[7] = 1;
        }
        if (PinPress[7] > KeyLong2)     // если кнопка удерживается дольше 16 секунд (для входа в настройки  и корректировки серво)
        {
            KeyLongPress2[7] = 1;
            PinPress[7] = KeyLong2;    // не даем выйти за предел 255
        }
    }    
    else                                   // если отпущена или не нажата
    {
        if ((PinPress[7] > KeyCount) && (PinPress[7] <= KeyLong2))      // до  отпускания кнопка удерживалась более 0.1 сек но меньше 2х секунд
        {
            KeyPressed[7] = 1;
        }
        else
        {
            KeyPressed[7] = 0;
            KeyLongPress[7] = 0;
            KeyLongPress2[7] = 0;
        }
        PinPress[7]=0;                    // после отпускания обнуляем счетчик


    }


}


	
unsigned int GetADCValue(void)
{
	while(GODONE);        // Wait for conversion completion

	return ((ADRESH<<8)+ADRESL);   // Return 10 bit ADC value
}



void InitPWM(void)
{
	TRISC1  = 0; 			  // Make CCP2 pin as output
	TRISC2  = 0;              // Make CCP1 pin as output
	CCP1CON = 0x0C;           // Configure CCP1 module in PWM mode
	CCP2CON = 0x0C;           // Configure CCP2 module in PWM mode

	PR2   = PWMMax;             // Configure the Timer2 period (46) 4000000\4\22000+1
	T2CON = 0x00;             // Set no Prescaler, hence PWM frequency is set to 22KHz.

	SetPWMDutyCycle(1, 0);    // Intialize the CCP1 PWM to 0 duty cycle
	SetPWMDutyCycle(2, 0);    // Intialize the CCP2 PWM to 0 duty cycle

	T2CON |= 0x04;            // Enable the Timer2, hence enable the PWM.
    PWMMotorSel = 0;
}

void SetPWMDutyCycle(unsigned char CCP, unsigned int DutyCycle)      // Give a value in between 0 and 255 for DutyCycle
{
	switch(CCP)
	{
	case 1:
		CCPR1L   = DutyCycle;        	// Put MSB 8 bits in CCPR1L
		break;
	case 2:
		CCPR2L   = DutyCycle;        	// Put MSB 8 bits in CCPR2L
		break;
	}
}

void WorkKey(void)
{
    if (KeyPressed[1])
    { 
        Servos[1] = PPM1[1];
        LATD5 = 1;
        LATD6 = 0;
        LATD7 = 0;
        LATD4 = 0;
        LATD2 = 0;
        Status1 = 1;
        NeedWriteEeprom = 1; //Записать новое значение в EEPROM
        PauseWrite = 500; //Но не сразу, а выждав 10 секунд (на случай если пользователь дальше настраивает климат))
    }    
    if (KeyPressed[2])
    { 
        Servos[1] = PPM1[2];
        LATD6 = 1;
        LATD5 = 0;
        LATD7 = 0;
        LATD4 = 0;
        LATD2 = 0;
        Status1 = 2;
        NeedWriteEeprom = 1; //Записать новое значение в EEPROM
        PauseWrite = 500; //Но не сразу, а выждав 10 секунд (на случай если пользователь дальше настраивает климат))
    }    
    if (KeyPressed[3])
    { 
        Servos[1] = PPM1[3];
        LATD7 = 1;
        LATD5 = 0;
        LATD6 = 0;
        LATD4 = 0;
        LATD2 = 0;
        Status1 = 3;
        NeedWriteEeprom = 1; //Записать новое значение в EEPROM
        PauseWrite = 500; //Но не сразу, а выждав 10 секунд (на случай если пользователь дальше настраивает климат))
    }    
    if (KeyPressed[4])
    { 
        Servos[1] = PPM1[4];
        LATD4 = 1;
        LATD5 = 0;
        LATD6 = 0;
        LATD7 = 0;
        LATD2 = 0;
        Status1 = 4;
        NeedWriteEeprom = 1; //Записать новое значение в EEPROM
        PauseWrite = 500; //Но не сразу, а выждав 10 секунд (на случай если пользователь дальше настраивает климат))
    }    
    if (KeyPressed[5])
    { 
        Servos[1] = PPM1[5];
        LATD2 = 1;
        LATD5 = 0;
        LATD6 = 0;
        LATD7 = 0;
        LATD4 = 0;
        Status1 = 5;
        NeedWriteEeprom = 1; //Записать новое значение в EEPROM
        PauseWrite = 500; //Но не сразу, а выждав 10 секунд (на случай если пользователь дальше настраивает климат))
    }    


    if (KeyPressed[6])
    {
        NeedWriteEeprom = 1; //Записать новое значение в EEPROM
        PauseWrite = 500;    //Но не сразу, а выждав 10 секунд (на случай если пользователь дальше настраивает климат))
        Vvod = 1 - Vvod;
        if (Vvod)
        {
            Servos[2] = PPM2[2];
            LATD1 = 1;
            Status2 = 1;
        }
        else
        {
            Servos[2] = PPM2[1];
            LATD1 = 0;
            Status2 = 0;
        }    
            
    }
    if (KeyPressed[7])
    {
        Obogrev = 1 - Obogrev;
        if (Obogrev)
        {
            LATD0 = 1;
            NOP();
            NOP();             
            LATA5 = 1;           
            NOP();
            NOP();
            ObogrevTime = 15000;   //Обогрев отключится через 5 минут 50Гц х 60сек х 5 мин
        }
        else
        {
            LATD0 = 0; 
            NOP();
            NOP();
            LATA5 = 0;
            NOP();
            NOP();
            ObogrevTime = 0;
        } 
    }       
    if (ObogrevTime>0)
    {
        ObogrevTime = ObogrevTime - 1;
    }
    else if (Obogrev == 1)
    {
        Obogrev = 0;
        LATD0 = 0;
        NOP();
        NOP();
        LATA5 = 0;
        NOP();
        NOP();
        ObogrevTime = 0;
    }
    if (PauseWrite>0)
    {
        PauseWrite = PauseWrite - 1;
    }
    else if (NeedWriteEeprom == 1)
    {
        EEPROM_WRITE(6, Status1);
        EEPROM_WRITE(7, Status2);
        NeedWriteEeprom = 0;
    }    
    if (KeyLongPress2[6] == 1)
    {
        Setup = 1;
        LATD5 = 0;
        LATD6 = 0;
        LATD7 = 0;
        LATD4 = 0;
        LATD2 = 0;
        LATD1 = 0;
        LATD0 = 0;
    }
}

void SetupKey(void)
{
    if (KeyPressed[3] == 1)
    {
        Menu = Menu + 1;
        if (Menu > 16)
        {
            Menu = 1;
        }
    }
    Correct = 0;
    if ((KeyPressed[2] == 1)||(KeyLongPress[2] == 1))
    {
        Correct = 1;
    }
    if ((KeyPressed[1] == 1)||(KeyLongPress[1] == 1))
    {
        Correct = -1;
    }
    if ((KeyPressed[5] == 1)||(KeyLongPress[5] == 1))
    {
        Correct = 10;
    }
    if ((KeyPressed[4] == 1)||(KeyLongPress[4] == 1))
    {
        Correct = -10;
    }    
        if (Menu == 1)    // настройки серво 1 обдув груди
        {
            LATD5 = 1;
            LATD6 = 0;
            LATD7 = 0;
            LATD4 = 0;
            LATD2 = 0;
            LATD1 = 0;
            LATD0 = 0;
            PPM1[1] = PPM1[1] + Correct; 
            Servos[1] = PPM1[1];
        }    
        if (Menu == 2)    // настройки серво 1 обдув груди_ног
        {
            LATD5 = 0;
            LATD6 = 1;
            LATD7 = 0;
            LATD4 = 0;
            LATD2 = 0;
            LATD1 = 0;
            LATD0 = 0;
            PPM1[2] = PPM1[2] + Correct; 
            Servos[1] = PPM1[2];
        }
        if (Menu == 3)    // настройки серво 1 обдув ног
        {
            LATD5 = 0;
            LATD6 = 0;
            LATD7 = 1;
            LATD4 = 0;
            LATD2 = 0;
            LATD1 = 0;
            LATD0 = 0;
            PPM1[3] = PPM1[3] + Correct; 
            Servos[1] = PPM1[3];        
        }
        if (Menu == 4)    // настройки серво 1 обдув ног_стекла
        {
            LATD5 = 0;
            LATD6 = 0;
            LATD7 = 0;
            LATD4 = 1;
            LATD2 = 0;
            LATD1 = 0;
            LATD0 = 0;
            PPM1[4] = PPM1[4] + Correct; 
            Servos[1] = PPM1[4];        
        }
        if (Menu == 5)    // настройки серво 1 обдув стекла
        {
            LATD5 = 0;
            LATD6 = 0;
            LATD7 = 0;
            LATD4 = 0;
            LATD2 = 1;
            LATD1 = 0;
            LATD0 = 0;
            PPM1[5] = PPM1[5] + Correct; 
            Servos[1] = PPM1[5];        
        }
        if (Menu == 6)    // настройки серво 2 забор воздуха улица
        {
            LATD5 = 1;
            LATD6 = 0;
            LATD7 = 0;
            LATD4 = 0;
            LATD2 = 0;
            LATD1 = 1;
            LATD0 = 0;
            PPM2[1] = PPM2[1] + Correct; 
            Servos[2] = PPM2[1];        
        }
        if (Menu == 7)    // настройки серво 2 забор воздуха салон
        {
            LATD5 = 0;
            LATD6 = 1;
            LATD7 = 0;
            LATD4 = 0;
            LATD2 = 0;
            LATD1 = 1;
            LATD0 = 0;
            PPM2[2] = PPM2[2] + Correct; 
            Servos[2] = PPM2[2];            
        }
        if (Menu == 12)                      // корректировка 0 положения мотора и низ отключения мотора
        {
            LATD5 = 1;
            LATD6 = 0;
            LATD7 = 0;
            LATD4 = 0;
            LATD2 = 0;
            LATD1 = 0;
            LATD0 = 1;
            PWMMin = PWMMin + Correct;
            PWMMotorSel = PWMMin;        
        }
        if (Menu == 11)                      // корректировка 1 положения мотора
        {
            LATD5 = 0;
            LATD6 = 1;
            LATD7 = 0;
            LATD4 = 0;
            LATD2 = 0;
            LATD1 = 0;
            LATD0 = 1;
            speedmotor[1] = speedmotor[1] + Correct;
            PWMMotorSel = speedmotor[1];
        }
        if (Menu == 10)                      // корректировка 2 положения мотора
        {
            LATD5 = 0;
            LATD6 = 0;
            LATD7 = 1;
            LATD4 = 0;
            LATD2 = 0;
            LATD1 = 0;
            LATD0 = 1;
            speedmotor[2] = speedmotor[2] + Correct;
            PWMMotorSel = speedmotor[2];
        }
        if (Menu == 9)                      // корректировка 3 положения мотора
        {
            LATD5 = 0;
            LATD6 = 0;
            LATD7 = 0;
            LATD4 = 1;
            LATD2 = 0;
            LATD1 = 0;
            LATD0 = 1;
            speedmotor[3] = speedmotor[3] + Correct;
            PWMMotorSel = speedmotor[3];        
        }
        if (Menu == 8)                     // корректировка 4 положения мотора и частоты ШИМ
        {
            LATD5 = 0;
            LATD6 = 0;
            LATD7 = 0;
            LATD4 = 0;
            LATD2 = 1;
            LATD1 = 0;
            LATD0 = 1;
            PWMMax = PWMMax + Correct;
            if (Correct)
            {
                PR2 = PWMMax;
                speedmotor[4] = PWMMax;
                PWMMotorSel = (PWMMax >>1);    // Выставляем частоту ШИМ по средним оборотам на слух, чтоб мотор не пел
            }
        }
        if (Menu == 13)                    // выставляем минимум для заслонки температуры воздуха, ручка должна быть в минимуме
        {
            LATD5 = 1;
            LATD6 = 1;
            LATD7 = 1;
            LATD4 = 0;
            LATD2 = 0;
            LATD1 = 0;
            LATD0 = 0;
            PPMMin = PPMMin + Correct;
            PWMMotorSel = 0;
        }
        if (Menu == 14)                    // выставляем максимум для заслонки температуры воздуха, ручка должна быть в максимуме 
        {
            LATD5 = 0;
            LATD6 = 0;
            LATD7 = 1;
            LATD4 = 1;
            LATD2 = 1;
            LATD1 = 0;
            LATD0 = 0;
            PPMMax = PPMMax + Correct;        
        }
        if (Menu == 15)                    // яркость подсветки с выключенными габаритами (день) Регулируется только с выключенными габаритами
        {
            LATD5 = 1;
            LATD6 = 1;
            LATD7 = 0;
            LATD4 = 0;
            LATD2 = 0;
            LATD1 = 1;
            LATD0 = 1;
            DayLight = DayLight + Correct;         
        }
        if (Menu == 16)                    // яркость подсветки с включенными габаритами (ночь) Регулируется только с включенными габаритами
        {
            LATD5 = 0;
            LATD6 = 0;
            LATD7 = 0;
            LATD4 = 1;
            LATD2 = 1;
            LATD1 = 1;
            LATD0 = 1;
            NightLight = NightLight + Correct;   
        }
    if (KeyLongPress2[7] == 1)
    {
        SaveParametrs();
        Setup = 0;
        InitParametrs();
    }    
}

void ADCMotor(void)
{
    if (Setup == 0)
    {
        ADCResult = (1023 - GetADCValue());
        if (ADCResult < 128)                            //выключено (в идеале 0)
        {
            PWMMotorSel = speedmotor[0];
        }
        if ((ADCResult >= 128)&&(ADCResult < 384))       //первое положение (256)
        {
            PWMMotorSel = speedmotor[1];
        }
        if ((ADCResult >= 384)&&(ADCResult < 640))       //середина 512
        {
            PWMMotorSel = speedmotor[2];
        }
        if ((ADCResult >= 640)&&(ADCResult < 896))       //третье положение (768)
        {
            PWMMotorSel = speedmotor[3];
        }
        if (ADCResult >896)                            //включено постоянно (в идеале 1024)
        {
            PWMMotorSel = speedmotor[4];
        }
    }    
}
void ADCTemper(void)
{
    ADCResult = (1023 - GetADCValue());
    Servos[3] = PPMMin + ((((PPMMax - PPMMin)>>5)*ADCResult)>>5); // растягиваем шкалу на весь РРМ сигнал.
}


void RefreshPWMMotor(void)
{
    if(PWM>PWMMotorSel)
    {
        PWM = PWM - 1;
    }
    if(PWM<PWMMotorSel)
    {
        PWM = PWM + 1;
    }
    if (PWM < PWMMin)
    {
        SetPWMDutyCycle(2, 0);
    }
    else
    {
        SetPWMDutyCycle(2, PWM);
    }
    if (RA2 == 0)
    {
        SetPWMDutyCycle(1, DayLight);
    }    
    else
    {
        SetPWMDutyCycle(1, NightLight);
    }    

}

void main(void)
{

    InitServo();
    InitButton();
    InitLed();
    InitParametrs();
	InitPWM();    
    InitADC();

	SetPWMDutyCycle(1,0);   //0% duty cycle 0-46
	SetPWMDutyCycle(2,0);   //0% duty cycle 0-46
 	while(1)
	{
        while(!Start); // ожидаем старта от прерывания
        Start = 0;
        Ticks = Ticks + 1;
        if (Ticks > 10)
        {
            RefreshPWMMotor();
            Ticks = 0;    // 5 Hz
        }
        if (Ticks == 1)
        {
            CHS0 = 0;
            CHS1 = 0;
            CHS2 = 0;
        }
        if (Ticks == 2)
        {
            GODONE = 1;        
        }
        if (Ticks == 3)
        {
            ADCMotor();        
        }
        if (Ticks == 5)
        {
            CHS0 = 1;
            CHS1 = 0;
            CHS2 = 0;     
        }
        if (Ticks == 6)
        {
            GODONE = 1;         
        }
        if (Ticks == 7)
        {
            ADCTemper();
        }
        KeyScan();
        if (Setup == 1)
        {
            SetupKey();
        }
        else
        {
            WorkKey();
        }    
	
    }
}

void interrupt isr(void)
{
    if(TMR1IF)
    {
    LATE0 = 0;
    LATE1 = 0;
    LATE2 = 0;
    TMR1ON = 0;
    TMR1IF =0;
    ServoWorks = ServoWorks + 1;
    if (ServoWorks == 1)
    {
         Temp = (65537 - Servos[1]);
         TMR1H = (Temp>>8);
         TMR1L = (Temp);
         LATE0 = 1;
         TMR1ON = 1;
    }
    else if (ServoWorks == 2)
        {
            Temp = (65537 - Servos[2]);
            TMR1H = (Temp>>8);
            TMR1L = (Temp);
            LATE1 = 1;
            TMR1ON = 1;
        }
        else if (ServoWorks == 3)
            {
                Temp = (65537 - Servos[3]);
                TMR1H = (Temp>>8);
                TMR1L = (Temp);
                LATE2 = 1;
                TMR1ON = 1;
            }
            else if (ServoWorks == 4)
            {
                TMR1H = 0xC9;
                TMR1L = 0x51; //пауза в 14 мс между работ серв (минимум 3 сервы отработают за 0,7*3 = 2,1мс, максимум 6,9 мс) итого пауза в диапазоне 16 - 21 мс, что допустимо для серв
                Start = 1; // Разрешаем остальной части программы работать, когда все сервы отработали
                ServoWorks = 0; // при следующем входе в прерывание приращение единицы выберет первую сервомашинку
                TMR1ON = 1;
            }
     }
}

 

axill
Offline
Зарегистрирован: 05.09.2011

AndreyFly пишет:

Я с Вами полностью согласен, но у меня не лексус 2016 года, а малолитражка с низкопроизводительным мотором вентилятора, и в пасмурный день у меня чтобы не потели стекла на выбор 2 варианта. Обдув на стекло, обдув на стекло и ноги. И ни в одном из вариантов нету, чтобы убавить обороты вентилятора, только на максимум. При этом стекла задних пассажиров и стекло заднее будет запотевшее. Ни о каком температурном комфорте у меня даже мыслей нет. Мне кажется, что переделывать печку начинают те, кого не устраивает штатная, а это машины среднего класса, где есть и сквозняки, и либо передние пассажиры сгорают от жары, а задние пассажиры едут комфортно, либо передние едут комфортно, а задние мерзнут. Чтобы исправить положение - требуется не только много датчиков по всей машине, но и много воздуховодов, во все точки авто с независимой регулировкой температуры воздуха в каждом. Возможно я и ошибаюсь, но это мое личное мнение. Проблема многих машин не в управлении печкой, а в ее возможностях физически прогревать салон равномерно и комфортно для всех одинаково.

то о чем я писал я видел на японке 1994 года выпуска ) конечно возможности системы отопления и обдува ограничены (даже в премиальных авто, просто там границы возможностей шире), но это не повод ставить один датчик и тем более ставить датчик который не обдувается и в итоге замеряет что то еще, но не температуру воздуха в салоне. Я об этом, а не о том, что надо делать идеальную систему

AndreyFly
Offline
Зарегистрирован: 26.03.2016

Так и поставьте датчик температуры посередине салона, сделайте ему небольшое разряжение (воздуховод от датчика до вентилятора, со стороны забора воздуха, там всегда разрежение). Градиент температуры в салоне авто не  более 2 градусов. Прогрев салона машины - очень инерционное мероприятие, а если еще добавить кондиционер, то например у меня уже знаний не хватит рассчитать параметры и учесть все особенности. Если это кому то под силу, пусть выскажут свое мнение. Но на мой взгляд - это не так просто, как кажется.

Иногда приходится включать кондиционер, на полную мощность, и печку на самую горячую (чтобы осушить влажный воздух).

 

mfil1979
Offline
Зарегистрирован: 05.07.2016

есть интерес переделать блок управления кондиционером в блок климата, можно без автоматического управления. https://yadi.sk/i/gw8woiyat38SN

Как правильно подключить кнопки к серво.

AndreyFly
Offline
Зарегистрирован: 26.03.2016

mfil1979 пишет:

есть интерес переделать блок управления кондиционером в блок климата, можно без автоматического управления. https://yadi.sk/i/gw8woiyat38SN

Как правильно подключить кнопки к серво.

а не получится у Вас крутить ручки с помощью серво. Усилия не хватит. У меня сервы с тягой в 10 кг\см не справляются без дополнительного редуктора. Ведь момент удержания и момент сдвига - оказалось разными вещами.

mfil1979
Offline
Зарегистрирован: 05.07.2016

.

TIMSAN
Offline
Зарегистрирован: 25.08.2020

мужики. я так думаю у вас тут немного не доработка. читал ваши комменты. тут ситуация с таким делом, нужно несколько датчиков температур. и каждый настрое на определенные температуры. то есть: 1) датчик температуры охлаждающей жидкости. Ардуино должна считывать данные с ЭБУ. это для тех авто у которых не электрическая печь. при температуре жидкости, например: в 50 градусов, включает печь на малых температурах на лобовое. 2) датчик температуры на лобовом, будет давать сигнал и заслонка приоткрывается четок, давая слабый обогрев стекла. при высоком обогреве стекло просто лопнет. когда стекло прогреется до нужной температуры, заслонка откроется больше и => идет обогрев салона. тут уже будет регулировать датчик температур и влажности в салоне. вот думаю такой алгоритм должен быть при пуске машины на прогреве. а дальше работа системы уже просто на поддержку климата в салоне.