31 Aralık 2018 Pazartesi

MH-Z16 Co2 SENSÖR ve PROTON BASİC

Merhabalar..

Üzerinde çalıştığım Mantarhane otomasyonu için özellikle istenen Co2 ölçümü üzerine epey bir araştırdıktan sonra MH-Z16  5000PPM lik sensörünü seçtim ve nihayetinde elime geçti ve biraz bızıkladıktan sonra ( biraz dediğime bakmayın aşağıda değineceğim sebeplerden dolayı 3 gün uğraştım ) çalışır hale getirebildim.

En büyük sıkıntı protonda basit kod örneklerinin olmayışı.Çoğunluk ile ardunio için hazır kütüphaneleri mevcut.Ben proton basic te donanımsal usart ile haberleştim.




Sensörden biraz bahsetmek istiyorum.Aslında datasheeti biraz kurcaladığınızda çok basit bir kullanımının olduğunu göreceksiniz...


Sensör kısaca NDIR dedikleri mantık ile çalışıyor.İç yapısında IR ışık kaynağı karşısında da alıcı kısımları mevcut bu alıcı kısımlarında önünde anladığım kadarı ile CO2 moleküllerini görecek 4.3um bir filitre mevcut..Teknolojisini fazla kurcalamadım zira evde yapabileceğimiz bir şey değil alıp kullanacağız mecburen.. 


Sensörün anladığım kadarı ile birkaç versiyonu mevcut.Benim elimdekinin sadece MH-Z16 olduğunu ve 5000ppm e kadar ölçüm yaptığını biliyorum.

NOT: Sensörü sipariş etmeden önce max. ölçüm aralığınızı bilmelisiniz fabrikasyon ayarlı max. sınırlı geliyor mesela 1000ppm e kadar ölçüm yapacaksanız siz yine 2000ppm felan alın derim benim max. 2000ppm gibi bir değer okumam gerekli ben ne olur ne olmaz diye 5000ppm aldım.

Sensörün besleme voltajı +5v.Üzerinde 1 adet PWM çıkışı ve Analog voltaj çıkışı ve USART serial haberleşme mevcut..

En basiti usart üzerinden direk değer okumak bana kalırsa.

NOT: resimdeki gibi V2.4 olan versiyonda Serial pinler TTL 5V.Ben elimdeki sensörün versiyonunu bilmediğim için araya çevirici yapmıştım.


Bu şekilde çalışıyor.Riski göze alıp rx tx pinlerini direk pic'in ayaklarına bağladığımda da çalıştığını gözlemledim.Sorun olmadı.



Pin bağlantısı yukarıdaki gibidir.Yeniliyorum.RX TX pinlerini ilk olarak TTL seviyesinde çalıştırmayın.En azından işlemcinin tx çıkışını gerilim bölücü direnç ile sensöre girin derim.

Evet yavaş yavaş en eylenceli yere doğru geliyoruz.. :P


Sensöre belirli komutları göndermemiz gerekiyor ve bununda bir sırası var.Yukarıdaki resim birazdan anlatacağım sıralamada BYTE2 ye verilen değerin karşılığında sensörün ne yapacağını anlatıyor.

Yani 0x86 gönderirseniz sensör co2 miktarını ölçüp serial olarak gönderiyor.Diğerlerini hiç denemedim.Kalibrasyon işlemlerine hiç kalkışmadım çünki elimde kalibrasyon yaparken kullanacağım doğruluğuna inandığım bir CO2 metre şuan için yok.


Tabi sensöre kafamıza göre veri gönderemiyoruz.Üretici firmanın belirlediği bir sıralama var sensör bu sıralamada beklediği dataları alırsa geri dönüş yapıyor.

Bunu kodda anlatmak gerekirse : 

  CO2_SENSOR_OKU:
  DelayMS 10
  HSerOut2 [$FF,$01,$86,$00,$00,$00,$00,$00,$79]
  Return

