27 Mart 2014 Perşembe

3 Eksen İvmeölçer İle Konum Kontrolü

Merhabalar
Bu projede 3 eksenli ivmeölçerden gelen x,y ve z verini 8051 mikrodenetleyicisinde hesaplayarak C# ile yazdığım bir arayüz programı ile bilgisayarda kullanıcıya göstermeyi işledim. Projede MEMs yapıdaki ivme sensörü olan MMA7361, ADC0808 ve 89C5131 mikrodenetleyici kullanıldı.

Proje kapsamında bilgisayarın standart seri portu RS232 üzerinden 89C51 mikrodenetleyicisi ile haberleşme sağlanmıştır. Arayüz C# dili ile yazılmış olup 8051 kodlar için ise Keil µVision derleyicisi kullanılmıştır. Şimdi biraz ivmeölçere değinerek çalışma prensibi hakkında bilgi verelim.

İvmeölçerler, üzerlerine düşen statik(yerçeimi), dinamik(aniden hızlanma veya durma), ivme, titreşim ve mekanik şok değerlerini ölçmede kullanılan elektromekanik elemandır. Sensörden aldığımız değer
m/s2 veya yer çekimi (g-Force) türünden ifade edilebilir. Uygulamalarda genelde yerçekimi türünden ifade edilmektedir. Sensör sürekli yerçekimi etkisi altında kaldığından eğim ölçer(akıllı cihazlarda cihazın yatay ya da dikey konumu algılamasında kullanılması) veya hareket algılayıcı(nintendo wii ürünlerde kullanılan el ve kol hareketlerinin algılanması) olarak kullanılabilmektedir. Daha fazla detayı Barış hocanın bu yazısında bulabilirsiniz.

Kullandığımız sensör analog çıkışlara sahip. 89C5131 mikrodenetleyicisine direk olarak bağlayamayız. ADC kullanarak sensör çıkışlarından alınan analog verileri dijitale çevirdikten sonra mikrodenetleyiciye giriş yapabiliriz. ADC kullandığımız için adım büyüklüğünü hesaplamamız gerekmekte. ADC den aldığımız ham değerleri bu adım büyüklüğü ile çarparak gerilim değerini elde ederiz. Besleme gerilimi 3.3 volt ve adc 8 bit olduğundan dolayı adım büyüklüğümüz 3.3/256 olur.
Örneğin x ekseni için adc den gelen ham verimiz 152 olsun. x eksenindeki gerilim değerini bulmak için
       VoltX=152*(Adım Büyüklüğü)
       VoltX=152*3.3/256                        işlemleri yapılır.

Elde ettiğimiz gerilim değerlerini g türünden ifade etmemiz gerekmektedir. Her ivmeölçerin 0g de vermiş olduğu bir gerilim vardır ve Zero-G değeri olarak isimlendirilir. Bu değer genelde Vdd/2 dir. Kullandığımız sensör 3.3V besleme geriliminde Zero-G 1.65V tur. Yukarıdaki voltaj değerinden bu değer çıkartılıp sensörün hassasiyetine bölersek o eksendeki g değerini bulmuş oluruz. Kullandığımız sensör hassasiyeti için datasheetine bakmamız gerekmektedir. Kullandığımız sensörün 1.5g de hassasiyeti 800mV/g dir. Formül sonuc olarak şöyle olacaktır.
       X=(VoltX-ZeroG)/Hassasiyet
       X=(VoltX-1.65)/0.8

Bu temel bilgilerden sonra projemize geçebiliriz.

  
Yukarıdaki görülen blok diyagram sistemin daha iyi anlaşılmasını sağlayacaktır.
Aşağıda ise devre şeması proteus üzerinde görülüyor.

ADC0808 in 8 bit bir ADC olduğundan bahsetmiştim ayrıntısına girmeyeceğim bu konuda bol miktarda bilgi mevcut.
Aşağıda ise eksenlerin volt ve g değerlerini görebildiğimiz görsel arayüz programımız yer alıyor.


8051 kodları ve satır açıklamaları:

#include <at89c51RC2.h>
#include <stdio.h>

#define Kanal_Secim P0     // Kanal Seçim Uçlari x,y,z
#define VERI P2            //ADC Çikislarinin bagli oldugu port
#define OE P3_2            //ADC çikislarini yetkilendirme ucu
#define EOC P3_3     // Çevrimin sonlandigini gosteren uç
#define START P3_4     // Çevrimin baslama ucu
#define Kanal_Sayisi 3     // 3 farkli analog giris

float Giden_Veri;      //Hesaplanan 
float Adim_Buyuklugu;  //ADC nin bir adimi
int Maksimum_Olcum=3.3;    //ADC de orneklenecek maks deger
float Bit_Sayisi=256;       //ADC' nin ornekleme sayisi

void main() {
int i;

SCON=0x40;         // 8 bit uart modu
TMOD=0x20;      // Z/S1icin 8 bit otomatik yukleme modu
TH1=0xFD;      // Yaklasik 9600 bps(11.0592)
TR1=1;       // Z/S1' i calistir
TI=1;       // Gonderilmeye hazir
EA=1;

Adim_Buyuklugu=Maksimum_Olcum/Bit_Sayisi;

while(1) {
for (i=0;i<Kanal_Sayisi;i++) {     //Her bir konum için çevrim
Kanal_Secim=i;           //Çevrim yapilacak kanalin seçimi
START=1;            //Çevrime basla NOT: Çevrimin başlaması için 
START=0;
while(!EOC);                       //Çevrim bitene kadar don
OE=1;             //Çikisi aktif yap

Giden_Veri=VERI*Adim_Buyuklugu;    //Gönderilecek verinin hesaplanmasi

OE=0;                              //Çikis pasif
printf("%d%f\n",i+1,Giden_Veri);  
}
}
}
C# kodları ise:
using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Drawing;

using System.Text;

using System.Windows.Forms;

using System.IO;

using System.IO.Ports;

using System.Timers;

using System.Threading;

using System.Globalization;

namespace murat1

{

    public partial class Form1 : Form

    {

        public Form1()

        {

            InitializeComponent();

        }

        CultureInfo culture = new CultureInfo("en-US");

        private void Form1_Load(object sender, EventArgs e)

        {

            CheckForIllegalCrossThreadCalls = false;

            SerialPort serialPort1 = new SerialPort();

            serialPort1.PortName = "COM2";

            serialPort1.BaudRate = 9600;

            serialPort1.DataBits = 8;

            serialPort1.StopBits = System.IO.Ports.StopBits.One;

            serialPort1.Parity = System.IO.Ports.Parity.None;

            serialPort1.ReadTimeout = 500;

            serialPort1.Close();

         

        }

        private void button2_Click(object sender, EventArgs e)

        {

            DialogResult c;

           c = MessageBox.Show("Çıkmak istediğinizden emin misiniz ?", "ÇIKIŞ", MessageBoxButtons.YesNo, MessageBoxIcon.Question);

           if (c == DialogResult.Yes)

               

                this.Close();

        }

        private void button3_Click(object sender, EventArgs e)

        {

            serialPort1.Close();

           

            button1.Enabled = true;

            if (serialPort1.IsOpen!=true)

            label7.Text = "Seri Port Kapatıldı";

        }

        private void button1_Click(object sender, EventArgs e)

        {

            serialPort1.Open();

            if (serialPort1.IsOpen == true)

            {

                label7.Text = ("Seri Port Açık");

                button1.Enabled = false;

            }

            else

                label7.Text = ("Seri Port Açılamadı");

        }

        // KONTROL DEĞİŞKENLERİ

        string X = "1";

        string Y = "2";

        string Z = "3";

        string gelenveri;

        double Zero_g = 1.65;

        double hassasiyet = 0.8;

        double V_X = 0;

        double V_Y = 0;

        double  V_Z = 0;

        string g_X;

        string g_Y;

        string g_Z;

        private void button1_Click(object sender, SerialDataReceivedEventArgs e)

        {

            // VERİ ALMA, KONTROL VE KONUM YAZDIRMA BLOĞU

           

            try {

               gelenveri = (serialPort1.ReadLine());

                if (gelenveri.StartsWith(X))

                {

                    label4.Text = gelenveri.Substring(1, 8);

                    V_X = Convert.ToDouble(label4.Text);

                    g_X = Convert.ToString((V_X - Zero_g) / hassasiyet, culture);

                  label9.Text = g_X.Substring(0, 8);

                }

                   else if (gelenveri.StartsWith(Y)){

                    label5.Text = gelenveri.Substring(1, 8);

                    V_Y = Convert.ToDouble(label5.Text);

                    g_Y = Convert.ToString((V_Y - Zero_g) / hassasiyet, culture);

                    label10.Text = g_Y.Substring(0, 8);

                }

                else if (gelenveri.StartsWith(Z))

                {

                    label6.Text = gelenveri.Substring(1, 8);

                    V_Z = Convert.ToDouble(label6.Text);

                    g_Z = Convert.ToString((V_Z - Zero_g) / hassasiyet, culture);

                    label11.Text = g_Z.Substring(0, 8);

                }

            }

            catch (TimeoutException ex)

            {

                MessageBox.Show(ex + "Zaman Aşımı");

            }

        }   

       

        }

    }