Mikrokontrolery - Jak zacząć?

... czyli zbiór praktycznej wiedzy dot. mikrokontrolerów.

niedziela, 20 marca 2011

DIY: Stacja rozlutownicza z chwytakiem podciśnieniowym na ATmega16


Autor: RafalJ645
Redakcja: Dondu

Wpadł mi kiedyś w ręce spora ilość złomu elektronicznego. Po szybkim przeglądzie okazało się, że są tam różnego rodzaju elementy, głównie półprzewodnikowe, które mógłbym kiedyś wykorzystać.

Złapałem za lutownice i odsysacz i zacząłem wylutowywać co się dało ... no właśnie, zacząłem, bo szybko się zniechęciłem, wizja demontażu elementów z płytek takim sprzętem mnie zniechęcała do roboty.

Szybko wpadłem na pomysł, że może czas kupić stacje rozlutowującą. Po przejrzeniu oferty sklepów internetowych pomysł upadł z racji, że ceny w miarę przyzwoitych stacji zaczynają się od około 1000zł. Tak pomyślałem sobie, żeby może samemu zrobić takie urządzenie, w końcu nie ma tu nic nie wiadomo jak skomplikowanego.

No i zaczął się czas poszukiwać jakiegoś tego typu projektu w internecie, na którym mógłbym się wzorować, coś podpatrzyć itp. Może jakoś dokładnie nie szukałem, ale nie znalazłem nic porządnego. Trochę mnie to zdziwiło, bo urządzenie nie jest jakieś super skomplikowane, bardzo przydatne w warsztacie, a budując samemu można zaoszczędzić sporo pieniędzy.

Tak więc wziąłem się do roboty ...






Rozlutownica

Pierwszym etapem był wybór samej rozlutowicy. Wybór padł na PENSOL-SL916-D2. W zasadzie to nie miałem zbytnio wielkiego wyboru, więc sprawa była w miarę jasna. Jest ona całkiem niezłej jakości, nie ma problemu z jej dostępnością jak i częściami zamiennymi do niej. Posiada grzałkę o mocy 50W zasilaną napięciem 24V.

Rozlutownica.





Chwytak podciśnieniowy

W między czasie wpadł mi jeszcze do głowy jeden pomysł. Skoro mam już urządzenie, w którym wykorzystuje podciśnienie, czemu od razu nie zrobić w jednej obudowie chwytaka podciśnieniowego? Sprawa ogólnie dość prosta, sam chwytak to banalna konstrukcja, jednak wymagał on dodatkowych elementów, o których w dalszej części artykułu.

Chwytak podciśnieniowy.




Podciśnienie

Jednym z ważniejszych elementów w takim urządzeniu jest moduł/element wytwarzający podciśnienie. Początkowo szukałem jakiejś pompki membranowej, jednak nie chciałem wsadzać do obudowy żadnego złomu, a nowe pompki o odpowiednich parametrach kosztowały naprawdę sporo.

Przeszukując swoje graty wpadłem na inżektor. Stwierdziłem że użycie jego jest świetnym pomysłem; wytwarzał zadowalające podciśnienie, element taki nie ma żadnej części ruchomej, więc się nie zepsuje. Ma tylko jedną wadę. Zasilany jest sprężonym powietrzem, które musi mieć dość wysokie ciśnienie (ok. 0,6mPa).

Zużycie powietrza też nie jest małe, przez co zasilany musiał być z zewnętrznego źródła. Pomimo tej wady ostatecznie zostałem przy tym rozwiązaniu. Inżektor jest sterowany elektrozaworem. Przed elektrozaworem umieszczony został reduktor ciśnienia, aby w momencie kiedy nie potrzebne jest podciśnienie o dużej wartości ograniczyć zużycie powietrza. Zrezygnowałem z umieszczenia na panelu manometru, ponieważ zajmowałby sporo miejsca, ciśnienie nie musi być to dokładnie ustawione, a bardzo łatwo można ustawić go na wyczucie.


Inżektor.

Elektrozawór na płycie montażowej.




Automatyczny zawór trójdrożny

Jednym z elementów, który był dodatkowo potrzebny do chwytaka, jest zawór przełączający odbiornik podciśnienia pomiędzy rozlutownicą a chwytakiem. No więc zrobiłem to co prawie zawsze, kiedy rodzi się nowy pomysł, czyli poszedłem przeszukać graty. No i jest! Trójdrożny zawór krzywkowy montowany na panel. Idealnie!

No ale im dłużej o tym myślałem, tym bardziej chciałem czegoś automatycznego. Tym razem nie znalazłem żadnego gotowego rozwiązania, więc przerobiłem mój zawór, dodając do niego serwomechanizm modelarski. No i się udało, cały zawór zamknięty jest we wnętrzu obudowy, a użytkownik nie musi martwić się o to, czy przełączył zawór na odpowiednią pozycje.


Zawór trójdrożny z serwomechanizmem.




Obudowa

Obudowa została wykonana z dwóch blaszanych ceowników o grubości 1,5mm i dwóch elementach stalowych łączący ceowniki (dolny ceownik jest przynitowany do tych elementów, a górny przykręcany). Elementy złożone w jedną całość tworząc prostopadłościan bez przedniej i tylnej ściany.

Na przednich i tylnych krawędziach od strony wewnętrznej zostały przyklejone paski z tworzywa sztucznego z wyfrezowanymi rowkami, w które wsuwa się panel. Opis może nie obrazuje jak to wszystko zostało zrobione, ale poniższe zdjęcia powinny rozstrzygnąć wszelkie wątpliwości.



Przekrój obudowy (rzut z góry).



Obudowa.



Łącznik połówek obudowy.


Panel przedni i tylny został wycięty z przezroczystej plexy o grubości 4mm. Zewnętrzna część każdego panelu pomalowana jest na szary kolor, a wewnętrzna na pomarańczowo. Napisy zostały wygrawerowane laserem, a dzięki przezroczystemu materiałowi i pomalowanej drugiej stronie panelu wszystkie są pomarańczowe.


