Síťový teploměr

Petr Navrátil
xnavra37stud.feec.vutbr.cz  

Obsah:

  1. Úvod
  2. Realizace a popis základních bloků
  3. Popis programu
  4. Program v C++ Builderu
  5. Ukázky síťové komunikace
  6. Závěr
  7. Odkazy
  8. Použitá literatura

Úvod

Projekt je zaměřen na vyčtení teploty z digitálního teploměru DS18B20 a následným zasláním naměřené hodnoty pomocí rozhraní ethernet (10Mbit/s) do jednoduchého programu v PC.

Realizace

Realizace teploměru je pomocí dvou zařízení: 1. vývojový KIT s ATmega16 [1] (obr. č.1) a rozhraní Ethernet <-> SPI pomocí integrovaného obvodu ENC28J60 (obr. č.2). Pro obsluhu jednotlivých zařízení byli napsány dvě knihovny. Jedna zabývající se teplotním čidlem firmy Dallas DS18B20, ze které je možné jedním příkazem dostat informace o teplotě. Dále už obtížnější bylo sestavení knihovny pro obsluhu ethernetového řadiče, která obsahuje všechny potřebné funkce pro práci s tímto řadičem. Obě knihovny jsou podrobně popsány a ke stažení níže.

Obr.1: Vývojová KIT s ATmega16 [1]

Obr.2: Ethernetový řadič ENC28J60

DS18B20 (Teplotní čidlo)

Teplotní čidlo DS18B20 je umístěno na vývojové desce [1]. Komunikace s nim probíhá pouze pomocí jedné sběrnice (1-wire bus). Na tuto sběrnici může být připojeno i několik takto komunikujících teplotních čidel. Každé čidlo má unikátní 64-bitovou identifikaci. Tato identifikace není v knihovně řešena. Jelikož je použito pouze jedno teplotní čidlo, používá se příkazu k přeskočení adresace. Teplotní čidlo má rozsah od -55°C až po +125°C s přesností +/-0,5°C. Digitalizovaná hodnota má rozlišení 12 bitů.

Při komunikaci na sběrnici s teplotním čidlem je nejdůležitější časování jednotlivých signálů, jak pro zápis tak pro čtení. Přesné hodnoty i s určitou tolerancí můžeme najít v katalogu výrobce [3]. Na obr. č.3 je uveden přehled 4 typů průběhů na sběrnici (zápis 0/1 a čtení 0/1). Speciálním případem pro komunikaci na 1-wire sběrnici je průběh pro reset, který se od zde uvedených liší.

Obr.3: Zápis a čtení logických stavů 0 a 1 na sběrnici 1-wire

Po realizaci jednoduchých funkcí pro reset, čtení a zápis na sběrnici (viz. knihovna) můžeme přejít k samotné komunikaci s čidlem. Na sběrnici se zasílají 8 bitové příkazy. Pro samotné měření a vyčtení naměřené teploty budeme používat pouze 3 příkazy, ostatní příkazy jsou uvedeny v katalogu výrobce [3]. Pro přeskočení adresace slouží příkaz 0xCCh, zahájení měření teploty 0x44h a pro vyčtení z tabulky scratchpad (vyčtení teploty) slouží příkaz 0xBEh. Všechny tyto příkazy se zapisují na danou sběrnici ve specifikovaném pořadí. Jako první se vyšle reset, následuje přeskočení adresa (0xCC) , příkaz pro převod teploty (0x44), následně je potřeba čekat 750 ms na dokončení převodu. Po dokončení převodu následují operace reset, přeskočení adresace a tentokrát příkaz 0xBE, po kterém nám teplotní čidlo začne vypisovat tabulku scratchpad. Pokud požadujeme pouze teplotu, stačí nám zaznamenat pouze prvních 16 bitů. První 4 bity jsou znaménkové (1111 - záporné číslo), následuje 8 bitů celočíselná hodnota teploty a poslední 4 bity jsou ve zlomkovém tvaru (hodnota 0,5 až 0,0625). Vnitřní schema teplotního čidla je uvedeno na obr. č.4.

Teploměr je připojen na pin A1 mikrokontroléru ATmega16.

Obr.4: Vnitřní schéma teplotního čidla

Ethernetový řadič ENC28J60

