ESP8266 ile SPI Flash Dosya Sistemi, Multi-Tasking ve TCP Server Kullanımı

Merhaba arkadaşlar ben Murat. Bir önceki yazımızda ESP8266 serisi için programlama ortamının kurulumunu anlatmıştım. Bu yazıya bu linkten erişilebilir. Şimdi ise ESP8266 üzerinden ismini ve şifresini bildiğimiz bir ağa bağlanalım. Bu arada unutulmaması gereken 2 noktadan birisi ise  ESP8266 bir ağa bağlanır iken aynı anda kendi Wi-Fi ağını da kurabilir ve aynı anda da bu kanallardan gelen veriyi handle edebilir. Burda Wi-Fi ağına bağlanabilmek adına iki tane farklı kullanım sunulucaktır.

Başlangıç seviyede ESP kullananlar için ESP8266 Arduino fonksiyonları ile Wi-Fi ağına bağlanma

Burda ESP8266 için Arduino çekirdeği gönüllü kullanıcılar ve Espressif firması tarafından geliştirilmektedir. Aşağıdaki örnek kodlar ESP modüle yüklendiğinde Wi-Fi ağına bağlanıldığı görülür.

#include <ESP8266WiFi.h>
// wifi ağ ayarları
const char* ssid     = "Airties";
const char* password = "elinux44343";

void setup() {
  Serial.begin(115200);
  delay(10);

  // We start by connecting to a WiFi network
  Serial.println();
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);
  
  WiFi.begin(ssid, password);
  
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("WiFi connected");  
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}

void loop() {
  
}

Bu kodlar ESP8266’ya kendi Wi-Fi parametrelerinizi girmek koşulu ile derlenip, yüklenildiğinde ESP modül belirtilen Wi-Fi ağı ile handshake yapıp, IP adresi alacaktır. Bu aşağıdaki resimde görülebilir. Lakin burda ESP’nin hazır Arduino sınıfları kullanıldığı için hem arka planda ne döndüğünü göremiyoruz hemde bu fonksiyon gereksiz 50 tane fonksiyon çağrısı yaptığı için bağlantı kurulma süresi çok uzundur. Bu yüzden profesyonel kullanıcılar için Espressif sınıfları ile Wi-Fi yapılandırılması anlatılıcaktır.

Profesyonel seviyede ESP kullananlar için ESP8266 Arduino fonksiyonları ile Wi-Fi ağına bağlanma

Burda da sadece ESP Arduino fonksiyonları aradan çıkartılıcaktır. Espressifin API’si kullanılıcaktır. Öncelikle Espressifin kütüphaneleri koda dahil edilir.

//Extract Espressif methods 
extern "C" {
#include "user_interface.h"
#include "espconn.h"
}

Ardından aşağıdaki yapı ile WiFi.Begin() fonksiyonu yer değiştirilir.

struct station_config stationConf;
stationConf.bssid_set = 0;
memcpy(&stationConf.ssid, ssid, 32);
memcpy(&stationConf.password, password, 64);
wifi_station_set_config(&stationConf);
wifi_station_connect();

wifi_station_connect(); ile birlikte ESP hedef ağa bağlanır , burda çok fazla fonksiyon çağrısı olmadığı ve native kütüphaneler kullanıldığı için ESP’ye güç verildiği an çok hızlı bir şekilde Wi-Fi ağına bağlanmaktadır. Benim ölçümüme göre arada 8 kat fark var. Programın çıktısı aşağıdaki gibi olur.

 

ESP8266 için SPI Flash Dosya Sistemi kullanımı

ESP8266 kendi içinde 4Mb veya 16MB’lık bir SPI flash modüle sahiptir. Bu SPI flashın genelde 3Mb’lık kısmı program dosyaları için 1 Mb’lık kısmıda dosya sistemi olarak kullanılır. Tabiki bunun tam terside mevcuttur.  1Mb program dosyası, 3Mb flash şeklindede olabilmektedir. Bu sayede eğer ESP8266 içine bir web sayfası kurulmak istenir ise bu belirtilen alana Web sayfasının dosyaları yerleştirilebilir. Bu alanın 3Mb olduğuna bakmayın eğer sağlam bir algoritmanız var ise bu 3MB içine 100 MB’lık dosyayı bile sıkıştırıp koyabilirsiniz. Örnek olarak derlenmiş Linux Kerneli’nin 30GB olmasına ragmen kernelin 6-7Mb’a sığdırıldığı gibi. İşin garip yanı Linux kerneli, initialRamdisk,U-boot,dtb dosyaları 16Mb’lık Bir SPI Flasha tam fittir. Bu sayede bazı gömülü linux sistemler SPI Flash üzerinden açılabilir. Neyse fazla bilgi göz çıkarmaz. İşimize bakar ise biz bu alana istediğimiz veriyi yazabiliriz. Ben buraya kendi Wi-Fi ağ parametrelerimi kaydetmek istersem bu linkte belirtilen SPIFFS kütüphanesini kullanıcağım. Bu kütüphane Arduino ESP çekirdeği ile birlikte gelir. Aşağıdaki kodlar ESP’ye SPI dosya sistemini kullanabilme özelliği kazandırmaktadır.

Kodlar gayet anlaşılırdır. Öncelikle sistem parameters.txt dosyasını SPI Flash üzerinde arar yoksa yeniden oluşturur ve write-only olarak içini doldurur. Bir sonraki resette ise bu dosya read-only olarak açılır  ve okuma işlemi gerçekleştirilir. Bu dosya sisteminin içine JSON bazlı dosyada yüklenebilir ve kod yazım süreçini olduğu gibi azaltabilir.

#include <ESP8266WiFi.h>
#include "FS.h"

void setup() {

	Serial.begin(9600);
	Serial.println();
	int result = SPIFFS.begin();
	Serial.println("SPIFFS opened with code: " + result);

	File f = SPIFFS.open("/parameters.txt", "r");

	if (!f) {
		Serial.println("File doesn't exist yet. Creating it");

		// open the file in write mode
		File f = SPIFFS.open("/parameters.txt", "w");
		if (!f) {
			Serial.println("file creation failed");
		}
		// now write two lines in key/value style with  end-of-line characters
		f.println("ssid=abc");
		f.println("password=123455secret");
		f.println("istedigim herseyi buraya yazabilirim, istersede json bile olur");
	}
	else {
		// we could open the file
		while (f.available()) {
			//Lets read line by line from the file
			String line = f.readStringUntil('n');
			Serial.println(line);
		}
	}
	f.close(); 
}

void loop()
{

}

Programın çıktısı aşağıdaki gibi olucaktır.

ESP8266 için TCP server kurulumu

ESP8266 ya bağlı bir elektronik devremiz var ve uzaktan kontrol etmek istiyor isek TCP/IP veya UDP/IP gibi haberleşme protokollerini kullanmamız gerekmektedir. Bu sayede ESP8266’ya uzaktan bağlantıve veri haberleşmesi söz konusu olabilecektir. Unutmadan söylemem gerekir ki ESP8266 160Mhz’de çalışabilir. Mükemmel değilmi?. Bu örnek uygulama için öncelikle ESP8266 bir Wi-Fi ağa bağlatılır, DHCP üzerinden bir IP adresi aldırılır ve TCP server kurulur.

Aşağıdaki örnek kodlar ESP8266 üzerinde TCP server kuracaktır.

#include <ESP8266WiFi.h>

//Extract Espressif methods
extern "C" {
#include "user_interface.h"
#include "espconn.h" 
}

esp_tcp serverTcp;   //tcp client olusturmak icin
espconn serverConn;  //yuva olusturmak icin
#define port 8888    //TCP serverin port numarası

//wifi ağ ayarları
const char* ssid = "Airties";
const char* password = "elinux44343";

//eğer birisi tcp servere bağlanır ise callback
static void connectCB(void *arg) {
	Serial.println("Someone Connected");
}

//eğer birisi tcp üzerinden veri yollar ise callback
static void receivedCB(void *arg, char *data, unsigned short length)
{
	//gelen veriyi byte byte seriale yaz
	for (int i = 0; i <= length; i++)
		Serial.print(data[i]);

        //gelen veriyi bir kontrol et, eğer LED1 ise istenenleri yap.
	int rc = strcmp(data, "LED1");
	if (rc == 0) {
		Serial.print("LED 1 ACILACAK");
		digitalWrite(D1, HIGH);
		String response = "ok";
		sint8 errCode = espconn_send(&serverConn, (uint8*)response.c_str(), response.length());

		if (errCode != 0) {
			Serial.print("TCP RESPONSE GONDERILEMEDI");
		}
		else 
		{
			Serial.print("TCP RESPONSE GONDERILDI");
		}
	}
}

void setup() {

	Serial.begin(9600);
	delayMicroseconds(500);
	Serial.println();

        //wifi ağına bağlan
	struct station_config stationConf; 
	stationConf.bssid_set = 0; 
	memcpy(&stationConf.ssid, ssid, 32);
	memcpy(&stationConf.password, password, 64);
	wifi_station_set_config(&stationConf);
	wifi_station_connect();

        //D1 pinini ayarla
	pinMode(D1, OUTPUT);
	digitalWrite(D1, LOW);


	serverConn.type = ESPCONN_TCP;     //server TCP bazlı olacak
	serverConn.state = ESPCONN_NONE;
	serverConn.proto.tcp = &serverTcp; //tcp clienti sec
	serverConn.proto.tcp->local_port = port;  //portu ayarla
       
        //callback fonksiyonlarını ayarla
	espconn_regist_connectcb(&serverConn, connectCB);
	espconn_regist_recvcb(&serverConn, receivedCB);

	while (WiFi.status() != WL_CONNECTED) {
		delay(500); Serial.print(".");
	} 

	Serial.println(""); 
	Serial.println("WiFi connected");
	Serial.println("IP address: "); 
	Serial.println(WiFi.localIP());

	Serial.println("WIFI: TCP SERVER CREATING");

        //TCP serveri olustur.
	sint8 ret = espconn_accept(&serverConn);
	if (ret == 0)
		Serial.println("WIFI: TCP SERVER STARTED");
	else
		Serial.println("FATAL ERROR: TCP SERVER FAILED");

	return;

}

void loop()
{

}

Aşağıda ise Putty Telnet clienti ile ESP8266’nın haberleşmesi görülebilir. LED1 komutunu TCP üzerinden alan ESP8266 , D1 nolu pini yakar ve de karşıya bir adet response mesaj gönderir. Bu sayede remote I/O işlemlerini gerçekleştirebilirsiniz. Burda JSON haberleşme veya bit parçalama da kullanılabilir. Bu sayede birden fazla pin aynı anda kontrol edilebilir.

 

ESP8266 için Multi Tasking

ESP8266 kendi içinde bir operating system barındırmakta ve bu işletim sistemine sistem çağrıları atarak CPU frekansını, Wi-Fi gücünü, Os Memset, Os timer veya os thread gibi yapıları kullanabiliyoruz. Lakin infinite yani sonsuz looplara ESP tarafından izin verilmemektedir. Bu yüzden Threadler for(;;) döngüsüne sahip değillerdir.Bu threadler işi bittikten sonra kendini sonlandırırlar. Bu threadleri kendimiz schedule etmemiz gerekmekte. Bunuda örnek olarak 500ms de bir threadi ayağa kaldıran bir timer ile çözebilmekteyiz. Aşağıdaki örnek kodlar ile bir multi threading örneği verilmiştir. Sonsuz döngü olan loop() fonksiyonu içine bir adet 10 saniyelik blocking delay konulmuştur. Bir tane işletim sistemi timeri , for döngüsü olmadığı için işini bitirdikten sonra sonlanan threading idsini, işletim sistemine tekrardan bildirerek threadi ayağa kaldırmaktadır. Bu timer 500ms’de bir thread tarafından tekrardan tetiklenmektedir. Bu süre 1ms bile olabilir. Bu sayede işletim sisteminin kaldırabileceği kadar thread oluşturabilir, bu threadler de mutex, semaphore ve message queue oluşturabilir, TCP/IP bağlantısı kurabilir veya sensörleri okuyabilirsiniz. Kurulan bir web sunucuyu veya MQTT Clienti birer threade aktarıp sürekli onları kontrol ederek ana döngüyü boşaltabilirsiniz.

“commonHeaders.h”

//Setup for porting Arduino classes.
#if defined(ARDUINO) && ARDUINO >= 100
#include "arduino.h"
#else
#include "WProgram.h"
#endif

“main.ino”

#include "commonHeaders.h"
#define MY_TASK_PRIORITY 0
#define MY_QUEUE_SIZE    1

static os_event_t my_queue[MY_QUEUE_SIZE];
volatile uint32_t value = 0;
static os_timer_t task_start_timer;

//os_timer timeout callback
void run_task(void*) {
	system_os_post(MY_TASK_PRIORITY, 0, 0);
}

//thread entry point
void my_task(os_event_t *) {
	// start the task again in 500  msec
	 Serial.println("Worker Thread Running");
	 os_timer_arm(&task_start_timer, 500 /*ms*/, 0 /*once*/);
}

void setup() {
	
	Serial.begin(9600);

        //thread olusturma
	system_os_task(my_task,
		MY_TASK_PRIORITY, my_queue,
		MY_QUEUE_SIZE);

	//timer olusturma
	os_timer_setfn(&task_start_timer, (os_timer_func_t*)&run_task, 0);

	//taski baslatma
	run_task(0);
}

// the loop function runs over and over again until power down or reset
void loop() {
	delay(10000);
}




Son

Bu arada belirtmem gerekirki tüm ESP8266’lar aynı anda hem kendi ağını kurabilir hemde farklı bir kablosuz ağa bağlanabilir. Eğer farklı bir kablosuz ağa bağlanıldı ise Station modu, kendi ağını kurdu iseniz AP modu, iki modda da aynı çalışır iseniz BOTH(STA+AP) modundasınız demektir.Aşağıdaki kod ESP8266’ya kendi kablosuz ağını kurduracak ve de içine bir web sunucu yerleştirecektir. Biz kendi bilgisayarımız veya telefonumuzdan bu ağa eriştiğimizde hemen tarayıcıyı açıp 192.168.4.1 (ESP’nin kendi DHCP adresi) tıkladığımızda bize bir karşılama mesajı gelicektir. Burda karşılama yerinde ESP8266’nın pinlerini kontrol edecek veya anlık durumlarını çekebilecek butonlarla ve kutucuklarla dolu bir web sayfasıda olabilirdi.

#include <ESP8266WiFi.h>
#include <WiFiClient.h> 
#include <ESP8266WebServer.h>

/* Set these to your desired credentials. */
const char *ssid = "ESP866-YAYIN";
const char *password = "1234567890*";

ESP8266WebServer server(80);
/* Just a little test message.  Go to http://192.168.4.1 in a web browser
* connected to this access point to see it.
*/
void handleRoot() {
	server.send(200, "text/html", "<h1>ESPNIN WIFI AGINA BAGLANDINIZ.</h1>");
}

void setup() {
	delay(1000);
	Serial.begin(115200);
	Serial.println();
	Serial.print("Configuring access point...");
	/* You can remove the password parameter if you want the AP to be open. */
	WiFi.softAP(ssid, password);

	IPAddress myIP = WiFi.softAPIP();
	Serial.print("AP IP address: ");
	Serial.println(myIP);
	server.on("/", handleRoot);
	server.begin();
	Serial.println("HTTP server started");
}

void loop() {
	server.handleClient();
}

ESP8266’nın kablosuz ağına bağlanılır.

 

Bağlanıldıktan sonra ise tarayıcı açılarak ESP’nin IP adresi girilir ve karşımıza ESP8266 response mesaj gelir.

 

 

Bu sayede elektronik projeler internete çıkabilir ve Endüstri 4.0 bu tarz modüllerle insanlığın hayatını kolaylaştırabilir. Unutmayın ESP8266’nın burda bağlandığı yer bir Akıllı Telefonda olabilirdi ve öyle bir program yazardınız ki istenmeyen durumlarda size notification atabilirdi. Aşağıdaki video daha açıklayıcı olabilir.

Bir yazının daha sonuna geldik kendinize iyi bakın.

 

 

 

3 thoughts on “ESP8266 ile SPI Flash Dosya Sistemi, Multi-Tasking ve TCP Server Kullanımı

  • Nisan 12, 2018 tarihinde, saat 1:48 pm
    Permalink

    Detaylı açıklama için çok teşekkürler; bir cihazdan PC ye serial porttan kablo ile tek yönlü olarak gönderilen data yı ,
    ESP 8266 ile kablosuz wifi olarak ayrıca daha fazla PC tablet,vb. İletilmesini nasıl yapabilirim ?
    Alıcı cihazların kullandığı program UDP veya TCP olarak bağlanabiliyor
    Fakat belirttiğim gibi esp8266 sadece data sinyalini tx yapacak
    Bu konuda yardımcı olabilirseniz çok makbule geçer.

    Yanıtla
  • Mayıs 11, 2021 tarihinde, saat 1:53 am
    Permalink

    Gerçekten çok güzel bir yazı tam da cevabını aradığım soruları yanıtlamışsınız. Teşekkürler.

    Yanıtla
  • Eylül 9, 2022 tarihinde, saat 9:06 am
    Permalink

    İhtiyacı karşılayan bir paylaşım olmuş teşekkürler. Çalışmalarında başarılar

    Yanıtla

Bir cevap yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir