STM32 HAL Kütüphaneleri ile Nextion Ekran Kullanımı

Merhaba,

Bu konuda STM32 ile HAL kütüphaneleri kullanarak Nextion ekran kullanımına değineceğiz. Bu konunun benzerini Mbed kullanılarak nasıl yapılabileceğini göstermiştik. Ancak HAL kütüpahaneleri kullanarak yapımı üzerine de soru sorulduğu ve arada bazı farklılıklar olduğu için bunun ile alakalı da bir konu hazırlamak istedim. Karşılaştırmanın kolay olması açısından benzer özelliklerden bahsetmeye çalışacağım.

Yapacağımız uygulamada STM32F103 ve 3.5 Nextion cihazı kullanacağım. Uygulama içerisinde sayfa geçişleri, butonlar, yazılar ve slider gibi konular olacaktır. Konunun uzun olmaması için Nextion’ un veri sırası yada instrcution set gibi temel şeylere burada değinmeyeceğim. Bunlar için bağlantıdaki konulara bakabilirsiniz. Sadece yeri geldikçe kullandığımız widget’ lerin komutlarına anlatmaya çalışacağım.

Şimdi öncelikle yapmak istediğimiz uygulamadan bahsedelim. Uygulamada bir potansiyometre ve 3 adet LED kullanacağız. 2 adet LED’ i ekran üzerinden açıp kapatma yaparken, diğer LED’ in parlaklığını ekran üzerindeki bir slider kullanarak değiştireceğiz. Potansiyometre verisini belirli zaman aralıklarında ekrana göndereceğiz. Yapmak istediğimiz uygulamaya göre bağlantı şemamız şu şekilde olacaktır.

Bağlantı şemasında iki ayrı güç hattı kullanıldığına dikkat edilmelidir. Nextion 5V ile çalışırken STM32 ADC’ si en fazla 3.3V ile çalışabilmektedir. Bu sebeple potansiyometreye 3.3V, Nextion’ a 5V bağlanmıştır. Nextion’ un RX ve TX pinleri STM32 üzerinde UART1 pinlerine bağlanmıştır. Ayrıca soldaki mavi renkteki LED PWM çıkışı alabilmek için Timer3 pinine bağlanmıştır. Böylece parlaklığını Nextion üzerinden değiştirebilmek mümkün olacaktır. Diğer LED’ ler ise tamamen keyfi olarak iki adet dijital pine bağlanmıştır.

Bağlantı şemasını belirledikten sonra CubeIde üzerinde gerekli ayarları yapalım. İlk olarak kristal ayarlarından başlayalım. F103 kartı üzerinden 8Mhz krsital osilatör mevcut. Onu aktif ediyoruz.

Daha sonrasında ADC’ yi aktif edelim. ADC1′ in 1. kananalını potansiyometre gerilimini okumak için kullanacağız. Yapacağımız örneklemenin çok hızlı olmasına gerek yok. Bu sebeple keyfi olarak bir örnekleme değeri seçebiliriz. Ben 71.5 cycle seçmek istedim. Parametre kısmındaki diğer ayarları değişmemize gerek yok. ANcak NVIC ayarları kısmında ADC kesmesini aktif etmeliyiz. Bu önemli bir nokta. Normalde ADC işlemi ana yazılımı bloklayıcı bir işlemdir. Yani ADC işlemi sırasında işlemci farklı bir işlem yapmaz, dönüşümün tamamlanmasını bekler. Bu durum dönüşüm sırasında ekrandan gelen komutların alınamamasına sebep olabilir. Elbette UART kesmesi kullanarak da ADC dönüşüm işleminin bitmesi beklenmeden verinin alınması sağlanabilir. Ancak ADC kesmesi kullanma gibi bir opsiyonumuz var ve onu da kullanmanın zararı olmayacaktır. Bu sebeple ADC kesmesini de aktif edelim.

