Merhabalar,
Projemizde PIC mikrodenetleyici kullanarak bir web sayfasını ENC28J60 aracılığıyla internet üzerinden yayınlayacağız. Yayınladığımız web sayfası üzerinden röle kontrolü yapabileceğiz. Nem, sıcaklık, LDR ve hava kalite sensörlerimizden okuduğumuz verileri bu sayfada yayınlayacağız. Yani bir otomasyon web sunucusu yapmış olacağız. Projemizde kullanılacak donanımlar şunlardır;
- PIC18F4520 Mikrodenetleyici,
- ENC28J60 Ethernet LAN Modülü,
- DHT22 Nem ve Sıcaklık Sensör Modülü,
- MQ-135 Hava Kalitesi Ölçüm Modülü,
- Röle Modülü,
- LDR,
- 16x2 LCD Ekran.
Bu donanımlardan 16x2 LCD ekranı zaten daha önceki birçok projemizde kullandık. Diğerlerinin özelliklerine kısaca değineceğiz.
PIC18F4520 mikrodenetleyicisi PIC18FXXX serisine ait 8 bit mikrodenetleyicidir. Pin yapısı daha önce birçok projemizde kullandığımız 40 bacağa sahip PIC16F877A ile aynıdır. PIC18FXXX serisinde yüksek performanslı RISC işlemci kullanılmaktadır. 32KB program hafızası ve 1536 byte veri hafızasına sahiptir. 13 tane ADC kanalı bulunmaktadır. Mikrochip web sayfasından detaylı bilgi edinebilirsiniz.

- PIC18F4520 Mikrodenetleyici,
- ENC28J60 Ethernet LAN Modülü,
- DHT22 Nem ve Sıcaklık Sensör Modülü,
- MQ-135 Hava Kalitesi Ölçüm Modülü,
- Röle Modülü,
- LDR,
- 16x2 LCD Ekran.
Bu donanımlardan 16x2 LCD ekranı zaten daha önceki birçok projemizde kullandık. Diğerlerinin özelliklerine kısaca değineceğiz.
PIC18F4520 mikrodenetleyicisi PIC18FXXX serisine ait 8 bit mikrodenetleyicidir. Pin yapısı daha önce birçok projemizde kullandığımız 40 bacağa sahip PIC16F877A ile aynıdır. PIC18FXXX serisinde yüksek performanslı RISC işlemci kullanılmaktadır. 32KB program hafızası ve 1536 byte veri hafızasına sahiptir. 13 tane ADC kanalı bulunmaktadır. Mikrochip web sayfasından detaylı bilgi edinebilirsiniz.

ENC28J60 ethernet LAN modülü, üzerinde ethernet girişi bulunan ve ethernet girişini SPI arayüzüne çeviren bir karttır. Üzerinde Microchip'in ENC28J60 entegresi bulunan bu modül SPI aracılığıyla birçok mikrodenetleyiciyle haberleşebilir. Bu modül ile pic mikrodenetleyicimizi internete bağlayabilecek ve internete bağlı bir cihazla mikrodenetleyicimize erişebileceğiz.