Panel, widoczna strona.

Panel, niewidoczna strona.

Grawerowanie napisów na panelu.




Sterowanie

Kolejnym krokiem było zaprojektowanie sterownika, a w szczególności części odpowiedzialnej za pomiar temperatury z termopary. Nigdzie w internecie nie mogłem znaleźć, jakiego typu termoparę producent montuje w tych rozlutownicach. Znalazłem w intenecie wiele projektów stacji lutowniczych, opartych na kolbach tego samego producenta.

Tak w zasadzie, to sam wykonałem kiedyś taką stacje, tak więc schemat części sterującej częściowo zaczerpnięty jest z innej konstrukcji, a konkretniej z projektu opisanego w 7 wydaniu Elektroniki Praktycznej z 2007r. W sterowniku nie ma większej filozofii. Składa się w zasadzie z trzech „modułów”.

Pierwszy to zasilanie. Obejmuje ono stabilizatory napięcia +5V, -9V i +9V. Te dwa ostatnie wykorzystywane są tylko do zasilenia wzmacniacza operacyjnego. W części zasilającej znajdziemy także dwa triaki z optotrikami, jeden do zasilania rozlutownicy, drugi do elektrozaworu (zamiast elektrozaworu może być także pompka próżniowa, lub cokolwiek, wytwarzającego/ załączającego podciśnienie zasilane napięciem zmiennym).

Drugim „modułem” jest logika. Tu nie ma za dużo co się rozpisywać, jest to po prostu mikrokontroler atmega16, który steruje pracą całego urządzenia.

Ostatnim bardzo ważnym „modułem” jest pomiar temperatury. Złożony ze wzmacniacza operacyjnego i elementów pasywnych moduł wzmacnia prąd z termopary na prąd o takim potencjale, który najlepiej przetworzy przetwornik ADC.

Wszystkie potrzebne informacje dla użytkownika wyświetlane są na wyświetlaczu LCD 2*16. Użytkownik steruje stacją za pomocą 6 przycisków umieszczonych na panelu i dwóch na narzędziach.

Na płytce znajduje się kilka dodatkowych złącz i wyprowadzeń. Są one zarezerwowane na cele rozwojowe. Mam w planach zrobić jakąś magistrale, którą połączę wszystkie urządzenia w warsztacie z komputerem. Ale na razie to tylko plany ;-)


Schemat.


Oczywiście moduły piszę w „”, bo podział sterownika na nie jest tylko na schemacie a wszystkie z nich umieszczone są na jednej płytce PCB. Obwód został wykonany przy pomocy frezarki CNC. W pierwszej wersji zrobiłem kilka głupich błędów, ponieważ siedziałem nad tym po nocach. Jednak w wersji, która tu udostępniam wszystkie te błędy zostały poprawione ;-)


Płytka PCB sterownika.



Gotowa płytka.

Sterownik.


Projekt sterownika w programie Eagle: Projekt sterownika.rar (kopia)




Program

Program napisany jest w języku C. Zajmuje niecałe 20% dostępnej pamięci. Głównym jego zadaniem jest kontrolowanie temperatury grota i przełączanie zaworu. Zakres nastawy temperatury został ograniczony od 200 do 450 *C.

Nie niezbędnym ale na pewno poprawiającym bezpieczeństwo użytkowania stacji zadaniem programu jest wyłączanie grzania po ustawionym przez użytkownika czasie. Wiadomo, niektóre prace mogę trwać 5 min, inne kilka godzin, więc czas jest liczony od ostatniego naciśnięcia przycisku na rozlutownicy. Po ustalonym czasie po prostu program wyłącza grzanie i przechodzi do menu głównego. Czas można ustawić w zakresie 1 do 10 minut, ale jest to ograniczenie programowe, więc ten zakres można bez problemu zmienić.

W programie korzystam z bibliotek do wyświetlacza LCD HD44780 ze strony radzio.dxp.pl. Zgodnie z prośbą autora nie umieszczam tych plików tutaj, tylko podaję wyżej link do bibliotek na jego stronie.

Po umieszczeniu biblioteki w projekcie wystarczy zmienić konfiguracje pinów wyświetlacza w pliku z rozszerzeniem HD44780.h. Powinno to wyglądać tak:

#define LCD_RS_DIR     DDRC
#define LCD_RS_PORT     PORTC
#define LCD_RS          (1 << PC5)

#define LCD_E_DIR       DDRC
#define LCD_E_PORT      PORTC
#define LCD_E           (1 << PC4)

#define LCD_DB4_DIR     DDRC
#define LCD_DB4_PORT    PORTC
#define LCD_DB4         (1 << PC3)

#define LCD_DB5_DIR     DDRC
#define LCD_DB5_PORT    PORTC
#define LCD_DB5         (1 << PC2)

#define LCD_DB6_DIR     DDRC
#define LCD_DB6_PORT    PORTC
#define LCD_DB6         (1 << PC1)

#define LCD_DB7_DIR     DDRC
#define LCD_DB7_PORT    PORTC
#define LCD_DB7         (1 << PC0)

Pewnie prawie wszystkim rzuci się w moim kodzie sposób wysyłania zmiennych liczbowych do wyświetlacza. W w/w bibliotece brak jest takiej funkcji, a nie chciałem modyfikować tych bibliotek, więc za każdym razem wygląda to mniej więcej tak:

LCD_WriteText( itoa(nastawa, bufor, 10) );

Oczywiście mogłem stworzyć w pliku głównym taką funkcje, ale stwierdziłem, ze jest to na tyle prosta i oczywista instrukcja, że nie zrobiłem tego.

Należy też pamiętać, żeby ustawić fuse bity na (0xE4 0xD9)i w ustawieniach IDE ustawić częstotliwość taktowania procesor na 8Mhz.

Struktura menu wygląda tak jak na poniższym obrazie:


Struktura menu.


Nastawiona temperatura i czas wyłączenia zapisywane są do pamięci EEPROM po włączeniu grzania rozlutownicy. Podczas pracy można zmieniać temperaturę grota, jednak żeby została ona zapisana do pamięci, należy wcisnąć przycisk „Ok”.