Tento řadič nám zajistí fyzickou vrstvu pro komunikaci po rozhraní ethernet (10Mbit/s). Pro komunikaci s mikrokontrolérem využívá sériové rozhraní SPI (MISO, MOSI, SCK, SS[CS] ), které je možné použít až do kmitočtu 25 MHz (v našem případě omezeno mikrokontrolérem na 16MHz). Bohužel řadič používá jiné napájecí napětí než mikrokontrolér ATmega16, tudíž bylo nutné do obvodu přidat stabilizátor (TS1117CW33), který napájecí napětí 5V upravuje na 3,3V. Vstupní piny pro rozhraní SPI jsou na 5V výstupy mikrokontroléru přizpůsobeny.

Obr.5: Vnitřní uspořádání řadiče ENC28J60

Samotný obvod ENC28J60 je uvnitř složen z několika částí, z těch nejdůležitějších to jsou např. rozhraní SPI, kontrolní registry, fyzické registry a 8kB Buffer. Rařízení může pracovat jako plně duplexní nebo polovičně (Half-Duplex). V našem případě je realizován řadič jako Half-Duplex. Buffer je 8kB paměť pro přijímané a vysílané pakety. Tato paměť se pomocí ukazatelů v kontrolním registru rozdělí na paměť určenou pro příjem a pro odesílání. Fyzické registry slouží k nastavení režimu, nastavení přerušení a nastavení indikace LED. Kontrolní registry se starají o celkový chod a nastavení řadiče, včetně ukazatele na paměť apod. Všechny kontrolní registry jsou rozděleny do tzv. registrových bank (celkem 4). Přičemž přepínání mezi těmito bankami je pomocí registru ECON1. Přehled kontrolních registrů je uveden v obr.č.6. Nastavení a obsah jednotlivých registrů je možné vyčíst z datsheetu výrobce [2].

Obr.6: Kontrolní registry ENC28J60

Registry MAADR1 až MAADR6 slouží k nastavení MAC adresy zařízení ENC, MACOON registry jsou určeny k nastavení připojení ENC zařízení k mikrokontroléru. V bance 0 můžeme nalézt ukazatele na buffer. Každý režim, ať už čtení, nebo zápis jsou určeny třemi ukazately, které jsou 16 bitové (H - horní polovina a L - spodní polovina). Tyto tři ukazatele představují startovací adresu ST (např. ERXSTL) - místo odkud se má číst, zapisovat, ukončovací adresu ND (např. ERXNDL) - kde je ukončen paket a aktuání ukazatel na pozici v bufferu PT (např ERDPTL) - ukazuje na aktuálně zapisovaný (čtený) údaj v bufferu. Hlavní řídící registr ECON1 se stará tedy o aktuální nastavenou registrovou banku, ale také o příjem a vysílání paketů. Podrobný popis nastavovaných funkcí v daných registrech je uveden ve zdrojovém kódu.

UDP protokol

Komunikace probíhá pomocí IP protokolu obsahující datagram UDP. Jedná se o nespolehlivé a nespojované přenášení dat. Nastavení jednotlivých hlaviček paketů pro vyslání do PC je uvedeno na obr. č.7. Před samotnou IP hlavičkou je 14 bytů obsahujících cílovou MAC adresu, zdrojovou MAC adresu, typ a CRC výpočet. Dále 20 bytů IP hlavičky a zbytek do 60 bytů je doplněn UDP datagramem, první dva byty představují vyčtenou hodnotu teploty a zbytek je doplněn do velikosti 60 bytů nulami. Na obr.č.9 v sekci Ukázky síťové komunikace je možnost podívat se na takto vyslaný paket s touto strukturou.

Obr.7: IP hlavička + UDP protokol

Popis programu

Po spuštění mikrokontroleru se začne v pravidelných intervalech zasílat pomocí broadcastových zpráv údaj o hodnotě teploty do PC ve formě UDP paketu o velikosti 60B. Komponenta UART vyskytující se ve zdrojovém kódu byla použita pro debuging, zejména pro příjem paketů a samotné zprovoznění aplikace. V PC byly informace z rozhraní UART zpracovány pomocí programu terminál [4].


#include <avr/io.h>
#include <util/delay.h>
#include "enc28j60.h"
#include "DS18B20.h"


void CalculateCRC(void);  // výpočet CRC pro hlavičku paketu
void ConfigureIP(void);  // změna IP a MAC adresy příjemce, pokud je doručen nastavovací paket

unsigned char *poslat_Data;  // ukazatele na použitá pole v programu
unsigned char *prijato_Data;
unsigned char *register_Data;
unsigned char *status_Data;

uint16_t teplo = 0;
uint16_t adresace = 0x1A19;


unsigned char Prijato[60];  // pole pro příjem paketu
unsigned char StatusVektor[6]={0};  // 4.pole vektoru udává velikost paketu ==> ukazatel +(délka+1) = adresa dalšího paketu
unsigned char Packet[45] = "\xFF\xFF\xFF\xFF\xFF\xFF\2\4\5\1\2\6"  // // MAC address (příjemce, odesílatel)
                           "\x08\x00"  // Ethernet freame type 
//začátek IP rámce-------------------------------------------------------
//-----------------------------------------------------------------------
//1. řádek IP hlavičky: verze+IHL; Typ služby; celková délka (2bajty)		
			 "\x45\x00\x00\x2D"	
//2. řádek IP hlavičky: Idetifikace (2B); Offset fragmentu(2B)
			"\x00\x01\x00\x00"
//3. řádek IP hlavičky: TTL;Protokol; CRC hlavičky (2B) (doplnit CRC kód) 
			"\x80\x11\x00\x00"		
//4. řádek IP hlavičky: Zdrojová adresa
			"\x0A\x00\x00\x09"		// 10.0.0.9
//5. řádek IP hlavičky: cílová adresa
			"\x0A\x00\x00\x65"		//  10.0.0.101
//UDP hlavička-----------------------------------------------------------
//-----------------------------------------------------------------------
//1. řádek UDP: zdrojový port(2B), cílový port(2B)  //port 55 555		
			"\xD9\x03\xD9\x03"
//2. řádek UDP: délka(2B), CRC(2B)
			"\x00\x19\x00\x00"
//3. řádek UDP: data (2B)
			"\x08\xAA";   // vyšle DATA = číslo 88 - signalizace, že nejde teploměr;


// inicializace SPI rozhraní pro komunikaci 
void init_SPI(void)
{
	DDRB = (1<<PB4)|(1<<PB5) | (1<<PB7);	 // nastaví MOSI , SCK , and SS jako výstup 
	SPCR = ( (1<<SPE)|(1<<MSTR)  );	         // Enable SPI, Master, set clock rate fck = 8MHz 
}


//------ hlavní program -----------------------------------------------------------------
int main (void)
{
	CS_out;					// DDRB pin SS je určen jako CS (viz. knihovna enc28J60.h)
	CS_set;					// CS nastaven do log 1
	DDRC = 0xFF;			        // nastavení portu C jako výstupního pro periferie na desce
	PORTC = 0b01000011;		        // nastavení periferií na desce

	init_SPI();				// incializace SPI rozhraní
	
	// ukazatelé na data
	poslat_Data = &Protokol[0];
	prijato_Data = &Prijato[0];
	status_Data = &StatusVektor[0];
	register_Data = &Protokol[11];          // v první řadě nastaví 6. byte (pozice MAC pro ENC)


	// inicializace (restart) ENC
	SysReset();
	_delay_ms(10);

	// MAC adresa se uloží do ENC
	Init_ENC(register_Data);

	// výpočet CRC pro výchozí IP hlavičku
	CalculateCRC();	


	while(1)
	{
		/* vyčtení teploty z teplotního čidla (standartně 12 bitů) */
		teplo=Read_Teplota();	
				
		/* pozice dat pro teplotu 42 a 43 byte protokolu*/
		Protokol[42] = (unsigned char)(teplo>>8);
		Protokol[43] = (unsigned char)(teplo);
		
		WriteBuffer(poslat_Data,44);	    // zapíše data k odeslání do bufferu v ENC, MAX paket je nastaven na 60 bytů
		SendPacket(0x00);		    // zapíše paket na dané adrese 0x00xx,. kde xx je pozice začátku paketu (nejjednoduší případ na začátku 0x00)

		// wait cca 2 sekundy ------------------
		_delay_ms(200);		// 1 sekunda
		_delay_ms(200);
		_delay_ms(200);
		_delay_ms(200);
		_delay_ms(200); 
		_delay_ms(200);		// 2 sekunda
		_delay_ms(200);
		_delay_ms(200);
		_delay_ms(200);
		_delay_ms(200); 
		/* --------------------------------- */

		ConfigureIP();					// otestuje přijaté pakety na případnou změnu IP adresy příjemce
	
	}

	return(1);

}

