9 Nisan 2013 Salı

ATMega168/328 Bootloader yükleme


Atmel programlayıcınız yoksa ve bootloader yüklü kontrolcü satın almadıysanız, aşağıdaki yöntemle ATMega168 ve AtMega328 kontrolcülerine bootloader kodunu atabilirsiniz. Tabi bunun için elinizde en azından bir Arduino kartı olması gerekiyor.



UNO kartını bilgisayara takıyoruz ve "Examples" klasöründeki ArduinoISP kodunu IDE'ye yüklüyoruz.



Arduino 1.0 sürümünü kullanıyorsanız bu kod içinde bir değişiklik yapmak gerekiyor.
Bunun için; kod içinde heartbeat fonksiyonunu aratın ve fonksiyon içindeki delay(40) değerini, delay(20) olarak değiştirin.

Bu kodu karta yükleyin ve alttaki devrelerden birini kurun.




Ben ATMega328P-PU için sağdaki devreyi kurdum ancak RESET ucundaki 10k direnci kullanmadım. Bağlantılar aşağıdaki şekilde;

UNO D10  ->  ATmega RESET (1)
UNO D11  ->  ATmega SCK (19)
UNO D12  ->  ATmega MISO (18)
UNO D13  ->  ATmega MOSI (17)
UNO 5V    ->  ATmega VCC (7,20)
UNO GND ->  ATmega GND (8,22)

Bunların dışında; isterseniz UNO'ya status ledlerini de bağlayabilirsiniz. 


D9: Heartbeat         - shows the programmer is running
D8: Error                - Lights up if something goes wrong (use red if that makes sense)
D7: Programming    - In communication with the slave

Seri port seçimini de yaptıktan sonra, Programlayıcı olarak "Arduino as ISP" seçiyorsunuz
ve <Burn Bootloader> 'ı seçiyorsunuz.  Birkaç saniyede, bootloader kodu yükleniyor. 




Uno'nun yeni sürümlerinde deneme şansım olmadı. Yüklemede sorun yaşarsanız, ArduinoISP kodunu attıktan sonra, Uno'nun reset ucunu 10uF kondansatör ile şaseye bağlayarak deneyebilirsiniz. 
Ardunio sayfasında bu konuyla ilgili detaylı bilgi bulabilirsiniz. link


ATMEGA 328P

21 Mart 2013 Perşembe

LM317 Ayarlı Voltaj Regülatörü


LM317 Regülatör entegresi ile ayarlı güç kaynağı uygulaması ve sabit çıkış için direnç değerlerinin hesaplanması:




Aşağıdaki yazılım ile direnç değerlerini hesaplayabilirsiniz.


LM317 Calculator -indir-

9 Mart 2013 Cumartesi

DMX-512 4 Kanal AC DIMMER




Daha önce şemasını verdiğim 220V AC dimmer devresine, DMX512 protokolü ile kontrol edilebilen ve 4 adet lambayı sürebilen bir kart tasarlamak için başlamıştım.

Ledler yaygın olarak kullanılmaya başlandığından beri 220V AC dimmer ihtiyacı pek kalmadı ama bazı uygulamalar için hala gerekebiliyor. 

Devre, bir mikrokontrolcü, bir sıfır geçiş dedektörü ve dört adet AC sürücü katından oluşuyor. Mikrokontrolcü olarak 16F73 kullandım, 28 pin herhangi bir PIC de kullanılabilir.


sıfır geçiş dedektörü
AC altında triac sürme konusundan daha önce bahsetmiştim, bununla ilgili 220V AC DIMMER konusuna bakabilirsiniz. 
Burada farklı olarak, 4 kanal için parlaklık ayarı, başka bir cihaz (ışık masası gibi) veya PC yazılımı üzerinden yapılabiliyor. Bunun için DMX-512 protokolü kullanılıyor. 
Her lamba, 0-255 kademe aralığında sürülebiliyor. 


DMX-512 Sender
Burada kullandığım DMX sender kartı, USB'den aldığı dataları, hatta bağlı dimmer kartlarına gönderiyor. Bir hat üzerinde 512'ye kadar adres tanımlanabiliyor.