Po włączeniu urządzenia wybieramy na panelu narzędzie, jakim chcemy pracować. Można też to zrobić przy pomocy przycisków na nich. W przypadku chwytaka nie ma to większego znaczenia, ale po naciśnięciu przycisku na rozlutownicy zostanie pominięta możliwość zmiany ustawień, od razu zostaną wczytane ostatnio zapisane ustawienia i rozlutownica zacznie się nagrzewać.

To chyba tyle z tych najważniejszych rzeczy, kod starałem się napisać jak najbardziej czytelnie, tak więc wydaje mi się, że osoby które dopiero zaczynają programować nie będą miały problemu z rozumieniem jego działania ;). Dodatkowo w załączniku przesyłam wersje kodu do stacji bez chwytaka, jakby ktoś chciał zbudować takie urządzenie, ale w wersji bez chwytaka (main2.c).


Wersja z chwytakiem

main.c
/*
 * Stacja_Rozlutownicza.c
 *
 * Created: 2013-08-18 13:09:15
 *  Author: Rafał
 */

#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <avr/eeprom.h>

#include "HD44780.h"


//************************** PORTY IO

#define P_KOLBA_PIN (1<<PA1)
#define P_KOLBA_WCISNIETY !(PINA & P_KOLBA_PIN)

#define P_CHWYTAK_PIN (1<<PA2)
#define P_CHWYTAK_WCISNIETY !(PINA & P_CHWYTAK_PIN)

#define ZAWOR_PIN (1<<PA6)
#define ZAWOR_OFF PORTA &= ~ZAWOR_PIN
#define ZAWOR_ON PORTA |= ZAWOR_PIN


#define PRAWO_PIN (1<<PD2)
#define PRAWO_WCISNIETY !(PIND & PRAWO_PIN)

#define LEWO_PIN (1<<PD3)
#define LEWO_WCISNIETY !(PIND & LEWO_PIN)

#define DOL_PIN (1<<PD4)
#define DOL_WCISNIETY !(PIND & DOL_PIN)

#define GORA_PIN (1<<PD5)
#define GORA_WCISNIETY !(PIND & GORA_PIN)

#define ELZAWOR_PIN (1<<PD6)
#define ELZAWOR_OFF PORTD &= ~ELZAWOR_PIN
#define ELZAWOR_ON PORTD |= ELZAWOR_PIN

#define GRZALKA_PIN (1<<PD7)
#define GRZALKA_OFF PORTD &= ~GRZALKA_PIN
#define GRZALKA_ON PORTD |= GRZALKA_PIN


#define OK_PIN (1<<PB0)
#define OK_WCISNIETY !(PINB & OK_PIN)

#define COFNIJ_PIN (1<<PB1)
#define COFNIJ_WCISNIETY !(PINB & COFNIJ_PIN)


//************************** ZMIENNE

EEMEM unsigned char a, a2, b; // rezerwacja pamięci EEPROM (zmienna a
                              // jest 16 bitowa, więc a2 jest
                              // jej 'kontynuacją')

uint16_t nastawa = 300; // zmienna przechowująca nastawioną temperaturę
uint16_t temp_grota;    // zmienna przechowująca temperaturę grota
uint8_t rozlutownica_praca = 0; // flaga pracy rozlutownicy (0 - wyłączona,
                                // 1 - włączona)

volatile uint16_t licznik_wylaczenia = 0;// licznik czasu od ostatniego
                                         //uruchomienia rozlutownicy [sek]
volatile uint16_t czas_wylaczenia = 10;  //czas, po którym rozlutownica 
                                         //zostanie wyłączona (od ostatniego
                                         //naciśnięcia przycisku na kolbie)
                                         //[sek]


uint8_t zawor_stan = 0;  // stan, w którym aktualnie znajduje się zawór 
                         //(0 - nieokreślony, 1 - chwytak, 2 - rozlutownica)

volatile uint8_t czas_zawor =  0; // czas, przez który na serwo będzie podawany
                                  // sygnał zmiany położenia [sek]

volatile uint8_t zawor_PWM; // wartość PWM

uint8_t flaga = 0; // flaga ustawiana na 1 co sekundę

char bufor[17];    // bufor pomocniczy do wysyłania zmiennych
                   // int do wyświetlacza LCD


//************************** FUNKCJE

uint16_t POMIAR(void);
uint8_t PRZYCISK_WCISNIETY(uint8_t makro);
void ODCZYT_EEPROM(void);
void PRZELACZ_ZAWOR(uint8_t wyjscie);
void ZAPIS_EEPROM(void);

//**************************

enum MENU {WYBOR_NARZEDZIA,CHWYTAK,USTAWIENIA_KOLBY,USTAWIENIA_KOLBY_2,KOLBA};
enum MENU MENU_P=WYBOR_NARZEDZIA;

int main(void)
{
  //************************** USTAWIENIA ADC

  ADMUX |= (1<<REFS0);        // napięcie odnisienia - VCC

  // włączenie ADC i ustawienie preskalera na 64
  ADCSRA |= (1<<ADEN) | (1<<ADPS1) | (1<<ADPS0);       

  ADMUX|= (ADMUX & 0xF8) | 0; // ustawienie kanału pomiarowego na ADC0


  //************************** INICJALIZACJA

  DDRA &= ~(P_CHWYTAK_PIN| P_KOLBA_PIN);
  PORTA |= (P_CHWYTAK_PIN| P_KOLBA_PIN);

  DDRD &= ~(DOL_PIN | GORA_PIN | LEWO_PIN | PRAWO_PIN);
  PORTD |= (DOL_PIN | GORA_PIN | LEWO_PIN | PRAWO_PIN);

  DDRB &= ~(OK_PIN | COFNIJ_PIN);
  PORTB |= (OK_PIN | COFNIJ_PIN);

  DDRD |= (GRZALKA_PIN | ELZAWOR_PIN);

  DDRA |=(ZAWOR_PIN);
  PORTA|=(ZAWOR_PIN);


  //************************** USTAWIENIA TIMERA

  // tryb CTC i ustawienie preskalera na 256
  TCCR2 |= (1<<WGM21)|(1<<CS21)| (1<<CS22); 
  OCR2 = 6;            // podział przez 6
  TIMSK |= (1<<OCIE2); // zezwolenie na przerwania

  //**************************

  LCD_Initalize(); // inicjalizacje LCD

  LCD_Clear();
  LCD_WriteText("Stacja");
  LCD_GoTo(3,1);
  LCD_WriteText("Rozlutownicza");
  _delay_ms(1500);
  LCD_Clear();

  sei();            // zezwolenie na przerwania
  ODCZYT_EEPROM();  // wczytanie danych z pamiie EEPROM

  while(1) {

    switch(MENU_P) {
    case WYBOR_NARZEDZIA:

      LCD_GoTo(0,0);
      LCD_WriteText("<-Rozlutownica");
      LCD_GoTo(7,1);
      LCD_WriteText("Chwytak->");

       // wybrane narzędzie: kolba, edycja parametrów pracy przed
       // rozpoczęciem grzania
      if(PRZYCISK_WCISNIETY(LEWO_WCISNIETY)) {
        MENU_P = USTAWIENIA_KOLBY;
        PRZELACZ_ZAWOR(2);
        LCD_Clear();
      }

      // wybrane narzędzie: kolba, praca na zapisanych parametrach
      if(PRZYCISK_WCISNIETY(P_KOLBA_WCISNIETY)) {
        MENU_P = KOLBA;
        rozlutownica_praca = 1;
        PRZELACZ_ZAWOR(2);
        LCD_Clear();
      }

      // wybrane narzędzie: chwytak
      if(PRZYCISK_WCISNIETY(PRAWO_WCISNIETY) ||
          PRZYCISK_WCISNIETY(P_CHWYTAK_WCISNIETY)) { 
        MENU_P = CHWYTAK;
        PRZELACZ_ZAWOR(1);
        LCD_Clear();
      }

      break;

    case  CHWYTAK:

      LCD_GoTo(0,0);
      LCD_WriteText("<Chwytak");
      LCD_GoTo(1,1);
      LCD_WriteText("podcisnieniowy>");

      // wyjście z Chwytaka i przejście do menu "wybór narzędzia"
      if(PRZYCISK_WCISNIETY(COFNIJ_WCISNIETY)) {
        MENU_P = WYBOR_NARZEDZIA;
        LCD_Clear();
      }

      if(P_CHWYTAK_WCISNIETY) {
        ELZAWOR_ON;  // otwarcie zaworu po naciśnięciu przycisku
                     // na chwytaku (bez eliminacji drgań styków)
      } else {
        ELZAWOR_OFF;
      }


      break;

    case  USTAWIENIA_KOLBY:

      LCD_GoTo(0,0);
      LCD_WriteText("Nastawa: ");
      LCD_WriteText(itoa(nastawa, bufor, 10));
      LCD_WriteText("*C ");
      LCD_GoTo(13,1);
      LCD_WriteText("1/2");

      // zmniejszenie nastawionej temperatury
      if(PRZYCISK_WCISNIETY(DOL_WCISNIETY)) {
        nastawa = nastawa - 10;
        LCD_GoTo(11,0);
        LCD_WriteText("   ");
      }

      // zwiększenie nastawionej temperatury
      if(PRZYCISK_WCISNIETY(GORA_WCISNIETY)) {
        nastawa = nastawa + 10;
        LCD_GoTo(11,0);
        LCD_WriteText("   ");
      }

      // przejście od meunu "USTAWIANIA_KOLBY_2"
      if(PRZYCISK_WCISNIETY(PRAWO_WCISNIETY)) {
        MENU_P = USTAWIENIA_KOLBY_2;
        LCD_Clear();
      }

      // włączenie pracy rozlutownicy i zapisanie ustawionych parametrów
      // do pamięci EEPROM
      if(PRZYCISK_WCISNIETY(OK_WCISNIETY)) {
        MENU_P = KOLBA;
        rozlutownica_praca = 1;
        ZAPIS_EEPROM();
        LCD_Clear();
      }

      // wyjście z ustawień rozlutownicy i przjeście do menu wyboru narzędzia
      if(PRZYCISK_WCISNIETY(COFNIJ_WCISNIETY)) {
        MENU_P = WYBOR_NARZEDZIA;
        LCD_Clear();
      }

      break;


    case  USTAWIENIA_KOLBY_2:

      LCD_GoTo(0,0);
      LCD_WriteText("Czas wylaczenia: ");
      LCD_GoTo(0,1);
      LCD_WriteText(itoa((czas_wylaczenia / 60), bufor, 10));
      LCD_WriteText(" min ");
      LCD_WriteText(itoa((czas_wylaczenia % 60), bufor, 10));
      LCD_WriteText(" sek  ");
      LCD_GoTo(13,1);
      LCD_WriteText("2/2");

      // włączenie pracy rozlutownicy i zapisanie ustawionych parametrów
      // do pamięci EEPROM
      if(PRZYCISK_WCISNIETY(
            OK_WCISNIETY)) {
        MENU_P = KOLBA;
        rozlutownica_praca = 1;
        ZAPIS_EEPROM();

        LCD_Clear();
      }

      // zmniejszenie nastawiongo czasu
      if(PRZYCISK_WCISNIETY(DOL_WCISNIETY)) {
        czas_wylaczenia = czas_wylaczenia - 1;
      }

      // zwiększenie nastawionego czasu
      if(PRZYCISK_WCISNIETY(GORA_WCISNIETY)) {
        czas_wylaczenia = czas_wylaczenia + 1;
      }

      // wyjście z ustawień rozlutownicy i przjeście do menu wyboru narzędzia
      if(PRZYCISK_WCISNIETY(LEWO_WCISNIETY)) {
        MENU_P = USTAWIENIA_KOLBY;
        LCD_Clear();
      }

      break;


    case KOLBA:

      LCD_GoTo(0,0);
      LCD_WriteText("Nastawa: ");
      LCD_WriteText(itoa(nastawa, bufor, 10));
      LCD_WriteText("*C ");
      LCD_GoTo(0,1);
      LCD_WriteText("Temp: ");
      LCD_WriteText(itoa(temp_grota, bufor, 10));
      LCD_WriteText("*C ");

      // otwarcie zaworu po naciśnięciu przycisku na kolbie (bez eliminacji
      // drgań styków)
      if(P_KOLBA_WCISNIETY) {
        ELZAWOR_ON;
        licznik_wylaczenia = 0;
      } else {
        ELZAWOR_OFF;
      }

      // wyłączenie pracy rozlutownicy i przejcie do menu wybierania narzędzia
      if(PRZYCISK_WCISNIETY(COFNIJ_WCISNIETY)) {
        rozlutownica_praca = 0;
        MENU_P = WYBOR_NARZEDZIA;
        LCD_Clear();
      }


      // zmniejszenie nastawionej temperatury
      if(PRZYCISK_WCISNIETY(DOL_WCISNIETY)) {
        nastawa = nastawa - 10;
        LCD_GoTo(10,0);
        LCD_WriteText("   ");
      }

      // zwiększenie nastawionej temperatury
      if(PRZYCISK_WCISNIETY(GORA_WCISNIETY)) {
        nastawa = nastawa + 10;
        LCD_GoTo(10,0);
        LCD_WriteText("   ");
      }

      // zapisanie ustawionych parametrów do pamięci EEPROM
      if(PRZYCISK_WCISNIETY(OK_WCISNIETY)) {
        ZAPIS_EEPROM();
        LCD_Clear();
        LCD_WriteText("NASTAWA ZAPISANA");
        _delay_ms(500);
        LCD_Clear();
      }
      break;
    }

    if(flaga == 1) { //operacje wykonywane co sekundę
      if(rozlutownica_praca == 1) {
        temp_grota = POMIAR();

        temp_grota *= 11;  // przeliczanie wartości ADC na temperaturę
        temp_grota /= 10;
        temp_grota  += 20;

        licznik_wylaczenia++;


        // wyłączenie rozlutownicy po bezczynności przez ustawiony czas
        if(licznik_wylaczenia >= czas_wylaczenia) {
          rozlutownica_praca = 0;
          licznik_wylaczenia = 0;
          MENU_P = WYBOR_NARZEDZIA;
          LCD_Clear();
        }
      }

      if(czas_zawor != 0) { // ustawienie zaworu do wymaganej pozycji
        if(zawor_stan == 1) {
          zawor_PWM = 248;
        } else if(zawor_stan == 2) {
          zawor_PWM = 251;
        }
        czas_zawor --;
      } else {
        zawor_PWM = 0;  // jeśli zawór ustawiony, to wyłączenie serwa
      }

      flaga = 0;
    }

    if(nastawa > 450) {
      nastawa = 450;  // ograniczenie wartości nastawionej temperatury
                      // do przedziału <200;450> [*C]
    } else if(nastawa < 200) {
      nastawa = 200;
    }

    if(czas_wylaczenia > 600) {
      czas_wylaczenia = 600;  // ograniczenie wartoci nastawionego czasu
                              // wyłączenia do przedziału <60;600> [sek]
    } else if(czas_wylaczenia < 60) {
      czas_wylaczenia = 60;
    }
  }
}