//-------------------------------------------------------------------------------
//-------------------------------------------------------------------------------
void CalculateCRC (void)
{
	//vymazat první kalkulaci!!!!  pozice 24,25
	Protokol[24]=0x00;
	Protokol[25]=0x00;

	uint16_t cisla[10];
	uint32_t soucet = 0;
	uint16_t CRC_kod;

	unsigned char i,preteceni;

	//sloučení do 16 bitových slov
	for(i=0; i<10;i++)
	{
		cisla[i]=(uint16_t)Protokol[14+(2*i)];
		cisla[i]= cisla[i]<<8;
		cisla[i]+= Protokol[15+(2*i)];
		//index 14 (1 IP) až 33 (20IP)
	}
	
	// provedeme součet všech 16 bitových čísel
	for(i=0; i<10;i++)
	{
		soucet+= cisla[i];
		
	}

	CRC_kod = (uint16_t)(0xFFFF&soucet); 		  // uložený výsledek CRC
	preteceni = (unsigned char)(soucet>>16);	  // výsledek přetečení
	CRC_kod +=preteceni;                              // přičtení přetečení k hodnotě CRC
	CRC_kod = ~CRC_kod;				  // negace výsledného CRC kódu

	Protokol[24] = (unsigned char)(0xFF&(CRC_kod>>8));
	Protokol[25] = (unsigned char)0xFF&(CRC_kod));

}

void ConfigureIP (void)
{
		/* Procedura na čtení paketu a nastavení IP komunikace */
		// 1. zjištění nového paketu - přečtení status vektoru
		ReadPacketData(status_Data,adresace);			// přečtu status vektor příchozího paketu
		// kontrola vektoru paketu
		if ((StatusVektor[0]==0x60)&(StatusVektor[1]==0x1A))
		{
			//2. pokud nalezl paket přeskočím status vektor a přečtu buffer, očekávám 60 bytů packet
			adresace = adresace+6;
			ReadBuffer(prijato_Data,(adresace));			// přečtu paket

		
	
		// 3. Hledání daného výrazu v paketu od bytu 43 až po 47 (po 44)
			if((Prijato[42]==0x53)&(Prijato[43]==0x54)&(Prijato[44]==0x41)&(Prijato[45]==0x52)&(Prijato[46]==0x54))	
			{
				// pokud je nalezeno slovo START => ascii {53,54,41,52,54}
				// jedná se o nastavovací paket a potřebuji načíst IP adresy a MAC adresu daného PC

				// zařízení dostane na dané síti automaticky adresu s koncovkou 09
				// změna IP pro danou síť 
				Protokol[26]=Prijato[26];
				Protokol[27]=Prijato[27];
				Protokol[28]=Prijato[28];
				Protokol[29]=0x09;

				// adresa kam posílat
				Protokol[30]=Prijato[26];
				Protokol[31]=Prijato[27];
				Protokol[32]=Prijato[28];
				Protokol[33]=Prijato[29];

				// změna MAC adresy na kterou posílat -> již nebude broadcast
				Protokol[0]=Prijato[6];
				Protokol[1]=Prijato[7];
				Protokol[2]=Prijato[8];
				Protokol[3]=Prijato[9];
				Protokol[4]=Prijato[10];
				Protokol[5]=Prijato[11];

				// proběhla změna rámce, je nutné přepočítat CRC
				CalculateCRC();
				

			}
			else 					        // pokud se nejedná o nastavovací paket, potom se v paměti posunu na další paket
			{
				adresace = adresace+StatusVektor[3]-5;  // na začátek dalšího paketu 
			}


		}
		else   // pokud nebyl nalezen začátek dalšího paketu probíhá hledání znovu
		{
			adresace = 0x1A19;
		}
}


Program v C++ Builderu

Program pro zpracování paketů byl naprogramován v programu C++ Builder a výsledný program i se szdrojovými kódy včetně popisů jsou rovněž dostupné níže se všemi zdrojovými kódy. C++ Builder byl vybrán, jelikož obsahuje jednoduchou komponentu s názvem Indy, která umí pomocí jednoduchých povelů pracovat se sítí i s UDP datagrami a předává pouze uživatelská data. Program je pospán níže.

Obr.8: Program vytvořený v C++ Builderu za běhu

Ukázky síťové komunikace

Zde jsou zachyceny obrázky z provozu teploměru na dané podsíti pomocí programu WireShark.

Obr.9: Paket zasílaný mikrokontrolérem do PC

Na obr.č.9 lze vidět strukturu paketu zasílaného mikrokontrolérem do PC. Délka celého rámce je 60 bytů, data tvoří 17 bytů, první dva byty jsou naměřená hodnota, zbytek je doplněn nulami, viz. modře zvýrazněná část. Dále je možné si všimnout prvních 6 bytů celého rámce má hodnotu 0xFFh, tedy paket je cílem ve formě broadcast. Následně je MAC adresa zařízení, tedy námi zvolená a dva byty pro CRC a typ rámce MAC který ENC doplní za nás. Po prvních 14 bytech teprve následuje IP rámec, který je směrován z IP adresy mikrokotroléru 10.0.0.9 (výchozí adresa), pokud není nakonfigurován jinak. Číslo portu je uvedeno v hlavičce datagramu UDP, tedy 55555.

Obr.10: Nastavovací paket pro síťovou komunikaci s PC (konfigurační)

Na obr. č.10 je uvedena struktura paketu pro nastavení IP rámce mikrokontroléru. Tento paket má za úkol nastavit adresu mikrokontroléru pro danou síť, dále nastaví IP i MAC adresu příjemce, tedy bude posílat pakety již pouze na danou adresu v síti. Nastavovací paket je broadcastový, tudíž se do mikrokontroléru vždy dostane i přes volbu jiné MAC adresy zařízení. Veškeré informace vezme z příchozího paketu (informace o odesílateli nastavovacího paketu). Mikrokontrolér ve svém zdrojovém kódu následně při příjmu paketu kontroluje, zda obsahuje sekvenci "START" (viz. modře vybarveno). Pokud paket obsahuje tuto sekvenci na daném místě, považuje ho za nastavovací a změní parametry hlavičky a přepočítá CRC.

Závěr

Cílem projektu bylo naprogramovat síťový teploměr, tedy vyčítání informací o teplotě pomocí sítě ethernet. K projektu je tedy i software na ovládání a vyčítání, který zpracovává UDP datagram a zobrazuje hodnotu. Schéma zapojení zde není uvedeno, jelikož přípravky byly propojeny pouze 4 vodiči rozhraní SPI a dvěmi napájecími. V souboru projektu je ponechána i část kódu pro debuging pomocí rozhraní UART, kdy je možnost si daná data, např. přijímaný packet, zaslat do pc. Většina problematiky k tomuto projektu je popsaná v rámci komentářů přímo u zdrojového kódu. Jako další námět k rozšíření,by bylo zajímavé dodělat pro mikrokontrolér TCP/IP stack a DHCP síťové funkce, ale to je spíše pro zkušenějšího znalce sítí. Pro demonstraci jednoduché komunikace přes ethernet je tento projekt vhodný i pro začátečníky.

Odkazy

Zdrojové kódy pro mikrokontrolér
Zdrojové kódy (C++ Builder) a program pro PC

Použitá literatura

[1] Friedl, M. Vývojový kit s ATmega16. Praktická elektronika a radio, 2010, roč.XV/2010,č.3, s 19-20. ISSN:1211-328X.
[2] Microchip. ENC28J60 datasheet. Stand-Alone Ethernet Controller with SPI Interface [on-line]. [citováno 2012-05-18]. Dostupné z: http://ww1.microchip.com/downloads/en/devicedoc/39662b.pdf
[3] Maxim. DS18B20 Programmable Resolution 1-Wire Digital Thermometer. [on-line]. [citováno 2012-05-18]. Dostupné z: http://datasheets.maxim-ic.com/en/ds/DS18B20.pdf
[4] HW server. Program Terminal pro komunikaci přes RS-232. [on-line]. [citováno 2012-18-05]. Dostupné z : http://rs232.hw.cz/#Terminal
[5] Atmel Corporation. ATmega16 datasheet [on-line]. Vydáno 20.7.2009, [citováno 2012-05-18]. Dostupné z: http://www.atmel.com/dyn/resources/prod_documents/doc8154.pdf