Płytki developerskie zapewniające interface RS232 i USB, oraz moduły XBee XB24.
Płytka z interface USB: dane i zasilanie jednym przewodem. Widać diody sygnalizacyjne i przyciski, które można wykorzystać przy testach konfiguracji.
Płytka z interface RS232 i gniazdem zasilania.
Moduły występują z różnymi antenami, a co za tym idzie różnią się też zasięgiem:
Płytka z anteną "chip antenna" - nie wiem czy istnieje jakieś dobre polskie tłumaczenie.
Antena z kawałka drutu, zapewne o długości zbliżonej do 31,2mm bo tyle wynosi 1/4 fali 2.4GHz.
Moduł ze złączem U.FL.
... i odpowiednia antena do modułu ze zdjęcia powyżej.
By uniknąć zwarcia warto zamocować płytki z modułami. Jeden moduł zasilam z USB, a drugi z akumulatorka.
Moduły trzeba podłączyć pod firmowy program XCTU (X-CTU) by sprawdzić, czy wszystkie moduły posiadają jednakową, najlepiej najnowszą, wersję firmware. Wygląd starszej wersji programu był dla mnie czytelniejszy.
Wybór urządzenia XBee podłączonego do komputera.
Gdybym odzyskiwał komunikację z modułem to wybrał bym dla posiadanych modułów następująca konfigurację.
W modułach mam skonfigurowaną większą prędkość transmisji i taką też ustawiam.
Część konfiguracji modułu XBee.
Sprawdzam, czy każdy moduł ma identyczną wersję firmware.
Jeśli jakiś moduł - jak na zdjęciu powyżej - ma inną wersję to go uaktualniam.
Proces uaktualnienia firmware. Z zasady przeprowadzam taką operację na laptopie lub na komputerze z UPS (jeden z modułów zasilam w tym wypadku z USB, a drugi z akumulatorka)
Przykładowe ustawienia minicom ( xminicom -oD /dev/ttyUSB1)
.
Przykładowe ustawienia minicom, cdn.
Moduły mogą pracować w dwóch topologiach sieci IEEE 802.15.4:
1) Gwiaździstej (mesh). Komunikacja odbywa się przez koordynatora, a sieci pracujące na danym obszarze są niezależne od siebie, dzięki stosowaniu unikalnych identyfikatorów sieci.
2) Partnerskiej (multipoint). Komunikacja może odbywać się bezpośrednio pomiędzy urządzeniami, z pominięciem koordynatora. Można budować skomplikowane sieci, a komunikaty przekazywać do urządzeń znajdujących się poza zasięgiem nadawcy, z wykorzystaniem innych urządzeń (realizuje się to w warstwie sieci, czyli poza 802.15.4)
Komunikację z modułami można zrealizować również na dwa sposoby:
1) Z użyciem trybu transparentnego (tryb domyślny).
2) Z użyciem trybu API.
Można zdalnie przekazywać zmianę stanu wejść i ADC.
***
Poniżej zamieszczam konfigurację trybu transparentnego, multipoint, z uproszczonym adresowaniem i przekazywaniem danych pomiędzy portami UART. Urządzenia można skonfigurować np. takimi komendami (w dokumentacji XBee te opcje są dokładnie opisane):
Urządzenie 1:
ce=0
a1=0
id=100
ch=b
my=1
dh=0
dl=2
Urządzenie 2:
ce=0
a1=0
id=100
ch=b
my=2
dh=0
dl=1
I to wszystko :-)
***
Poniżej publikuję ważniejsze fragmenty aplikacji realizującej wyszukiwanie innych stacji i odczyt stanu portów wejściowych i ustawianie stanu portów wyjściowych (programy pod FreeBSD i Windows). Nie umieszczę całego kodu, ponieważ te moduły wykorzystywane są na niektórych uczelniach w celach dydaktycznych. By uszanować wykładowców podaję wędkę, nie rybę :-) Przestrzegam też przed bezmyślnym kopiowaniem - wykładowcy, przynajmniej znani mi, zorientują się natychmiast :-)
Zachęcam do dokładnego zapoznania się z dokumentacją układów , która jest wykonana na wysokim poziomie.
Wersja FreeBSD:
#include <fcntl.h>
#include <termios.h>
#include <iostream>
void czekaj(const int sekundy, const int setne);
void openPort(int &portCom, struct termios &optCom, const char *portx);
void ustawPort(const int &portCom, struct termios &optCom, const int ustawCzas);
void wewy_ppp(const int &portCom);
void wewy(const int &portCom, const char *komenda, const int kdl, char *wynik, const int wdl);
void wewy_nd(const int &portCom, char *wyborDL);
bool wewy_przycisk(const int &portCom);
bool wewy_wyswietl(const int &portCom, const bool test);
int main(int argc, char *argv[])
{
int portCom,
licznik;
bool przycisk = false,
dioda = false,
dioda_znacznik = false;
char wyborDL[22] = {0};
struct termios optCom;
const int kCzas = 2,
kCzas2 = 5,
dCzas = 20;
char k_OK[] = {"OK"};
char k_CH[] = {"ATCH=F\r"}; //kanal radiowy
char k_DH[] = {"ATDH=0\r"}; //ustawia: Destination Address High
char k_CN[] = {"ATCN\r"}; //koniec trybu command
char k_CT[] = {"ATCT=0x64\r"}; //timeout dla trybu command
char k_ID[] = {"ATID=3332\r"}; //ustawia: ID (Pan ID)
char k_ATDL[] = {"ATDL "};
char k_r[] = {"\r"};
char port0[] = {"/dev/cuaU0"};
char port1[] = {"/dev/cuaU1"};
char k_NI[17] = {0};
char k_MY[17] = {0};
char k_DL[17] = {0};
char portX[15] = {0};
char k_NI_1[] = {"ATNI Stacja1\r"};
char k_MY_1[] = {"ATMY=111\r"};
char k_NI_2[] = {"ATNI Stacja2\r"};
char k_MY_2[] = {"ATMY=222\r"};
if(argc==1)
{
printf("Nie podano parametrow w wywolaniu programu.\n");
return(129);
};
if(argc>2)
{
printf("Za duzo parametrow, maksymalnie podaj jeden parametr (np.: -h)\n");
return(130);
};
switch (*argv[1])
{
case 'v':
printf("Versja 1.9\n");
return(131);
case 'h':
printf("Poprawne wywolanie programu: zad01 <numer portu 0 lub 1>\n");
return(132);
case '0':
strcpy(k_NI, k_NI_1);
strcpy(k_MY, k_MY_1);
strcpy(portX, port0);
break;
case '1':
strcpy(k_NI, k_NI_2);
strcpy(k_MY, k_MY_2);
strcpy(portX, port1);
break;
};
srand(time(0));
openPort(portCom, optCom, portX);
// konfiguracja XBee
ustawPort(portCom, optCom, kCzas);
wewy_ppp(portCom);
wewy(portCom, k_CH, sizeof(k_CH), k_OK, sizeof(k_OK)); //ATCH
wewy(portCom, k_NI, sizeof(k_NI), k_OK, sizeof(k_OK)); //ATNI
wewy(portCom, k_MY, sizeof(k_MY), k_OK, sizeof(k_OK)); //ATMY
wewy(portCom, k_ID, sizeof(k_ID), k_OK, sizeof(k_OK)); //ATID
wewy(portCom, k_DH, sizeof(k_DH), k_OK, sizeof(k_OK)); //ATDH
wewy(portCom, k_CT, sizeof(k_CT), k_OK, sizeof(k_OK)); //ATCT
wewy(portCom, k_CN, sizeof(k_CN), k_OK, sizeof(k_OK)); //ATCN
wewy_ppp(portCom);
ustawPort(portCom, optCom, dCzas);
strcpy(k_DL, k_ATDL);
strcat(k_DL,wyborDL);
strcat(k_DL, k_r);
// ustawiam adres DL
ustawPort(portCom, optCom, kCzas);
wewy_ppp(portCom);
wewy(portCom, k_DL, sizeof(k_DL), k_OK, sizeof(k_OK)); //DL
ustawPort(portCom, optCom, kCzas2);
for (licznik=0; licznik<21; licznik++)
// while (true)
{
wewy(portCom, k_CN, sizeof(k_CN), k_OK, sizeof(k_OK)); //CN
// sprawdza czy przyszla komenda wyswietl
dioda = wewy_wyswietl(portCom, przycisk);
wewy_ppp(portCom);
if (dioda)
{
dioda_znacznik = true;
}
else
{
if (dioda_znacznik)
{
dioda_znacznik = false;
};
};
// sprawdza nacisniecie przycisku
przycisk = wewy_przycisk(portCom);
};
close(portCom);
printf("Koniec programu.\n");
};
void czekaj(const int sekundy, const int setne)
// jednostka = 10ms
{
timespec czas,
czasPozostaly;
czas.tv_sec = sekundy;
czas.tv_nsec = (long)10000000 * setne;
nanosleep(&czas,&czasPozostaly);
};
void openPort(int &portCom, struct termios &optCom, const char *portx)
{
portCom = open(portx, O_RDWR | O_NOCTTY | O_NDELAY);
if (portCom < 0) {perror(portx); return; }
fcntl(portCom, F_SETFL, 0);
tcgetattr(portCom, &optCom);
cfsetispeed(&optCom, B9600);
cfsetospeed(&optCom, B9600);
optCom.c_cflag |= (CLOCAL | CREAD);
optCom.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
optCom.c_oflag &= ~OPOST;
tcsetattr(portCom, TCSANOW, &optCom);
};
void ustawPort(const int &portCom, struct termios &optCom, const int ustawCzas)
{
optCom.c_cc[VMIN] = 0;
optCom.c_cc[VTIME] = ustawCzas;
tcsetattr(portCom, TCSANOW, &optCom);
};
void wewy_ppp(const int &portCom)
{
char bufor[255];
char *bufptr;
int rbytes;
int proba;
czekaj(1,20);
for (proba = 0; proba < 12; proba++)
{
if (proba > 0)
{
if (proba>2)
{
czekaj(1,0);
};
}
else
{
printf("Wysylam do modemu: +++\n");
};
write(portCom, "+++", 3);
czekaj(1,20);
write(portCom, "AT\r", 3);
bufptr = bufor;
while ( (rbytes = read(portCom, bufptr, bufor + sizeof(bufor) - bufptr - 1)) > 0 )
{
bufptr += rbytes;
if (bufptr[-1] == '\r')
break;
};
if ( strncmp(bufor, "OK", 2) == 0 )
{
bufor[3]='\0';
return;
};
}
printf("Koncze program, nie moge wyslac: '+++'.\n");
abort();
};
void wewy(const int &portCom, const char *komenda, const int kdl, char *wynik, const int wdl)
{
char bufor[255],
*bufptr;
int rbytes,
proba;
for (proba = 0; proba < 4; proba ++)
{
if (proba > 0)
{
}
else
{
};
if (write(portCom, komenda, kdl) < kdl)
continue;
bufptr = bufor;
while ( (rbytes = read(portCom, bufptr, bufor + sizeof(bufor) - bufptr - 1)) > 0 )
{
bufptr += rbytes;
if (bufptr[-1] == '\r')
break;
};
*bufptr = '\0';
wynik[wdl] = '\0';
if ( strncmp(bufor, wynik, wdl-1) == 0 )
{
return;
};
wewy_ppp(portCom);
};
};
void wewy_nd(const int &portCom, char *wyborDL)
{
char bufor[255]={0},
*bufptr,
*spis[20][5];
int rbytes,
nrWpisu=0,
nrPola=0,
wybor,
znacznik0D=0,
licz;
for (int i=0; i<20; i++)
{
for (int j=0; j<5; j++)
{
spis[i][j] = new char[22];
};
};
for (licz=0; licz<7; licz++)
{
bufptr = bufor;
while ( (rbytes = read(portCom, bufptr, 1)) > 0 )
{
if ( (*bufptr==10) and (znacznik0D>0) )
{
printf("======\n");
znacznik0D++;
}
else
{
if (*bufptr==10)
{
znacznik0D++;
if (bufptr != bufor+1)
{
*bufptr = '\0';
printf("-- %s\n", bufor);
strcpy(spis[nrWpisu][nrPola], bufor);
bufptr = bufor;
if (nrPola==4)
{
nrPola=0;
if (nrWpisu==19)
{
printf("Przekroczono zakres tablicy.\n");
abort();
}
else
{
nrWpisu++;
};
}
else
{
nrPola++;
};
};
}
else
{
znacznik0D=0;
bufptr++;
};
};
};
if (nrWpisu>0)
{
break;
}
else
{
czekaj(1,0);
};
};
if(nrWpisu==0)
{
printf("Koncze dzialanie programu.\n\n");
abort();
};
for (int i=0; i<nrWpisu; i++)
{
printf(" nr. %i: %s NI=%s\n",i+1, spis[i][4],spis[i][0]);
};
do
{
if ( !scanf("%d",&wybor) )
{
std::cin.clear();
std::cin.ignore(10, '\n');
};
}
while ( wybor<1 or wybor>nrWpisu);
// while ( !(wybor>0 and wybor<nrWpisu+1));
strcpy(wyborDL, spis[wybor-1][0]);
for (int i=0; i<20; i++)
{
for (int j=0; j<5; j++)
{
delete spis[i][j];
};
};
};
bool wewy_przycisk(const int &portCom)
{
char bufor[255],
*bufptr;
int rbytes,
proba;
for (proba = 0; proba < 4; proba ++)
{
if (proba > 0)
{
}
else
{
};
if (write(portCom, "ATIS\r", 5) < 5)
continue;
bufptr = bufor;
while ( (rbytes = read(portCom, bufptr, bufor + sizeof(bufor) - bufptr - 1)) > 0 )
{
bufptr += rbytes;
};
*bufptr = '\0';
if ( (bufor[6]=='0') and (bufor[7]=='0') and (bufor[8]=='0') )
{
return(true);
}
wewy_ppp(portCom);
};
return(false);
};
bool wewy_wyswietl(const int &portCom, const bool test)
{
char bufor[255],
*bufptr,
komunikat[] = {'*','G','R','1','*'};
int rbytes,
komunikatDl = 5,
licznik;
if (test)
{
for (licznik=0; licznik<8; licznik++)
{
write(portCom, komunikat, komunikatDl);
czekaj(0,25);
};
};
bufptr = bufor;
while ( (rbytes = read(portCom, bufptr, bufor + sizeof(bufor) - bufptr - 1)) > 0 )
{
bufptr += rbytes;
};
if (test)
{
write(portCom, komunikat, komunikatDl);
};
*bufptr = '\0';
if ( strncmp(bufor, komunikat, komunikatDl) == 0 )
{
if (test)
{
write(portCom, komunikat, komunikatDl);
};
for (licznik=0; licznik<3; licznik++)
{
if (test)
{
czekaj(0,50);
write(portCom, komunikat, komunikatDl);
};
};
return (true);
};
czekaj(0,(rand()%25));
if (test)
{
write(portCom, komunikat, komunikatDl);
};
return (false);
};
//end
Wersja Windows:
#include <windows.h>
//#include "stdio.h"
#include "string.h"
//#include <stdio.h>
//#include <iostream>
//#include <iomanip>
//#include <list>
//#include <time.h>
//#include <windows.h>
//#include <conio.h>
//#include <stdlib.h>
//#include <cstdio>
//#include <ctime>
//#include <iostream>
//#include <stdio.h>
char * k_OK = {"OK"};
char * k_ppp = {"+++"};
char * k_ppp_spr = {"OK"};
char * k_ATCT = {"ATCT=64"};
char * k_ATCT_spr = {"ATCT=64"};
//NAZWA
char * k_ATNI_1 = {"ATNI Unit1"};
char * k_ATNI_spr_1 = {"ATNI"};
char * k_ATNI_2 = {"ATNI Unit2"};
char * k_ATNI_spr_2 = {"ATNI"};
//KANAL
char * k_ATCH = {'A','T','C','H','=','B',13,0};
char * k_ATCH_spr = {"ATCH,",13};
char * k_ATDH = {"ATDH=0"};
char * k_ATDH_spr = {"ATDH"};
char * k_ATMY_1 = {"ATMY=1357"};
char * k_ATMY_spr_1 = {"ATMY"};
char * k_ATDL_1 = {"ATDL=2468"};
char * k_ATDL_spr_1 = {"ATDL"};
char * k_ATMY_2 = {"ATMY=2468"};
char * k_ATMY_spr_2 = {"ATMY"};
char * k_ATDL_2 = {"ATDL=1357"};
char * k_ATDL_spr_2 = {"ATDL"};
//KONIEC
char * k_ATCN = {"ATCN"};
char * k_ATCN_spr = {""};
HANDLE portCOM;
DCB dcb;
BOOL fSuccess;
BYTE RS_buf;
DWORD RS_ile;
COMMTIMEOUTS ustawCOM={0, 0, 0, 0, 0};
int licznik_komunikatow = 0;
const byte czekaj_1 = 1;
const byte czekaj_10 = 10;
const byte czekaj_100 = 100;
void czekaj(byte czekaj)
// jednostka = 10ms
{
int i;
for (i = 0; i < czekaj; i++)
{
Sleep(10);
}
}
void rs_otworz_urzadzenie()
{
//port COM1 z prawami RW
portCOM = CreateFile( TEXT("COM1"), GENERIC_READ | GENERIC_WRITE,
0, // exclusive access
NULL, // default security attributes
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (portCOM == INVALID_HANDLE_VALUE)
{
printf("Open - blad %d.\n", GetLastError());
}
}
int rs_ustaw_parametry()
{
int blad;
blad = GetCommState(portCOM, &dcb);
if (!blad)
{
printf ("GetCommState - blad %d.\n", GetLastError());
return 2;
}
dcb.BaudRate = CBR_9600;
dcb.ByteSize = 8;
dcb.Parity = NOPARITY;
dcb.StopBits = ONESTOPBIT;
blad = SetCommState(portCOM, &dcb);
if (!blad)
{
printf ("SetCommState - blad %d.\n", GetLastError());
return 3;
}
}
int rs_znak_pisz(char znak)
{
int blad;
RS_buf=znak;
printf("%c",znak);
ustawCOM.ReadTotalTimeoutConstant=0;
blad = WriteFile( portCOM, &RS_buf, 1, &RS_ile, 0);
if (!blad)
{
return 4;
}
}
char rs_znak_czytaj()
{
}
void pisz_raw(char *wyslij, char *odczytaj, byte czekaj_przed, byte czekaj_pomiedzy, byte czekaj_po, byte ilosc_powt)
// string do wyslania,
// string, ktory ma zwrocic urzadzenie
// czekaj przed wyslaniem w ms
// czekaj pomiedzy powtorzeniami wyslania w ms
// czekaj po wyslaniu w ms
// ilosc prob powtorzen operacji
{
int i;
//czekaj(czekaj_przed);
int len = strlen(wyslij);
for (i = 0; i < len; i++)
{
//printf("%c",wyslij[i]);
rs_znak_pisz(wyslij[i]);
}
czekaj(czekaj_po);
}
void pisz(char *wyslij, char *odczytaj, byte czekaj_przed, byte czekaj_pomiedzy, byte czekaj_po, byte ilosc_powt)
{
}
char czytaj(int czekaj_max)
//jak dlugo ma czekac na znaki
{
int blad;
int testuj=1;
while(testuj!=0)
{
czekaj(10);
testuj--;
ustawCOM.ReadTotalTimeoutConstant=1100;
SetCommTimeouts(portCOM,&ustawCOM);
//if(RS_ile==1)
// {
// if(RS_buf == )
// {
// testuj=0;
// break;
// };
// printf("%c", RS_buf);
printf("%s", &RS_buf);
FlushFileBuffers(portCOM);
// }
}
}
void xbee_ustaw_parametry_stanowisko_1(void)
{
}
void xbee_ustaw_parametry_stanowisko_2(void)
{
}
void xbee_ustaw_parametry(void)
{
xbee_ustaw_parametry_stanowisko_1();
}
int main()
{
rs_otworz_urzadzenie();
rs_ustaw_parametry();
//+++
czekaj(110);
czytaj(1);
czekaj(5);
printf ("\n");
printf ("\n");
czytaj(1);
czekaj(5);
/*
//ATCH=B
pisz_raw(k_ATCH, k_ATCH_spr, 110, 120, 10, 100);
czytaj(1);
czekaj(10);
printf ("\n");
*/
/*
pisz_raw(k_ATCH_spr, k_ATCH_spr, 110, 120, 10, 100);
czytaj(1);
czekaj(10);
printf ("\n");
*/
//pisz_raw(k_ENTER, k_ENTER, 110, 120, 10, 100);
//pisz_raw(k_ATCH_spr, k_ATCH_spr, 110, 120, 10, 100);
// czytaj(1);
// czekaj(10);
//ATNI Unit1
//pisz_raw(k_ATNI_1, k_ATNI_spr_1, 110, 120, 10, 100);
// czytaj(1);
//ATCH=B
//pisz_raw(k_ATCH, k_ATCH_spr, 110, 120, 10, 100);
// czytaj(1);
//ATDH=0
//pisz_raw(k_ATDH, k_ATDH_spr, 110, 120, 10, 100);
// czytaj(1);
//ATMY=1357
//pisz_raw(k_ATMY_1, k_ATMY_spr_1, 110, 120, 10, 100);
// czytaj(1);
//ATDL=2468
//pisz_raw(k_ATDL_1, k_ATDL_spr_1, 110, 120, 10, 100);
// czytaj(1);
printf ("\n");
system("pause");
return (0);
}
***
Użyłem adapterów:
- Z interface RS232: XBIB-R-DEV
- Z interface USB: XBIB-U-DEV
Brak komentarzy:
Prześlij komentarz