niedziela, 20 marca 2011

DIY: Timer silników rakietowych


Autor: Templarious
Redakcja: Dondu

Modelarstwo rakietowe to piękny sport uprawiany przez nielicznych. Jego piękno tkwi w modelach rakiet oraz wielu silników rakietowych które tworzą amatorzy tego sportu. Elektroniczne moduły zapalające silniki są nieodzownym elementem stanowiącym bezpieczeństwo tego sportu.

Moja propozycja timera (spark ignition system) do silników rakietowych jest wspaniałym rozwiązaniem niosącym ze sobą frajde z odpalania silnika bez lontu - a cyfrowo, a przy tym całkowicie bezpiecznie. Daje to dużo frajdy, słysząc odliczanie sekund po którym następuje start rakiety albo to wszystko za nacisnięciem jednego przycisku (tryb manualny).

Całość sterowana jest przez mikrokontroler ATMega8 oraz 2 rejestry przesuwne, kilka tranzystorów i mosfet IRF371S wykonawczy, który przepala drut.







Hardware

Timer prezentuje się następująco:

Timer do silników rakietowych
Timer do silników rakietowych

Schemat

 Schemat układu został narysowany w programie Eagle 6.4.0 i jest widoczny poniżej.

Rysunek 1 Schemat układu w programie Eagle 6.4.0

Sercem całego układu jest mikrokontroler ATmega8L, który taktowany jest wewnętrznym sygnałem 8Mhz. Mikrokontroler został zasilony przetwornicą impulsową LM2675M-5.0NOPB.

Układ projektowałem z myślą odprzęgania zasilania, tzn. dobranie elementów i rozłożenie ich na płytce PCB aby EMC było jak najniższe. Oczywiście EMC, to emisja fal elektromagnetycznych. Do tego użyłem kondensatorów ceramicznych o wartości 100nF zarówno przy przetwornicy jak i przy mikrokontrolerze przy pinach AVCC oraz AREF (gdyż nie jest wykorzystywane) oraz 2 kondensatory 330uF elektrolityczne tuż za przetwornicą. Kondensatory elektrolityczne odprzęgają zasilanie z zakresu niskich częstotliwości a kondensatory ceramiczne - z wyższych częstotliwości tętnienia zasilania. Oczywiście rezystor 10k ohm podciągnięty jest od pinu RESET do zasilania VCC równym +5V.


Płytka PCB oraz opis elementów



Rysunek 2 Opis elementów po stronie TOP
Rysunek 2 Opis elementów po stronie TOP


Rysunek 3 Opis elementów po stronie BOTTOM

Do pobrania: Timer-PCB.zip (kopia)


Zasilanie

Zdecydowałem się na zastosowanie przetwornicy impulsowej LM2675M-5.0NOPB. Jest ona zastosowana nad "wyrost" ponieważ wg. noty katalogowej dopuszczalny prąd na wyjściu to 1A, a cały układ nie pobiera więcej niż 300mA. Zastosowanie jej ma jednak swoje uzasadnienie, ze względu na jej sprawność oraz to, że nie grzeje się. Wcześniejszy stabilizator liniowy LM7805 niestety po krótkim czasie grzał się dosyć mocno i uznałem, że trzeba zainwestować w coś dobrego i cieszyć się zabawką dłuższą chwilą.

Wyświetlacz

Do wyświetlania czasu, użyłem wyświetlacza 7-mio segmentowego o wysokości znaku około 2 cm, który sterowany jest bezpośrednio z 2 rejestrów (po 1 rejestrze na cyfrę) 74HC595. Same rejestry są sterowane za pomocą interfejsu SPI ale o nim powiem troszkę dalej. Obie cyfry wyświetlacza są włączane za pomocą tranzystorów PNP BC807.

Wyświetlacz posiada wspólną anodę (+) i stereowany jest masą od strony rejestrów przesuwnych z ograniczeniem prądu poprzez oporniki 330 ohm. Użyte rejestry przesuwne zapewniają brak duchów na wyświetlaczu ponieważ wyposażone są w zatrzaski. Przepisują one zawartość buforu na wyjście :). Oczywiście całość nie jest multipleksowana. Każda cyfra wyświetlacza ma osobny rejestr 8śmio bitowy.