Dimmer devresinde kullanılacak yük akımına göre triak seçimi yapılarak, 5000KW güçlere kadar flaman ampullerin dimlenmesi mümkün. bunun için BTA41 kullanabilirsiniz.





7 Mart 2013 Perşembe

Arduino ve CAN BUS


Elm ve OBD konusunda bahsetmiştim, araç bilgilerini okumanın başka bir yolu da, araç içinde dolaşan farklı canbus hatlarına girmektir. Bus sayısı, hızları, ve içerdiği bilgiler farklı olabiliyor ancak genelde tüm araçlarda CANBUS protokolü kullanılıyor.




Farklı hatlar, farklı bilgiler topluyor ve bu hatlar aynı zamanda, gateway ünitesi üzerinden birbirleri ile de haberleşiyor. 


gateway
OBD portundan alınan bilginin fazlasını, diğer hatlardan almak mümkün. VAG araçlarına ait canbus diagramı aşağıdaki gibi.





Burada şeması verilen devre, bir CAN kontrolcü ve mikrokontrolcüden oluşuyor.
CAN kontrolcü olarak Mikrochip firmasının MCP2515 entegresi, mikrokontrolcü olarak da, Arduino nano kartı kullandım. 




Arduino'nun (veya ATMEGA'nın) MCP2515 bağlantısı için SPI ve INT pinleri kullanılıyor. 
MCP2515'in RST ucu, arduino kartının reset ucuna bağlanacak. (hardware reset için)

Devre 3 modda çalışabiliyor.
  • mod-1 Sniffer
  • mod-2 OBD2 Reader
  • mod-3 Sender
Mod seçimi D6 ve D7 pinlerine bağlı switch ile yapılıyor. Şemada göstermedim ama D6 ve D7 pinleri 10k direnç ile şaseye çekilmeli.

anahtar "B" konumunda ise; devre, periyodik olarak, bazı OBD komutlarını gönderiyor ve bu komutların yanıtlarını alıyor. Bu, bağlantı testi için kullanılabilir. Aynı kodları veya daha fazlasını "C" konumunda da gönderebilirsiniz.

OBD için gönderilen komutlar:
ENGINE_COOLANT_TEMP  (0x05) 
ENGINE_RPM           (0x0C)  
VEHICLE_SPEED        (0x0D)  
INTAKE_AIR_TEMP      (0x0F)  
CONT_MODULE_VOLT     (0x42) 
AMBIENT_AIR_TEMP     (0x46)  
CATALYST_TEMP_B1S1   (0x3C)  

Switch "A" konumunda ise, canbus hattındaki data trafiği dinleniyor. Filtre veya mask tanımlanmamış ise, hat üzerindeki tüm datalar izlenebilir.
Switch "C" konumunda ise, yazılan komutu can hattına gönderiyor ve yanıtını bekliyor.

Hattan alınan tüm datalar, tanımlanmış bir formatta, arduino'nun seri çıkışına gönderiliyor.
PC arayüzü bu dataları alıp tabloya yazıyor. Bu arayüz üzerinden, hat hızı, maske ve filtre tanımlamak ve komut göndermek de mümkün.




Başta da dediğim gibi, araç içindeki tüm can hatları gateway'de birleşiyor ve gateway
bu hatlar üzerinde geçiş sağlıyor. OBD soketi üzerinden de bu hatlara geçiş olduğunu düşünüyorum ama bu konuda fazla deneme imkanım olmadı. Bazı markalarda, OBD soketinde, diagnostik hattının haricindeki hatlar da bulunabiliyor. Şayet yoksa, yapılması gereken, hattın geçtiği bir noktadan, paralel uç almak. 
Örneğin, vw grubunda, radyo soketindeki can hattına bağlanıp data akışını dinlemek ve
buradan bazı işlemler yapmak mümkün. (direksiyondaki butonları okumak, radyo veya yol bilgisayarı ekranına yazı yazmak gibi) Diğer bilgiler için başka hatlara bağlanmak gerekiyor.
Gateway soketinde araya girip 3 CAN hattından da uç almak en iyi çözüm bence.

Yukarıdaki şema için hex dosyasını ve PC yazılımını aşağıdaki linklerden indirebilirsiniz.

Win7 32/64bit uyumludur.


27 Şubat 2013 Çarşamba

220V AC Dimmer


220V AC Dimmer



Bir ihtiyaçtan dolayı akkor lambalar için dimmer yapmam gerekiyordu.
Finalde 4-8 kanal ve PC/DMX kontrollü bir kart olacak. 

AC sinyalde triac tetikleme ile ilgili dökümanlar, nette mevcut, o nedenle fazla detaya girmiyorum. Kısaca bahsetmek gerekirse, Çalışma mantığı şöyle;

  • Şebeke sıfır geçiş noktasını bul
  • istenilen gecikme kadar bekle
  • triac'ı tetikle

her alternansta bu işi tekrarla. 

AC gerilim altında, triac'ı 1 kez tetiklediğinizde, bir dahaki sıfır geçişine kadar iletimde kalır. 2 geçiş noktası arasında (50Hz şebekede 10mS) ne kadar önce tetiklerseniz lamba, o kadar parlak yanar.

Diyelimki lambayı %50 parlaklıkta yakmak istiyoruz.
Sıfır geçişini tespit ettik, timer'ı sıfırladık, 5mS bekledik ve triac'ı tetikledik. sonraki 5mS boyunca (bir dahaki sıfır geçişine kadar) triac iletimde kalacaktır.

Sıfır geçişini nasıl buluruz? Bunun da benzer bir çok yöntemi var. 
Benim kullandığım devre aşağıdaki gibi.




Bu devrenin çıkışını PIC'in RB0 pinine giriyoruz. Gerekli interrupt konfigürasyonu yapıldığında, her sıfır geçişinde bir kesmemiz oluyor.

Bundan sonrası, gecikme zamanını saymak ve çıkışı tetiklemek.
Triac sürücü devresi de aşağıdaki gibi.



ben, BT138 triac ve sürmek için de MOC30xx serisi optodiac kulllandım. PIC ile doğrudan triac sürmek de mümkün. Test devresinde snubber kullanmadım. İsterseniz, triac'ın A1-A2 uçları arasına; 39ohm ve 100nf'ı seri bağlayabilirsiniz.





PIC 16F628A xtal: 20MHz

RA0 portu Triac sürücü devresine bağlanacak, RB0 girişi de sıfır geçiş dedektörünün çıkışına. RA1'de led var, bu led, sıfır geçişi algılanıyorsa, periyodik olarak yanıp söner.
Triac, 255 kademede sürülebilir. Kademe (parlaklık) ayarı için RA2 ve RA3 portlarına bağlı butonları kullanabilirsiniz. 

Aşağıda, devrenin giriş ve çıkış sinyallerini görebilirsiniz.
Kırmızı sinyal şebeke voltajıdır. Bu sinyalin sıfır geçişlerinde üretilen sinyal de yeşil ile gösterilmiştir. (zero dedektör çıkışı)

Sarı ile gösterilen sinyal de yarı güçte sürülen triac'ın tetikleme sinyalidir.





Devreler test için yapılmıştır. Kullanılan bazı dirençler, seçilecek komponentlere göre yeniden hesaplanmalıdır. 


Aşağıdaki linkten hex dosyasını indirebilirsiniz. 

F628_Hex dosyası


12 Ocak 2013 Cumartesi

Delphi ile USB port okuma/yazma


Mikrochip firmasının USB destekli çiplerini uzun zamandır kullanıyorum. Özellikle HID protokolü ile kullanıldığında, sürücü gerektirmeden, hızlı bir haberleşme sağlıyor. bunun için yazılması gereken kodu da bazı programlar sizin için üretiyor. Size de gelen dataları işlemek ve göndermek kalıyor.

Bu iş için benim kullandığım yazılım, Mecanique firmasının  EasyHID yazılımı.
Bu program, hem PIC için hem de PC tarafı için örnek kod üretiyor.