// eliminacja drgań styków i opóźnienie przełączania
uint8_t PRZYCISK_WCISNIETY(uint8_t makro) 
{
  if(makro) {
    _delay_ms(50); // czas drgań styków

    if(makro) {
      _delay_ms(150); // opóźnienie
      return 1;
    }
  }
  return 0;
}


uint16_t POMIAR(void)
{
  ADCSRA |= (1<<ADSC);
  while(ADCSRA & (1<<ADSC));
  return ADCW;
}

void ZAPIS_EEPROM(void)
{
  eeprom_write_word(&a, nastawa); //zapisz wartość nastawy w lokalizacji 'a'
  eeprom_write_word(&b, czas_wylaczenia); //zapisz wartość czasu
                                          //wyłącznia w lokalizacji 'b'
}

void ODCZYT_EEPROM(void)
{
  nastawa = eeprom_read_word(&a); //odczytaj wartość nastawy z lokalizacji 'a'
  czas_wylaczenia = eeprom_read_word(&b); //odczytaj wartość czasu
                                          // wyłącznia z lokalizacji 'b'

  //wyeliminowanie problemów podczas pierwszego uruchomienia
  //po wbraniu programu
  if((nastawa%10) != 0) {
    nastawa = 300;  
  }

  //wyeliminowanie problemów podczas pierwszego uruchomienia
  //po wybraniu programu
  if(czas_wylaczenia > 600) {
    czas_wylaczenia = 60; 
  }
}


void PRZELACZ_ZAWOR(uint8_t wyjscie) // wyjscie: 2 - rozlutownica, 1 - chwytak
{
  //jeśi zawór ustawiony w wymaganej pozycji, to nic nie rób
  if(wyjscie != zawor_stan) {

    czas_zawor = 2; //czas podawania sygnału (2 sek wystarczą,
                    //żeby przestawić zawór)

    if(wyjscie == 1) {
      zawor_stan = 1;
    } else {
      zawor_stan = 2;
    }
  }
}


ISR(TIMER2_COMP_vect)
{
  static uint8_t licznik_1; //licznik wykorzystywany do programowego PWM
  static uint16_t
  licznik_2;  //licznik wykorzystywany do odmierzania czasu,
              //co który mają być wykonywane określone operacje

  if(licznik_1>=zawor_PWM) {
    ZAWOR_ON;
  } else {
    ZAWOR_OFF;  // PWM
  }


  if(licznik_2 > 4500) { // co około sekundę (w tym przypadku 
                            //nie musi to byś bardzo dokładnie)
    flaga = 1;
    licznik_2 = 0;
  }

  if(temp_grota < nastawa && rozlutownica_praca == 1) {
    GRZALKA_ON;  //regulacja temperatury kolby
  } else {
    GRZALKA_OFF;
  }

  licznik_1++;
  licznik_2++;

}

