Модуль управления стеклоподъемниками своими руками

23 апр. 2018 г., 13:52:07
Модуль управления стеклоподъемниками своими руками

Как известно, в Volkswagen Polo Sedan во всех комплектациях установлено 4 электрических стеклоподъемника. Но, чтобы всеми ими управлять с водительской двери, нужно купить самую дорогую комплектацию. Во всех остальных комплектациях установлено только 2 кнопки. Это я решил исправить.

Казалось бы, что сложного? Купи кнопки от комплектации Хайлайн и поставь в свою машину. На деле все сложнее.

В комплектации Хайлайн управление стеклоподъемниками происходит через микроконтроллеры (по микроконтроллеру в каждой двери и главный блок комфорта в салоне). В них используются слаботочные "цепи" управления. В остальных комплектациях управление происходит без микроконтроллеров методом коммутации. И все управление завязано на блоке кнопок в водительской двери.


Тогда я решил сделать свой контроллер стеклоподъемников.

Подготовка:

В качестве микроконтроллера я выбрал Atmega 328P на платформе Arduino Nano. Потребуется 2 штуки.

Модуль управления стеклоподъемниками своими руками

Изначально, для управления силовой нагрузкой планировал использовать модули реле для Arduino. Но, "порывшись" в интернете, обнаружил замечательный модуль управления моторами с рабочим током 14А и максимальным до 30А Monster motor module. Для него подходит корпус G1013. Фиксировал плату в корпусе на термоклей.

Модуль управления стеклоподъемниками своими руками

Этого более чем достаточно для управления одним мотором стеклоподъемника. Плюсом в модуле присутствует датчик тока, который понадобится для отслеживания остановки мотора. Так как этот модуль управляет одним мотором, то нужно приобрести 4 штуки.

Также нужно приобрести кнопки на все двери:

Кнопки под хром

  • 5ND 959 857 - блок кнопок в водительской двери
  • 5ND 959 855 - кнопка в пассажирской двери (3 штуки)

Просто черные кнопки:

  • 1K4 959 857 - - блок кнопок в водительской двери
  • 6RU 959 856 - кнопка в пассажирской двери (3 штуки)

Разъемы для них:

  • 1K0 972 776 - для водительской двери
  • 1K0 972 704 C - для пассажирской двери
  • N 907 647 01 - пины в разъем 19 штук.

Накладки для кнопок:

  • 6RU 867 255 A 9B9 - для пассажиров (3 шт.)
  • 6RU 867 255 9B9 - для водителя

Провод использовал НВМ-4 0,35 мм2.


Изготовление:

Почему решил использовать 2 микроконтроллера? Очень просто. Для управления всеми окнами достаточно и одного. Но при монтаже не хватит места в разъеме из салона в дверь. Там есть место только для 3 проводов. Этого хватит для обмена данными между контроллерами по шине (потребуется 2 провода).

  • В итоге получилась такая схема:

Модуль управления стеклоподъемниками своими руками

Масса силовых модулей (Monster motor module) соединяется между собой попарно (пара передних, пара задних) и подключается к основному блоку. Это нужно для того, чтобы отключать их при постановке авто на охрану.

  • Схема блока водительской двери:

Модуль управления стеклоподъемниками своими руками

Модуль управления стеклоподъемниками своими руками

В первой таблице распиновка разъема. Во второй - список компонентов с их значениями. Стабилизатор напряжения использовал L7805 в корпусе d2pak. Оптопара - самая простая PC817.


  • Схема основного блока:

Модуль управления стеклоподъемниками своими руками

Модуль управления стеклоподъемниками своими руками

В этой схеме добавлено 2 мосфета для управления питанием на силовых модулей.


Изготовление плат:


Изготавливал платы сам методом ЛУТ (лазерно-утюжная технология). Достаточно иметь лазерный принтер и утюг. Как с помощью этой технологии изготовить печатную плату можно прочитать в интернете.

Также можно воспользоваться услугами по изготовлению печатных плат ссылка1 ссылка2 (их услугами не пользовался).

Плата в водительской двери:

Модуль управления стеклоподъемниками своими руками

Модуль управления стеклоподъемниками своими руками

Размер подгонял под этот корпус. U12 - обычный угловой ATX разъем.

Основная плата. К ней заказал корпус, но он оказался слишком большим. Подобрал от какого-то блока питания для внешнего бокса жесткого диска.

Модуль управления стеклоподъемниками своими руками

Модуль управления стеклоподъемниками своими руками

Здесь также используются разъемы ATX на 20 и 4 выхода. Мосфеты Q1 и Q2 использовал в корпусе TO220. Ноги у них загнул и положил на плату. Дорожки к ним узковаты для больших токов, поэтому залудил их толстым слоем припоя.

В конце покрыл плату Цапонлаком в три слоя.


Ссылки на схемы и платы (для программы Diptrace):

Плата в водительской двери, основная плата, схема в водительской двери, схема основной платы.


Программирование плат:

Код модуля в водительской двери

#include <Arduino.h>

void sendButton(int pinInput, String Up, String Down, int ur[], unsigned long *times, bool *autoUp, bool *autoDown);
void Dovodchik(int stepD, unsigned long *times);
void moveWindow(int pinUp, int pinDown, int CS, bool *autoUp, bool *autoDown, unsigned long *times);

#define TIMEWORK 6000

bool autoDownLF = false; //автоматическое опускание переднего левого окна
bool autoUpLF = false; //автоматическое поднимание переднего левого окна

bool autoDownRF = false; //автоматическое опускание переднего правого окна
bool autoUpRF = false; //автоматическое поднимание переднего правого окна
bool autoDownLB = false; //автоматическое опускание заднего левого окна
bool autoUpLB = false; //автоматическое поднимание заднего левого окна
bool autoDownRB = false; //автоматическое опускание заднего правого окна
bool autoUpRB = false; //автоматическое поднимание заднего правого окна

unsigned long timesLF = 0; //для подсчета времени между нажатиями кнопок левого переднего окна
unsigned long timesRF = 0; //для подсчета времени между нажатиями кнопок правого переднего окна
unsigned long timesLB = 0; //для подсчета времени между нажатиями кнопок левого заднего окна
unsigned long timesRB = 0; //для подсчета времени между нажатиями кнопок правого заднего окна

char cs = A4; //датчик тока
int led = 5; //светодиод блокировки
int blockButton = 4; //кнопка блокировки задних окон

bool blockFlag = false; //флаг блокировки окон
int butFlag = 0; //флаг нажатия кнопки
int stepD = 0; //шаг работы доводчика
float startCS=0; // начальное значение датчика тока при старте мотора

//bc - передн. правая дверь B-авто опуск, b-ручное опуск, c-ручной подъем, C-авто подъем
//de - задняя ПРАВАЯ дверь D-авто вниз, d-ручно. вниз, e-ручное вверх, E-авто вверх
//fg - задняя ЛЕВАЯ дверь F-авто вниз, f-ручн. вниз, g-ручн. вверх, G-авто вверх

//w - сигнал блокировки для светодиода после спящего режима W-вкл, w-выкл.
//x - кнопка блокировки отключена, Х - включена
//z - поступил сигнал для доводчика закрыть передее левое окно. Z - ответ, что окно закрыто.

int button1 = 0; //уровень напряжения кнопок окон

int RF[5] = {660, 880, 1020, 380, 100}; //уровни кнопок переднего правого окна 1-е автоподнятие, последнее автоопускание
int LB[5] = {660, 880, 1020, 380, 100}; //уровни кнопок заднего левого окна 1-е автоподнятие, последнее автоопускание
int RB[5] = {660, 880, 1020, 380, 100}; //уровни кнопок заднего правого окна 1-е автоподнятие, последнее автоопускание

int ch =0; //для подсчета сигналов с датчика тока при полность закрытом/ открытом окне

void setup() {
    Serial.begin(57600);
    pinMode(A0, INPUT); //кнопка переднего левого мотора
    pinMode(A1, INPUT); //кнопка переднего правого мотора
    pinMode(A2, INPUT); //кнопка заднего левого мотора
    pinMode(A3, INPUT); //кнопка заднего правого мотора

    pinMode(7, OUTPUT); //enA левого переднего окна
    pinMode(6, OUTPUT); //enB левого переднего окна
    pinMode(cs, INPUT); //датчик тока левого переднего мотора

    pinMode(led, OUTPUT); //светодиод блокировки кнопок
    pinMode(blockButton, INPUT_PULLUP); //кнопка блокировки задних окон

}

void loop() {

    if (Serial.available() > 0) {
        int inBlock = Serial.read();
        if (inBlock == 'W'){ //вкл
            blockFlag = true;
            digitalWrite(led, blockFlag);
            Serial.write('Y');
        }else if (inBlock == 'w'){ //выкл
            blockFlag = false;
            digitalWrite(led, blockFlag);
            Serial.print('Y');
        }
        //закрытие окна и переход в спящий режим
        if (inBlock == 'z'){
            Dovodchik(0, &timesLF);
        }        
    }
    
    button1 = analogRead(A0);
    
    //переднее левое окно
    moveWindow(7, 6, cs, &autoUpLF, &autoDownLF, &timesLF);

    //переднее правое окно
    sendButton(A1, "b", "c", RF, &timesRF, &autoUpRF ,&autoDownRF);
    
    //заднее ПРАВОЕ окно
    sendButton(A2, "d", "e", RB, &timesRB, &autoUpRB, &autoDownRB);

    //заднее ЛЕВОЕ окно
    sendButton(A3, "f", "g", LB, &timesLB, &autoUpLB, &autoDownLB);

    //кнопка и светодиод блокировки задних окон
    int block = !digitalRead(blockButton);
    if (block == 1 && butFlag == 0){
        butFlag = 1;
        blockFlag = !blockFlag;
        if (blockFlag){
            Serial.print('X');
        }else{
            Serial.print('x');
        }
    }else{
        butFlag = !digitalRead(blockButton);    
    }
    
    digitalWrite(led, blockFlag);
    
    
}