Şimdi sıra UART’ a geldi. UART için yapmamız gereken çok fazla ayar yok. UART1′ i aktif ettikten sonra baud rate’ i kontrol etmelisiniz. Kullandığınız Nextion cihazın baud rate’ i ile buradaki baud rate aynı olmalıdır. Buna ek olarak bir de NVIC ayarlarından UART kesmesini aktif etmeliyiz. UART kesmesini neden aktif etmemiz gerektiğinden az önce bahsetmiştim.

CubeMx ayarları bittikten sonra sıra geldi Nextion tasarımına bakalım. Daha önceki konuda kullandığım tasarımın aynısını kullanacağım. Ancak slider widget’ inin kullanımı bu sefer farklı yapacağım. Önceki konuda slider’ ın Nexiton’ dan “get” komutu ile istemiştik. Bu sefer slider’ ın dokunma eventini kullanarak gerçekleştireceğiz. Nextion’ da herhangi bir widget’ a tıkladığımızda sağ alttaki event kısmı aşağıdaki şekilde görünür. Genelde event’ lerin bir tanesi widget’ e basma (Press), diğeri ise widget’ den elimizi kaldırma (Release) eventidir. Eğer kullandığınız widget slider ise bir de “Move” eventi ekleniyor. Hangisini kullanmak istediğiniz sizin isteğinize kalmış. Bana daha kullanışlı geldiği için Release event’ ini tercih ediyorum. Move eventi kullanırsak, slider her hareketinde tetikleneceği için UART çok fazla meşgul edecektir. Bunun yerine Release kullanılırsa elinizi slider’ dan çektiğinizde tetiklenecektir.

Yukarıdaki resimde de görüldüğü üzere Release eventine bazı komutlar yazılmış. Bu komutların kullanımına detaylı bir şekilde Nextion instruction set’ e bakabilirsiniz. Ben yüzeysel olarak bahsedeceğim. Bu komutları kullanarak Slider hareketini tamamlayınca STM32′ ye veri gönderebiliriz.

printh komutu sonrasında hex veriyi gönderir. Hex veri gruplar halinde sıra ile gönderilir. 0 ile FF arasında veriler gönderilebilir.

prints komutu iki parametre alır. İlki gönderilemek istenen değerdir. İkincisi ise gönderilmek istenilen değerin uzunluğudur.

Instruction set’ e de bakarsanız bu komutların kullanımları resimde verilen şekildedir. Yani bir widget’ in değeri gönderilecekse prints kullanılmış, keyfi hex değer gönderilecekse printh kullanılmıştır. Bu sebeple sizin de bu şekilde kullanmanızı tavsiye ederim. Veri formatını Nextion’ un diğer widget eventlerine benzemesi için bu şekilde seçtim. Bu tamamen keyfidir. Siz isterseniz değişebilirsiniz. “h0” slider’ ının değeri 0 ile 100 arsaında değişecek şekilde ayarlanmıştır. Bu sebeple slider’ ın değerini UART üzerinden göndermek için 1 byte yeterli olacaktır.

Gerekli ayarlamaları yaptıkran sonra şimdi yazılıma bakalım. Aslında yazılım mantığımız öncekiler ile aynı olacak. Sadece platform değiştiği için farklı ifadeler kullanacağız. UART’ dan veri geldiği zaman, gelen veriyi UART interrupt fonksiyonu içerisinde bir diziye kayıt edeceğiz. Gelen verinin içerisinde ID’ ye bakarak hangi araçtan geldiğini anlayıp STM32 içerisinde işlem gerçekleştireceğiz. Kesme fonksiyonu içerisine bakarak başlayalım. Az önce de söylediğimi gibi kesme fonksiyonu içerisinde UART’ dan gelen veriyi sıra ile bir diziye atıyoruz. Aynı zamanda gelen veriler içerisimde 0xFF sayısını sayısıyoruz. Çünkü Nextion’ dan gelen bütün komutlar 3 adet 0xFF ile bitecek şekilde ayarlanmış. Biz kendi oluşturduğumuz komutları da aynı şekilde bitecek şekilde ayarladık. Böylece paketin tamamının geldiğini anlayabiliriz.

//UART Rx data receieve callback function
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	if(huart == &huart1)
	{
		//add received data to buffer
		recArr[cnt++] = recData;

		// count received 0xFF
		if(recData == 0xFF)
		{
			endPackCnt++;
		}else{
			endPackCnt = 0;
		}

		// if 0xFF count reach 3, make packet flag true
		if(endPackCnt == 3)
		{
			packReady = 1;
			endPackCnt = 0;
		}


		HAL_UART_Receive_IT(&huart1, (uint8_t *)&recData, 1);
	}
}

 

Yazılımda da görüldüğü üzere 0xFF geldikçe saçay değişkenin sayısını birer birer arttırdık. 3 olduğu zaman paketin sonu geldi diyerek paket alındı değişkenini 1 yaptık. Arka arkaya 0xFF geldiğini garanti etmek için gelen veri 0xFF değilse sayacı tekrar 0 yaptık. En sonda da fonksiyondan çıkmadan tekrar 1 adet veri gelince interrupt tetiklenmesi için gerekli ayarı yaptık.

Veriyi “recArr” isimli bir diziye kayıt ettik. Ayrıca kullandığımız “cnt” isimli değişken dizide indis işlemini gerçekleştirirken aynı zamanda gelen veri uzunluğunu da belirlemekte. Yani bu değişkenin değerine bakarak kaç veri geldiğini bilebiliriz. Bu bilgiyi ve “packReady” değişkenini kontrol ederek veriyi ayırma işlemine başlayabiliriz. Nextion gönderdiği verileri aşağıdaki sırada göndereceğini biliyoruz. Ayırmayı da buna göre yapmalıyız.

0x65 <page_ID> <widget_ID> <value> 0xFF 0xFF 0xFF

Bu sıraya göre ayırma işlemini gerçekleştirecek yazılım aşağıdaki gibidir. Yazılımın başında paket hazır değişkenine ve byte sayısını tutan değişkene bakarak işlemlere başlıyoruz. İkisini de kullanarak paketin gelmiş olmasını garantilemeye çalıştık. Yazılımdaki “for” döngüsü de verinin tam baştan yakalanmamış ya da veriyi kayıt ettiğimiz dizi içerisinde önceden veri kalmış olma ihtimalini gidermek için kullanılmıştır. Sonrasında 0x65 aranmış ve eğer bulundu ise sonrası sıra ile parçalanmmıştır. Aslında bu çok güvenli bir ayırma metodu değil. Ancak nextion herhangi bir cheksum ya da benzeri bir şey göndermiyor. Yapılabilecek çok bir şey yok. Araya veri girmeyeceğini ya da verinin çok hızlı gelmeyeceğini umacağız :)

// check nextion packet flag is true
// if flag is true all of bytes in buffer received
if(packReady && cnt > 0)
{
  // check all received packet to where is start byte
  for(int i = 0; i < cnt; i++)
  {
	  // check 0x65 byte index in buffer
	  if(recArr[i] == 0x65)
	  {
		  // read bytes from receive buffer
		  uint8_t pId = recArr[i + 1];
		  uint8_t mId = recArr[i + 2];
		  uint8_t mVal = recArr[i + 3];

		  uint16_t pwmVal = mVal * 10;

		  // make choose according to used button' s pageId and widget ID
		  if(pId == 0)
		  {
			  switch(mId)
			  {
				  // LED 1 toggle button ID
				  case 2:
					  HAL_GPIO_TogglePin(LED1_GPIO_Port, LED1_Pin);
					  setTextNextion("t0", HAL_GPIO_ReadPin(LED1_GPIO_Port, LED1_Pin) ? "LED Yandi" : "LED Sondu");
					  break;
				  // LED 2 toggle button ID
				  case 3:
					  HAL_GPIO_TogglePin(LED2_GPIO_Port, LED2_Pin);
					  setTextNextion("t1", HAL_GPIO_ReadPin(LED2_GPIO_Port, LED2_Pin) ? "LED Yandi" : "LED Sondu");
					  break;
				  // change page 1 button ID
				  case 6:
					  pageId = 1;
					  HAL_Delay(10);
					  break;
			  }
		  }else if(pId == 1)
		  {
			  switch(mId)
			  {
				  // change page 0 button ID
				  case 2:
					  pageId = 0;
					  setTextNextion("t0", HAL_GPIO_ReadPin(LED1_GPIO_Port, LED1_Pin) ? "LED Yandi" : "LED Sondu");
					  setTextNextion("t1", HAL_GPIO_ReadPin(LED2_GPIO_Port, LED2_Pin) ? "LED Yandi" : "LED Sondu");
					  break;
				  // LED 1 switch button ID
				  case 4:
					  HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, mVal);
					  break;
				  // slider ID
				  case 7:
					  __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_3, pwmVal);
					  break;
			  }
		  }

		  lastTimeSend = HAL_GetTick();

	  }
  }
  packReady = 0;
  cnt = 0;
}

 