DHT22 Nem ve Sıcaklık Sensör Modülü, üzerinde AM2302 sensörü bulunan bir karttır. Bu modülü bir önce ki yayınladığımız projede detaylı bir şekilde incelemiştik. Detaylı bilgi için DHT22 İLE SICAKLIK VE NEM ÖLÇÜMÜ başlıklı yayınımızı inceleyebilirsiniz.
MQ-135 Hava Kalitesi Ölçüm Modülü, ev- iş yeri gibi kapalı alanların hava kalitesine etki eden zehirli gazları tespit etmeye yarayan karttır. Üzerinde bulunan SnO2 bileşiğinden yapılmış sensör ünitesi temiz havada düşük iletkenliğe sahiptir. Hava kirlenince sensör ünitesinin iletkenliği artar. Modülün analog çıkışında ki sinyal mikrodenetleyicinin ADC birimi ile okuyacağız. Elde edilen ADC değerine bazı matematiksel işlemlerden geçirerek hava kalitesini ppm olarak elde edeceğiz.
Röle Modülü, 5V ile kontakların kontrol edilebildiği 4 ayrı kanaldan oluşan röle kartıdır. Kartın üzerindeki röleler optokuplör ve transistör ile tetiklenmekdedir. Herhangi bir giriş pinine lojik '0' (0V) verildiğinde ilgili röle çeker, lojik 1 (5V) verildiğinde ise bırakır.
LDR (light dependent resistör) bir foto dirençdir. Foto dirençlerin değeri ışığa bağımlı olarak değişir. LDR, üzerine düşen ışık şiddeti artıkça direnç değeri azalır. Işık ile direç arasındaki ilişki lineer değil paraboliktir. LDR ile 10K' lık bir direnci birbirine seri bağlayıp voltaj bölücü yapacağız. Voltajın bölündüğü orta kısımdan mikrodenetleyicinin ADC birimi ile okuma yapacağız.
Mikrodenetleyici ile modüllerin bağlantısı aşağıda ki şemada yer almaktadır.
LDR (light dependent resistör) bir foto dirençdir. Foto dirençlerin değeri ışığa bağımlı olarak değişir. LDR, üzerine düşen ışık şiddeti artıkça direnç değeri azalır. Işık ile direç arasındaki ilişki lineer değil paraboliktir. LDR ile 10K' lık bir direnci birbirine seri bağlayıp voltaj bölücü yapacağız. Voltajın bölündüğü orta kısımdan mikrodenetleyicinin ADC birimi ile okuma yapacağız.
Mikrodenetleyici ile modüllerin bağlantısı aşağıda ki şemada yer almaktadır.
DHT22 modülü için microC PRo for PIC derleyicisinde kullanabileceğimiz bir kütüphane oluşturduk. Projemizin programında da bu kütüphaneyi kullanacağız. AM2302-DHT22 kütüphane dosyalarına buradan ulaşabilirsiniz. İndirdiğiniz .mpkg uzantılı dosya kütüphanemizdir. Kütüphaneyi mikroC PRO for PIC derleyicisine yükleyebilmeniz için Mikro Elektronika'nın Package Manager programına ihtiyacınız olacak. Package Manager programını buradan indirebilirsiniz. Programı kurduktan sonra .mpkg uzantılı kütüphane dosyasını açtığınızda aşağıdaki gibi bir arayüzle karşılaşacaksınız.
Install package butonuna tıklayarak yüklemeyi gerçekleştirebilirsiniz. Yükleme bittikten sonra microC PRo for PIC derleyicisinde library manager içerisinde AM2302-DHT22 kütüphanesine ulaşabilirsiniz. Artık bu kütüphaneyi DHT22 sensörü kullandığınız farklı projelerinizde kolayca kullanabilirsiniz.
Yazdığımız mikrodenetleyici programı aşağıdadır.
Çalışmamızın fotoğrafı aşağıdadır.
Projemizin çalışma videosu aşağıda yer almaktadır.
Yazdığımız mikrodenetleyici programı aşağıdadır.
#include "__EthEnc28j60.h"
// duplex config flags
#define Spi_Ethernet_HALFDUPLEX 0x00 // half duplex
#define Spi_Ethernet_FULLDUPLEX 0x01 // full duplex
// mE ehternet NIC pinout
sfr sbit SPI_Ethernet_Rst at RC0_bit;
sfr sbit SPI_Ethernet_CS at RC1_bit;
sfr sbit SPI_Ethernet_Rst_Direction at TRISC0_bit;
sfr sbit SPI_Ethernet_CS_Direction at TRISC1_bit;
// end ethernet NIC definitions
//************ LCD module connections ******************
sbit LCD_RS at RB5_bit;
sbit LCD_EN at RB4_bit;
sbit LCD_D4 at RB3_bit;
sbit LCD_D5 at RB2_bit;
sbit LCD_D6 at RB1_bit;
sbit LCD_D7 at RB0_bit;
sbit LCD_RS_Direction at TRISB5_bit;
sbit LCD_EN_Direction at TRISB4_bit;
sbit LCD_D4_Direction at TRISB3_bit;
sbit LCD_D5_Direction at TRISB2_bit;
sbit LCD_D6_Direction at TRISB1_bit;
sbit LCD_D7_Direction at TRISB0_bit;
//****************************************************
// AM2302 module connections
sbit AM2302_pin_in at RD0_bit;
sbit AM2302_pin_out at RD0_bit;
sbit AM2302_Pin_Direction at TRISD0_bit;
// END AM2302 module connections
/************************************************************
* ROM constant strings
*/
const unsigned char httpHeader[] = "HTTP/1.1 200 OK\nContent-type: " ; // HTTP header
const unsigned char httpMimeTypeHTML[] = "text/html\n\n" ; // HTML MIME type
const unsigned char httpMimeTypeScript[] = "text/plain\n\n" ; // TEXT MIME type
unsigned char httpMethod[] = "GET /";
/*
* web page, splited into 2 parts :
* when coming short of ROM, fragmented data is handled more efficiently by linker
*
* this HTML page calls the boards to get its status, and builds itself with javascript
*/
const char *indexPage = // Change the IP address of the page to be refreshed
"<meta http-equiv=\"refresh\" content=\"10;url=http://192.168.1.50\">\
<HTML><HEAD><title>mikrohex</title></HEAD><BODY>\
<h1>PIC18F4520 + ENC28J60 Web Server</h1>\
<a href=/>Reload</a>\
<script src=/s></script>\
<table><tr><td valign=top><table border=1 style=\"font-size:20px ;font-family: terminal ;\">\
<tr><th colspan=2>DHT22-MQ135-LDR</th></tr>\
<tr><td bgcolor=#00ffcc>SICAKLIK</td><td><script>document.write(SCT)</script>.<script>document.write(SCK)</script>°C</td></tr>\
<tr><td bgcolor=#00ffcc>NEM</td><td>%<script>document.write(NEMT)</script>.<script>document.write(NEMK)</script></td></tr>\
<tr><td bgcolor=#00ffcc>HAVA</td><td><script>document.write(AN2)</script> ppm</td></tr>\
<tr><td bgcolor=#00ffcc>IŞIK</td><td><script>document.write(AN1)</script></td></tr>\
" ;
const char *indexPage2 = "</table></td><td>\
<table border=1 style=\"font-size:20px ;font-family: terminal ;\">\
<tr><th colspan=3>PORTD</th></tr>\
<script>\
var str,i;\
str=\"\";\
for(i=0;i<4;i++)\
{str+=\"<tr><td bgcolor=yellow>RÖLE \"+i+\"</td>\";\
if(~PORTD&(1<<(i+4))){str+=\"<td bgcolor=red>ON\";}\
else {str+=\"<td bgcolor=#cccccc>OFF\";}\
str+=\"</td><td><a href=/t\"+i+\">AÇ/KAPAT</a></td></tr>\";}\
document.write(str) ;\
</script>\
</table></td></tr></table>\
This is HTTP request #<script>document.write(REQ)</script></BODY></HTML>\
" ;
/***********************************
* RAM variables
*/
unsigned char myMacAddr[6] = {0x00, 0x14, 0xA5, 0x76, 0x19, 0x3f} ; // my MAC address
unsigned char myIpAddr[4] = {192, 168, 1, 50} ; // my IP address
unsigned char getRequest[15] ; // HTTP request buffer
unsigned char dyna[30] ; // buffer for dynamic response
unsigned long httpCounter = 0 ; // counter of HTTP requests
const double Rl = 1000.0; // Rl (Ohm) - Load resistance
const double Vadc_5 = 0.0048828125; // ADC step 5V/1024 4,88mV (10bit ADC)
double Vrl; // Output voltage
double Rs; // Rs (Ohm) - Sensor resistance
double ppm; // ppm
double ratio; // Rs/Rl ratio
unsigned int adc_rd;
char txt[6];
bit izci;
void calculatePPM() {
double lgPPM;
Vrl = (float)adc_rd * Vadc_5; // For 5V Vcc use Vadc_5 and for 3V Vcc use Vadc_33
Rs = Rl * (5 - Vrl)/Vrl; // Calculate sensor resistance
ratio = Rs/Rl; // Calculate ratio
lgPPM = (log10(ratio) * -0.8)+ 0.9; // Calculate ppm
ppm = pow(10,lgPPM); // Calculate ppm
}
const char degree[] = {14,10,14,0,0,0,0,0};
void degreeChar(char pos_row, char pos_char) {
char i;
Lcd_Cmd(64);
for (i = 0; i<=7; i++) Lcd_Chr_CP(degree[i]);
Lcd_Cmd(_LCD_RETURN_HOME);
Lcd_Chr(pos_row, pos_char, 0);
}
#define putConstString SPI_Ethernet_putConstString
#define putString SPI_Ethernet_putString
/*
* this function is called by the library
* the user accesses to the HTTP request by successive calls to Spi_Ethernet_getByte()
* the user puts data in the transmit buffer by successive calls to Spi_Ethernet_putByte()
* the function must return the length in bytes of the HTTP reply, or 0 if nothing to transmit
*
* if you don't need to reply to HTTP requests,
* just define this function with a return(0) as single statement
*
*/
unsigned int SPI_Ethernet_UserTCP(unsigned char *remoteHost, unsigned int remotePort, unsigned int localPort, unsigned int reqLength, TEthPktFlags *flags)
{
unsigned int len = 0 ; // my reply length
unsigned int i ; // general purpose integer
// should we close tcp socket after response is sent?
// library closes tcp socket by default if canClose flag is not reset here
// flags->canClose = 0; // 0 - do not close socket
// otherwise - close socket
if(localPort != 80) // I listen only to web request on port 80
{
return(0) ;
}
// get 10 first bytes only of the request, the rest does not matter here
for(i = 0 ; i < 10 ; i++)
{
getRequest[i] = SPI_Ethernet_getByte() ;
}
getRequest[i] = 0 ;
//Lcd_Out(2, 1, getRequest);
if(memcmp(getRequest, httpMethod, 5)) // only GET method is supported here
{
return(0) ;
}
httpCounter++ ; // one more request done
if(getRequest[5] == 's') // if request path name starts with s, store dynamic data in transmit buffer
{
// the text string replied by this request can be interpreted as javascript statements
// by browsers
len = putConstString(httpHeader) ; // HTTP header
len += putConstString(httpMimeTypeScript) ; // with text MIME type
if (AM2302_Read() == 0){
if(get_temperature_sign())
IntToStr(get_temperature_whole()*(-1),dyna);
else
IntToStr(get_temperature_whole(),dyna);
len += putConstString("var SCT=") ;
len += putString(dyna) ;
len += putConstString(";") ;
WordToStr(get_temperature_fraction(),dyna);
len += putConstString("var SCK=") ;
len += putString(dyna) ;
len += putConstString(";") ;
WordToStr(get_humidity_whole(), dyna) ;
len += putConstString("var NEMT=") ;
len += putString(dyna) ;
len += putConstString(";") ;
WordToStr(get_humidity_fraction(), dyna) ;
len += putConstString("var NEMK=") ;
len += putString(dyna) ;
len += putConstString(";") ;
}
adc_rd=ADC_Read(2);
calculatePPM();
FloatToStr(ppm, txt) ;
strncpy(dyna,txt,6);
// add AN2 value to reply
//IntToStr(ADC_Read(2), dyna) ;
len += putConstString("var AN2=") ;
len += putString(dyna) ;
len += putConstString(";") ;
// add AN1 value to reply
len += putConstString("var AN1=") ;
adc_rd=ADC_Read(1);
if(adc_rd>=450)
len += putConstString("\"AYDINLIK\"") ;
else len += putConstString("\"KARANLIK\"") ;
len += putConstString(";") ;
if(izci){
LCD_Cmd(_LCD_CLEAR);
ByteToStr(get_temperature_whole(), txt);
Lcd_Out(1,1,"SICAKLK:");
Lcd_Out(1,9,txt);
if(get_temperature_sign()) Lcd_Out(1,9,"-");
Lcd_Out(1,12,".");
Lcd_Chr(1,13,get_temperature_fraction()+48);
degreeChar(1, 14);
Lcd_Out(1,15,"C");
ByteToStr(get_humidity_whole(), txt);
Lcd_Out(2,1,"NEM :");
Lcd_Out(2,9,txt);
Lcd_Out(2,12,".");
Lcd_Chr(2,13,get_humidity_fraction()+48);
Lcd_Out(2,14,"%RH");
}
else{
LCD_Cmd(_LCD_CLEAR);
Lcd_Out(1,1,"HAVA:");
Lcd_Out(1,7,dyna);
Lcd_Out(1,13," ppm");
if(adc_rd>=450)
Lcd_Out(2,1,"ORTAM AYDINLIK");
else
Lcd_Out(2,1,"ORTAM KARANLIK");
}
izci=~izci;
// add PORTD value (LEDs) to reply
len += putConstString("var PORTD=") ;
IntToStr(PORTD, dyna) ;
len += putString(dyna) ;
len += putConstString(";") ;
// add HTTP requests counter to reply
IntToStr(httpCounter, dyna) ;
len += putConstString("var REQ=") ;
len += putString(dyna) ;
len += putConstString(";") ;
}
else if(getRequest[5] == 't') // if request path name starts with t, toggle PORTD (LED) bit number that comes after
{
unsigned char bitMask = 0 ; // for bit mask
if(isdigit(getRequest[6])) // if 0 <= bit number <= 9, bits 8 & 9 does not exist but does not matter
{
bitMask = getRequest[6] - '0' ; // convert ASCII to integer
bitMask = 1 << (bitMask + 4) ; // create bit mask
PORTD ^=bitMask; // toggle PORTD with xor operator
}
}
if(len == 0) // what do to by default
{
len = putConstString(httpHeader) ; // HTTP header
len += putConstString(httpMimeTypeHTML) ; // with HTML MIME type
len += putConstString(indexPage) ; // HTML page first part
len += putConstString(indexPage2) ; // HTML page second part
}
return(len) ; // return to the library with the number of bytes to transmit
}
/*
* this function is called by the library
* the user accesses to the UDP request by successive calls to Spi_Ethernet_getByte()
* the user puts data in the transmit buffer by successive calls to Spi_Ethernet_putByte()
* the function must return the length in bytes of the UDP reply, or 0 if nothing to transmit
*
* if you don't need to reply to UDP requests,
* just define this function with a return(0) as single statement
*
*/
unsigned int SPI_Ethernet_UserUDP(unsigned char *remoteHost, unsigned int remotePort, unsigned int destPort, unsigned int reqLength, TEthPktFlags *flags)
{
unsigned int len ; // my reply length
// reply is made of the remote host IP address in human readable format
ByteToStr(remoteHost[0], dyna) ; // first IP address byte
dyna[3] = '.' ;
ByteToStr(remoteHost[1], dyna + 4) ; // second
dyna[7] = '.' ;
ByteToStr(remoteHost[2], dyna + 8) ; // third
dyna[11] = '.' ;
ByteToStr(remoteHost[3], dyna + 12) ; // fourth
dyna[15] = ':' ; // add separator
// then remote host port number
WordToStr(remotePort, dyna + 16) ;
dyna[21] = '[' ;
WordToStr(destPort, dyna + 22) ;
dyna[27] = ']' ;
dyna[28] = 0 ;
// the total length of the request is the length of the dynamic string plus the text of the request
len = 28 + reqLength;
// puts the dynamic string into the transmit buffer
SPI_Ethernet_putBytes(dyna, 28) ;
// then puts the request string converted into upper char into the transmit buffer
while(reqLength--)
{
SPI_Ethernet_putByte(toupper(SPI_Ethernet_getByte())) ;
}
return(len) ; // back to the library with the length of the UDP reply
}
void main() {
ADCON0 = 0x09;
ADCON1 |= 0x0C; // no analog inputs
ADFM_bit=1;
CMCON |= 0x07 ; // turn off comparators
PORTD = 0xFF;
TRISD = 0 ; // set PORTD as output
PORTA = 0 ;
TRISA = 0xff ; // set PORTA as input for ADC
PORTB = 0 ;
izci=1;
Lcd_Init(); // initialize Lcd.
Lcd_Cmd(_LCD_CLEAR); // clear Lcd.
Lcd_Cmd(_LCD_CURSOR_OFF); // turn off cursor.
Lcd_Out(1, 1, " MIKROHEX ");
Lcd_Out(2, 1, " WEB SERVER ");
SPI1_Init();
SPI_Ethernet_Init(myMacAddr, myIpAddr, Spi_Ethernet_FULLDUPLEX) ;
while(1) {
SPI_Ethernet_doPacket() ;
}
}
Programda kullanılan fonksiyonlar hakkında bilgi edinmek için MikroC PRO for PIC derleyicisinin Library Manager bölümünü inceleyebilirsiniz. Devremizi yukarıdaki şemada olduğu gibi kurduktan ve programı PIC mikrodenetleyiciye yükledikten sonra ENC28J60 modülümüzü ethernet kablosuyla modemimize bağlamamız gerekmektedir. Tüm bağlantıları yapıp devremizi besledikten sonra web tarayıcımızda 192.168.1.50 IP adresine giderek web server sayfamıza ulaşmış olacağız. Karşılaşacağımız sayfa aşağıdaki gibi olacaktır.Çalışmamızın fotoğrafı aşağıdadır.
Projemizin çalışma videosu aşağıda yer almaktadır.
Proje hakkında sormak istediklerinizi sayfanın altında yorum kutusuna yazabilirsiniz. Bir başka yazıda görüşmek üzere...
Başarılar...
Başarılar...
Harika bir yazı olmuş .Eline sağlık
YanıtlaSilTeşekkür ederim. Sağolun.
YanıtlaSilEser Bey çok güzel ve eğitici olmuş. Emeğinize sağlık...
YanıtlaSilYalnız bir ricam var... MicroC yi yeni öğreniyorum sizinle. Ben genellikle PicBasic kullanıyorum. Biraz zorlanacağım.
Aynı projede sadece ilgisayarımdaki saat bilgisini pic'e nasıl gönderebilirim... 6 digit seven segment display kullanacağım...
Yardımcı olursanız sevinirim...
Saygılarımla...
hocam wep server arayüzünü nasıl tasarladınız acaba bilgi verirmisiniz
YanıtlaSil