Yani yukarıdaki resimdeki gibi sırası ile sensöre okuma yaptırmak için 18F24K22 nin 2. usartından sensöre gönderiliyor.


Sonrasında sensörden geri yanıt geliyor.Bu o kadar hızlı ki arada bir zaman gecikmesi vs. koymamışlar.Bu adamı gıcık ediyor.Bundan dolayı ben okuma işlemini usart interrupt ile yaptırıyorum ki gelen bilgiyi kaçırmıyım.Bunu yaparken de döngü ve ana program içinde uzun süreli bekleme komutları kullanmamaya dikkat ediyorum.Malum basic'in en muhim olayıda bu :P



Yukarıdaki gibi sensör sırası ile 8 byte geri dönüş yapıyor bunlardan 2. ve 3. byte ölçüm sonucu..

Gerisini kod ile anlatmak gerek...:

  Device=18F24K22
  Xtal=20
  All_Digital=TRUE
  TRISA=0
  PORTA=0
 
  TRISB=%10000000
  PORTB=0
 
 
 
  '*****************/ 16X20 LCD /***************
   
  Declare Hserial_Baud  = 9600 ' Set baud rate to 9600
  Declare Hserial_RCSTA = %10010000 ' Enable continuous receive
  Declare Hserial_TXSTA = 100000 ' Enable transmit and asynchronous mode       ' LCD İÇİN KULLANILACAK
  Declare Hserial_Clear  = On ' Clear the buffer before receiving

  Declare Hserial2_Baud  = 9600
  Declare Hserial2_RCSTA = %10010000 ' Enable continuous receive
  Declare Hserial2_TXSTA = 100000 ' Enable transmit and asynchronous mode      ' DIGER HABERLEŞME İÇİN KULLANILACAK
  Declare Hserial2_Clear = On ' Clear the buffer before receiving
 
  RCSTA1.4 = 1    'Continuous Receive Enabled
  RCSTA2.4 = 1    'Continuous Receive Enabled

  'Symbol PEIE2 = INTCON2.6        'Peripheral(çevresel) interrupt enable bit usart kesmesi için
  'Symbol GIE2  = INTCON2.7        'global interrupt enable

  Symbol RCIE2 = PIE3.5          'Receiver interrupt enable bit
  Symbol RCIF2 = PIR3.5          'Receiver interrupt flag


  Symbol PEIE = INTCON.6         'Peripheral(çevresel) interrupt enable bit usart kesmesi için
  Symbol GIE  = INTCON.7         'global interrupt enable
  Symbol RCIE = PIE1.5           'Receiver interrupt enable bit
  Symbol RCIF = PIR1.5           'Receiver interrupt flag

 ' PIR1.5 ve PIR3.5


  On_Interrupt GoTo KESME       'Hardware Interrupt oluştuğunda int etiketine dallan
 
 
 
  GIE=0
  PEIE=0
 
'********************************
 
  Symbol CO2_ANALOG_INPUT        = PORTA.0
  Symbol BUZZER                  = PORTA.3
  Low BUZZER
 
  Symbol LED                     = PORTA.2
  Output LED
 
  Low LED
 
'******************/ DEGISKEN TANIMLAMALARI /**********************

  Dim USART2_DATA[15] As Byte
 
  Dim NEXTION_BILGI               As Byte
  NEXTION_BILGI=0

  Dim A           As Word
  Dim CO2         As Word

  Dim SAYAC       As Byte
 
 
  Dim BYTE_0  As Byte
  Dim BYTE_1  As Byte
  Dim BYTE_4  As Byte
  Dim BYTE_5  As Byte
  Dim BYTE_6  As Byte 
  Dim BYTE_7  As Byte
 
  Dim CHECKSUM As Byte

  CHECKSUM=0
 
  BYTE_0=0
  BYTE_1=0
  BYTE_4=0
  BYTE_5=0
  BYTE_6=0
  BYTE_7=0

  USART2_DATA=0

  SAYAC=0
  CO2=0
  A=0

 

