Monday, August 13, 2012

Światła do jazdy dziennej 2

Trzy płyty drukowane włącznika świateł do jazdy dziennej dotarły już jakiś czas temu. Po obłożeniu elementami okazało się że popełniłem jeden błąd - w ferworze walki o rozłożenie elementów i ścieżek na jednej stronie źle podłączyłem sygnał do pomiaru napięcia zasilania. Kawałek kynaru rozwiązał problem ale jest nauczka:
W małych mikrokontrolerach może i są wejścia przetwornika analogowego ale nie są w pełni elastycznie konfigurowalne, np. w PIC12F510 jeżeli chcesz korzystać z jednego kanału przetwornika ADC to musi być kanał AN2. (Logiczne, prawda?).
Zamontowałem układ w samochodzie, po wgraniu programu wszystko ruszyło. Wnioski z użytkowania są takie:

  • Napięcie w instalacji samochodu (w tym przypadku Opel Corsa C) wynosi przy odpalonym silniku 14.2V, ale osiąga tą wartość dopiero kilka sekund po odpaleniu.
  • Regulator alternatora ma pewną bezwładność czasową - kiedy włączę jednocześnie dmuchawę (10A) i światła mijania (ponad 10A) to napięcie w instalacji spada i powrót do wartości 14.2V zajmuje około sekundę. To byłby problem gdyby nie opóźnione wyłączenie świateł do jazdy dziennej.
  • Dzięki sterowaniu świateł do jazdy dziennej na podstawie napięcia w sieci osiągnąłem (to nie był mój podstawowy cel) zabezpieczenie przed nadmiernym rozładowaniem akumulatora
  • Funkcja załączania świateł w momencie kiedy centralny zamek zamyka lub otwiera drzwi - sterownik wykrywa pojedyncze mignięcie kierunkowskazu i włącza światła, ale wykrywa również włączenie świateł awaryjnych, w takiej sytuacji światła nie zostaną załączone (w przeciwnym razie zgaszone auto z włączonymi światłami awaryjnymi zawsze miałoby włączone światła do jazdy dziennej)
Kod jest tak prosty że pozostawiłem go w jednym pliku, poniżej źródło:
#include <stdio.h>
#include <stdlib.h>
#include <htc.h>

__CONFIG(OSC_IntRC & WDT_OFF & CP_OFF & IOSCFS_OFF);

#define MINIMUM_RUNNING_VOLTAGE  (180)
#define MAXIMUM_IDLE_VOLTAGE     (168)

void main(void)
{
    char power=0;
    enum {UP, DOWN}mode;
    enum {ON, OFF}kierun;
    enum {AON, AOFF}awaryjne;
    int lans=0;
    char kierZalaczenia=0;       //ilosc zalczen kieruna w okresie czasu
    int kierOkres=0;

    kierun = OFF;
    awaryjne = AOFF;
    mode = UP;
    CM1CON0 = 0; //wylacz komparator
    OPTION = 0xC4;
    ADCON0 = (1<<7); //wejscie analogowe
    TRIS = (1<<0)|(1<<1)|(1<<2);   //wejscie analogowe

    ADCON0bits.ANS=1; //AN2 configured as analog input
    ADCON0bits.CHS=2; //wybierz do konwersji kanal 2
    ADCON0bits.ADON=1;//wlacz ADC

    while(1)
    {
        //wystaw PWM
        if(TMR0<power)
            GPIObits.GP5=1;
        else
            GPIObits.GP5=0;
        //mierz ADC
        if(GO_nDONE==0)
        {
            if(lans==0)               //normalna praca
            {
                if(ADRES<=MAXIMUM_IDLE_VOLTAGE)         //silnik zgaszony
                {
                    mode=DOWN;                   
                    if(kierun==ON && awaryjne==AOFF)
                        lans=4096;
                }
                if(ADRES>=MINIMUM_RUNNING_VOLTAGE)         //silnik w ruchu
                {
                    if(GPIO & (1<<1)) //swiatla mijania wlaczone
                        mode=DOWN;
                    else              //swiatla mijania wylaczone
                        mode=UP;
                }
            }
            else                      //tryb odmierzania lansu
            {
                mode=UP;
                if(ADRES>=MINIMUM_RUNNING_VOLTAGE)         //silnik w ruchu
                    lans=0;           //wylacz tryb lansu - wroc do normalnego sterowania
                if(awaryjne==AON)     //jezeli wlaczone awaryjne to
                    lans=0;           //wyjdz z trybu lansu
            }
            GO_nDONE=1;//wyzwol kolejna konwersje
        }
        //sprawdzaj czy wlaczone sa swiatla awaryjne
        if(kierOkres>=500)
        {
            kierOkres=0;
            if(kierZalaczenia>1)
                awaryjne=AON;
            else
                awaryjne=AOFF;
            kierZalaczenia=0;
        }
        //odmierzaj sciemnianie i rozjasnianie
        if(TMR0>=0xFA)
        {
            TMR0=0;
            if(mode==UP && power<0xFF)
                power++;
            if(mode==DOWN && power>0)
                power--;
            if(lans>0)  
                lans--;
            kierOkres++;      //odmierzaj okres zliczania migniec
            if(GPIO & (1<<0)) //sprawdz czy kierun jest zalaczony
            {
                if(kierun==OFF)
                    kierZalaczenia++;//inkrementuj ilosc migniec tylko na zbocze zalaczajace
                kierun=ON;                
            }
            else
                kierun=OFF;
        }
    }
}