PIC tarafında üretilen kod için söylenecek fazla birşey yok. Yapmanız gereken; 
ProductID, VendorID ve data uzunluklarını belirlemek ve kodu oluşturmak.

Burada, easyHID tarafından oluşturulan, cUSBInterface ve cUSBInterfaceTypes dosyalarının ve mcHID.dll dosyasının, yazdığınız programla aynı klasörde olması gerekiyor. Uygulama derlendikten sonra, dll dosyasının olması yeterli. 

aşağıda, Delphi için oluşturulmuş, 8 byte data alıp gönderen bir kod örneği var. Sayfanın sonunda da, indirme linkini bulabilirsiniz.

HID kullanan diğer cihazları da, hazırladığınız yazılımla izleyebilirsiniz. Aşağıdaki uygulama, UPS bilgilerini, USB portundan okumakta ve ekrana yazmaktadır.


UPS'in Vendor ve product ID'lerini ve cihazdan gelen dataları, HID terminal yazılımı ile görebilirsiniz.
Bu bilgileri aldıktan sonra, yapmanız gereken; Vendor ve product ID'lerini, kodun başında tanımlamak ve USBEvent fonksiyonunda gelen bilgileri alıp işlemek.



----------------------------------------Örnek program kodu--------------------------------------------------

unit FormMain;

interface

uses
   Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, OleCtrls, DBOleCtl, ComCtrls, VrControls, VrSlider;

const

   // input and out buffer size constants...
   BufferInSize  = 8;
   BufferOutSize = 8;
type

   // input and output buffers...
   TBufferIn = array[0..BufferInSize] of byte;
   TBufferOut = array[0..BufferOutSize] of byte;

   // main form
   TForm1 = class(TForm)
    LabelProductName: TStaticText;
    LabelVendorName: TStaticText;
    LabelUsbStat: TStaticText;
    Button3: TButton;
    Button1: TButton;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure Button1Click(Sender: TObject);
   private
      FBufferIn:TBufferIn;
      FBufferOut:TBufferOut;
      function USBEvent(var Msg: TMessage): Boolean;
      function SendData: Boolean;
   public
   end;

var
  Form1: TForm1;

implementation

uses
   cUSBInterface,
   cUSBInterfaceTypes, Math;

const
   // vendor and product ID constants...
   VENDOR_ID  = $1234;
   PRODUCT_ID = 0001;

{$R *.DFM}

{
****************************************************************************
* Name    : Create                                                         *
* Purpose : Create the main form                                           *
****************************************************************************
}
procedure TForm1.FormCreate(Sender: TObject);
begin
   Application.HookMainWindow(USBEvent);
   Connect(Application.Handle);
end;
{
****************************************************************************
* Name    : Destroy                                                        *
* Purpose : Free the main form                                             *
****************************************************************************
}
procedure TForm1.FormDestroy(Sender: TObject);
begin
   Application.UnHookMainWindow(USBEvent);
end;
{
****************************************************************************
* Name    : USBEvent                                                       *
* Purpose : DLL message handler hook                                       *
****************************************************************************
}
function TForm1.USBEvent(var Msg: TMessage): Boolean;
var
   i: integer;
   DevHandle:cardinal;
   TextBuffer:array[0..255] of char;
