PIC ile wireless termometre

rainalert

Üye
Katılım
20 Eki 2009
Mesajlar
4
Puanları
1
Eklerde 433Mhz RF verici-alıcı ile tasarlanmış bir kablosuz termometre örnek devresi mevcut. PIC olarak verici tarafında PIC16F688 alıcı tarafında PIC16F877 kullanılmıştır. Veri iletişim kısmında PIC'lerin UART özelliği kullanılmıştır. RF çalışması yapacak arkadaşlar için fikir vereceğini umuyorum. Hex kodlar 9 bit çözünürlüklü DS1620 sıcaklık sensörüne göre derlenmiştir. Eklerde şemayı, isis dosyasını, hex kodları ve MikroC kaynak kodlarını bulabilirsiniz.


Alıcı taraf - 16F877
Kod:
#define DIGIT_GECIKMESI 1000 //herbir digitin ekranda bekletilme süresi  (us olarak)

unsigned short d1,d2,d3,d4;
char text[10]="-1.0";
char tmp,pre_tmp;
char receive_flag,status_flag;
float sicaklik;
unsigned char count;

//7Segment displaye rakam yazılması
void ss_rakam_yaz(unsigned short sayi,unsigned short pos,unsigned short flag)
{

unsigned short i;

//PORTD kapatılıyor. A,B,C,D,E,F,G,DP
PORTD=0;

if (pos==1)
     {
     PORTB=0b00001110;
     }
else if (pos==2)
     {
     PORTB=0b00001101;
     }
else if (pos==3)
     {
     PORTB=0b00001011;
     }
else if (pos==4)
     {
     PORTB=0b00000111;
     }

if (sayi==0)      i=0x3F;
else if (sayi==1) i=0x06;
else if (sayi==2) i=0x5B;
else if (sayi==3) i=0X4F;
else if (sayi==4) i=0X66;
else if (sayi==5) i=0X6D;
else if (sayi==6) i=0X7D;
else if (sayi==7) i=0X07;
else if (sayi==8) i=0X7F;
else if (sayi==9) i=0X6F;
else if (sayi==10) i=0x40;
else if (sayi==11) i=0x00;
else if (sayi==12) i=0x79;

//Rakamdan sonra noktada konuluyor
if (flag==1) i+=0x80;

PORTD=i;

Delay_us(DIGIT_GECIKMESI);

//PORTB nin ortak katotları kapatılıyor.
PORTB=0b00001111;

//PORTD kapatılıyor
PORTD=0;
}

//7Segment displaye sayı yazılması
void ss_sayi_yaz(float sayi,unsigned tekrar)
{

unsigned short i;
unsigned short flag;

//Sayiya bağlı olarak digitler hesaplanıyor
if (sayi<10 && sayi>0)
   {
   d1=11;
   d2=11;
   d3=floor(sayi);
   d4=sayi*10.0-floor(sayi)*10.0;
   flag=3;
   }
else if (sayi>=10 && sayi<100)
   {
   d1=11;
   d2=floor(sayi/10.0);
   d3=floor(sayi)-d2*10;
   d4=sayi*10.0-floor(sayi)*10.0;
   flag=3;
   }
else if (sayi>=100 && sayi<1000)
   {
   d1=floor(sayi/100.0);
   d2=floor((sayi-floor(sayi/100.0)*100)/10.0);
   d3=floor(sayi-floor(sayi/10.0)*10);
   d4=sayi*10.0-floor(sayi)*10.0;
   flag=3;
   }
else if (sayi>=1000 && sayi<10000)
  {
    d1=floor(sayi/1000.0);
    d2=floor((sayi-floor(sayi/1000.0)*1000)/100.0);
    d3=floor((sayi-floor(sayi/100.0)*100)/10.0);
    d4=sayi-floor(sayi/10.0)*10.0;
    flag=0;
    }
else if (sayi<0 && sayi>-10)
   {
   d1=11;
   d2=10;
   d3=fabs(ceil(sayi));
   d4=fabs(sayi*10.0-ceil(sayi)*10.0);
   flag=3;
   }
else if (sayi<=-10 && sayi>-100)
   {
   d1=10;
   d2=fabs(ceil(sayi/10.0));
   d3=fabs(ceil(sayi))-d2*10;
   d4=fabs(sayi*10.0-ceil(sayi)*10.0);
   flag=3;
   }

else if (sayi==0)
   {
   d1=11;
   d2=11;
   d3=0;
   d4=0;
   flag=3;
   }

else
  {
  d1=11;
  d2=11;
  d3=11;
  d4=12;
  flag=0;
  }

i=tekrar;

while(i!=0)
{
ss_rakam_yaz(d1,1,0);
ss_rakam_yaz(d2,2,0);
if (flag==3) ss_rakam_yaz(d3,3,1);
else ss_rakam_yaz(d3,3,0);
ss_rakam_yaz(d4,4,0);
i--;
}

}


void interrupt() //RF bilgi geldiğinde bu interrupt devreye giriyor.
{


INTCON=0;

tmp=UART1_Read();

if (pre_tmp==0x24 && tmp==0x45 && receive_flag==1)
{
text[count]=0;
receive_flag=0;
status_flag=1;
}

else if (pre_tmp==0x24 && tmp==0x42 && receive_flag==0)
{
receive_flag=1;
status_flag=0;
count=0;
}

else if (receive_flag==1)
{
text[count]=tmp;
count++;
status_flag=0;
}

pre_tmp=tmp;

INTCON=0b11000000;

}


void main() {

INTCON=0b11000000;  // Peripheral ve unmaskked interruptlar açılıyor. Böylece data geldiğinde işlemci diğer işlemleri bırakıp gelen rf datayı alacak.
PIE1=0b00100000; //Diğer bir interrupt ayarlaması
ADCON1=0b00000111; //ADC Devre dışı
CCP1CON=0; //Komparatör kapatılıyor

TRISD=0; //D portu çıkış olarak ayarlanıyor
TRISB=0; //B portu çıkış olarak ayarlanıyor


Delay_ms(100);

UART1_Init(1200); //1200baudrate olarak ayarlanıyor. Kullandığım noname rf modülde problem çıkarmadı.
Delay_ms(100); //Stabilizasyon

pre_tmp=0;
receive_flag=0;
status=0;
sicaklik=10000;


while(1)
{

if (status_flag==1) sicaklik=atof(text); //Text değeri sicaklik çevrimi için uygunsa text değerini sıcaklığa çevir
ss_sayi_yaz(sicaklik,1); //Sıcaklık değerini 4 digit 7 segment displaye yazan alt program çağrılıyor

}


}

Verici taraf-16F688
Kod:
const unsigned short TEMP_RESOLUTION = 9;

char *text = "000.0000";
unsigned temp;


void get_temp() //Bu fonksiyon sıcaklık değerini DS18B20 üzerinde one-wire yöneti ile alarak değeri text olarak *text değeri içine atar
{
  const unsigned short RES_SHIFT = TEMP_RESOLUTION - 8;
  char temp_whole;
  unsigned int temp_fraction;

  Ow_Reset(&PORTC, 0);
  Ow_Write(&PORTC, 0, 0xCC);
  Ow_Write(&PORTC, 0, 0x44);
  Delay_us(120);

  Ow_Reset(&PORTC, 0);
  Ow_Write(&PORTC, 0, 0xCC);
  Ow_Write(&PORTC, 0, 0xBE);

  Delay_ms(500);
 
  temp =  Ow_Read(&PORTC, 0);
  temp = (Ow_Read(&PORTC, 0) << 8) + temp;


  if (temp & 0x8000) {
     text[0] = '-';
     temp = ~temp + 1;
     }

  temp_whole = temp >> RES_SHIFT ;


  if (temp_whole/100)
  text[0] = temp_whole/100  + 48;
  else
  text[0] = '0';

  text[1] = (temp_whole/10)%10 + 48;
  text[2] =  temp_whole%10     + 48;

  temp_fraction  = temp << (4-RES_SHIFT);
  temp_fraction &= 0x000F;
  temp_fraction *= 625;


  text[4] =  temp_fraction/1000    + 48;
  text[5] = (temp_fraction/100)%10 + 48;
  text[6] = (temp_fraction/10)%10  + 48;
  text[7] =  temp_fraction%10      + 48;
  text[8]=0;

}


void preamble() //Bir aradan sonra rf modül tarafı ile rf alıcı tarafı arasındaki senkron kayboluyor. Preamble işi bu senkronu tekrar sağlıyor. Eğer gönderim sırasında bu programda olduğu gibi ara verildiğinde senkron kayboluyor.
{

//Preamble - Senkron sağlanamazsa 0x55 gönderim sayısı arttırılabilir.

UART1_Write(0x55);
UART1_Write(0x55);
UART1_Write(0x55);
UART1_Write(0x55);
UART1_Write(0x55);
 
//Senkron
UART1_Write(0x00);
UART1_Write(0x00);
UART1_Write(0x00);
UART1_Write(0x00);
UART1_Write(0x00);
UART1_Write(0xff);
UART1_Write(0xff);
UART1_Write(0xff);
UART1_Write(0xff);
UART1_Write(0xff);
}

void main() {

INTCON=0; // Interruptlar devre dışı
ANSEL=0; //ADC Devre dışı
CMCON0=0b00000111; //Komparatör devre dışı
TRISC=0b00000001;

Delay_ms(100);

get_temp();
UART1_Init(1200);
Delay_ms(100);
preamble();

while(1)
{
get_temp();
preamble();
UART1_Write_Text("$B"); //Başlangıç textini gönder
UART1_Write_Text(text); //Sıcaklığı gönder
UART1_Write_Text("$E"); //Bitiş textini gönder
RC1_bit=1; //Ledi kısa bir süre aç ve kapa
Delay_ms(100);
RC1_bit=0;
Delay_ms(1000); //Veriyi 10sn bir gönder.Esas amacım buraya pic'in  sleep özelliğini koyup güç tasarrufu sağlamtı. Programın genel yapısının karışmaması için sadece Delay_ms fonksiyonu ile yetindim.

}

}



Dosya, Dosya Paylaşım Sitesinden Silindiği İçin Konu Çöpe Taşınmıştır.
 
Seri iletişimde UART alıcının (PIC16F877) overrun ve frame error kontrolü için aşağıdaki interrupt kodu ilk mesajımdaki interrupt kodu ile değiştirilmelidir. Aksi taktirde belli bir süre sonra UART overrun olup, verici ile bağlantısı kopmaktadır.

Kod:
void interrupt() //RF bilgi geldiğinde bu interrupt devreye giriyor.
{


if (RCSTA.OERR==1 || RCSTA.FERR==1)
{
RCSTA.CREN = 0;
RCSTA.CREN = 1;
while(PIR1.RCIF==1) {tmp = UART1_Read();}
}

else {
while (PIR1.RCIF==1)
{
tmp=UART1_Read();

if (pre_tmp==0x24 && tmp==0x45 && receive_flag==1)
{
text[count]=0;
receive_flag=0;
status_flag=1;
}

else if (pre_tmp==0x24 && tmp==0x42 && receive_flag==0)
{
receive_flag=1;
status_flag=0;
count=0;
}

else if (receive_flag==1)
{
text[count]=tmp;
count++;
status_flag=0;
}
pre_tmp=tmp;
}
}

Ayrıca 16F877 alıcı tarafının alternatifi için 18F252 kodu da aşağıda verilmiştir.

Kod:
#define DIGIT_GECIKMESI 1000 //herbir digitin ekranda bekletilme süresi  (us olarak)

unsigned short d1,d2,d3,d4;
char text[10]="-1.0";
char tmp,pre_tmp;
char receive_flag,status_flag;
float sicaklik;
unsigned char count;

//7Segment displaye rakam yazılması
void ss_rakam_yaz(unsigned short sayi,unsigned short pos,unsigned short flag)
{

unsigned short i;

//PORTB kapatılıyor. A,B,C,D,E,F,G,DP
PORTB=0;

if (pos==1)
     {
     PORTC=0b00001110;
     }
else if (pos==2)
     {
     PORTC=0b00001101;
     }
else if (pos==3)
     {
     PORTC=0b00001011;
     }
else if (pos==4)
     {
     PORTC=0b00000111;
     }

if (sayi==0)      i=0x3F;
else if (sayi==1) i=0x06;
else if (sayi==2) i=0x5B;
else if (sayi==3) i=0X4F;
else if (sayi==4) i=0X66;
else if (sayi==5) i=0X6D;
else if (sayi==6) i=0X7D;
else if (sayi==7) i=0X07;
else if (sayi==8) i=0X7F;
else if (sayi==9) i=0X6F;
else if (sayi==10) i=0x40;
else if (sayi==11) i=0x00;
else if (sayi==12) i=0x79;

//Rakamdan sonra noktada konuluyor
if (flag==1) i+=0x80;

PORTB=i;

Delay_us(DIGIT_GECIKMESI);

//PORTC nin ortak katotları kapatılıyor.
PORTC=0b00001111;

//PORTB kapatılıyor
PORTB=0;
}

//7Segment displaye sayı yazılması
void ss_sayi_yaz(float sayi,unsigned tekrar)
{

unsigned short i;
unsigned short flag;

//Sayiya bağlı olarak digitler hesaplanıyor
if (sayi<10 && sayi>0)
   {
   d1=11;
   d2=11;
   d3=floor(sayi);
   d4=sayi*10.0-floor(sayi)*10.0;
   flag=3;
   }
else if (sayi>=10 && sayi<100)
   {
   d1=11;
   d2=floor(sayi/10.0);
   d3=floor(sayi)-d2*10;
   d4=sayi*10.0-floor(sayi)*10.0;
   flag=3;
   }
else if (sayi>=100 && sayi<1000)
   {
   d1=floor(sayi/100.0);
   d2=floor((sayi-floor(sayi/100.0)*100)/10.0);
   d3=floor(sayi-floor(sayi/10.0)*10);
   d4=sayi*10.0-floor(sayi)*10.0;
   flag=3;
   }
else if (sayi>=1000 && sayi<10000)
  {
    d1=floor(sayi/1000.0);
    d2=floor((sayi-floor(sayi/1000.0)*1000)/100.0);
    d3=floor((sayi-floor(sayi/100.0)*100)/10.0);
    d4=sayi-floor(sayi/10.0)*10.0;
    flag=0;
    }
else if (sayi<0 && sayi>-10)
   {
   d1=11;
   d2=10;
   d3=fabs(ceil(sayi));
   d4=fabs(sayi*10.0-ceil(sayi)*10.0);
   flag=3;
   }
else if (sayi<=-10 && sayi>-100)
   {
   d1=10;
   d2=fabs(ceil(sayi/10.0));
   d3=fabs(ceil(sayi))-d2*10;
   d4=fabs(sayi*10.0-ceil(sayi)*10.0);
   flag=3;
   }

else if (sayi==0)
   {
   d1=11;
   d2=11;
   d3=0;
   d4=0;
   flag=3;
   }

else
  {
  d1=11;
  d2=11;
  d3=11;
  d4=12;
  flag=0;
  }

i=tekrar;

while(i!=0)
{
ss_rakam_yaz(d1,1,0);
ss_rakam_yaz(d2,2,0);
if (flag==3) ss_rakam_yaz(d3,3,1);
else ss_rakam_yaz(d3,3,0);
ss_rakam_yaz(d4,4,0);
i--;
}

}


void interrupt() //RF bilgi geldiğinde bu interrupt devreye giriyor.
{


if (RCSTA.OERR==1 || RCSTA.FERR==1)
{
RCSTA.CREN = 0;
RCSTA.CREN = 1;
while(PIR1.RCIF==1) {tmp = UART1_Read();}
}
  
else {
while (PIR1.RCIF==1)
{
tmp=UART1_Read();

if (pre_tmp==0x24 && tmp==0x45 && receive_flag==1)
{
text[count]=0;
receive_flag=0;
status_flag=1;
}

else if (pre_tmp==0x24 && tmp==0x42 && receive_flag==0)
{
receive_flag=1;
status_flag=0;
count=0;
}

else if (receive_flag==1)
{
text[count]=tmp;
count++;
status_flag=0;
}
pre_tmp=tmp;
}
}

}


void main() {


INTCON=0b10000000;  // Tüm high priority interruptlar açılıyor
RCON.IPEN=1; // High-low interrupt durumu aktif hale getiriliyor
IPR1.RCIP=1; // UART receive interruptı high priority
PIE1=0b00100000; // UART receive interruptı aktif
ADCON1=0b00000111; //ADC Devre dışı
CCP1CON=0; //Komparatör kapatılıyor
CCP2CON=0; //Komparatör kapatılıyor

TRISB=0; //B portu çıkış olarak ayarlanıyor
TRISC=0b10000000; //C portu çıkış olarak ayarlanıyor
TRISA=0; //PORTA çıkış
LATA=0; //PORTA tüm çıkışları 0


Delay_ms(100);

UART1_Init(1200); //1200baudrate olarak ayarlanıyor. Kullandığım noname rf modülde problem çıkarmadı.
Delay_ms(100); //Stabilizasyon

pre_tmp=0;
receive_flag=0;
status=0;
sicaklik=10000;


while(1)
{

if (status_flag==1) sicaklik=atof(text); //Text değeri sicaklik çevrimi için uygunsa text değerini sıcaklığa çevir
ss_sayi_yaz(sicaklik,1); //Sıcaklık değerini 4 digit 7 segment displaye yazan alt program çağrılıyor

}


}
 
Sadece mikroc üzerinde hazırladım. Pic Basic versiyonu maalesef mevcut değil.
 
merhabalar verdiğiniz rar dosyası içindeki C programlarının kütüphaneleri ve tanıtım kodları yazılmamış yüzden MLAB IDE de programı derleyemiyorum acaba eklemeniz mümkünmü ?

Teşekkürler.
 
Sadece mikroc üzerinde hazırladım. Pic Basic versiyonu maalesef mevcut değil.


kardes ben wıreless termometre ıcın rahatsız edıyorum senı termometre dogru degerı gostermıyo sensoru 39 ayarlıyorum lcd de 59 goruyorum acaba nerde sorun var
 
Moderatör tarafında düzenlendi:
devrenin ds18b20 sensörüne göre düzenlenmişi elinde varmı acaba
 
Verici tarafta bulunan 9V'luk pilin ömrü ne kadar oluyor?
 
Verici tarafta bulunan 9V'luk pilin ömrü ne kadar oluyor?

pil çıkışında direk zaten 7805 var sen devreyi bağlamasan bile 7805 in quiescent current ı 5mA. bu bile birkaç güne bitirir.

ayrıca atx vericinin gönderme esnasında çektiği akım 10mA dir. total 15 mA 1 hafta ya dayanır ya dayanmaz pil.

bu tip devrelerde donanımın ve yazılımın uyku moduna uygun yapılması gerekir. mesela 5sn herşey uyuycak.sonra pic uyanıp modulleri açar sıcaklık okunur,gönderme yapılır sonra tekrar uyur.ancak pil ömrünü öyle uzatırsınız.
 
Pil ömrünü arttırmaya yönelik örnek bir program yazmış olan varsa paylaşırsa çok sevinirim.
Microdenetleyici ve rf haberleşmeyi uyku moduna alan gibi...
 

Forum istatistikleri

Konular
129,007
Mesajlar
922,451
Kullanıcılar
451,218
Son üye
emrah asrav

Yeni konular

Geri
Üst