Paket başı yakalandıktan sonra kullanılan aracın sayfasına ve ID’ sine göre sorgular ile yapılacak işlemler seçilmiştir. Komponentlerin ID’ leri önceki konudakiler ile aynıdır. Zaten tasarımı da paylaştığım için ordan da bakabilirsiniz. O yüzden üzerinde tekrar durmayacağım. Arada kullandığım “setTextNextion” fonksiyonu kendi oluşturduğum bir fonksiyondur. Bir de “setValueNextion” diye bir fonksiyonu var şimdi bu ikisini inceleyelim. Bu fonksiyonlar nextion içerisindeki yazı aracı ve progress bar aracına veri göndermeyi kolaylaştırmak için oluşturulmuştur. İçerikleri basit olup aşağıdaki gibidir.

// update widget function which have value parameter
void setValueNextion(const char *pId, int pVal)
{
	sendLen = sprintf((char *)sendStr, "%s.val=%d%c%c%c", pId, pVal, 0xFF, 0xFF, 0xFF);
	HAL_UART_Transmit(&huart1, sendStr, sendLen, 2000);
	HAL_Delay(10);
}

// update widget function which have text parameter
void setTextNextion(const char *pId, const char *pVal)
{
	sendLen = sprintf((char *)sendStr, "%s.txt=\"%s\"%c%c%c", pId, pVal, 0xFF, 0xFF, 0xFF);
	HAL_UART_Transmit(&huart1, sendStr, sendLen, 2000);
	HAL_Delay(10);
}

 

Nextion içerisindeki araçlara veri gönderirken kullanılacak format belli olduğunda bu fonksiyonları kullanarak gönderilecek veriyi o formata uygun hale getirdik. İki farklı fonksiyon olmasının sebebi label araçları “text” parametresine sahipken, progress bar gibi araçlar “value” parametresine sahip olmasıdır.

Tasarlanan arayüzün resimleri aşağıdaki gibidir. Başta da söylediğim gibi karşılaştırmanın kolay olması için önceki konulardaki tasarımın aynısını kullandım.

Bu konuda yeni olarak aracı kullanırken istediğimiz veriyi nasıl denetleyicye gönderebileceğimizi göstermeye çalıştım. Bunun önemli ve kullanışlı bir özellik olduğunu düşünüyorum. Ben diğer araçların veri gönderim formatına benzeyecek şekilde bir paket oluşturdum. Siz daha farklı bir paket sırası oluşturup verinin alınmasını daha kolay hale getirebilirsiniz. Nextion’ dan gönderilen veri paketinin değişmesi durumda STM32′ de ki yazılımın da değişmesi gerekeceğini unutmamalısınız.

Hazırlanan yazılımın tamamına bağlantıdan ulaşabilirsiniz. Ayrıca Nextion ekran tasarım dosyalarını içeren dosya bağlantıdan ulaşabilirsiniz.

Umarım eksik bir şey kalmamıştır, konuyu parça parça yazabildim. Eksik ya da hata varsa lütfen bildirin.

İyi çalışmalar dilerim…

Add a Comment

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