Do pobrania: main.c (kopia)


Wersja bez chwytaka

main2.c
/*
 * Stacja_Rozlutownicza.c
 *
 * Created: 2013-08-18 13:09:15
 *  Author: Rafał
 */

#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <avr/eeprom.h>

#include "HD44780.h"


//************************** PORTY IO

#define P_KOLBA_PIN (1<<PA1)
#define P_KOLBA_WCISNIETY !(PINA & P_KOLBA_PIN)

#define P_CHWYTAK_PIN (1<<PA2)
#define P_CHWYTAK_WCISNIETY !(PINA & P_CHWYTAK_PIN)

#define ZAWOR_PIN (1<<PA6)
#define ZAWOR_OFF PORTA &= ~ZAWOR_PIN
#define ZAWOR_ON PORTA |= ZAWOR_PIN


#define PRAWO_PIN (1<<PD2)
#define PRAWO_WCISNIETY !(PIND & PRAWO_PIN)

#define LEWO_PIN (1<<PD3)
#define LEWO_WCISNIETY !(PIND & LEWO_PIN)

#define DOL_PIN (1<<PD4)
#define DOL_WCISNIETY !(PIND & DOL_PIN)

#define GORA_PIN (1<<PD5)
#define GORA_WCISNIETY !(PIND & GORA_PIN)

#define ELZAWOR_PIN (1<<PD6)
#define ELZAWOR_OFF PORTD &= ~ELZAWOR_PIN
#define ELZAWOR_ON PORTD |= ELZAWOR_PIN

#define GRZALKA_PIN (1<<PD7)
#define GRZALKA_OFF PORTD &= ~GRZALKA_PIN
#define GRZALKA_ON PORTD |= GRZALKA_PIN


#define OK_PIN (1<<PB0)
#define OK_WCISNIETY !(PINB & OK_PIN)

#define COFNIJ_PIN (1<<PB1)
#define COFNIJ_WCISNIETY !(PINB & COFNIJ_PIN)


//************************** ZMIENNE

// rezerwacja pamięci EEPROM (zmienna a jest 16 bitowa, 
// więc a2 jest jej 'kontynuacją')
EEMEM unsigned char a, a2, b; 

uint16_t nastawa = 300; // zmienna przechowująca nastawioną temperaturę
uint16_t temp_grota;    // zmienna przechowująca temperaturę grota
uint8_t rozlutownica_praca =  0; // flaga pracy rozlutownicy 
                                 //(0 - wyłączona, 1 - włączona)

volatile uint16_t licznik_wylaczenia =  0; //licznik czasu od ostatniego
                                           //uruchomienia rozlutownicy [sek]
volatile uint16_t czas_wylaczenia = 10;    // czas, po którym rozlutownica 
                                           //zostanie wyłączona (od ostatniego 
                                           //naciśnięcia przycisku na kolbie) 
                                           //[sek]

uint8_t flaga = 0; // flaga ustawiana na 1 co sekundę

char bufor[17];    // bufor pomocniczy do wysyłania zmiennych int 
                   //do wyświetlacza LCD


//************************** FUNKCJE

uint16_t POMIAR(void);
uint8_t PRZYCISK_WCISNIETY(uint8_t makro);
void ODCZYT_EEPROM(void);
void ZAPIS_EEPROM(void);

//**************************

enum MENU {WYBOR_NARZEDZIA, CHWYTAK, USTAWIENIA_KOLBY, USTAWIENIA_KOLBY_2, KOLBA};
enum MENU MENU_P=WYBOR_NARZEDZIA;

int main(void)
{
  //************************** USTAWIENIA ADC

  ADMUX |= (1<<REFS0); // napięcie odnisienia - VCC

  // włączenie ADC i ustawienie preskalera na 64
  ADCSRA |= (1<<ADEN) | (1<<ADPS1) | (1<<ADPS0);

  ADMUX|= (ADMUX & 0xF8) | 0; // ustawienie kanału pomiarowego na ADC0

  //************************** INICJALIZACJA

  DDRA &= ~(P_CHWYTAK_PIN| P_KOLBA_PIN);
  PORTA |= (P_CHWYTAK_PIN| P_KOLBA_PIN);

  DDRD &= ~(DOL_PIN | GORA_PIN | LEWO_PIN | PRAWO_PIN);
  PORTD |= (DOL_PIN | GORA_PIN | LEWO_PIN | PRAWO_PIN);

  DDRB &= ~(OK_PIN | COFNIJ_PIN);
  PORTB |= (OK_PIN | COFNIJ_PIN);

  DDRD |= (GRZALKA_PIN | ZAWOR_PIN);


  //************************** USTAWIENIA TIMERA

  // tryb CTC i ustawienie preskalera na 256
  TCCR2 |= (1<<WGM21)|(1<<CS21)|(1<<CS22); 
  OCR2 = 6;               // podział przez 6
  TIMSK |= (1<<OCIE2); // zezwolenie na przerwania

  //**************************

  LCD_Initalize(); // inicjalizacje LCD

  LCD_Clear();
  LCD_WriteText("Stacja");
  LCD_GoTo(3,1);
  LCD_WriteText("Rozlutownicza");
  _delay_ms(1500);
  LCD_Clear();

  sei();           // zezwolenie na przerwania
  ODCZYT_EEPROM(); // wczytanie danych z pamiie EEPROM

  while(1) {

    switch(MENU_P) {
    case WYBOR_NARZEDZIA:

      LCD_GoTo(0,0);
      LCD_WriteText("<-Rozlutownica");
      LCD_GoTo(7,1);
      LCD_WriteText("Chwytak->");

      // wybrane narzędzie: kolba, edycja parametrów pracy 
      // przed rozpoczęciem grzania
      if(PRZYCISK_WCISNIETY(LEWO_WCISNIETY)){
        MENU_P = USTAWIENIA_KOLBY;
        LCD_Clear();
      }

      // wybrane narzędzie: kolba, praca na zapisanych parametrach
      if(PRZYCISK_WCISNIETY(P_KOLBA_WCISNIETY)){ 
        MENU_P = KOLBA;
        rozlutownica_praca = 1;
        LCD_Clear();
      }

      //wybrane narzędzie: chwytak
      if(PRZYCISK_WCISNIETY(PRAWO_WCISNIETY) || 
         PRZYCISK_WCISNIETY(P_CHWYTAK_WCISNIETY)){
        MENU_P = CHWYTAK;
        LCD_Clear();
      }

      break;


    case  CHWYTAK:

      LCD_GoTo(0,0);
      LCD_WriteText("<Chwytak");
      LCD_GoTo(1,1);
      LCD_WriteText("podcisnieniowy>");

      // wyjście z Chwytaka i przejście do menu "wybór narzędzia"
      if(PRZYCISK_WCISNIETY(COFNIJ_WCISNIETY)) {
        MENU_P = WYBOR_NARZEDZIA;
        LCD_Clear();
      }

      // otwarcie zaworu po naciśnięciu przycisku na chwytaku 
      // (bez eliminacji drgań styków)
      if(P_CHWYTAK_WCISNIETY) {
        ELZAWOR_ON;  
      } else {
        ELZAWOR_OFF;
      }

      break;


    case  USTAWIENIA_KOLBY:

      LCD_GoTo(0,0);
      LCD_WriteText("Nastawa: ");
      LCD_WriteText(itoa(nastawa, bufor, 10));
      LCD_WriteText("*C ");
      LCD_GoTo(13,1);
      LCD_WriteText("1/2");

       // zmniejszenie nastawionej temperatury
      if(PRZYCISK_WCISNIETY(DOL_WCISNIETY)) {
        nastawa = nastawa - 10;
        LCD_GoTo(11,0);
        LCD_WriteText("   ");
      }

      // zwiększenie nastawionej temperatury
      if(PRZYCISK_WCISNIETY(GORA_WCISNIETY)) {
        nastawa = nastawa + 10;
        LCD_GoTo(11,0);
        LCD_WriteText("   ");
      }

      // przejście od meunu "USTAIWNIA_KOLBY_2"
      if(PRZYCISK_WCISNIETY(PRAWO_WCISNIETY)) {
        MENU_P = USTAWIENIA_KOLBY_2;
        LCD_Clear();
      }

      // włączenie pracy rozlutownicy i zapisanie ustawionych
      // parametrów do pamięci EEPROM
      if(PRZYCISK_WCISNIETY(OK_WCISNIETY)) {
        MENU_P = KOLBA;
        rozlutownica_praca = 1;
        ZAPIS_EEPROM();
        LCD_Clear();
      }

      // wyjście z ustawień rozlutownicy i przjeście do menu wyboru narzędzia
      if(PRZYCISK_WCISNIETY(COFNIJ_WCISNIETY)) { 
        MENU_P = WYBOR_NARZEDZIA;
        LCD_Clear();
      }

      break;


    case  USTAWIENIA_KOLBY_2:

      LCD_GoTo(0,0);
      LCD_WriteText("Czas wylaczenia: ");
      LCD_GoTo(0,1);
      LCD_WriteText(itoa((czas_wylaczenia / 60), bufor, 10));
      LCD_WriteText(" min ");
      LCD_WriteText(itoa((czas_wylaczenia % 60), bufor, 10));
      LCD_WriteText(" sek  ");
      LCD_GoTo(13,1);
      LCD_WriteText("2/2");


      // włączenie pracy rozlutownicy i zapisanie ustawionych
      //parametrów do pamięci EEPROM
      if(PRZYCISK_WCISNIETY(OK_WCISNIETY)) { 
        MENU_P = KOLBA;
        rozlutownica_praca = 1;
        ZAPIS_EEPROM();

        LCD_Clear();
      }

      // zmniejszenie nastawiongo czasu 
      if(PRZYCISK_WCISNIETY(DOL_WCISNIETY)) {
        czas_wylaczenia = czas_wylaczenia - 1;
      }

      // zwiększenie nastawionego czasu
      if(PRZYCISK_WCISNIETY(GORA_WCISNIETY)) {
        czas_wylaczenia = czas_wylaczenia + 1;
      }

      // wyjście z ustawień rozlutownicy i przjeście do menu wyboru narzędzia
      if(PRZYCISK_WCISNIETY(LEWO_WCISNIETY)) {
        MENU_P = USTAWIENIA_KOLBY;
        LCD_Clear();
      }

      break;


    case KOLBA:

      LCD_GoTo(0,0);
      LCD_WriteText("Nastawa: ");
      LCD_WriteText(itoa(nastawa, bufor, 10));
      LCD_WriteText("*C ");
      LCD_GoTo(0,1);
      LCD_WriteText("Temp: ");
      LCD_WriteText(itoa(temp_grota, bufor, 10));
      LCD_WriteText("*C ");

      // otwarcie zaworu po naciśnięciu przycisku na kolbie
      // (bez eliminacji drgań styków)
      if(P_KOLBA_WCISNIETY) {
        ELZAWOR_ON;
        licznik_wylaczenia = 0;
      } else {
        ELZAWOR_OFF;
      }

      // wyłączenie pracy rozlutownicy i przejcie do menu wybierania narzędzia
      if(PRZYCISK_WCISNIETY(COFNIJ_WCISNIETY)) {
        rozlutownica_praca = 0;
        MENU_P = WYBOR_NARZEDZIA;
        LCD_Clear();
      }

      // zmniejszenie nastawionej temperatury
      if(PRZYCISK_WCISNIETY(DOL_WCISNIETY)) {
        nastawa = nastawa - 10;
        LCD_GoTo(10,0);
        LCD_WriteText("   ");
      }

      // zwiększenie nastawionej temperatury
      if(PRZYCISK_WCISNIETY(GORA_WCISNIETY)) {
        nastawa = nastawa + 10;
        LCD_GoTo(10,0);
        LCD_WriteText("   ");
      }

      // zapisanie ustawionych parametrów do pamięci EEPROM
      if(PRZYCISK_WCISNIETY(OK_WCISNIETY)) {
        ZAPIS_EEPROM();
        LCD_Clear();
        LCD_WriteText("NASTAWA ZAPISANA");
        _delay_ms(500);
        LCD_Clear();
      }
      break;
    }

    if(flaga == 1) { //operacje wykonywane co sekundę
      if(rozlutownica_praca == 1) {
        temp_grota = POMIAR();

        temp_grota *= 11;  // przeliczanie wartości ADC na temperaturę
        temp_grota /= 10;
        temp_grota  += 20;

        licznik_wylaczenia++;

        // wyłączenie rozlutownicy po bezczynności przez ustawiony czas
        if(licznik_wylaczenia >= czas_wylaczenia) {
          rozlutownica_praca = 0;
          licznik_wylaczenia = 0;
          MENU_P = WYBOR_NARZEDZIA;
          LCD_Clear();
        }
      }

      flaga = 0;
    }

    // ograniczenie wartości nastawionej temperatury do 
    //przedziału <200;450> [*C]
    if(nastawa > 450) {
      nastawa = 450; 
    } else if(nastawa < 200) {
      nastawa = 200;
    }

    // ograniczenie wartoci nastawionego czasu wyłączenia do
    // przedziału <60;600> [sek]
    if(czas_wylaczenia > 600) {
      czas_wylaczenia = 600;
    } else if(czas_wylaczenia < 60) {
      czas_wylaczenia = 60;
    }
  }
}


// eliminacja drgań styków i opóźnienie przełączania
uint8_t PRZYCISK_WCISNIETY(uint8_t makro)
{
  if(makro) {
    _delay_ms(50); // czas drgań styków

    if(makro) {
      _delay_ms(150); // opóźnienie
      return 1;
    }
  }
  return 0;
}


uint16_t POMIAR(void)
{
  ADCSRA |= (1<<ADSC);
  while(ADCSRA & (1<<ADSC));
  return ADCW;
}


void ZAPIS_EEPROM(void)
{
  eeprom_write_word(&a, nastawa);            //zapisz wartość nastawy
                                             //w lokalizacji 'a'
  eeprom_write_word(&b, czas_wylaczenia);    //zapisz wartość czasu 
                                             //wyłącznia w lokalizacji 'b'
}


void ODCZYT_EEPROM(void)
{
  nastawa = eeprom_read_word(&a);         //odczytaj wartość nastawy 
                                          //z lokalizacji 'a'
  czas_wylaczenia = eeprom_read_word(&b); //odczytaj wartość czasu wyłącznia
                                          //z lokalizacji 'b'

  //wyeliminowanie problemów podczas pierwszego uruchomienia
  //po wybraniu programu
  if((nastawa%10) != 0) {
    nastawa = 300; 
  }

  //wyeliminowanie problemów podczas pierwszego uruchomienia
  //po wybraniu programu
  if(czas_wylaczenia > 600) {
    czas_wylaczenia = 60; 
  }
}


ISR(TIMER2_COMP_vect)
{

  static uint16_t licznik_2; //licznik wykorzystywany do odmierzania czasu,
                             // co który mają być wykonywane określone operacje


  if(licznik_2 > 4500) { // co około sekundę (w tym przypadku nie musi
                         // to byś bardzo dokładnie)
    flaga = 1;
    licznik_2 = 0;
  }

  //regulacja temperatury kolby
  if(temp_grota < nastawa && rozlutownica_praca == 1) {
    GRZALKA_ON;  
  } else {
    GRZALKA_OFF;
  }

  licznik_2++;

}

Do pobrania: main2.c (kopia)




Podsumowanie

Trochę już wylutowałem elementów tą stacją i na prawdę pracuje się nim znakomicie! Na razie nie wychwyciłem nic, co mógłbym zmienić. Tak więc zachęcam do składania własnych stacji i chwaleniem się nim na forum ;-)









Oceń artykuł.
Wasze opinie są dla nas ważne, gdyż pozwalają dopracować poszczególne artykuły.
Pozdrawiamy, Autorzy
Ten artykuł oceniam na:

3 komentarze:

  1. Cześć. Fajny projekt. Dlaczego zastosowałeś wzmacniacz o zasilaniu symetrycznym? Nie można tego zrealizować inaczej?

    OdpowiedzUsuń
    Odpowiedzi
    1. Dzięki ;) Jak pisałem wyżej, wzorowałem się na innym projekcie, bo wcześniej za dużo ze wzmacniaczami nie miałem do czynienia, a nie miałem czasu na próby. Ale jakby się nad tym zastanowić, to to zasilanie symetryczne chyba nie jest tam do niczego potrzebne, termopara z tego co wiem daje tylko napięcie dodatnie.

      Usuń
  2. Witam,
    Czy udało się ustalić jaki typ termopary jest w tej kolbie rozlutownicy? Zastanawiam się nad zakupem tego modelu lub kolby od ZD-915 lub ZD-985.Jeśli można o kontakt do autora artykułu byłbym wdzięczny. proszę o kontakt rafalparzyszek@poczta.onet.pl

    OdpowiedzUsuń

Działy
Działy dodatkowe
Inne
O blogu




Dzisiaj
--> za darmo!!! <--
1. USBasp
2. microBOARD M8


Napisz artykuł
--> i wygraj nagrodę. <--


Co nowego na blogu?
Śledź naszego Facebook-a



Co nowego na blogu?
Śledź nas na Google+

/* 20140911 Wyłączona prawa kolumna */
  • 00

    dni

  • 00

    godzin

  • :
  • 00

    minut

  • :
  • 00

    sekund

Nie czekaj do ostatniego dnia!
Jakość opisu projektu także jest istotna (pkt 9.2 regulaminu).

Sponsorzy:

Zapamiętaj ten artykuł w moim prywatnym spisie treści.