'*************************/ ANA PROGRAM /*****************************
 
 
  GoSub MELODI
 
  ACILIS_BEKLE:
 
  For A=0 To 3500
  DelayMS 5
  Next
 
  GoSub MELODI
 
  RCIE2=1
  PEIE=1
  GIE=1
 
  BASLA:

  For A=0 To 500
  DelayMS 5
 
 ' Gas concentration= high level *256+low level
 ' CO2 = USART_DATA[3]* 256 + USART_DATA[2]
 
  If SAYAC>8 Then GoSub MELODI : SAYAC=0 : GoSub BUFFER_BOSALT  : GoSub  CO2_GONDER : USART2_DATA=0
 
 
  If NEXTION_BILGI=$10 Then GoSub MELODI : GoSub CAL_ON   :  NEXTION_BILGI=0
  If NEXTION_BILGI=$20 Then GoSub MELODI : GoSub CAL_OFF  :  NEXTION_BILGI=0
 

 
  Next
   
 
  GoSub CO2_SENSOR_OKU 
 
  GoTo BASLA

  '*****************/ KESME /**********************

  KESME:
 
  Context Save
 
  GIE=0
  PEIE=0
 
  If RCIF=1  And  RCIF2 =1  Then NEXTION_BILGI=0 : USART2_DATA=0 : GoTo  EXIT
  If RCIF=1                 Then EKRAN_INTERUPT
  If RCIF2=1                Then SENSOR_INTERUPT


  GoTo EXIT


'*************/yenı/**************************

  EKRAN_INTERUPT:
  NEXTION_BILGI = RCREG1   : GoTo EXIT

  SENSOR_INTERUPT:
  USART2_DATA[SAYAC] = RCREG2 : SAYAC=SAYAC+1 : NEXTION_BILGI=0 : GoTo EXIT
 
'******************************************

  EXIT:
 
  GIE=1
  PEIE=1
  RCIF2=0
  RCIF=0             'General interrupt enable bit

  Context Restore

  End
 
 '**********************/ MELODI /******************************* 

  MELODI:
  High BUZZER
  DelayMS 38
  Low BUZZER
  DelayMS 80
  High BUZZER
  DelayMS 14
  Low BUZZER
  DelayMS 50
  Return 
 
 '*************

  CO2_SENSOR_OKU:
  DelayMS 10
 
  HSerOut2 [$FF,$01,$86,$00,$00,$00,$00,$00,$79]
  Return
 
  CAL_OFF:
  DelayMS 10
  HSerOut2 [$FF,$01,$79,$00,$00,$00,$00,$00,$86]
  Return
 
  CAL_ON:
  DelayMS 10
  HSerOut2 [$FF,$01,$79,$A0,$00,$00,$00,$00,$E6]
  Return
 
  SET_2000PPM:
  DelayMS 10
 
  HSerOut2 [$FF,$01,$99,$00,$00,$00,$07,$D0,$8F]
  Return
 
  SET_10000PPM:
  DelayMS 10
  HSerOut2 [$FF,$01,$99,$00,$00,$00,$27,$10,$2F]
  Return
 

 

  CO2_GONDER:
  HSerOut ["n0.val=",Dec5 CO2,$ff,$ff,$ff]    'BURADA KALDIK
  Return
 
  '*************************************
 
  BUFFER_BOSALT:
 
  BYTE_0 = USART2_DATA[0]
  BYTE_1 = USART2_DATA[1]

  CO2.HighByte = USART2_DATA[2]
  CO2.LowByte  = USART2_DATA[3]
 
  BYTE_4 = USART2_DATA[4]
  BYTE_5 = USART2_DATA[5]
  BYTE_6 = USART2_DATA[6]
  BYTE_7 = USART2_DATA[7]
  CHECKSUM=USART2_DATA[8]
 
  Return
 