void sendButton(int pinInput, String Up, String Down, int ur[], unsigned long *times, bool *autoUp, bool *autoDown){
    delay(20);
    int button = analogRead(pinInput);
    if ((button < (ur[3]+50) && button > (ur[3]-50))  && (millis() - *times >300)){ //ручное опускание
            Down.toLowerCase();
            Serial.print(Down);       
    }else if((button < (ur[1]+50) && button > (ur[1]-50)) && (millis() - *times >300)){ // ручное поднятие
            Up.toLowerCase();
            Serial.print(Up);
    }else if(button < (ur[4]+50)){ // автоматическое опускание
        *times = millis();
        Down.toUpperCase();
        Serial.print(Down);
    }else if(button < (ur[0]+50) && button > (ur[0]-50)){ //автоматическое поднятие
        *times = millis();
        Up.toUpperCase();
        Serial.print(Up);   
    }
}

/* Закрывает/открывает окна в ручном и автоматическом режиме
*  @var pinUp integer - управляющий пин enA
*  @var pinDown integer - управляющий пин enB
*  @var CS integer - Датчик тока для отслеживания остановки мотора
*  @var autoUp bool - флаг автоматического опускания
*  @var autoDown bool - флаг автоматического поднятия
*  @var times unsigned long - счетчик времени подсчета нажатия кнокоп и работы двигателей
*/
void moveWindow(int pinUp, int pinDown, int CS, bool *autoUp, bool *autoDown, unsigned long *times){
        int ISens = analogRead(CS);
        if ((button1 < 450 && button1 > 350) && (millis() - *times >300)){ //ручное опускание
          *times = millis();
          if (*autoUp){ //останавливаем автоматическое поднятие окна
            digitalWrite(pinUp, LOW);
            digitalWrite(pinDown, LOW);
            startCS = 0;
            delay(200); //для плавной остановки мотора
          }else{ //опускаем вручную
            digitalWrite(pinUp, HIGH);
            digitalWrite(pinDown, LOW);
          }
          *autoDown = false;
          *autoUp = false;
          *times = 0;
        }else if((button1 < 920 && button1 > 820) && (millis() - *times >300)){ // ручное поднятие
          *times = millis();
          if (*autoDown){ //останавливаем автоматическое опускание окна
            digitalWrite(pinUp, LOW);
            digitalWrite(pinDown, LOW);
            startCS = 0;
            delay(200); //для плавной остановки мотора
          }else{ //поднимаем вручную
            digitalWrite(pinDown, HIGH);
            digitalWrite(pinUp, LOW);  
          }
          *autoUp = false;
          *autoDown = false;
          *times = 0;
        }else if(button1 < 150  && (millis() - *times >100)){ // автоматическое опускание
          *times = millis();
          *autoDown = true;
          *autoUp = false;
          digitalWrite(pinUp, HIGH);
          digitalWrite(pinDown, LOW);
          
          delay(50);
          //читаем датчик тока во время старта мотора
           if (startCS == 0){
            startCS = analogRead(CS);
           }
        }else if((button1 < 700 && button1 > 600) && (millis() - *times >100)){ //автоматическое поднятие
          *times = millis();
          *autoUp = true;
          *autoDown = false;
          digitalWrite(pinUp, LOW);
          digitalWrite(pinDown, HIGH);
          
          delay(150);
          //читаем датчик тока во время старта мотора
           if (startCS == 0){
            startCS = analogRead(CS);
           }
        }else if (button1 > 1010){ //кнопки отпущены
          if (*autoDown && (millis() - *times < TIMEWORK) && ((float)(ISens/startCS) < 1.9)){ //если ранне была нажата кнопка автоспуска и не прошло 10 секунд на опускание окна
            digitalWrite(pinUp, HIGH);
            digitalWrite(pinDown, LOW);
          }else if(*autoUp //если есть флаг автоподнятия
                    && (millis() - *times < TIMEWORK) //время работы мотора меньше заданного
                    && ((float)(ISens/startCS) < 2.0) //окно поднимается/опускается (стартовый ток меньше текущего)
                ){
            //если ранне была нажата кнопка автоподъем и не прошло 10 секунд на поднятия окна
            digitalWrite(pinUp, LOW);
            digitalWrite(pinDown, HIGH);
          }else{
            *autoDown = false;
            *autoUp = false;
            digitalWrite(pinUp, LOW);
            digitalWrite(pinDown, LOW);
            *times = 0;
            startCS = 0;
          }
        }
        
       
}

void Dovodchik(int stepD, unsigned long *times){
  /* step = 0 - доводчик не работает
  *  1 - Начало движения окон. Ни одно окно не закрыто
  *  2 - Закрыто переднее левое окно
  */

    int stopSens = 0; // для определения когда стекло остановилось, но датчик тока не показывает уровень

    float iSens = 0; //текущее значение тока мотора
    float startCS = 0; //начальное значение тока мотора
    bool ok = true;
    *times = millis();
             
    if (stepD == 0){
      stepD++;
    }
    
    //левое переднее
    if (stepD>0 && stepD<2){
        do {
            digitalWrite(6, HIGH);
            delay(30);
            if (startCS == 0){
                startCS = analogRead(A4); //значение тока в начале работы
            }
            iSens = analogRead(A4); //текущее значение тока мотора
            if ((millis() - *times) > TIMEWORK+1000){
                ok=false;
            }else if ((float)iSens/startCS > 1.9){ //если разница в токе между работающим и остановленным мотором больше 195, то выключаем.
                ok=false;
            }
            if((float)(iSens/startCS) < 1.5 && iSens > 75){
                //если 10 раз подряд датчик тока покажет значение больше 195, то закрыто
                if (stopSens > 10){
                    ok=false;
                    stopSens = 0; //сбрасываем в ноль для следующего окна
                }else{
                    stopSens++;
                }
            }else{
                stopSens = 0; //сбрасываем, чтобы было 10 раз ПОДРЯД
            }
        }while (ok);
        if (ok == false){
            digitalWrite(6,LOW);
            stepD = stepD+1;
            *times=millis();
            startCS = 0;
        }
        Serial.print('Z');
    }
}


Код основного модуля:

#include <avr/sleep.h>

#define TIMEWORK 6000
#define CSMOTOR 45
#define DOVODCHIK_CS 190

void moveWindow(int *button, int pinUp, int pinDown, int CS, int ur[], boolean *autoUp, boolean *autoDown, unsigned long *times, int *ISens);

int FR = 1023; //напряжение кнопки передне правой двери в текущий момент
int BL = 1023; //напряжение кнопки задней левой двери в текущий момент
int BR = 1023; //напряжение кнопки задней правой двери в текущий момент

//bc - передн. правая дверь B-авто опуск, b-ручное опуск, c-ручной подъем, C-авто подъем
//de - задняя правая дверь D-авто вниз, d-ручно. вниз, e-ручное вверх, E-авто вверх
//fg - задняя левая дверь F-авто вниз, f-ручн. вниз, g-ручн. вверх, G-авто вверх

//z - сигнал для закрытия переднего левого окна при постановке на охрану. Z - ответный сигнал, что окно закрыто.
//w - сигнал блокировки для светодиода после спящего режима W-вкл, w-выкл.
//x - кнопка блокировки отключена, Х - включена

int str = 0; //значение, переданное другим блоком

boolean autoDownRF = false; //автоматическое опускание переднего правого окна
boolean autoUpRF = false; //автоматическое поднимание переднего правого окна
boolean autoDownLB = false; //автоматическое опускание заднего левого окна
boolean autoUpLB = false; //автоматическое поднимание заднего левого окна
boolean autoDownRB = false; //автоматическое опускание заднего правого окна
boolean autoUpRB = false; //автоматическое поднимание заднего правого окна

unsigned long timesRF = 0; //для подсчета времени между нажатиями кнопок правого переднего окна
unsigned long timesLB = 0; //для подсчета времени между нажатиями кнопок левого заднего окна
unsigned long timesRB = 0; //для подсчета времени между нажатиями кнопок правого заднего окна
       int RigthForwardWin = 0; //датчик тока правого переднего окна
       int LeftBackWin = 0; //датчик тока левого заднего окна
       int RigthbackWin = 0; //датчик тока правого заднего окна
boolean lockWindows = false; //память для блокировки задних кнопок
       boolean forwardRight = false; //флаг что работает мотор переднего правого для выставления цровня тока отличного от задних
int dovodchStep = 0; //для функции доводки окон при постановке на охрану (0-не работает; 1-начало работы доводчика; 2- одно окно (ЛП); 3-второе окно (ПП) и т.д.)
unsigned long dovodchTime = 0; //для подсчета времени закрытия доводчика
volatile int sleepStatus = 0;  //статус режима сна
boolean mainbutFR = false; //флаг нажатия на водительской двери
boolean mainbutBL = false; //флаг нажатия на водительской двери
boolean mainbutBR = false; //флаг нажатия на водительской двери

//таймер для плавности работы пассажирских дверей от водительской кнопки
//без него моторы работают с щелчками
unsigned long timeAllWin=0;

unsigned long timeSleep = 0; //для посчета времеи простоя без зажигания для засыпания

//уровни дополнительных кнопок
int DRF[5] = {690, 910, 1020, 410, 220}; //уровни кнопок переднего правого окна 1-е автоподнятие, последнее автоопускание (карта кнопок для определения в какой из уровней произошло нажатие)
int DRB[5] = {690, 890, 1020, 400, 100}; //уровни кнопок заднего ПРАВОГО окна 1-е автоподнятие, последнее автоопускание
int DLB[5] = {680, 890, 1020, 400, 220}; //уровни кнопок заднего ЛЕВОГО окна 1-е автоподнятие, последнее автоопускание

boolean breakSleep = false;

void setup() {
    Serial.begin(57600);
    pinMode(A0, INPUT); //передняя правая кнопка
    pinMode(A1, INPUT); //задняя левая кнопка
    pinMode(A2, INPUT); //задняя правая кнопка

    //переднее правое окно
    pinMode(4, OUTPUT); //enA переднего правого окна
    pinMode(5, OUTPUT); //enB переднего правого окна
    pinMode(A3, INPUT); //датчик тока переднего правого окна

    //заднее ЛЕВОЕ окно
    pinMode(6, OUTPUT); //enA переднего правого окна
    pinMode(7, OUTPUT); //enB переднего правого окна
    pinMode(A4, INPUT); //датчик тока переднего правого окна

    //заднее правое окно
    pinMode(8, OUTPUT); //enA переднего правого окна
    pinMode(9, OUTPUT); //enB переднего правого окна
    pinMode(A5, INPUT); //датчик тока переднего правого окна

    pinMode(2, INPUT_PULLUP); //автодоводчик от сигнализации
    pinMode(3, INPUT_PULLUP);
    pinMode(10, OUTPUT);
    digitalWrite(10, HIGH); //подача питания на моторы через модуль сна

}

void loop() {
       
    //переднее правое окно
    if (mainbutFR==false ){ //проверяем если не нажата кнопка на водительской двери
        FR = analogRead(A0);
        forwardRight = true;
    }
    moveWindow(&FR, 4, 5, A3, DRF, &autoUpRF, &autoDownRF, &timesRF, &RigthForwardWin);

    //заднее ПРАВОЕ окно
    if (mainbutBR==false){
        if (lockWindows == false){
            BR = analogRead(A1);

        }else{
            BR = 1023;
        }
    }
    moveWindow(&BR, 6, 7, A4, DRB, &autoUpRB, &autoDownRB, &timesRB, &RigthbackWin);
    

    //заднее ЛЕВОЕ окно
    if (mainbutBL==false){
        if (lockWindows == false){
            BL = analogRead(A2);     
        }else{
            BL = 1023;
        }
    }
    moveWindow(&BL, 8, 9, A5, DLB, &autoUpLB, &autoDownLB, &timesLB, &LeftBackWin);
    

    if (Serial.available()>0){
            str = Serial.read();
          
            //передняя правая дверь
            if (str == 'B'){
                FR = DRF[0];
                mainbutFR = true;
                timeAllWin = millis();
            }
            if (str == 'b'){
                FR = DRF[1];
                mainbutFR = true;
                timeAllWin = millis();
            }
            if (str == 'c'){
                FR = DRF[3];
                mainbutFR = true;
                timeAllWin = millis();
            }
            if (str == 'C'){
                FR = DRF[4];
                mainbutFR = true;
                timeAllWin = millis();
            }
            moveWindow(&FR, 4, 5, A3, DRF, &autoUpRF, &autoDownRF, &timesRF, &RigthForwardWin);
            
            //Задняя ПРАВАЯ дверь
            if (str == 'D'){
                BR = DRB[0];
                mainbutBR = true;
                timeAllWin = millis();
            }
            if (str == 'd'){
                BR = DRB[1];
                mainbutBR = true;
                timeAllWin = millis();
            }
            if (str == 'e'){
                BR = DRB[3];
                mainbutBR = true;
                timeAllWin = millis();
            }
            if (str == 'E'){
                BR = DRB[4];  
                mainbutBR = true;
                timeAllWin = millis();
            }
            moveWindow(&BR, 6, 7, A4, DRB, &autoUpRB, &autoDownRB, &timesRB, &RigthbackWin);            

            //Задняя ЛЕВАЯ дверь
            if (str == 'F'){
                BL = DLB[0];
                mainbutBL = true;
                timeAllWin = millis();
            }
            if (str == 'f'){
                BL = DLB[1];
                mainbutBL = true;
                timeAllWin = millis();
            }
            if (str == 'g'){
                BL = DLB[3];
                mainbutBL = true;
                timeAllWin = millis();
            }
            if (str == 'G'){
                BL = DLB[4];
                mainbutBL = true;
                timeAllWin = millis();
            }
            moveWindow(&BL, 8, 9, A5, DLB, &autoUpLB, &autoDownLB, &timesLB, &LeftBackWin);            

            //кнопка блокировки задних окон
            if (str == 'x'){
                lockWindows = false;
            }
            if (str == 'X'){
                lockWindows = true;
            }

    }else{

        if (millis() - timeAllWin > 100){ //для работы моторов пасажиров от кнопок с водительской двери без щелчков и дерганий стекла
            mainbutFR = false;//больше кнопки на водительской двери не нажаты
            mainbutBR = false;
            mainbutBL = false;
            timeAllWin =0;
        }
    }

    delay(30);
    //Закрываем окна при постановке на охрану
    if ((digitalRead(2)==0 && sleepStatus == 0) || dovodchStep>0){
        delay(1000); //ждем пока закроются двери
        if (dovodchStep == 0){
          dovodchTime = millis();  
        }
        Dovodchik(&dovodchStep, &dovodchTime);
        if (dovodchStep == 5){ //все окна закрыты
            dovodchStep = 0; //обнуляем, чтобы сработало при следующей постановке на охрану
            delay(1000);
            if (breakSleep == false){ //если во время закрытия окон не снималась с сигналки , то в сон
              sleepNow(); //перевод в режим сна
            }else{
              sleepStatus = 0;
              breakSleep = false;
            }
            
        }
    }

}

/* Закрывает/открывает окна в ручном и автоматическом режиме
*  @var pinUp integer - управляющий пин enA
*  @var pinDown integer - управляющий пин enB
*  @var CS integer - Датчик тока для отслеживания остановки мотора
*  @var ur[] integer - массив уровней напряжения управляющих кнопок
*  @var autoUp boolean - флаг автоматического опускания
*  @var autoDown boolean - флаг автоматического поднятия
*  @var times unsigned long - счетчик времени подсчета нажатия кнокоп и работы двигателей
*/
void moveWindow(int *button, int pinDown, int pinUp, int CS, int ur[], boolean *autoUp, boolean *autoDown, unsigned long *times, int *ISens){
        *ISens = analogRead(CS);
        int sensData = 250;
        if ((*button < (ur[3]+70) && *button > (ur[3]-70)) && (millis() - *times >300)){ //ручное опускание
          if (*autoUp){ //останавливаем автоматическое поднятие окна
            digitalWrite(pinUp, LOW);
            digitalWrite(pinDown, LOW);
            delay(200); //для плавной остановки мотора и не "палить" проводку мотора
          }else{ //опускаем вручную
            digitalWrite(pinDown, HIGH);
          }
          *autoDown = false;
          *autoUp = false;
          *times = 0;
        }else if((*button < (ur[1]+70) && *button > (ur[1]-70)) && (millis() - *times >300)){ // ручное поднятие
          if (*autoDown){ //останавливаем автоматическое опускание окна
            digitalWrite(pinUp, LOW);
            digitalWrite(pinDown, LOW);
            delay(200); //для плавной остановки мотора
          }else{ //поднимаем вручную
            digitalWrite(pinUp, HIGH);
          }
          *autoUp = false;
          *autoDown = false;
          *times = 0;
        }else if(*button < (ur[4]+70)){ // автоматическое опускание
          *times = millis();
          *autoDown = true;
          *autoUp = false;
          digitalWrite(pinDown, HIGH);
        }else if((*button < (ur[0]+70) && *button > (ur[0]-70))){ //автоматическое поднятие
          *times = millis();
          *autoUp = true;
          *autoDown = false;
          digitalWrite(pinUp, HIGH);
        }else if (*button > (ur[2]-50)){ //кнопки отпущены
          if (forwardRight){
            sensData = 370; //уровень тока остановленного мотора для переднего правого окна
          }else{
            sensData = 250; //уровень тока остановленного мотора для  задних окон
          }
          if (*autoDown && (millis() - *times < TIMEWORK) && *ISens < sensData){ //если ранне была нажата кнопка автоспуска и не прошло 10 секунд на опускание окна
            digitalWrite(pinDown, HIGH);
          }else if(*autoUp && (millis() - *times < TIMEWORK) && *ISens < sensData){ //если ранне была нажата кнопка автоподъем и не прошло 10 секунд на поднятия окна
            digitalWrite(pinUp, HIGH);
          }else{
            *autoDown = false;
            *autoUp = false;
            digitalWrite(pinUp, LOW);
            digitalWrite(pinDown, LOW);
            *times = 0;
            *button = 1023;
            forwardRight = false;
          }
        }
}

void Dovodchik(int *stepp, unsigned long *times){
  /* step = 0 - доводчик не работает
  *  1 - Начало движения окон. Ни одно окно не закрыто
  *  2 - Закрыто переднее левое окно
  *  3 - Закрыто заднее левое окно
  *  4 - Закрыто переднее правое окно
  *  5 - Закрыто заднее правое окно
  */
  boolean ok1 = true; //переднее левое
  boolean ok2 = true; //заднее левое
  boolean ok3 = true; //переднее правое
  boolean ok4 = true; //заднее правое
  boolean sendd = false; //флаг об отправке сигнала на переднее левое окно
  int stopp = 0; //для фильтрации ложных данных с датчика тока
  float CS = 0; //для вычисления изменений датчика тока мотора при остановке
 
        if (*stepp == 0){
          *stepp = 1;
        }

        //Переднее правое
        
        do {
            if (digitalRead(3) == 0){
              breakSleep = true;
            }
            digitalWrite(5, HIGH);
            delay(30);
            if (CS == 0){
                CS = analogRead(A3); //значение тока в начале работы
            }
            RigthForwardWin = analogRead(A3); //текущее значение тока мотора
            if ((millis() - *times) > TIMEWORK+500){
                ok3=false;
            }else if ((float)RigthForwardWin/CS > 1.6){ //если разница в токе между работающим и остановленным мотором больше 195, то выключаем.
                ok3=false;
            }
            if(((float)RigthForwardWin/CS) < 1.1 && RigthForwardWin > 350){
                //если 10 раз датчик тока покажет значение больше 250, то закрыто
                if (stopp > 10){
                    ok3=false;
                    stopp = 0; //сбрасываем в ноль для следующего окна
                }else{
                    stopp++;
                }
            }else{
                stopp = 0;    
            }
        }while (ok3);
        if (ok3 == false){
            digitalWrite(5,LOW);
            *stepp = *stepp+1;
            *times=millis();
            CS = 0;
        }
        delay(250);

        //Заднее ПРАВОЕ
        do{
            if (digitalRead(3) == 0){
              breakSleep = true;
            }
            digitalWrite(7, HIGH);
            delay(30);
            if (CS == 0){
                CS = analogRead(A4); //начальные данные тока в момент старта
            }
            RigthbackWin = analogRead(A4); //текущие данные во время работы/остановки

            if ((millis() - *times) > TIMEWORK){
                ok2=false;
            }else if ((float)RigthbackWin/CS > 1.6){
                ok2=false;
            }else if((float)RigthbackWin/CS < 1.1 && RigthbackWin > 220){
                //если 10 раз датчик тока покажет значение, то окно закрыто
                if (stopp > 10){
                   ok2=false;
                   stopp = 0; //сбрасываем в ноль для следующего окна
                }else{
                    stopp++;
                }
            }
            
        }while (ok2);
        if (ok2 == false){
            digitalWrite(7, LOW);
            *stepp = *stepp+1;
            *times=millis();
            CS = 0;
        }
        delay(250);

        //левое переднее
        do{
            if (digitalRead(3) == 0){
              breakSleep = true;
            }
            if (Serial.available() > 0) {
                int strLF = Serial.read();
                if (strLF == 'Z'){
                    ok1 = false;
                }
            }
            if ((millis() - *times) > TIMEWORK+1000){
                ok1=false;
            }
            if (!sendd){
                Serial.print('z');
                sendd = !sendd;           
            }
        }while(ok1);
        if (ok1 == false){
            *stepp = *stepp+1;
            *times=millis();  
        }
        delay(250);
        
        //Заднее ЛЕВОЕ
        delay(30);
        do {
            if (digitalRead(3)==0){
              breakSleep = true;
            }
            digitalWrite(9, HIGH);
            delay(30);
            if (CS == 0){
                CS = analogRead(A5);
            }
            LeftBackWin = analogRead(A5);
            if ((millis() - *times) > TIMEWORK){
                ok4=false;
            }else if ((float)LeftBackWin/CS > 1.6){
                ok4=false;
            }else if((float)LeftBackWin/CS < 1.1 && LeftBackWin > 290) {
                //если 10 раз датчик тока покажет значение, то окно закрыто
                if (stopp > 10){
                    ok4=false;
                    stopp = 0; //сбрасываем в ноль для следующего окна
                }else{
                    stopp++;
                }
            }
        }while (ok4);
        if (ok4 == false){
            digitalWrite(9,LOW);
            *stepp = *stepp+1;
            *times=millis();
            CS=0;
        }
        delay(250);
}

void wakeUpNow()        // Прерывание сработает после пробуждения
{
    detachInterrupt(1);                    // Выключаем прерывание - при нормальном режиме wakeUpNow() не будет вызываться
    
    
  // Код, который здесь выполнится перед возвращением в цикл loop()
  // Таймеы и код, использующий таймеры (serial.print и др...) здесь не будет работать
  // Также мы не должны выполнять какие-то спец. функции здесь,
  // Т.к. здесь мы просто просыпаемся
}

void sleepNow()         // Функция увода ардуины в спячку.
{
  attachInterrupt(1, wakeUpNow, LOW);   // Используем прерывание 1 (pin 3) для выполнения функции wakeUpNow при включении зажигания
  //(прерывание вызывается только при смене значения на порту с HIGH на LOW и наоборот - подтянуть ногу 2 на 5в.)
  delay(100);
  digitalWrite(10, LOW);             // Выключаем моторы
  sleepStatus = 1;                       // В переменную заносим статус сна
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);   // Здесь устанавливается режим сна
  sleep_enable();                        // Включаем sleep-бит в регистре mcucr. Теперь возможен слип
  sleep_mode();     // Здесь устройство перейдет в режим сна!!!
 
  // -----------------------------------------------ПОСЛЕ ПРОСЫПАНИЯ ВЫПОЛНЕНИЕ КОДА ПРОДОЛЖИТСЯ ОТСЮДА!!!
 
  // Первое, что нужно сделать после просыпания - выключить спящий режим                       
  sleep_disable();   
  digitalWrite(10, HIGH);  // Включаем моторы
  sleepStatus = 0;             // В переменную заносим статус бодрствования
  delay(500);
  if(lockWindows){
      Serial.print('W');
  }else{
      Serial.print('w');
  }
}


Монтаж в машину:

Все работы выполнял при отключенном аккумуляторе.

Прежде, чем начать монтаж блоков стеклоподъемников, сделал их работу постоянной. Их отключение после постановки на охрану будет выполнять основной блок стеклоподъемников.

Для этого воспользовался вот этой инструкцией.

Стандартная схема стеклоподъемников в водительской двери.

Модуль управления стеклоподъемниками своими руками

Сразу видно, что провода питания всех стеклоподъемников идут через блок кнопок. Если он выйдет из строя, то задние стеклоподъемники работать не будут, т.к. от этого блока идет желто-черный провод +12 вольт на них. Возможно будет работать только передний пассажирский стеклоподъемник. На него идет отдельно питание от предохранителя S1 (выход 169 на схеме).

Итак, первым делом приступил к монтажу модуля для мотора. От мотора идут 2 провода - черно-белый, и красно-белый. Отрезал их и соединил с высокотоковыми выводами OUTA и OUTB. +12 вольт взял от черного провода из 28-пинового разъема между салоном и дверью (пин 25). От этого провода также запитался и блок в водительской двери. Массу прокинул отдельную, т.к. этот моторы буду отключать после постановки на охрану. Общую массу двери (коричневый провод) отрезал только от кнопок. Соединение 267 нельзя разрывать. В качестве массы для блоков использовал желто-черный провод. Разрезал его в салоне между соединением В278 и 28 контактным разъемом в двери. Конец, который идет в дверь подключил к 4-пиновому разъему основного блока стеклоподъемников (к какому конкретно указано в таблице на схеме платы). Другой конец, который идет в салон соединил с черным либо с черным с красной полосой (в зависимости от года выпуска автомобиля) проводом от предохранителя S2. В двери отрезал черно-желтый провод от кнопок и подключил к массе модулей. Теперь управляющие провода сечением 0,35 мм2. +5 вольт поступают от модуля в водительской двери. Разъемы GND и EN оставил пустыми (GND общий с высокотоковым разъемом, EN я так и не понял зачем нужен). EnA и EnB - управляющие сигналы поднятия/опускания. Разъем PWM - управляющий ШИМ сигнал. Сюда тоже подал +5 вольт.

Следующим идет управляющий блок в водительской двери. Его приклеил на двухсторонний скотч в районе подлокотника. Оставшиеся провода подключил согласно распиновке на схеме платы (выше по тексту). В качестве проводов для шины UART (пины Rx и Tx) использовал провода красно-зеленый и черно-зеленый.

Кнопки в водительской двери. Распиновка разъема.

1 - кнопка блокировки задних окон. 2 - светодиод блокировки задних окон. 3 и 9 - подсветка кнопок (подключил к голубому проводу подсветки кнопки открытия багажника). 4 и 10 - масса. 5, 6, 7 и 8 - кнопки открытия/закрытия окон.

Получилась такая схема:

Модуль управления стеклоподъемниками своими руками

Остался один лишний провод сечением 2,5 кв. мм. в 28-контактном разъеме. Его использовал в другой двери.

К задним дверям протянул 6 проводов: 5 - сечением 0,35 кв. мм. и 1 - сечением 2,5 кв. мм. для массы. В передней пассажирской двери на 2 провода меньше, т.к. там уже протянуты черно-зеленый и красно-зеленый провод.

Распиновка проводов такая же, как на водительской двери. 2 провода пойдут на кнопку в двери: 1 - подсветка, 2 - сигнал с кнопки. Массу для кнопки взял в двери. Остальные 3 тонких провода: 1 - +5В (подключается в +5V и PWD), 2 и 3 - EnA и enB.

Основной блок в салоне.

Расположил его за ручкой открытия капота под пластиковой обшивкой.

Распиновка разъемов есть в таблице выше со схемой платы. Интересны только 17 и 18 пины разъема. На 17 пин подается импульс +12 В при постановке на охрану. Тогда срабатывает доводчик окон и блок отключает питание на стеклоподъемники. На 18 пин подается импульс +12 В при снятии с охраны. После чего подается питание на стеклоподъемники.

Итог.

Какие плюсы такой схемы:

  • Возможность управлять всеми окнами с водительской двери;
  • Полная автоматика на все окна;
  • Появилась подсветка кнопок;
  • Реализована функция доводчика стекол при постановке на охрану;
  • Пропал глюк когда окно останавливалось на какое-то время и никуда не двигалось.

Теперь про минусы:

  • Проводка уже не будет иметь заводской вид;

Комментарии

Чтобы оставить комментарии небходимо войти с помощью своего аккаунта.
Ничего не найдено.