begin
  result := False;
  if Msg.Msg = WM_HID_EVENT then
  begin
     case Msg.WParam of
        // a HID device has been plugged in...
        NOTIFY_PLUGGED :
        begin
           // is it our HID device...
           DevHandle := Msg.LParam; // handle of HID device in this message
           if (GetVendorID(DevHandle) = VENDOR_ID) and (GetProductID(DevHandle) = PRODUCT_ID) then
           begin
              // add your code here, for example...
              GetProductName(DevHandle, TextBuffer, 256);
              LabelProductName.Caption := string(TextBuffer);
              GetVendorName(DevHandle, TextBuffer, 256);
              LabelVendorName.Caption := string(TextBuffer);
              LabelUsbStat.Caption := 'Plugged';
           end;
           result := true;
        end;

        // a HID device has been device removed...
        NOTIFY_UNPLUGGED :
        begin
           // is it our HID device...
           DevHandle := Msg.LParam; // handle of HID device in this message
           if (GetVendorID(DevHandle) = VENDOR_ID) and (GetProductID(DevHandle) = PRODUCT_ID) then
           begin
              // add you code here
              LabelUsbStat.Caption := 'Unplugged';
           end;
           result := true;
        end;

        // a HID device has been attached or removed. This event is fired after
        // either NotifyPlugged or NotifyUnplugged.
        NOTIFY_CHANGED :
        begin
           // get the handle of the device we are interested in
           // and set it's read notification flag to true...
           DevHandle := GetHandle(VENDOR_ID,PRODUCT_ID);
           SetReadNotify(DevHandle,true);
           result := true;
        end;

        // a HID device has sent some data..
        NOTIFY_READ :
        begin
           DevHandle := Msg.LParam; // handle of HID device in this message
           if (GetVendorID(DevHandle) = VENDOR_ID) and (GetProductID(DevHandle) = PRODUCT_ID) then
           begin
               // read the data - remember that first byte is report ID...
               Read(DevHandle,@FBufferIn);
               // USB aygıttan gelen datalar burada işlenecek!
           end;
           result := true;
        end;
     end;
  end;
end;

//USB'ye data gönder
function TForm1.SendData: Boolean;
var r: boolean;
begin
   r := WriteEx(VENDOR_ID, PRODUCT_ID, @FBufferOut);
   result := r;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
   FBufferOut[0] := 0;
   FBufferOut[1] := 80;
   FBufferOut[2] := 70;
   FBufferOut[3] := 1;
   FBufferOut[4] := 0;
   FBufferOut[5] := 0;
   FBufferOut[6] := 0;
   FBufferOut[7] := 0;

   SendData(); //Fbuufferout'a yazılanlar gönderilir
end;
end.
-----------------------------------------Program kodu--------------------------------------------------






delphi kod örneği

11 Ocak 2013 Cuma

Sharp IR Sensör ile mesafe ölçümü


SHARP IR sensör (GP2Y) çıkışını, bir ADC ile okuyarak mesafe ölçümü yapmak mümkün.
Sensör çıkışı doğrusal olmadığı için küçük bir hesaplama yapmak gerekiyor.

10 bit çözünürlük ve 5V besleme ile, aşağıdaki formülden mesafe (R) hesaplanabilir.






aşağıdaki mikroPascal kodu, PORTA.2'ye bağlanan IR sensörün, okuduğu mesafe bilgisini hesaplar ve 'cm' olarak lcd'ye yazar.


------------------------------------------program kodu--------------------------------------------

//PIC 16F877A 
//GP2 sensor to A.2
//ADC 10bit

program IRSensor;

var ch: byte;
    t : integer;
    range : real;
    Text : string[2];
    rstr : string[2];
    rr : integer;

begin
  PORTB  := 0;                      
  TRISB  := 0;                      
  intcon := 0;                      

  OPTION_REG := $80;
  ADCON1     := $82;                
  TRISA      := $FF;                


  Lcd_Init(PORTD);                    
  Lcd_Cmd( LCD_CURSOR_OFF);        
  Lcd_Cmd(LCD_CLEAR);               

  Delay_ms(500);

  Text  := 'Mesafe:';             
  Lcd_Out(1, 1, Text);       

  while true do
    begin
      t := ADC_read(2);     
      range := (1/(t*0.000147 + (0.00042*-1))) - 4;
      FloatToStr(range, Text);
      strncpy(rstr,text,2);
      rr := StrToInt(rstr);

      if (rr > 9) and (rr < 81) then begin
         Lcd_Cmd(LCD_CLEAR);
         Lcd_Out(1, 8, rstr);
         Lcd_Out(1, 11, 'cm');
      end
      else
         Lcd_Out(1, 1, '  Out Of range  ');
         
      delay_ms(150);
    end;
end.


------------------------------------------program kodu--------------------------------------------