Programın kısaca özeti şu:
Giriş kısmında  2 usartı olan 18F24K22 nin usart ayarları kesme ayarları tanımlamalar vs. 

  1. Sonrasında kesmeleri açıp ana programda for next ile uzun beklemeler ile gecikmeli olarak sensöre okuma komutu gönderip geri dönüp tekrar ana programda gelen datayı interrupt  sayacını kontrol ederek sırası ile gelen byteları alıp nextion ekrana serial den göndermek.


Program devamlı bu şekilde dönüyor..

Dediim gibi gelen datalardan 2. ve 3. byte okunan co2 miktarı.Bunu da programda bir byte tanımlayıp düşük ve yüksek byteleri alıp bu word'e yerleştiriyorum sonrada yallah ekrana gönderiyorum.

Sensörün kullanımı  buraya kadar kolay gibi duruyor.Fakat datasheette anlatılmayan durumlar var.

Sensör ilk açıldığında 8byte veri gönderiyor daha açıldığı gibi hemde ve hemen ardından bir süre 4 kez bana gelen ölçüm değerine baktığımda 410 bilgisini 4 defa okuyorum sensör kendini kuruyor yada kalibre ediyor sonrasında normal ölçüm degerini gönderiyor.

Benim kodumda ilk enerji verdiğimde döngüm takılıyor.Kesme kilitleniyor ekranda 5 haneli bir data görüyorum.Bunun önüne geçebilmek için açılışta gecikme koyanlarda var serialden 410 datasını 4 kez okuyanlarda var..

Ben sensörü transistör ile enerjisini kesmekten yanayım.Bilmiyorum başka bir fonksiyonuda yok gibi bu durum için.

En basit okuduğum çözüm ise sensörün beslemesini kart açıldıktan sonra vermek ve işlemcinin kendini programdaki interrupt ayarlarını kurmasına müsade etmek gibi görünüyor.



Bunun için buna benzer bir şema kullanabilirsiniz sorunsuz bir kullanım olacağına kanat getirdiğim yöntem budur..


Bu arada bu tarz şeyler ile çalışırken elinizin altında USB to Serial modül olmalı ve sağlam fonsksiyonları olan bir serial terminal programı ile çalışınız.Ben ilk sensörde değer alamadığım için serial porttan  dinliyim bakım dedim pic ten sensöre dönderdiğim 8 byte dizideki  0X86 datasını program 0X3F olarak gördüğünden 2 günüm boşuna gitti.

Sonra bir abimizin tavsiyesi ve uyarı ile başka bir serail terminal programı ile denemeler yaptığımda aslında benim gönderdiğim veride sorun olmadığını alıcı kısımda sorun olduğunu farkettim..

Beni yanıltan serial terminal programı oldu yani.

Sonradan daha kallavi bir program indirip kurdum.

Kullandığım serial port programı : 





Son olarak eklemek istediğim bir husus data var.Sensörün yanında gelen kablosunu ben çok ince olduğu için 0.25mm lik papuç basarak 3.8mm lik klemens ile karta bağladım.kendi soketi kutudan 1 adet çıktığı içi tercih etmedim.Piyasadan da nereden bulunur yedek olarak bilmiyorum.

Size son görselim mutlu son ile biten Co2 ölçümünden:



Sağlıcakla kalın...



EDİT: 01.01.2019 Yani yazıyı yazdıktan tam bir yıl sonra ( ertesi gün yani ) programda ufak bir güncelleme ile sensörün açılıştaki verilerini görmezden gelip açılıştaki takılma olayını giderdim.

Yaptığım işlem işlemciye enerji verdiğimizde kesmeleri kapalı tutup sensörün açılması kendini toparlaması için yaklaşık 15sn kadar bekledikten sonra kesmeleri açıp sensörle haberleşmek..Şuan gayet iyi çalışıyor.

NOT: sensörün açılışta bağlı olup olmadığını gözlemlemek için bekleme süresini biraz kısıp yukarıda bahsettiğim 410 datasını 4 defa okuduktan sonra sensörün bağlı olup olmadığını teyit edebilirsiniz...




1 yorum: