3 Ağustos 2015 Pazartesi

SDCC ile Ultrasonick Sensör Mesafe Ölçümü, Timer1, LCD kullanımı (16F877A) -Ders13




bizim_lcd.h” dosyası
=======================================================================

/* Durali Kiraz 2015
* www.duralikiraz.blogspot.com
*
* D4,D5,D6,D7 pinlerini kullanarak 4 bit iletişim kullanır.
* Cursor kapalıdır.
* RW kullanılmadığı için direk toprağa bağlanabilir.
* 2x16 LCD Kullanım Klavuzu
*
* lcd_baslat(); ile LCD'nin ilk ayarlarını yap
* lcd_ekranisil(); ile LCD'yi sil
* lcd_yaz("deneme"); Şeklinde yazı yazdır.
* veri_yolla('F'); Şeklinde tek ascii kodu yazdır.
* lcd_konumlanxy(1,13); Şeklinde LCD'nin istenilen yerine git.
*
*
*/


#define rs RC0 //Pin tanımlamaları
#define rw RC1
#define e RC2
#define lcd_port PORTB


/* LCD'de kullanilan komutlarin tanimlamasi*/
#define Sil 1 // Ekrani temizler
#define BasaDon 2 // Imleci sol üst köseye getirir
#define SolaYaz 4 // Imlecin belirttigi adres azalarak gider
#define SagaYaz 6 // Imlecin belirttigi adres artarak gider
#define ImlecGizle 12 // Göstergeyi ac, kursor görünmesin
#define ImlecAltta 14 // Yanip sönen blok kursor
#define ImlecYanSon 15 // Yanip sönen blok kursor
#define ImleciGeri 16 // Kursoru bir karakter geri kaydır
#define KaydirSaga 24 // Göstergeyi bir karakter sağa kaydır
#define KaydirSola 28 // Göstergeyi bir karakter sola kaydır
#define EkraniKapat 8 // Göstergeyi kapat (veriler silinmez)
#define BirinciSatir 128 // LCD'nin ilk satir başlangıç adresi
// (DDRAM adres)
#define IkinciSatir 192 // İkinci satirin başlangıç adresi
#define KarakUretAdres 64 // Karakter üreteci adresini belirle
// (CGRAM adres)

/* LCD'de Kullanilan Fonksiyon Seçimi */
#define CiftSatir8Bit 56 // 8 bit ara birim, 2 satir, 5*7 piksel
#define TekSatir8Bit 48 // 8 bit ara birim, 1 satir, 5*7 piksel
#define CiftSatir4Bit 40 // 4 bit ara birim, 2 satir, 5*7 piksel
#define TekSatir4Bit 32 // 4 bit ara birim, 1 satir, 5*7 piksel


extern void veri_yolla(unsigned char);
extern void lcd_ekranisil(void);
extern void lcd_yaz(const char *s);
extern void lcd_konumlanxy(unsigned char x, unsigned char y);
extern void lcd_baslat(void);
extern void lcd_komut(unsigned char c);
extern void lcd_int_yaz(int x,unsigned int y);
//
=======================================================================


bizim_lcd.c” dosyası
=======================================================================

/* Durali Kiraz 2015
* www.duralikiraz.blogspot.com
*/

#include <pic14regs.h> //mikrodenetleyici hazır tanımları alınıyor
#include "bizim_lcd.h" // bizim_lcd.h dosyası tanımlanıp, değerler alınıyor
#include "delay.h" // Gecikme fonksiyonu tanımlanıyor

void lcd_busy(void)
{
   us_delay_20(12); //DelayUs(250);
}

void lcd_komut(unsigned char c) // Komut gönderme fonksiyonu
{
   rw=0; // LCD'ye yazma yapılacak
   rs=0; // LCD'ye komut gönderilecek
   e=1; // Düşen kenar tetikleme olduğu için E önce 1
   lcd_port = ( c & 0xF0 ); // Yüksek değerlikli bitler gönderiliyor
   e=0; // E, 0 yapılıyor
   lcd_busy(); //Belirli süre bekleniyor
   e=1; // E, 1 yapılıyor
   lcd_port = ( (c & 0x0F)<<4 ); // Düşük değerlikli bitler gönderiliyor
   e=0; // E, 0 yapılıyor
   lcd_busy(); // Belirli bir süre bekleniyor
}

void veri_yolla(unsigned char c)
{
  rw=0;
  rs=1; // Komut yolladan tek farkı, RS'nin 1 olması
  e=1;
  lcd_port = ( c & 0xF0 );
  e=0;
  lcd_busy();
  e=1;
  lcd_port = ( (c & 0x0F)<<4 );
  e=0;
  lcd_busy();
}

void lcd_ekranisil(void) // LCD siliniyor
{
   lcd_komut(0x1);
   ms_delay(2);
}

void lcd_yaz(const char * s) // LCD'ye string ifade gönderiliyor
{
  lcd_busy();
  while(*s)
  veri_yolla(*s++);
}

void lcd_konumlanxy(unsigned char x,unsigned char y) //LCD'nin belli lcd_gotoxy
//bölgesine gidiliyor
{
  if(x==1)
     lcd_komut(0x80+((y-1)%16));
  else
     lcd_komut(0xC0+((y-1)%16));
}

void lcd_baslat() // LCD ilk yükleme ayarları yapılıyor
{
   rs = 0;
   e = 0;
   rw = 0;
   ms_delay(15);
   e=1;
   lcd_komut(0x02);
   ms_delay(2);

   lcd_komut(CiftSatir4Bit);
   lcd_komut(SagaYaz);
   lcd_komut(ImlecGizle);
   lcd_ekranisil();
   lcd_komut(BirinciSatir);
}

void lcd_int_yaz(int val,unsigned int field_length)
{
/***************************************************************
This function writes a integer type value to LCD module

Arguments:
1)int val : Value to print

2)unsigned int field_length :total length of field in which the value is printed
must be between 1-5 if it is -1 the field length is no of digits in the val

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

char str[5]={0,0,0,0,0};
int i=4,j=0;
while(val)
{
   str[i]=val%10;
   val=val/10;
   i--;
}
if(field_length==-1)
  while(str[j]==0) j++;
else
  j=5-field_length;

if(val<0) veri_yolla('-');
   for(i=j;i<5;i++)
   {
      veri_yolla(48+str[i]);
   }
}

=======================================================================


mesafeolcumu.c” ana dosyası

=======================================================================

// Durali Kiraz 2015
// PIC16F877A için hazırlanmıştır.

#include "ayarlar.h"
#include "bizim_lcd.h" // LCD kütüphanesi tanımlanıyor
#include "delay.h"

#define trigger RD0 //pin tanımları
#define ECHO RD1



void main(void) // Ana fonksiyon alanı
{
   unsigned int sure, mesafe;

   TRISD = 0b0000010; // RD1 giriş diğer D portları çıkış yapılıyor
   TRISB = 0x00; // LCD'ye bağlı portlar çıkış yapılıyor
   TRISC = 0x00; // C portları çıkış yapılıyor

   PORTD = 0x00;
   PORTB = 0x00;
   PORTC = 0x00;
   T1CON = 0b00000101; //TIMER1 ayarları yapılıp çalıştırılıyor

   lcd_baslat(); // LCD ilk ayarları yapılıyor
   ms_delay(100);
   lcd_ekranisil();

   for(;;) //Sonsuz döngüye giriliyor
   {
      trigger = 1;
      us_delay_20(1); //20us bekletiyoruz. Bu 15 us yada 10 us de olabilir.
      trigger = 0;
      
      while(!(ECHO)); //echo pini bekle
      TMR1=0; //echo pini 1 se timeri 0 la ve saymaya başla

      while((ECHO)); //echo pini 0 olunca timer değerini süreye eşitle
      sure=TMR1;

      mesafe = (sure/58); //mesafeyi hesapla cm olarak

      lcd_konumlanxy(1,1); //uzaklık ve sure lcdye yazdırılıyor
      lcd_yaz("uzaklik:");
      lcd_int_yaz(mesafe,2);
      lcd_yaz("cm");
      lcd_konumlanxy(2,1);
      lcd_yaz("sure:");
      lcd_int_yaz(sure,2);
      lcd_yaz("us");
      ms_delay(100); //yeni ölçüm için bekle.
   }

}

=======================================================================






Bu dersimizde Timer1 sayıcısını kullanarak ultrasonik sensörümüzden gelen verileri sayarak mesafe ölçümünü yapacağız. İstersek timer1 kullanmadanda ultrasonik sensörün echo yapma süresini hesaplamamız mümkün. Ancak Timer kullanarak yapmak hem daha sağlıklı hemde mikrodenetleyicinin yükünü biraz daha hafifletir.

Ultrasonik sensörler; özel bir hoparlörden gönderilen ses dalgasının karşısındaki bir engele çarpıp geri gelmesi esnasında arada geçen sürenin yol=hız*zaman formülünden hesaplanmasıyla kullanılır. Ses saniyede 340m/sn lk hızla hareket eder. Hesaplamalarımızda kolaylık olması açısından bu mesafeyi cm olarak 34000cm (340m), zamanı da 1000000us (1sn) olarak düşünelim. Hâl böyle olunca (340000/1000000=1/29) olarak düzenlersek formül mesafe=zaman/29 olarak bulunur. Burada ses sinyali hem gitmekte hemde gelmekte. Dolayısıyla 29*2 = 58 yapar. Mesafe formümüz Mesafe=zaman/58 olur. (Sesin havadaki hızına hava sıcaklığı ve nemin de azda olsa etki ettiğini unutmayınız. Ama normal şartlarda saniyede 340m kabul edilir.)

Mikrodenetleyici timer larından bahsedilince akla hemen timer kesmeleri gelebilir. Ancak unutulmamalıdırki timerlar illa timer kesmesi ile beraber kullanılacak diye bir kaide yoktur. Bu örneğide özellikle seçme sebeplerinden biride budur. Timer1'in zamanlayıcı olarak kullanılmasına güzel bir örnek olacağı kanaatindeyim. 4 MHZ lik bir kristal osilatör kullanıldığında mikrodenetleyici bunu 4 e bölerek kullanılmasından dolayı timer1 in her komut çevriminde bir artması söz konusudur. Dolayısıyla mikrosaniye olarak süreyi elde etmemiz mümkün olmaktadır. Tabi bunu yapabilmek için T1CON register ının ayarlanması gerekmektedir. T1CON registeri 8 bitlik bir kontrol registeridir.

Bit 7-6
Kullanılmayan bitler. Okunurken bu bitler 0 okunur
Bit 5-4 T1CKPS1-T1CKPS0
Timer1 bölme (prescaler) oranı
11 = 1:8
10 = 1:4
01 = 1:2
00 = 1:1
Bit 3 T1OSCEN
Timer1 osilatör kontrol biti
1: osilatör açık
0: osilatör kapalı
Bit 2 T1SYNC
Timer1 dış clock sinyali senkronizasyon kontrol biti
1: Harici clock sinyali girişi ile senkronize yok
0: Harici clock sinyali girişi ile senkronize
Bit 1 TMR1CS
Timer1 clock kaynağı seçme biti
1: RC0/T1OSO/T1CK1 pininden dış clock sinyali
0: Dahili clock sinyali (FOSC /4)
Bit 0 TMR1ON
Timer1 açma-kapama biti
1: Timer1 açık
0: Timer1 kapalı

(Bu tablo CCS C ile PIC programlama (Serdar Çiçek) Kitabından alınmıştır)

Biz zamanlayıcı olarak Timer1 in kullanılabilmesi için ana program dosyamızda

T1CON = 0b00000101;

ayarını yaptık. Yani burada yapılan 0.bitin 1 yapılması. Yukarıdaki tabloda bakarsak 0.bit Timer1 1 yapıldığında “açık” olduğu anlamına geliyor. 2. bitin 1 yapılması Harici clock sinyali ile senkronizasyonun olmadığını gösterir. Dikkat çeken diğer bir değer ise 5. ve 4. bitin 00 olması. Buda Timer1 bölme(prescaler) oranının 1:1 olacağını gösterir. Bu şartları sağladığımızda timer1 zamanlayıcı olarak kullanılmaya hazır demektir. Daha fazla teknik bilgi için lütfen pic programlama kitaplarına yada PIC16F877A datasheet belgelerine bakabilirsiniz.

Ana program dosyamızda PORTD nin 1. bacağını giriş olarak diğerlerini ise çıkış olarak seçtiğimizi gösteriyoruz. Giriş olan bacağı HC-SR04 ultrasonik sensörün Echo çıkışına bağladığımızda mikrodenetleyicimiz bu sönsörden sinyal okumayı yapabilecektir. Sensörün diğer trigger bacağı ise mikrodenetleyiciden gelen çıkışı giriş olarak alır. Bu sayade sensör çalışabilecek kararlılığa ulaşır. Bunun için en az 10us kadar trigger portunun lojik 1 olarak kalması gerekir. Aksi takdirde sensör çalışmaya hazır hale gelemez. Sonrasında echo pininden bir sinyal gelene kadar beklenir. Bu sinyalin gelmesi sensörden çıkan ses dalgasının herhangi bir engele çarpıp geri geldiği zamanı bize bildirir. İşte bu zamanı yakaladığımızda bu ses dalgasının aldığı yolu (mesafeyi) hesaplayabiliriz. Kodun diğer kısmı mesafenin hesaplama formulu ve lcd ye yazı gönderme işini kapsar. Burada da yeni olan bir lcd fonksiyonumuz lcd_int_yaz() fonksiyonumuzdan bahsedecek olursak, doğrudan tam sayı değerleri lcd ye gönderebilmemiz için oluşturulmuş bir fonksiyondur. İki parametre alır. Birincisi yazdırılacak integer değeri, diğeri ise bu değerin kaç basamaklı bir alana yazdırılacağı bilgisidir. Zaten sırf bu fonksiyonu eklemek için bizim_lcd.cd ve bizim_lcd.h dosyalarında değişiklik yapıldı. Değişikliğe uğramamış dosyalara ve derleme adımlarının nasıl yapılacağına önceki derslerden ulaşabilirsiniz. Başka bir derste görüşmek üzere hoşçakalın.


duralikiraz.blogspot.com
03 Ağustos 2015

Muvaffakiyet Allahtandır”



Kaynaklar :
* CCS C ile PIC programlama Serdar Çiçek.



Hiç yorum yok:

Yorum Gönder