Elektroda.pl
Elektroda.pl
X
Proszę, dodaj wyjątek www.elektroda.pl do Adblock.
Dzięki temu, że oglądasz reklamy, wspierasz portal i użytkowników.

Schemat z Atmega16 i pytania odnośnie prograwania w C

Gandziorz 17 Mar 2010 17:07 4056 32
  • #1 17 Mar 2010 17:07
    Gandziorz
    Poziom 16  

    Witam wszystkich,
    Stworzyłem schemat do zapłonu motocyklowego z użyciem dwóch transoptorów, wyświetlaczem LCD na sterowniku HD44780 a także dwóch tranzystorów do sterowania cewką (BU931). Jako kwarcu użyłem 24Mhz.

    Pierwsza prośba to czy ktoś może mi sprawdzić czy schemat jest prawidłowy.
    Schemat z Atmega16 i pytania odnośnie prograwania w C

    Teraz mam pytania odnośnie tego schematu, i wykorzystania tutaj języka "C".

    Porty "A" jako wyjścia definiuje się za pomocą:

    Code:
    DDRA = 0xFF;

    Stan niski na tym porcie wykonuje za pomocą:
    Code:
    PORTA = 0x00; 

    Stan wysoki na tym porcie wykonuje za pomocą:
    Code:
    PORTA = 0xff; 


    Teraz mam pytanie o przerwanie zewnętrzne, wszędzie gdzie znalazłem dotyczyło to podpięcia pod masę, a u mnie ma być odwrotnie. Sygnał będzie z transoptora kiedy wykryje szczelinę (wówczas przepuści napięcie). I teraz chciałbym to wykorzystać w taki sposób "Jeżeli wykryje napięcie na INT0 wykonaj akcję ...".
    Pewnie muszę ustawić INT0 i INT1 na zbocze wzrastające?

    Code:
    int main(void)
    
    {
      DDRA = 0xFF;                    // port A jako wyjście

      GICR = _BV(INT0)|_BV(INT1);               // włącz przerwania z INT0 i INT1
      MCUCR = (1<<ISC01)|(1<<ISC00);  // zbocze narastające
      sei();                          // przerwania globalne włączone

    // kontynuuje program, tutaj np. będzie przesyłanie informacji do HD44780...

      return(0);
    }


    Sygnał powinienem przetwarzać jak poniżej (dla INT0).

    Czy to powinno być tak:
    Code:
    SIGNAL (SIG_INTERRUPT0)
    
    {
    //otrzymalem sygnal wykonaj akcje ta i ta
    }


    Pod akcję rozumiem ustawienie niskiego stanu na porcie PA0 ale tylko na 10ms.
    Czy takie coś byłoby dobre:
    Code:
    SIGNAL (SIG_INTERRUPT0)
    
    {
    //otrzymalem sygnal ustawiam na porcie PA0 stan niski
    PORTA = 0x01;
    //po 10ms przestaw na stan wysoki
    waitms(10);
    PORTA = 0x11;
    }

    A dla INT1 i PA1 w taki sposób:
    Code:
    SIGNAL (SIG_INTERRUPT1)
    
    {
    //otrzymalem sygnal ustawiam na porcie PA1 stan niski
    PORTA = 0x02;
    //po 10ms przestaw na stan wysoki
    waitms(10);
    PORTA = 0x12;
    }


    Chciałbym również aby TIMER zliczał również ilość przerwań od INT0 przez 1s.
    W bascomie timer obsługiwałoby się za pomocą kodu:
    Code:
       Timer1 = 0                                             
    
       Start Timer1                                           
       Wait 1                                                 
       Stop Timer1                                             
     

    A w "C" nie znalazłem żadnego skrawka kodu by sobie "zerknąć".

    Jeżeli gdzieś są błędy w moim toku myślenia to proszę o poprawienie.

    0 29
  • #2 17 Mar 2010 17:26
    Dawid_20
    Poziom 17  

    Witam
    Sygnał R/W daj na stałe do masy, dorzuć elektrolity przy stabilizatorze.

    Zamiast:

    Code:
    SIGNAL (SIG_INTERRUPT0) 
    
    {
    //otrzymalem sygnal ustawiam na porcie PA0 stan niski
    PORTA = 0x01;
    //po 10ms przestaw na stan wysoki
    waitms(10);
    PORTA = 0x11;
    }

    Bo nadpisujesz cały port, zamiast ustawić tylko to co Cię interesuje

    Bardziej czytelnie:
    Code:
    SIGNAL (SIG_INTERRUPT0) 
    
    {
    //otrzymalem sygnal ustawiam na porcie PA0 stan niski
    PORTA &=~_BV(0);
    //po 10ms przestaw na stan wysoki
    _delay_ms(10);    //#include<util/delay.h>
    PORTA |= _BV(0);
    }


    Timer włączasz w momencie ustawienia preskalera w rejestrze TCCR, bity np CS01, CS10 itp. zajrzyj do noty, tam wszystko znajdziesz.

    A tak poza tym dobrze kombinujesz.

    0
  • #3 17 Mar 2010 17:40
    tmf
    Moderator Mikrokontrolery Projektowanie

    Jaki prad plynie przez cewke? Czy port ATMegi bedzie w stanie wysterowac tranzystor? On ma h21e wynoszace zaledwie 300 dla 5A, dla wiekszego pradu jeszcze mniej. Jakis bufor moze okazac sie konieczny. Dwa, 24MHz to poza specyfikacja procesora (jest do 16MHz), w takim miejscu jak motor gdzie sa zmienne warunki przetaktowanie procesora nie jest zalecane. No i nie jest potrzebne - przeciez nie potrzebujesz jakiejs kosmicznej mocy obliczeniowej.
    Do stabilizatora dodalbym tez jakies elektrolity.

    0
  • #4 17 Mar 2010 18:20
    Gandziorz
    Poziom 16  

    Dawid_20 napisał:
    Witam
    Sygnał R/W daj na stałe do masy, dorzuć elektrolity przy stabilizatorze.

    Zamiast:
    Code:
    SIGNAL (SIG_INTERRUPT0) 
    
    {
    //otrzymalem sygnal ustawiam na porcie PA0 stan niski
    PORTA = 0x01;
    //po 10ms przestaw na stan wysoki
    waitms(10);
    PORTA = 0x11;
    }

    Bo nadpisujesz cały port, zamiast ustawić tylko to co Cię interesuje

    Bardziej czytelnie:
    Code:
    SIGNAL (SIG_INTERRUPT0) 
    
    {
    //otrzymalem sygnal ustawiam na porcie PA0 stan niski
    PORTA &=~_BV(0);
    //po 10ms przestaw na stan wysoki
    _delay_ms(10);    //#include<util/delay.h>
    PORTA |= _BV(0);
    }


    Timer włączasz w momencie ustawienia preskalera w rejestrze TCCR, bity np CS01, CS10 itp. zajrzyj do noty, tam wszystko znajdziesz.

    A tak poza tym dobrze kombinujesz.

    _BV(0) oznacza port PA0 więc adekwatnie będzie _BV(1) dla portu PA1, tak?
    Gdzie znajdę bibliotekę hd44780 tak żeby lcd obsługiwać za pomocą sterowania 4 bitowego? Znalazłem bibliotekę ale do ster. 8 bitowego.

    Zatem jak ma wyglądać zliczanie impulsów przez 1s przy użyciu timer1 (16bit).
    Wiem że kasowanie wartości timer1 odbywa się poprzez:
    Code:
    TCNT1 = 0;


    Ale kurczę jak zrobić te liczenie przerwań INT0 (zbocze wysokie).

    Bo chyba później w main robię coś takiego:
    Code:
    obroty = TCNT1 * 60; //Wowczas wzroci obr/min a nie obr/s
    
    lcd_putchar(obroty);  //wyswietlenie obrotow na wyswietlaczu LCD


    Do kolegi wyżej przez cewkę płynie 12v, kwarc mogę zmienić na 16MHz.

    0
  • #5 17 Mar 2010 18:27
    tmf
    Moderator Mikrokontrolery Projektowanie
  • #6 18 Mar 2010 00:04
    Dawid_20
    Poziom 17  

    Co do zliczania ilości przerwań w ciągu 1s, to zadeklaruj sobie jakąś zmienną globalną (+volatile) którą inkrementujesz przy wywołaniu przerwania INT, puszczasz timer i po przekroczeniu 1s odczytujesz tą zmienną i wiesz ile razy nastąpiło przerwanie INT, a następnie zerujesz tą zmienna itd. Adekwatnie tak _BV(1) itd. :)
    Biblioteka do LCD 4bit, też kiedyś szukałem, ale w każdej co znalazłem było coś nie halo, wiec z tego co uzyskałem skleiłem to co było mi potrzebne, proszę:

    0
  • #7 18 Mar 2010 04:33
    Gandziorz
    Poziom 16  

    Dawid_20 napisał:
    Co do zliczania ilości przerwań w ciągu 1s, to zadeklaruj sobie jakąś zmienną globalną (+volatile) którą inkrementujesz przy wywołaniu przerwania INT, puszczasz timer i po przekroczeniu 1s odczytujesz tą zmienną i wiesz ile razy nastąpiło przerwanie INT, a następnie zerujesz tą zmienna itd. Adekwatnie tak _BV(1) itd. :)
    Biblioteka do LCD 4bit, też kiedyś szukałem, ale w każdej co znalazłem było coś nie halo, wiec z tego co uzyskałem skleiłem to co było mi potrzebne, proszę:

    Dzięki co prawda znalazłem coś takiego ale nie miałem jak sprawdzić jeszcze:
    http://mikrokontrolery.net/avr_c_08.htm

    Mógłbyś pokazać jakiś przykład z użyciem Timer1 w C?
    Na bascoma tego od cholery i ciut ciut.

    0
  • #8 18 Mar 2010 10:04
    Dawid_20
    Poziom 17  

    Do ustawiania jego parametrów służą dwa rejestry TCCR1A i TCCR1B, jeżeli ma chodzić jako zwykły tradycyjny timer to powinieneś tylko ustawić preskaler w rejestrze TCCR1B, w momencie ustawienia preskalera timer jest odpalany. W TCNT1 jest aktualna wartość licznika. Jeśli chcesz przerwanie od timera to w rejestrze TIMSK ustawiasz bit TOIE1(overflow), a obsługa to

    Code:
    SIGNAL(SIG_OVERFLOW1)
    
    {
    }

    0
  • #9 18 Mar 2010 15:09
    Gandziorz
    Poziom 16  

    Co do tranzystora to może nie uda się go samym prockiem otwierać i zamykać więc może wykorzystać LM358?
    Podłączyć go tak:
    Pin1 do tranzystora do bramki
    Pin2 "-" z masy
    Pin3 "+" z procka
    Pin4 do masy
    ...
    Pin8 "+" do 12V

    Ile by mi zwiększyło napięcie z 5V?

    0
  • #10 18 Mar 2010 16:09
    tmf
    Moderator Mikrokontrolery Projektowanie

    Zle kombinujesz. To jest tranzystor bipolarny, a takie wzmacniaja prad, a nie napiecie. Napiecie jest kwestia wtorna. Dlatego potrzebujesz uklad, ktory nie zwiekszy napiecia na bazie, tylko prad bazy. Moze to byc op-amp, ale zamiast tak komplikowac lepiej wstawic bufor, np. w postaci kolejnego tranzystora. Tu tylko pojawi sie problem, bo w ukladzie Darlingtona zwiekszy sie UCEsat, ktore dla tego tranzystora i tak juz jest wielkie, czyli bedzie sie mocno grzalo. Moze sa jakies nowoczesniejsze tranzystory do sterowania cewka? Moze lepiej MOSFETa mocy wpakowac? Driver oczywiscie i tak bedzie konieczny.
    Napisz tez cos o tych transoptorach, bo tu podejrzewam, ze masz kolejny blad. Co do liczenia czasu, to prosciej ci bedzie wykorzystac piny ICP. W sumie lepiej liczyc czas pomiedzy impulsami i z tego miec ilosc impulsow na sekunde, niz przy kazdym pomiarze czekac sekunde.

    0
  • #11 18 Mar 2010 16:49
    Gandziorz
    Poziom 16  

    tmf napisał:
    Zle kombinujesz. To jest tranzystor bipolarny, a takie wzmacniaja prad, a nie napiecie. Napiecie jest kwestia wtorna. Dlatego potrzebujesz uklad, ktory nie zwiekszy napiecia na bazie, tylko prad bazy. Moze to byc op-amp, ale zamiast tak komplikowac lepiej wstawic bufor, np. w postaci kolejnego tranzystora. Tu tylko pojawi sie problem, bo w ukladzie Darlingtona zwiekszy sie UCEsat, ktore dla tego tranzystora i tak juz jest wielkie, czyli bedzie sie mocno grzalo. Moze sa jakies nowoczesniejsze tranzystory do sterowania cewka? Moze lepiej MOSFETa mocy wpakowac? Driver oczywiscie i tak bedzie konieczny.
    Napisz tez cos o tych transoptorach, bo tu podejrzewam, ze masz kolejny blad. Co do liczenia czasu, to prosciej ci bedzie wykorzystac piny ICP. W sumie lepiej liczyc czas pomiedzy impulsami i z tego miec ilosc impulsow na sekunde, niz przy kazdym pomiarze czekac sekunde.

    BU931 stosuje się do sterowania cewką, po to został stworzony.
    Transoptory to TCST2300. W momencie wykrycia napięcia przepuszcza napięcia. Są one zasilane 5V.

    Póki co skroiłem taki kod:
    Code:
    //dolaczenie wymaganych plikow
    
    #include <avr/io.h>
    #include <util/delay.h>
    #include <avr/interrupt.h>
    #include <avr/signal.h>


    //DEFINICJE ODNOSNIE WYSWIETLACZA LCD NA STER. HD44780
    #define LCD  PORTC //pracuje na portach "C"
    #define E  5 //E jest na porcie PC5
    #define RS  4 //RS jest na porcie PC4
    //
    #define SET_E   LCD |= _BV(E)
    #define CLR_E   LCD &= ~_BV(E)
    //
    #define SET_RS  LCD |= _BV(RS)
    #define CLR_RS  LCD &= ~_BV(RS)



    // funkcja opóźniająca o x*1ms
    void waitms(char x)
    {
    unsigned char a, b; // zmnienne licznikowe
    for( ; x > 0; --x) // ta pętla zostanie wykonana x-razy
      for(b = 10; b > 0; --b) // a ta 10 razy
       for(a = 100; a > 0; --a) // natomiast ta 100 razy
       __asm("nop"); // dodatkowa instrukcja opóźniająca o 1 cykl
       // razem to da opóźnienie ok. x * 1ms
       // x od 0 do 255
    }

    // pcodedura zapisu bajtu do wyświetlacza LCD
    // bez rozróżnienia instrukcja/dana
    void write_to_lcd(char x)
    {
    SET_E; // ustaw na E stan wysoki
    LCD = ((LCD & 0x0F) | (x & 0xF0)); // zapis pierwszej połówki bajtu
    CLR_E; // opadające zbocze na E -> zapis do wyświetlacza
    SET_E; // ustaw na E stan wysoki
    LCD = ((LCD & 0x0F) | ((x & 0x0F) << 4)); // zapis drugiej połowki bajtu
    CLR_E; // opadające zbocze na E -> zapis do wyświetlacza




    waitms(1); // czekaj 1ms
    }

    // procedura zapisu instrukcji do wyświetlacza LCD
    void write_command(char x)
    {
    CLR_RS; // niski stan na RS -> zapis instrukcji
    write_to_lcd(x); // zapis do LCD
    }

    // procedura zapisu danej do wyświetlacza LCD
    void write_char(char x)
    {
    SET_RS; // wysoki stan na RS -> zapis danej
    write_to_lcd(x); // zapis do LCD
    }

    // procedura zapisu tekstu do wyświetlacza LCD
    void write_text(char * s)
    {
    while(*s) // do napotkania 0
      {
      write_char(*s); // zapisz znak wskazywany przez s na LCD
      s++; // zwiększ s (przygotuj nastepny znak)
      }
    }

    // procedura inicjalizacji wyświetlacza LCD
    void lcd_init(void)
    {
    waitms(15); // czekaj 15ms na ustabilizowanie się napięcia zasilającego
    CLR_E; // E = 0
    CLR_RS; // RS = 0
    char i; // zmianna licznikowa
    for(i = 0; i < 3; i++) // trzykrotne powtórzenie bloku instrukcji
      {
      SET_E; // E = 1
      LCD &= 0x3F; //
      CLR_E; // E = 0
      waitms(5); // czekaj 5ms
      }
    SET_E; // E = 1
    LCD &= 0x2E; //
    CLR_E; // E = 0
    waitms(1); // czekaj 1ms
    write_command(0x28); // interfejs 4-bity, 2-linie, znak 5x7
    write_command(0x08); // wyłącz LCD, kursor i miganie
    write_command(0x01); // czyść LCD
    write_command(0x06); // bez przesuwania w prawo
    write_command(0x0C); // włącz LCD, bez kursora i mrugania
    }

    //KONIEC FUNKCJI ODPOWIEDZIALNYCH ZA LCD

    //tablica z katami opoznienia/przyspieszenia zaplonu (co 1000rpm)
    char zaplon[9] = {15, 28, 31, 33, 34, 35, 35, 35, 35};


    //obsluga przerwan INT0 (dla prawego cylindra)
    SIGNAL (SIG_INTERRUPT0)
    {
    opoznij = opoznienie();
    waitms(opoznij);
    //otrzymalem sygnal ustawiam na porcie PA0 stan niski
    PORTA &=~_BV(0);
    //po 10ms przestaw na stan wysoki
    waitms(10);   
    PORTA |= _BV(0);
    }

    //obsluga przerwan INT1 (dla lewego cylindra)
    SIGNAL (SIG_INTERRUPT1)
    {
    opoznij = opoznienie();
    waitms(opoznij);
    //otrzymalem sygnal ustawiam na porcie PA1 stan niski
    PORTA &=~_BV(1);
    //po 10ms przestaw na stan wysoki
    waitms(10);   
    PORTA |= _BV(1);
    }



    //funkcja zwraca aktualne obroty/min, NIE WIEM JAK TO ZROBIĆ!?
    void obroty(void)
    {
    //obr wynosi 0
    obr = 0;
    //ilosc przerwan przez 1s z timer1 * 60 da nam obr/min
    obr = TCNT1 * 60;
    //zwroc obroty
    return obr;
    }

    //funckja ktora zwraca opoznienie od czasu otrzymania sygnalu
    void opoznienie(void)
    {
    ilerpm = obroty();
    ilerpms = ilerpm/60; //zmienia rpm/min na rpm/s np. 1200rpm/min na 20obr/s
    ileczasrpm = 1/ilerpms; //wskazuje czas 1 obrotu, np. 20obr/s = 1obr/0,05s

    switch (ilerpm)
    {
    //do 2000rpm
    case >= 2000:
    {
    //pobierz 1 wartosc z tablicy zaplon
    y = *(zaplon+1);
    //od kata 35st odejmij kat ktory jest przewidziany dla tych obrotow
    x = (35-y * ileczasrpm) / 360;
    beak;
    }

    //do 3000rpm
    case  >=3000:
    {
    y = *(zaplon+2);
    x = (35-y * ileczasrpm) / 360;
    beak;
    }

    ///////////////////////////////

    //do 4000rpm
    case >=4000:
    {
    y = *(zaplon+3);
    x = (35-y * ileczasrpm) / 360;
    beak;
    }
    //do 5000rpm
    case >= 5000:
    {
    y = *(zaplon+4);
    x = (35-y * ileczasrpm) / 360;
    beak;
    }
    //do 6000rpm
    case >= 6000:
    {
    y = *(zaplon+5);
    x = (35-y * ileczasrpm) / 360;
    beak;
    }
    //do 7000rpm
    case >= 7000:
    {
    y = *(zaplon+6);
    x = (35-y * ileczasrpm) / 360;
    beak;
    }
    //do 8000rpm
    case >= 8000:
    {
    y = *(zaplon+7);
    x = (35-y * ileczasrpm) / 360;
    beak;
    }
    //do 9000rpm
    case >= 9000:
    {
    //pobierz 1 wartosc z tablicy zaplon
    y = *(zaplon+8);
    x = (35-y * ileczasrpm) / 360;
    beak;
    }
    //powyzej 9000rpm
    case  <9000:
    {
    //pobierz 1 wartosc z tablicy zaplon
    y = *(zaplon+9);
    x = (35-y * ileczasrpm) / 360;
    beak;
    }
    return x;
    }



    //Program glowny
    int main(void)
    {
    // konfiguracja portów
    DDRA = 0xFF; //PORT "A" jako wyjscie
    DDRC = 0xFF; //PORT "C" jako wyjscie
    PORTC = 0xFF;

    // inicjalizacja LCD
    lcd_init();

    // zapisz na LCD przykładowy tekst
    write_text("Sterownik zapłonu");

    //na LCD wyswietli aktualne obroty/min
    wart = obroty();
    write_text (wart." obr/min");

    // globalne odblokowanie przerwań
    sei();


    // pusta pętla nieskoczona
    while(1);
    return 0;
    }

    Jest w nim zapewne masa błędów i dalej nie wiem jak rozwiązać sprawę zliczania do timer1 ilość przerwań przez 1s.

    0
  • #12 18 Mar 2010 18:46
    tmf
    Moderator Mikrokontrolery Projektowanie

    Owszem, pisza, ze do tego, ale nigdzie nie pisza, ze ma byc sterowany z mikroprocesora. Typowa jego aplikacja jest zapewne inna, stad ma takie, a nie inne parametry, ktore jednak nie przystaja do sterowania z portu IO procesora. Co do transoptorow to skoro jest tak jak piszesz to wnioskuje ze schematu, ze masz kolejny blad. Transoptor jest w ukladzie OE lub OC, wiec musisz zapewnic podciaganie, ktorego nie masz na schemacie. Przy okazji, czy stosowanie transoptora w motorze to dobry pomysl? Niesadze.
    Co do twojego programu - zamiast pisac wlasne opoznienia, skorzystaj z delay.h - to co stworzyles jako waitms bedzie generowalo wlasciwe opoznienie tylko przypadkowo. Opoznien nie nalezy umieszczac w procedurze obslugi przerwania - od tego masz timery.
    Co do liczenia obrotow - jak pisalem lepiej to zrobic tak, zeby timer liczyl stale odcinki czasu, np. zmienial stan co 1us i skorzystac z ICP. Wtedy mozesz liczyc okres impulsow, a z tego juz banalnie ilosc impulsow na sekunde.

    0
  • #13 18 Mar 2010 19:33
    atom1477
    Poziom 43  

    A do sterowania tranzystora BU931 możesz wstawić zwykłego BC547. Tylko nie w układzie Darlingtona tylko w układzie wtórnika emiterowego.
    Dzięki temu napięcie UCEsat tranzystora BU931 nie ulegnie zwiększeniu. Kolektor BC547 do +5V. Emiter do rezystora 220R który to do ma iść masy. I ten emiter jednocześnie rezystorem do bazy BU931.
    Baza BC547 rezystorem 2k2...10k do uC.

    0
  • #14 19 Mar 2010 14:32
    Gandziorz
    Poziom 16  

    Skupiam się cały czas na tym obrotomierzu i nerwicy dostaję bo wszystko co znajdę jest na Bascomie a nie na "C".

    W przerwaniu INT0 dałem zmienną impulsy (int):

    Code:
    //obsluga przerwan INT0 (dla prawego cylindra)
    
    SIGNAL (SIG_INTERRUPT0)
    {
    //liczenie impulsow do zmiennej "impulsy"
    impulsy++;
    //otrzymalem sygnal ustawiam na porcie PA0 stan niski
    PORTA &=~_BV(0);
    //po 10ms przestaw na stan wysoki
    delay_ms(10);   
    PORTA |= _BV(0);
    }


    Teraz buduję funkcję "obrotomierz" która ma zwracać obr/s
    Code:
    void obrotomierz(void) {
    
    rpm = 0; //zmiennej rpm przypisuje wartosc 0
    TCNT1 = 0; //do zegara timer1 przypisuje wartosc 0
    impulsy = 0; //zmienna impulsy przypisuje wartosc 0, od nowa zacznie się zwiększać przy każdej przerwie na INT0 o 1

    /*TU POWINIEN RUSZYC ZEGAR*/
    delay_ms(100); //przerwa 1s
    /*TU POWINIEN ZATRZYMAC SIE ZEGAR*/

    rpm = impulsy; //do zmiennej rpm przypisuje ilosc impulsow przez 1s
    return rpm;
    }


    Na końcu wyświetlanie obr/min na LCD za pomocą:
    Code:
    //pobiera informację o obrotach z funkcji obrotomierz
    
    x = obrotomierz();
    //jako ze wynik tej funkcji podawany jest w obr/s aby otrzymac obr/min przemnazam * 60
    x = x * 60;

    _lcd_ready();
    lcd_gotoxy(0,0); //pierwsza linijka
    lcd_putsf("Obroty:");
    lcd_putchar(x);
    lcd_putsf("obr/min");


    Ale jak zrobić dobrze tą funkcję "obrotomierz" to ja nie wiem :/ Na bascoma jak pisałem wystarczyło by "Start Timer1", "Stop Timer1". A tu jestem w błędnym kole i nie potrafię tego wykonać, pomożecie chłopaki napisać tą funkcję?
    Czytam, googluje i jestem załamany :(

    A takie coś zadziała bez timera?

    W momencie wykrycia przerwania (zbocze wysokie) do zmiennej "impulsy" dodawana jest wartość +1
    Code:
    //obsluga przerwan INT0 (dla prawego cylindra)
    
    SIGNAL (SIG_INTERRUPT0)
    {
    //liczenie impulsow do zmiennej "impulsy"
    impulsy++;
    //otrzymalem sygnal ustawiam na porcie PA0 stan niski
    PORTA &=~_BV(0);
    //po 10ms przestaw na stan wysoki
    delay_ms(10);   
    PORTA |= _BV(0);
    }


    W momencie wywowałania funkcji obrotomierz, w funkcji zmienna "impulsy" jest zerowana i zaczyna się na nowo dodawanie "+1" do zmiennej impulsy w procedurze przerwania. Po 1s (delay_ms(100)) funkcja zwraca wartość z zmiennej impulsy.

    Code:
    void obrotomierz(void) {
    
    rpm = 0; //zmiennej rpm przypisuje wartosc 0
    impulsy = 0; //zmienna impulsy przypisuje wartosc 0, od nowa zacznie się zwiększać przy każdej przerwie na INT0 o 1
    delay_ms(100); //przerwa 1s
    rpm = impulsy; //do zmiennej rpm przypisuje ilosc impulsow przez 1s
    return rpm;
    }


    Co do tranzystora załączania cewki to może bu931 zamienić na IRGB14C40LPBF ?

    0
  • #15 20 Mar 2010 11:14
    Dawid_20
    Poziom 17  

    Wiec tak, po pierwsze _delay_ms(100) to wcale nie jest 1s. Mając opóźnienie czasowe w przerwaniu INT0 nie jest to dobre rozwiązanie, a jak przerwanie będzie przychodzić częściej jak 10ms? Namiesza Ci się troszkę;] W przerwaniu INT0 zwiększaj tylko zmienną impulsy i ustaw jakąś flagę, a w programie głównym po wykryciu ustawionej właśnie tej flagi wykonaj akcję

    Code:
    //otrzymalem sygnal ustawiam na porcie PA0 stan niski 
    
    PORTA &=~_BV(0);
    //po 10ms przestaw na stan wysoki
    delay_ms(10);   
    PORTA |= _BV(0);

    Pomiar tych impulsów nie rób po przez zwieszanie procka na 1s, w interesującym momencie włączasz timer, a do TCNT1 ładujesz taką wartość aby po dobiciu licznika do końca minęła 1s, wartość ta jest zależna od ustawionego preskalera i właśnie moment kiedy ustawisz preskaler to licznik zaczyna pracować. W Bascomie jest trochę inaczej, tam na początku deklarujesz sobie preskaler a później Start Timer, a w C deklaracją preskalera go włączasz.
    Code:
    TCCR1B |= _BV(CS11);  //włączasz timer, prescaler 8
    
    TCCR1B &=~_BV(CS11); // nie ma sygnału zegarowego,timer zatrzymany

    No i po takim czymś wywołane zostanie przepełnienie od timera OVERFLOW w którym
    Code:
    TCNT1 = wartosc okreslajaca 1s
    
    rpm = impulsy; //do zmiennej rpm przypisuje ilosc impulsow przez 1s
    impulsy=0;

    Zamiast szukać gotowych rozwiązań, których jak piszesz nie możesz znaleźć wystarczy poczytać trochę ze zrozumieniem notę katalogową. To jest na tyle prosty program, że wystarczy zajrzeć jakie rejestry i jakie bity trzeba raz ustawić, a raz nie.

    0
  • #16 20 Mar 2010 15:12
    Gandziorz
    Poziom 16  

    Dawid_20 napisał:
    Wiec tak, po pierwsze _delay_ms(100) to wcale nie jest 1s. Mając opóźnienie czasowe w przerwaniu INT0 nie jest to dobre rozwiązanie, a jak przerwanie będzie przychodzić częściej jak 10ms? Namiesza Ci się troszkę;] W przerwaniu INT0 zwiększaj tylko zmienną impulsy i ustaw jakąś flagę, a w programie głównym po wykryciu ustawionej właśnie tej flagi wykonaj akcję
    Code:
    //otrzymalem sygnal ustawiam na porcie PA0 stan niski 
    
    PORTA &=~_BV(0);
    //po 10ms przestaw na stan wysoki
    delay_ms(10);   
    PORTA |= _BV(0);

    Pomiar tych impulsów nie rób po przez zwieszanie procka na 1s, w interesującym momencie włączasz timer, a do TCNT1 ładujesz taką wartość aby po dobiciu licznika do końca minęła 1s, wartość ta jest zależna od ustawionego preskalera i właśnie moment kiedy ustawisz preskaler to licznik zaczyna pracować. W Bascomie jest trochę inaczej, tam na początku deklarujesz sobie preskaler a później Start Timer, a w C deklaracją preskalera go włączasz.
    Code:
    TCCR1B |= _BV(CS11);  //włączasz timer, prescaler 8
    
    TCCR1B &=~_BV(CS11); // nie ma sygnału zegarowego,timer zatrzymany

    No i po takim czymś wywołane zostanie przepełnienie od timera OVERFLOW w którym
    Code:
    TCNT1 = wartosc okreslajaca 1s
    
    rpm = impulsy; //do zmiennej rpm przypisuje ilosc impulsow przez 1s
    impulsy=0;

    Zamiast szukać gotowych rozwiązań, których jak piszesz nie możesz znaleźć wystarczy poczytać trochę ze zrozumieniem notę katalogową. To jest na tyle prosty program, że wystarczy zajrzeć jakie rejestry i jakie bity trzeba raz ustawić, a raz nie.

    No okej, okej, ale chodzi o to że w przerwaniu musi nastąpić na "chwileczkę" przerwa do tranzystora, by cewka się rozładowała (iskra).
    I przed tą akcją jest opóźnienie (wyprzedzenie zapłonu).
    Np. po otrzymaniu sygnału na INT0 po okreslonej ilosci ms ma wystapic otwarcie tranzystora, po otwarciu znow ma sie zamykac.
    Np. dla obrotow 1200 i kata 15st. bedzie to wygladalo tak:
    1200obr/min = 20obr/s = 1obr/0,05s
    1s = 1000ms
    ((35-15)*0,05s)/360 = 0,0028s = 28ms

    I teraz mamy:
    1) otrzymałem sygnał na INT0
    2) poczekaj 28ms
    3) ustaw stan niski na porcie PA0 //w tym momencie tranzystor jest w pozycji otwartej i nastepuje iskra
    4) ustaw stan wysoki na porcie PA0 //w tym momencie tranzystor sie zamyka a cewka kumuluje energie do nastepnego wyladowania

    Wiec jezeli tego nie zrobic w INT to jak?

    0
  • #17 20 Mar 2010 20:06
    tmf
    Moderator Mikrokontrolery Projektowanie

    Inaczej :) Przerwanie INT ma tylko wywolac pewna sekwencje zdarzen, a nie ja realizowac. Tak wiec w procedurze obslugi tego przerwania ustawiasz tranzystor w stan, ktory cie interesuje, inicjalizujesz timer i w procedurze obslugi przerwania timera robisz z tranzystorem ponownie co tam jest potrzebne. Dzieki temu unikasz robienia opoznien w procedurze obslugi przerwania, a dodatkowo czas opoznienia jest latwo sterowany sprzetowo.

    0
  • #18 20 Mar 2010 20:48
    Gandziorz
    Poziom 16  

    tmf napisał:
    Inaczej :) Przerwanie INT ma tylko wywolac pewna sekwencje zdarzen, a nie ja realizowac. Tak wiec w procedurze obslugi tego przerwania ustawiasz tranzystor w stan, ktory cie interesuje, inicjalizujesz timer i w procedurze obslugi przerwania timera robisz z tranzystorem ponownie co tam jest potrzebne. Dzieki temu unikasz robienia opoznien w procedurze obslugi przerwania, a dodatkowo czas opoznienia jest latwo sterowany sprzetowo.

    Czyli w INT zrobić tylko odwołanie do funkcji i timer do zliczania impulsów. Dopiero funkcja do której się odwołuje ma wykonywać odpowiednią akcję, dobrze zrozumiałem?

    Więc w INT zrobić tak:
    Code:
    //obsluga przerwan INT0 (dla prawego cylindra)
    
    SIGNAL (SIG_INTERRUPT0)
    {
    zaplon(); //odwolanie do funkcji zaplon
    TCCR1B |= _BV(CS11);  //włączasz timer, prescaler 8
    TCCR1B &=~_BV(CS11); // nie ma sygnału zegarowego,timer zatrzymany
    }



    W funkcji obrotomierz czyli to co chce wykorzystać do funkcji zaplon i do wysw. informacji na LCD:
    Code:
    void obrotomierz(void) {
    
    TCNT1 = 62500; //wartosc okreslajaca 1s, 4000000Hz / 64 / 62500 = 1sekunda
    rpm = impulsy; //do zmiennej rpm przypisuje ilosc impulsow przez 1s
    impulsy = 0;
    return rpm;
    }


    Funkcja zaplon czyli wybieranie kata dostosowanego do obrotów, otwieranie/zamykanie tranzystora.

    Teraz zostaje jeszcze pytanie odnośnie:
    -IRGB14C40LPBF jako tranzystor do sterowania cewką

    Chciałbym mierzyć również prąd w instalacji (podejrzewam że będzie od 10-15V) więc chciałbym zrobić to na zasadzie dławików.
    Więc zakres chciałbym dać 0-20V. Jakie zastosować wartości do dzielnika? 2x47k wystarczą?

    0
  • #19 24 Mar 2010 05:00
    Gandziorz
    Poziom 16  

    Koledzy pomogą dobrać odpowiedni tranzystor do sterowania cewką?

    0
  • #20 28 Mar 2010 16:19
    Gandziorz
    Poziom 16  

    Żeby nie zakładać nowego tematu, zastanwiam się cały czas jaki tranzystor NPN mógłbym bezpośrednio otwierać/zamykać przy pomocy mikrokontrolera.
    Czy napięcie mikrokontrolera jest w stanie zamknąć tranzystor IRGB14C40LPBF?

    0
  • #21 28 Mar 2010 17:23
    tmf
    Moderator Mikrokontrolery Projektowanie

    Nie. MOSFETy mocy maja zwykle pojemność bramki kolo 1nF, procesor nie ma wystarczającej wydajności prądowej, żeby taką bramkę wysterować - w efekcie MOSFET albo będzie się grzał, albo się spali. Ciągle nie podałeś jakie parametry ma stosowana przez ciebie cewka zapłonowa. Każdy z wymienionych przez ciebie tranzystorów zapewne będzie dobry, pod warunkiem właściwego wysterowania - więc skup się raczej na tym problemie, a nie na tranzystorze sterującym cewką.

    0
  • #22 28 Mar 2010 18:25
    Dr_DEAD
    Poziom 28  

    tmf napisał:
    Nie. MOSFETy mocy maja zwykle pojemność bramki kolo 1nF, procesor nie ma wystarczającej wydajności prądowej, żeby taką bramkę wysterować - w efekcie MOSFET albo będzie się grzał, albo się spali.

    Bez przesady, przy częstotliwości 200-300Hz nie jest wymagany jakiś specjalny driver, chyba że ze względu na napięcie sterujące bramką - 5V może nie dać zadowalająco małej rezystancji drenu.

    Dodano po 7 [minuty]:

    Gandziorz napisał:

    Czy napięcie mikrokontrolera jest w stanie zamknąć tranzystor IRGB14C40LPBF?

    Jasne, że tak, pierwszorzędny wybór :-).

    0
  • #23 28 Mar 2010 19:11
    Gandziorz
    Poziom 16  

    tmf napisał:
    Nie. MOSFETy mocy maja zwykle pojemność bramki kolo 1nF, procesor nie ma wystarczającej wydajności prądowej, żeby taką bramkę wysterować - w efekcie MOSFET albo będzie się grzał, albo się spali. Ciągle nie podałeś jakie parametry ma stosowana przez ciebie cewka zapłonowa. Każdy z wymienionych przez ciebie tranzystorów zapewne będzie dobry, pod warunkiem właściwego wysterowania - więc skup się raczej na tym problemie, a nie na tranzystorze sterującym cewką.

    Jak byś kolego rozwiązał sterowanie tym tranzystorem?

    Jeżeli mój wybór jest pierwszorzędny to pozostanę przy nim, pozostaje kwestia dobrego sterowania.

    0
  • #24 28 Mar 2010 19:53
    tmf
    Moderator Mikrokontrolery Projektowanie

    Dr_DEAD zapomina, że nie tyle chodzi tu o częstotliwość, co czas przełączenia tranzystora - jeśli ma on pracować jako klucz z dużym prądem drenu to RDSon powinno szybko maleć - inaczej na tranzystorze wydzieli się sporo mocy, co go może uszkodzić. Czyli w możliwie krótkim czasie należy przeładować pojemność bramki, co daje nam duży prąd.
    Gandziorz - jeśli zdecydujesz sie na w/w MOSFETa to masz dwie możliwości - prosta i nie najtańsza (koszt pare zł) to kupić coś co się nazywa MOSFET driver, w TME maja takowe od kilku zł. Jeśli masz czas i ochotę, to możesz to zmajstrować za pomocą pary komplementarnej złożonej z dwóch tranzystorów bipolarnych + pare rezystorów.

    0
  • #25 01 Kwi 2010 12:39
    Gandziorz
    Poziom 16  

    Popatrzyłem na te drivery na tme, ale zwłaszcza na elektrodzie.

    Z tego co zobaczyłem i wyczytałem do mojego zastosowania może nadać się IR2110. Przepełnienie bramki następuje max 10ns.

    Myślicie że to dobry driver do tranzystora IRGB14C40LPBF?

    0
  • #26 05 Kwi 2010 23:38
    Gandziorz
    Poziom 16  

    Ponawiam prośbę, czy ten driver nada się do moich celów?

    Do moderatorów, przepraszam że post pod postem ale nie chce zakładać nowego wątku.

    0
  • #27 06 Kwi 2010 10:59
    tmf
    Moderator Mikrokontrolery Projektowanie

    No ale tranzystor IRGB14C40LPBF to tranzystor bipolarny z izolowaną bramką (IGBT), a nie MOSFET.

    0
  • #29 06 Kwi 2010 12:25
    tmf
    Moderator Mikrokontrolery Projektowanie