Impulsator

Impulsator (enkoder) służy do inkrementacji albo dekrementacji czasu. Możliwy jest zakres regulacji od 5 do 99 sekund gdzie 99 sekund to wejście w tryb manualny - zatem faktyczny zakres czasu wacha się od 5 do 98 sekund. Nie bez powodu minimalny czas do odpalenia jest równy 5, a jest on ze względów bezpieczeństwa. W razie omyłkowego naciśnięcia przycisku odliczania (enkodera) możliwe jest jego zatrzymanie poprzez naciśnięcie przycisku podłączonego do portu PD2 mikrokontrolera.

Przycisk enkodera służy do rozpoczęcia odliczania czasu, którego zliczenie do 0 powoduje odpalenie ładunku pirotechnicznego albo silnika etc.. (fajerwerki również) bądź też do wejścia w tryb manualny (o którym mowa była wczesniej) wtedy i tylko wtedy gdy czas będzie równy 99.

Kontrola zapalnika

Układ timera wyposażony jest również w kontrole obecności zapalnika, a realizuje to dzielnik napięcia złożony z rezystorów 12k ohm oraz 7,5k ohm który z 13V daje nam na wyjściu 5v. (13V ponieważ wiekszość akumulatorów ma około 12V z hakiem więc wziąłem pod uwagę 13V.). Całość podłączona jest do portu PC0 mikrokontrolera (ADC).

Gdy zapalnik zostanie wykryty, zostanie włączona kropka DP2 na wyświetlaczu (prawy dolny róg) który zasygnalizuje jego obecność. Port ten (ADC) i konfiguracja dzielnika napięcia umożliwia modyfikację programu do odczytywania napięcia na drucie oporowym. Ze względów bezpieczeństwa dodałem opornik 1k ohm, który ogranicza prąd docierający do uC i zabezpiecza go przed dużym prądem.

Buzzer

Buzzer jest tutaj fajnym gadżetem, który sygnalizuje akustycznie każdą sekundę oraz sam moment "odpalenia" :-)

Tranzystor MOSFET

Cała robotę rozpalania drutu oporowego pełni MOSFET IRF3711S który sterowany jest masą od strony Atmegi poprzez tranzystor PNP BC847A. Rezystory podciągające służą do wymuszenia stanu linii pomiędzy tranzystorem a MOSFET'em w taki sposób aby podczas uruchomienia układu oraz podłączonego zapalnika (co nie jest wskazane) nie było przypadkowego odpalenia ładunku - gdybyśmy byli koło niego.

Przyciski

Dodatkowo każdy przycisk posiada sprzętową eliminację drgań - jest ona zawsze pewna nie to co program :). Składa sie ona z: rezystora 330 ohm pomiędzy pinem uc a przyciskiem, w szeregu jest kondensator 100nF ceramiczny i całość tuż za opornikiem 330 ohm po stronie przycisku, podłączona przez rezystor 47k ohm do zasilania VCC +5V.

Dioda prostownicza

W układzie została użyta dioda prostownicza 1N4007 (SM4007 smd), która zabezpiecza układ przed odwrotnym podłączeniem zasilania. Należy pamiętać, że owa dioda powoduje spadek napięcia w okolicach 0.7V.





Software

Cały program został napisany w języku C (wydaje mi się włatwiejszy niż C++) w programie AVR studio 4 i przy użyciu kompilatora avr-gcc. Starałem się aby cały kod został opatrzony w niezbędne komentarze oraz niektóre elementy wpakowałem do osobnych plików nagłówkowych, tak aby ich modyfikacja była szybka bez długiego szukania fragmentu w kodzie.

Timery

W projekcie zostały użyte wszystkie timer'y tzn. Timer 16 bit, który zajmuje się odliczaniem sekundy (nie pełnej, tak naprawde to sekunda i 4 setne. - TIMER1) oraz 2 Timery 8 Bitowe. Jeden z nich zajmuje się sygnalizacją akustyczną czyli jednorazowym "beep" po sekundzie (TIMER0) a ostatni timer zajmuje się miganiem wyświetlacza w odpowiednim trybie lub z jego wyjścia (TIMER2).

Timer 16 bitowy:
 // Timer Counter 1 16bit = WGM12 - CTC for OCR1A, CS12 prescaler 256
TCCR1B = _BV(WGM12)|_BV(CS12);


Ten zapis świadczy o tym, że owy timer został użyty w trybie CTC (clear timer on compare w tym wypadku z OCR1A), a preskaler został ustawiony na 256.

Timer0:
// TIMER0 8 bit preskaler 1024 (dla buzzera)
TCCR0 = _BV(CS02)| _BV(CS00);


Jego inicjacja jest prosta, uchwyt wektora ISR(TIMER0_OVF_vect) - przepełnienie timera, powoduje uruchomienie uchwytu wektora ISR, w którym jest jakaś funkcja.

Kolejny Timer2 również jest w trybe OVF (przepełnienie) i jak w przypadku powyżej - jego przepełnienie powoduje wykonanie jakiejś funkcji.


Działanie przycisków

Pozwoliłem sobie stworzyć odpowiednio tabęlkę, która pokazuje dostępne opcje urządzenia, zarówno przed startem odliczania oraz po "starcie" - czyli naciśnięciu przycisku enkodera.

Przed uruchomieniem odliczania dostępne są opcje:

TRYB Przycisk enkodera obrót w lewo enk. obrót w prawo enk. Przycisk czerwony
automatyczny start odliczania zmniejsz czas zwieksz czas wstrzymaj odliczanie
manualny odpalenie ładunku - - powrót do trybu aut.

Po naciśnięciu przycisku enkodera i rozpoczęciu odliczania:

TRYB Przycisk enkodera obrót w lewo enk. obrót w prawo enk. Przycisk czerwony
automatyczny - - - wstrzymaj odliczanie


Fuse bits

Trzeba pamiętać również o własciwym ustawieniu Fuse bitów, a mianowicie ustawienie sygnału taktującego mikrokontroler. W tym projekcie jest to 8MHz wew. co odpowiada wartości:
  • High Fuse: 0xD9
  • Low Fuse: 0x24


sparkv2_nowy.c

Jest to główny plik (coś jak znane i lubiane main.c), który kontroluje wszystko. Posiada on zdefiniowane pliki nagłówkowe i standartowe biblioteki jak np. <avr/io.h>. Dzięki zdefiniowaniu makr (widoczne poniżej) możliwe jest szybkie zastosowanie wyrażenia BUZZER_ON; niż pisać _BV(PD7) i uniknąć przy ty błędów...

/*
  Autor: Tomasz Sikorski
  Created at: 25.02.2014

  Project: Rocket ignition Timer / Fireworks
*/

#include <avr/io.h>         // Załaduj bibliotekę input/output
#include <avr/interrupt.h> // Załaduj bibliotekę obsługi przerwań
#include <util/delay.h>    // Załaduj bibliotekę opóźnień
#include <stdbool.h>       // Załaduj bibliotekę typów logicznych (bool)
#include "enkoder.h"       // Załaduj bibliotekę zew. (do obsługi enkodera)
#include "ioinit.h"        // Załaduj bilbiotekę zew. (do ustawienia portów
                           // ATMega 8)

// Definicja makr (aby łatwiej było używać częstych zmian danego
// portu. (np. włacz/wyłącz buzzer)
#define RCK_ON  PORTB |= _BV(PB2)
#define RCK_OFF PORTB &= ~_BV(PB2)

#define HOT_WIRE_ON  PORTB &= ~_BV(PB1)
#define HOT_WIRE_OFF PORTB |= _BV(PB1)

#define BUZZ_OFF PORTD &= ~_BV(PD7)
#define BUZZ_ON  PORTD |= _BV(PD7)

#define WYS1_OFF PORTD |= _BV(PD0)
#define WYS1_ON  PORTD &= ~_BV(PD0)

#define WYS2_OFF PORTD |= _BV(PD1)
#define WYS2_ON  PORTD &= ~_BV(PD1)

#define FIRE_ON  PORTD &= ~_BV(PD6)
#define FIRE_OFF PORTD |= _BV(PD6)

// =============================================================

bool enkoder = 1,manual=0,manual_scan=0,
     hold=1;         // tryb automatyczny włączony
uint8_t time = 5,
        time_save;     // przechowuje aktualny czas do odliczania.

//Tablica znaków wyświetlacza: 0,1,2,3,4,5,6,7,8,9,-
uint8_t digits[11] = {0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0xBF};


// Procedura wysyłające dane po SPI
void SPI_send(uint8_t byte)
{
  PORTB&=~(_BV(PB2));
  SPDR=byte;
  while(!(SPSR & _BV(SPIF)));
  PORTB|=_BV(PB2);
}

// =============================================================

// Procedura wyświetlająca cyfry na wyświetlaczu
void ShowOn_LED(uint8_t val)
{
  SPDR = digits[val%10];
  while(!(SPSR & _BV(SPIF)));
  SPDR = (val>9) ? digits[((val/10)%10)]: 0xFF;
  while(!(SPSR & _BV(SPIF)));

  RCK_ON;
  RCK_OFF;
}

// =============================================================

// Procedura migająca kreskami na ekranie, mówiąca użytkownikowi
// o trybie manualnym
void manual_signal()
{
  SPI_send(0xBF);       // Wyświetl kreski na wyświetlaczu 1
  SPI_send(0xBF);       // Wyświetl kreski na wyświetlaczu 2
  for(int i=0; i<7; i++) {
    BUZZ_ON;
    WYS1_ON;
    WYS2_ON;
    _delay_ms(100);
    WYS1_OFF;
    WYS2_OFF;
    BUZZ_OFF;
    _delay_ms(100);
  }
  WYS1_ON;
  WYS2_ON;
}

// =============================================================

// Procedura powitania - wyświetlanie znaków [] na wyśw.
void hello()
{
  WYS1_ON;
  WYS2_ON;
  SPI_send(0b11110000);//]
  SPI_send(0b11000110);//[
  BUZZ_ON;
  _delay_ms(1000);
  BUZZ_OFF;
  _delay_ms(500);

}

// =============================================================


ISR(INT1_vect)  // uchwyt wektora INT1
{
  TCCR2=0; // wyłącz TIMER2 do migania wyswietlaczami w trybie hold
  if(bit_is_set(PINC,0)) {  // Jeśli wykryty zapalnik
    if(time!=99) {
      TCCR1B = _BV(WGM12)|_BV(CS12);  //Timer Counter 1 16bit = WGM12 - CTC 
                                      //for OCR1A, CS12 prescaler 256
      enkoder=0;            // zablokuj enkoder
      time_save=time;       // zapisz czas do zmiennej
    }
  }

  if(time==99) {
    // wejście w tryb manualny
    enkoder=0;
    manual=1;
    manual_scan=1;
  }
}

// =============================================================

ISR(TIMER1_COMPA_vect)  // Uchwyt wektora porównania TIMER1 z OCR1A
{

  BUZZ_ON;            // Potrzebne do sygnalizacji sekundy
  TCCR0 = _BV(CS02)| _BV(CS00); // TIMER0 8 bit preskaler 1024 (dla buzzera)
  time--;           // dekrementuj czas
}

// =============================================================

ISR(TIMER0_OVF_vect)  // Przepełnienie TIMER0 (BUZZER)
{
  BUZZ_OFF;           // Wyłącza BUZZER sygnalizacyjny sekunde
  TCCR0 = 0;          // Wyłącz preskaler TIMER0 8bit
}

// =============================================================

ISR(INT0_vect)            //Uchwyt wektora przycisku ABORT
{
  TCCR1B = 0;           // wyłącz odliczanie
  TCCR2 = _BV(CS20) | _BV(CS21) | _BV(
            CS22);  // prescaler 1024 Timer/Counter2 = uruchom timer2
}

// =============================================================

ISR(TIMER2_OVF_vect)
{
  hold=1;             // tryb hold
}

// =============================================================

int main(void)
{

  ioinit();                     // Wczytaj konfiguracje pinów
  SPCR = _BV(SPE) | _BV(MSTR) | _BV(SPI2X); // (SPE) SPI Enable, 
                                            // (MSTR)Master ON, (SPI2X) fosc/2
  GICR = _BV(INT1) | _BV(INT0);    // Włącz obsługe żądań przerwań na INT0/INT1
  MCUCR = _BV(ISC11) | _BV(ISC01); // INT1 INT0 zbocze opadające

  TCNT1 = 0x00;
  OCR1A = 31250;            // Wartość do której porównuje się TIMER1 16bit
  TCCR1A = 0;

  //Set bit 6 in TIMSK to enable Timer 1 compare interrupt,
  //TIMER/Counter0 overflow enable, Timer/Counter2 overflow enable
  TIMSK = _BV(OCIE1A) | _BV(TOIE1) | _BV(TOIE2) | _BV(TOIE0); 

  hello();                    // Powitanie
  sei();                      // Włącz przerwania

  while(1) {

    if(bit_is_set(PINC,0)) {  // Jeśli wykryty zapalnik
      HOT_WIRE_ON;            // Włącz diode na wyświetlaczu
    }
    if(bit_is_clear(PINC,0)){ // Jeśli nie wykyryto zapalnika
      HOT_WIRE_OFF;           // Zgaś diode na wyświetlaczu
    }

    if(hold==1) {             // Tryb hold
      for(int i=0; i<6; i++){
        WYS1_OFF;
        WYS2_OFF;
        _delay_ms(100);
        WYS1_ON;
        WYS2_ON;
        _delay_ms(100);
      }
      if(time<5) {         // Jesli zatrzymany czas był <5, przypisz
                              // aktualny czas na 5
        time=5;
      }
      TCCR2 =0;               // Wyłącz Timer/Counter2 do migania wyświetlaczem
      enkoder=1;              // Odblokuj enkoder
      hold=0;                 // Wyjdź z trybu hold
    }


    if(time==0) {             // Jeśli czas = 0, odpal.
      TCCR1B = 0;             // Wyłącz timer odliczania (timer 16 bit)
      TCCR0 = 0;              // Wyłącz timer buzzera
      ShowOn_LED(time);       // Wyświetl 0 gdy koniec odliczania

      // Wyłącz preskaler dla Timer Counter 1 16bit, wyłącz odliczanie.
      if(time_save<5) {       // Jesli nacisniety był tryb hold i wznowione
                              // odliczanie, aktualny czas powrotu byłby
                              // mniejszy niż 5, przypisz 5
        time_save=5;
      }
      time=time_save;   // Przypisz ustawiony ostatnio czas do kolejnego
                        // odliczania
      FIRE_ON;          // Odpal ładunek
      BUZZ_ON;          // Włącz buzzer
      _delay_ms(1500);      // Czekaj 1,5 s.
      BUZZ_OFF;         // Wyłącz buzzer
      FIRE_OFF;         // Wyłącz wyjście do odpalenia
      WYS1_OFF;         // Wyłącz wyświetlacz 1
      WYS2_OFF;         // Wyłącz wyświetlacz 2
      _delay_ms(500);   // Czekaj 0,5 s.

      WYS1_ON;          // Włącz wyÂświetlacz 1
      WYS2_ON;          // Włącz wyÂświetlacz 2
      ShowOn_LED(time); // Wyświetl ostatni czas
      HOT_WIRE_OFF;     // Zgaś diode na wyświetlaczu - przepalony drut.
      
      // mignij kilka razy pokazując gotowość do pracy (odliczania)
      for(int i=0; i<7; i++) {
        BUZZ_ON;        // Włącz buzzer
        WYS1_ON;        // Włącz wyświetlacz 1
        WYS2_ON;        // Włącz wyświetlacz 2
        _delay_ms(100);     // Czekaj 0,1 s.
        WYS1_OFF;       // Wyłącz wyświetlacz 1
        WYS2_OFF;       // Wyłącz wyświetlacz 2
        BUZZ_OFF;       // Wyłącz wbuzzer
        _delay_ms(100); // Czekaj 0,1 s.
      }

      WYS1_ON;          // Włącz wyświetlacz 1
      WYS2_ON;          // Włącz wyświetlacz 2
      enkoder=1;        // odblokuj enkoder

    }

    // tryb automatyczny ================================================

    ShowOn_LED(time);       // Pokaż aktualny czas
    if(enkoder) {
      switch(Read2StepEncoder()) { // Zczytaj enkoder czy wykonany ruch

      case -1 :
        if(time<=5) {
          time=99;
        } else {
          time-=1;
        }
        time_save=time;
        break;
      case 0 :
        break;

      case 1 :
        if(time>=99) {
          time=5;
        } else {
          time+=1;
        }
        time_save=time;
        break;
      };
    }

    // tryb manualny ====================================================

    if(manual) {
      cli();            // Wyłącz przerwania
      manual_signal();      // Opóźnienie, przycisk impulsatora wciąż naciśnięty.
                            // - daj czas na zwolnienie
      while(manual_scan) {

        if(bit_is_set(PINC,0)){      // Jeśli wykryty zapalnik
          HOT_WIRE_ON;               // Włącz diode na wyświetlaczu
        }
        if(bit_is_clear(PINC,0)){    // Jeśli nie wykyryto zapalnika
          HOT_WIRE_OFF;              // Zgaś diode na wyświetlaczu
        }
        while(bit_is_clear(PIND,3)){ // Jeśli naciśnięty przycisk enkodera PD3
          FIRE_ON;                   // Włącz napięcie na zapalniku
          BUZZ_ON;                   // Włącz buzzer
        }
        FIRE_OFF;                    // Wyłącz napiecie na zapalniku
        BUZZ_OFF;                    // Wyłącz buzzer

        if(bit_is_clear(PIND,2)){    // Przycisk ABORT, STOP
          enkoder=1;                 // Odblokuj enkoder
          manual=0;                  // Wyjdź z trybu manualnego
          manual_scan=0;             // Wyjdz z petli skanowania manualnego
          hold=1;                    // Włącz tryb hold
          BUZZ_ON;                   // Włącz buzzer
          _delay_ms(500);            // Czekaj 0,5 s.
          BUZZ_OFF;                  // Wyłącz buzzer
          sei();                     // Odblokuj przerwania
          TCCR1B = 0;                // Wyłącz profilaktycznie TIMER 16 bit
        }
      }
    }
  }
}

Do pobrania: sparkv2_nowy.c (kopia)

Oczywiście program oparty jest w dużej mierze na przerwaniach oraz TIMER'ach, które kontrolują odliczanie sekund i sygnalizacje akustyczną (Buzzer).

Tryb automatyczny jest domyślny. Zastosowanie funkcji if(argument), wykonuje przechodzenie pomiędzy trybami - automatycznym i manualnym. Naciśnięcie przycisku powoduje zmiane argumentu w funkcji if() co powoduje wyjście z niej i przejście do kolejnej. Wewnątrz funkcji if() zastosowałem pętlę while(), która w nagłówku posiada np. manual=1 (typ boolean) i gwarantuje mi jej wykonywanie dopóki nie zajdzie potrzeba np. wyjścia z tego trybu. Następuje to np. poprzez wpisanie do argumentu manual wartości 0, która powoduje przerwanie funkcji while.

enkoder.h

W tym pliku nagłówkowym zawarłem tylko i wyłącznie obsługę enkodera. Przechowuje ona i definuje niezbędne zmienne, do określania kierunku obrotu enkodera. Jest to gotowe rozwiązanie z ksiażki T. Francuz'a i uważam, że nie ma sensu wywarzania otwartych drzwi. Jest to znakomicie opisane w jego książce co serdecznie polecam.

int8_t enc_delta;
void ReadEncoder()
{
  static int8_t last;
  int8_t newpos, diff;

  newpos=0;
  if((PIND & _BV(PD4))==0) {
    newpos=3;
  }
  if((PIND & _BV(PD5))==0) {
    newpos ^=1;
  }
  diff=last-newpos;
  if(diff & 1) {
    last=newpos;
    enc_delta +=(diff & 2)-1;
  }

}

int8_t Read2StepEncoder()
{
  ReadEncoder();
  int8_t val=enc_delta;
  enc_delta=val & 1;
  return val >> 1;
}

Do pobrania: enkoder.h (kopia)


ioinit.h

Niniejszy plik nagłówkowy posiada inicjację portów I/O mikrokontrolera. Definiuje ona kierunek portów (wejście/wyjście) oraz czy ma zostać zastosowany Pull-up na danym porcie czy nie.
_BV(port); oznacza wpisanie logicznej "1" i powoduje odpowiedniu w rejestrze DDRx (gdzie x to literka portu, np.D) jako wejście, a w rejestrze PORTx jako Pull-up.

void ioinit()
{
  PORTB = _BV(PB1);  // Pull-up dioda na wysw.
  PORTC = 0b100000; 
  PORTD = 0b01111111; 

  DDRB = _BV(PB1) | _BV(PB2) | _BV(PB3) | _BV(PB5);
  DDRC = 0x00;
  DDRD = 0b11000011;
}

Do pobrania: ioinit.h (kopia)


spi.h

Niniejszy plik nagłówkowy zawiera funkcje do obsługi komunikacji przez interfejs SPI, wykorzystywanej do sterowania rejestrów 74HC595.

static inline void SPI_SET_SS()
{
 PORTB|=(1<<PB2);
}

static inline void SPI_RESET_SS()
{
 PORTB&=~(1<<PB2); // SS -> PB2
}

void SPI_master_init()
{
 SPI_SET_SS();

 // (SPE) SPI Enable, (MSTR)Master ON, (SPI2X) fosc/2
 SPCR = _BV(SPE) | _BV(MSTR) | _BV(SPI2X); 
 SPSR; 
 SPDR;   // skasuj flage SPIF
 SPDR=0;  // bufor SPI = 0;
}

void SPI_send(uint8_t byte)
{
 PORTB&=~(_BV(PB2));
 SPDR=byte;
 while(!(SPSR & _BV(SPIF))); 
 PORTB|=_BV(PB2);
}





Do pobrania

Do pobrania komplet plików:





Literatura

  1. Język C dla mikrokontrolerów AVR. Od podstaw do zaawansowanych aplikacji - Tomasz Francuz, Helion 2011
  2. Forum elektroda.pl

6 komentarzy:

  1. Dużo z tym pracy

    OdpowiedzUsuń
  2. Fajny pomysł - mam tylko pytanie - z jakiego materiału jest drut rozpalający? I jakie napięcie do niego dociera? 5V?

    OdpowiedzUsuń
  3. W jakim programie został narysowany schemat, w kicadzie?
    Czy są gotowe układy ( multipleksery ), które dzielą sygnał z większą precyzją niż narzuca mi to dany układ scalony?pozdro

    OdpowiedzUsuń
  4. W opisie jest błąd bo jest napisane ,że został użyty tranzystor PNP BC847A ale w schemacie jest tak jak i w nocie katalogowej jest on typu NPN

    OdpowiedzUsuń
  5. Jeszcze chciałbym się zapytać czy tranzystor BC847A mógłbym zastąpić BC337? a także czy mógłbym użyć 2 tranzystorów MOSFET tak aby jednym podłączać akumulator do kondensatorów na czas ładowania a następnie go odcinać a drugim rozpalać drut?

    OdpowiedzUsuń
  6. schemat narysowany został w Cadsoft Eagle 6.1
    Błąd może być, zatem jest to NPN. - mój błąd.

    Myślę, że można użyc 2 mosfetów. Mój projekt bezpośrednia ziera akumulator, nie wiem jak z kondensatorami. Chętnie poznam twój pomysł.

    OdpowiedzUsuń