Area SX srl - Informatica e Microelettronica
0
Torna a: Home Page Soluzioni Wireless Radio Frequenza Usare la SX16 sotto Linux

Usare la SX16 sotto Linux

Data di pubblicazione: 01-07-2005 | Versione Italiana  | (No English Version)The English version of this article does not exists
Parole chiave: - How-To - Linux - Schede Area SX -

Spesso per motivi professionali o più semplicemente per hobby, si ha la necessità di implementare nelle proprie applicazioni software uno strato hardware capace di comandare o verificare condizioni di stato da apparati esterni come ad esempio accendere lampadine o  verificare un contatto magari collegato ad una porta.

In quest' articolo vediamo come, grazie alla scheda d'espansione SX 16 prodotta da AreaSX S.r.l, sia semplice e veloce permettere ad un applicazione scritta in C sotto Linux di interagire con il mondo esterno.
La versione di SX16 che andremo ad usare è la stand alone la cui documentazione completa è disponibile all'URL:
http://www.areasx.com/index.php?D=1&id=8091

Questa versione si distingue da quella normale, perchè dotata di un microprocessore PIC a bordo già programmato con un firmware che semplifica notevolmente l'interfacciamento con un PC. Oltre al micro è presente anche un modulo RF modello ER400 che rende la SX16 completamente libera da fili (wireless) che la collegano al computer.
L'ER400, prodotto dalla LPRS, è un completo sistema per incapsulare una comunicazione seriale bidirezionale su una portante in radiofrequenza di 433MHz e capace di coprire distanze, in condizioni ottimali, di 250mt.

Per permettere al PC di inviare comandi su onde radio alla scheda SX16  usiamo il modulo RF04.
RF04 è un modulo di ridotte dimensioni che integra un convertitore USB - Seriale della FTDI (compatibile con il Kernel 2.4) e un ER400 per trasmettere e ricevere il segnale segnale su portante a 433MHz.

Appena collegato ad un PC Linux, RF04 viene riconosciuto automaticamente ed è visibile nella directory /dev/ con il nome ttyUSB0.

Nei paragrafi che seguono oltre ad essere descritto il protocollo completo di comunicazione della SX16 stand alone, è fornito un semplice programma d'esempio scritto in C e compilabile sotto Linux con il programma GCC usando la seguente sintassi:

[root@virtualinux sorgenti_c]# gcc -o nome_file_output  nome_file_sorgente.c

esempio:

[root@virtualinux sorgenti_c]# gcc -o sx16_linux_rele SX16_LINUX_RELE.c

Comandare i Relè della SX16

Il protocollo per attivare i relè della SX16, prevede l'invio di un comando composto da sei byte e ritorna altrettanti byte ad operazione eseguita, per indicare lo stato dei relè.

Nella tabella che segue viene descritto byte a byte il comando da inviare

Byte

Descrizione

Esadecimale

1

START

0x33

2

INDIRIZZO

0x01

3

COMANDO

0x03

4

RELE'

da 0x01 a 0x06

5

STATO

0x00 OFF - 0x01 ON

6

ZERO

0x00

Analisi dei byte che compongono la risposta inviata dalla SX16 al nostro PC ad operazione completata:

Byte

Descrizione

Esadecimale

1

SOR

0x22

2

INDIRIZZO

0x01

3

COMANDO

0x03

4

STATO RELE'

da 0x00 a 0x63

5

ZERO

0x00

6

ZERO

0x00

Sorgente d'esempio in C:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <stdio.h>

#define BAUDRATE B19200
#define DEVICE "/dev/ttyUSB0"

//COMUNCAZIONE CON SX16
#define START 0x33
#define RETURN_START 0x22
#define ADDR 0x01
#define WRITE_CMD 0x03
#define ALL_CMD 0xFF
#define CH 0x01
#define ON 0x01
#define OFF 0x00
#define ZERO_CHAR 0x00

///////////////////////
//PROTOTIPI
///////////////////////
int read_key();
int send2sx16 (int _fd, char *cmd2sx16, char *sx16return);

///////////////////////
//FUNZIONI
///////////////////////
//Legge l'input da tastiera
int read_key(){
    int cmd;
    while (cmd = getchar()){
      if (cmd!=10) break;
    }
    return cmd;
}
//Invia un comando alla SX16
int send2sx16 (int _fd, char *cmd2sx16, char *sx16return){
  int res;
 
  if (write(_fd, cmd2sx16, 6) < 0) {
    //Invio sulla seriale fallito
    return 0;
  } else {
    //Invio del comando riuscito
    usleep(100000); //sleep per 100mSec
    res = read(_fd,sx16return,6);
    sx16return[res]=0;
    return 1;
  }
}

////////////////////////////////
//
// MAIN
//
////////////////////////////////
main (int argc, char * argv[]) {
  int fd, res, i;
  int b;
  int cmd;
  int line_rele;
  int state_rele;
  struct termios oldtio,newtio;
  char buf[10];
  
  system("clear"); //Pulizia della console
  printf("----------------------------\n");
  printf(" LINUX 2 SX16\n\n");
  printf(" Ver: 1.0\n");
  printf(" Author: Daniele De Santis\n");
  printf(" E-Mail:
[email protected]\n\n");
  printf(" Test RELE'\n");
  printf("----------------------------\n");

  printf("Apertua Porta COM\n");
  fd = open(DEVICE, O_RDWR | O_NOCTTY);
  if (fd < 0 ) {
    printf("Device %s non pesente su questo sistema\n\n", DEVICE);
    exit(-1);
  }
  printf("Inizializzazione della comunicazione seriale\n");
  tcgetattr(fd,&oldtio); /* Salva i precedenti settaggi */
  bzero(&newtio, sizeof(newtio));
  newtio.c_cflag = BAUDRATE | CS8 | CLOCAL | CREAD;
  newtio.c_iflag = IGNPAR;
  newtio.c_oflag = 0;
  newtio.c_lflag = 0;
  newtio.c_cc[VTIME]    = 0;
  newtio.c_cc[VMIN]     = 6; 
  
  tcflush(fd, TCIFLUSH);
  tcsetattr(fd,TCSANOW,&newtio);
  //Inizializzazione device seriale terminata
 
  printf("Seleziona il relè da settare [1 - 6]\n");
  line_rele = read_key();
  if(line_rele < 49 && line_rele > 54) line_rele=49;
  
  printf("Seleziona lo stato [1 ON - 0 OFF]\n");
  state_rele = read_key();
  if (state_rele!=48 || state_rele!=49)  state_rele == 48;
            
  //FORMATTO IL PACCHETTO DA MANDARE ALLA SERIALE
  buf[0]=0;
  buf[0]=START;
  buf[1]=ADDR;
  buf[2]=WRITE_CMD;
  buf[3]=(line_rele - 48);
  if(state_rele==49)
    buf[4]=ON;
  else
    buf[4]=OFF;
  buf[5]=ZERO_CHAR;
  if (send2sx16 (fd, buf, buf)) {
    if((buf[0]==RETURN_START) && (buf[1]==ADDR) && (buf[2]==WRITE_CMD)) {
      printf("----------------------------\n");
      printf(" STATO DEI RELE SULLA SX 16 \n");
      printf("----------------------------\n");
      res = buf[3];
      for (i=0; i<=5; i++){
        b = res & 1;
        res >>=1;
        if(b){
          printf("RELE' %d   [X]  ON\n", (i + 1) );
        } else {
          printf("RELE' %d   [ ]  OFF\n", (i + 1));
        }
      }
    }
  }
  printf("\nChiusura comunicazione seriale...\n");
  tcsetattr(fd,TCSANOW,&oldtio);
  printf("Arrivederci :)\n");
  close(fd);
  exit(0);
}

Il sorgente soprariportato, va copiato e salvato in un file con estensione ".c" (es: SX16_LINUX_RELE.c) e compilato con il programma GCC come l'esempio che segue:

[root@virtualinux sorgenti_c]# gcc -o sx16_linux_rele SX16_LINUX_RELE.c

se la compilazione non ci da messaggi d'errore, troveremo nella stessa path del file sorgente, un file che dovremo rendere eseguibile con il comando chmod

[root@virtualinux sorgenti_c]# chmod +x sx16_linux_rele

a questo punto lanciando l'eseguibile con un "./" davanti al nome dell'eseguibile

[root@virtualinux sorgenti_c]# ./sx16_linux_rele

vedremo sulla nostra console una videata simile a quella che segue: 

Lettura della temperatura:

Sulla SX16 è montato un sensore di temperatura di tipo digitale a 8bit della Dallas DS1621 con range di lettura compreso tra -55 e + 128 con una precisione di 0.5 °C  

Il comando da inviare per effettuare l'acquisizione della temperatura è il seguente:

Byte

Descrizione

Esadecimale

1

START

0x33

2

INDIRIZZO

0x01

3

COMANDO

0x02

4

ZERO

0x00

5

ZERO

0x00

6

ZERO

0x00

La risposta che riceveremo dalla SX16 ad acquisizione terminata:

Byte

Descrizione

Esadecimale

1

SOR

0x22

2

INDIRIZZO

0x01

3

COMANDO

0x02

4

TEMPERATURA

da 0x00 a 0xC9

5

TEMPERATURA

0x00 o 0x80

6

ZERO

0x00

il 4 byte rappresenta la parte intera del valore della temperatura ed è positivo per valori esadecimali che vanno da 0x00 fino a 0x80 superata questa soglia le letture della temperatura sono negative.
Il quinto byte rappresenta il valore decimale della lettura è può avere solo due valori 0x00 che rappresenta ",0" o 0x80 che rappresenta il mezzo grado ",5".

Sorgente d'esempio in C:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <stdio.h>

#define BAUDRATE B19200
#define DEVICE "/dev/ttyUSB0"
#define DELAY_LOOP 10 //In sec

//COMUNCAZIONE CON SX16
#define START 0x33
#define RETURN_START 0x22
#define ADDR 0x01
#define WRITE_CMD 0x03
#define TMP_CMD 0x02
#define READ_CMD 0x01
#define ALL_CMD 0xFF
#define CH 0x01
#define ON 0x01
#define OFF 0x00
#define ZERO_CHAR 0x00
#define TEST 0x80

///////////////////////
//PROTOTIPI
///////////////////////
int read_key();
int send2sx16 (int _fd, char *cmd2sx16, char *sx16return);

///////////////////////
//FUNZIONI
///////////////////////
//Legge l'input da tastiera
int read_key(){
    int cmd;
    while (cmd = getchar()){
      if (cmd!=10) break;
    }
    return cmd;
}
//Invia un comando alla SX16
int send2sx16 (int _fd, char *cmd2sx16, char *sx16return){
  int res;
  char buffer[7];
  if (write(_fd, cmd2sx16, 6) < 0) {
    //Invio sulla seriale fallito
    return 0;
  } else {
    //Invio del comando riuscito
    usleep(500000); //sleep per 500mSec
    res = read(_fd,sx16return,6);
    return 1;
  }
}

////////////////////////////////
//
// MAIN
//
////////////////////////////////
main (int argc, char * argv[]) {
  int fd, res, i;
  auto float temp;
  int cmd;
  struct termios oldtio,newtio;
  unsigned char buf[20];

  system("clear"); //Pulizia della console
  printf("Apertua Porta COM\n");
  fd = open(DEVICE, O_RDWR | O_NOCTTY);
  if (fd < 0 ) {
    printf("Device %s non pesente su questo sistema\n\n", DEVICE);
    exit(-1);
  }
  printf("Inizializzazione della comunicazione seriale\n");
  tcgetattr(fd,&oldtio); /* Salva i precedenti settaggi */
 
  bzero(&newtio, sizeof(newtio));
  newtio.c_cflag = BAUDRATE | CS8 | CLOCAL | CREAD;
  newtio.c_iflag = IGNPAR;
  newtio.c_oflag = 0;
  newtio.c_lflag = 0;
  newtio.c_cc[VTIME]    = 0;
  newtio.c_cc[VMIN]     = 5; 

  tcflush(fd, TCIFLUSH);
  tcsetattr(fd,TCSANOW,&newtio);
  //Inizializzazione device seriale terminata
  while (1){
    system("clear");
    //FORMATTO IL PACCHETTO DA MANDARE ALLA SERIALE
    buf[0]=0;
    buf[0]=START;
    buf[1]=ADDR;
    buf[2]=TMP_CMD;
    buf[3]=ZERO_CHAR;
    buf[4]=ZERO_CHAR;
    buf[5]=ZERO_CHAR;
    if (send2sx16 (fd, buf, buf)) {
      if((buf[0]==RETURN_START) && (buf[1]==ADDR) && (buf[2]==TMP_CMD)) {
        printf("---------------------------------------\n");
        printf(" LINUX 2 SX16\n\n");
        printf(" Ver: 1.0\n");
        printf(" Author: Daniele De Santis\n");
        printf(" E-Mail:
[email protected]\n\n");
        printf(" LETTURA DELLA TEMPERATURA DALLA SX 16 \n");
        printf("---------------------------------------\n");
        printf("Temperatura letta dal sensore DS1621: ");
       
temp=0;
        // Imposto il mezzo grado
        if (buf[4]==0x80) temp=0.5;
        if (buf[3] & 0x80) {
          // Temperatura negativa
          temp+=(!buf[3])+1;
          temp=-temp;
        } else {
          // Temperatura >0
          temp+=buf[3];
        }
        printf("%.2f °C\n", temp);
      }  else {
        printf("ERRORE -Risposta dalla SX16 non valida\n");
      }
      printf("\nCTRL+C per uscire\n");
      usleep(1000000 * DELAY_LOOP);
    } else {
      printf("ERRORE -Comunicazione con il device %s fallito\n", DEVICE);
      exit(-1);
    }
  }
  printf("\nChiusura comunicazione seriale...\n");
  tcsetattr(fd,TCSANOW,&oldtio);
  printf("Arrivederci :)\n");
  close(fd);
  exit(0);
}

Modificando il valore dei define

#define DEVICE "/dev/ttyUSB0"
#define DELAY_LOOP 10 //In sec

è possibile cambiare il nome del device tty con cui comunicare e il ritardo, in sec, con cui viene letta la temperatura.
Per la compilazione e l'esecuzione si deve procedere come per l'esempio precedentemente visto per controllare i rele'.

A compilazione terminate lanciando l'eseguibile avremo a video una schermata come quella che segue:

Acquisizione dello stato dai 24 ingressi:

I 24 ingressi sono divisi a blocchi di otto ed ognuno di questi  è caratterizzato da una tipologia d'ingresso specifica.
I primi otto (punto 1 nella foto che segue) sono di tipo optoisolato, ideali per collegare segnali elettrici con tensioni superiori ai 5V fino ad un massimo di 24V.
Il secondo blocco (punto 2 nella foto che segue) è composto da ingressi di tipo TTL a su cui è possibile applicare livelli di tensione compesi tra 0V e massimo 5V.  
Il terzo blocco (punto 3) è identico per quanto riguarda i livelli di tensione al secondo blocco con la sola differenza che su ogni linea è presente un filtro antidisturbo del tipo CLC.

La lettura dei 24 ingressi viene effettuata con un unico comando il cui protocollo è descritto nella tabella che segue:

Byte

Descrizione

Esadecimale

1

START

0x33

2

INDIRIZZO

0x01

3

COMANDO

0x01

4

ZERO

0x00

5

ZERO

0x00

6

ZERO

0x00

come risposta dalla SX16 si avrà un pacchetto, sempre di sei byte, rispettante il seguente protocollo:

Byte

Descrizione

Esadecimale

1

SOR

0x22

2

INDIRIZZO

0x01

3

COMANDO

0x01

4

 INPUT CTC

da 0x00 a 0xFF

5

INPUT TTL

da 0x00 a 0xFF

6

INPUT OPT

da 0x00 a 0xFF

Sorgente d'esempio in C:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <stdio.h>

#define BAUDRATE B19200
#define DEVICE "/dev/ttyUSB0"
#define DELAY_LOOP 10 //In sec

//COMUNCAZIONE CON SX16
#define START 0x33
#define RETURN_START 0x22
#define ADDR 0x01
#define WRITE_CMD 0x03
#define READ_CMD 0x01
#define ALL_CMD 0xFF
#define CH 0x01
#define ON 0x01
#define OFF 0x00
#define ZERO_CHAR 0x00

///////////////////////
//PROTOTIPI
///////////////////////
int read_key();
int send2sx16 (int _fd, char *cmd2sx16, char *sx16return);

///////////////////////
//FUNZIONI
///////////////////////
//Legge l'input da tastiera
int read_key(){
    int cmd;
    while (cmd = getchar()){
      if (cmd!=10) break;
    }
    return cmd;
}
//Invia un comando alla SX16
int send2sx16 (int _fd, char *cmd2sx16, char *sx16return){
  int res;

  if (write(_fd, cmd2sx16, 6) < 0) {
    //Invio sulla seriale fallito
    return 0;
  } else {
    //Invio del comando riuscito
    usleep(100000); //sleep per 100mSec
    res = read(_fd,sx16return,6);
    sx16return[res]=0;
    return 1;
  }
}

////////////////////////////////
//
// MAIN
//
////////////////////////////////
main (int argc, char * argv[]) {
  int fd, res, i;
  int b;
  int cmd;
  struct termios oldtio,newtio;
  char buf[10];

  system("clear"); //Pulizia della console
  printf("Apertua Porta COM\n");
  fd = open(DEVICE, O_RDWR | O_NOCTTY);
  if (fd < 0 ) {
    printf("Device %s non pesente su questo sistema\n\n", DEVICE);
    exit(-1);
  }
  printf("Inizializzazione della comunicazione seriale\n");
  tcgetattr(fd,&oldtio); /* Salva i precedenti settaggi */
  bzero(&newtio, sizeof(newtio));
  newtio.c_cflag = BAUDRATE | CS8 | CLOCAL | CREAD;
  newtio.c_iflag = IGNPAR;
  newtio.c_oflag = 0;
  newtio.c_lflag = 0;
  newtio.c_cc[VTIME]    = 0;
  newtio.c_cc[VMIN]     = 6; 
  
  tcflush(fd, TCIFLUSH);
  tcsetattr(fd,TCSANOW,&newtio);
  //Inizializzazione device seriale terminata
  while (1){
    system("clear");
    //FORMATTO IL PACCHETTO DA MANDARE ALLA SERIALE
    buf[0]=0;
    buf[0]=START;
    buf[1]=ADDR;
    buf[2]=READ_CMD;
    buf[3]=ZERO_CHAR;
    buf[4]=ZERO_CHAR;
    buf[5]=ZERO_CHAR;
    if (send2sx16 (fd, buf, buf)) {
      if((buf[0]==RETURN_START) && (buf[1]==ADDR) && (buf[2]==READ_CMD)) {
        printf("---------------------------------------\n");
        printf(" LINUX 2 SX16\n\n");
        printf(" Ver: 1.0\n");
        printf(" Author: Daniele De Santis\n");
        printf(" E-Mail: [email protected]\n\n");
        printf(" STATO DELLE LINEE D'INPUT SULLA SX 16 \n");
        printf("---------------------------------------\n");
        printf("Stato degli ingressi CLC:\n");
        for (i=0; i<=7; i++){
          b = buf[3] & 1;
          buf[3] >>=1;
          if(b)
            printf("LINEA CLC %d    [X]  ON\n", (i + 1) );
          else
            printf("LINEA CLC %d    [ ]  OFF\n", (i + 1));
        }
        printf("Stato degli ingressi TTL:\n");
        for (i=0; i<=7; i++){
          b = buf[4] & 1;
          buf[4] >>=1;
          if(b)
            printf("LINEA TTL %d    [X]  ON\n", (i + 1) );
          else
            printf("LINEA TTL %d    [ ]  OFF\n", (i + 1));
        }
        printf("Stato degli ingressi OPTOISOLATE:\n");
        for (i=0; i<=7; i++){
          b = buf[5] & 1;
          buf[5] >>=1;
          if(b)
            printf("LINEA OPTO %d   [X]  ON\n", (i + 1) );
          else
            printf("LINEA OPTO %d   [ ]  OFF\n", (i + 1));
        }  
      }  else {
        printf("ERRORE -Risposta dalla SX16 non valida\n");
      }
      printf("\nCTRL+C per uscire\n");
      usleep(1000000 * DELAY_LOOP);
    } else {
      printf("ERRORE -Comunicazione con il device %s fallito\n", DEVICE);
      exit(-1);
    }
  }
  printf("\nChiusura comunicazione seriale...\n");
  tcsetattr(fd,TCSANOW,&oldtio);
  printf("Arrivederci :)\n");
  close(fd);
  exit(0);
}

Per la compilazione e l'esecuzione si deve procedere come per gli esempi precedenti.

Sulla console, lanciando il programma, apparirà una videata come a quella che segue:

Ogni dieci secondi la SX16 viene interrogata dal software e l'attivazione di un singolo ingresso viene segnalata con una X tra le parentesi "[ ]" della rispettiva riga che ne descrive il tipo di contatto.

Sorgenti in C d'esempio SX16_LINUX_SRC.zip


Segnala questo articolo: 



Parole chiave: - How-To - Linux - Schede Area SX -

Data di pubblicazione: 01-07-2005Hits: 25763
I marchi citati sono propriet� dei titolari dei relativi diritti. Le caratteristiche tecniche e i prezzi riportati sono indicativi e soggetti a variazioni senza preavviso. Le foto non hanno valore contrattuale. Nonostante accurate verifiche, il presente documento pu� contenere prezzi o specifiche errati. Area SX si scusa in anticipo e si impegna ad evitare tali imprecisioni.

 Area SX store
In questa sezione puoi ordinare direttamente i prodotti descritti in questo articolo
SX.PC.CONTROL;SX16-EXT;USBRF04;SX16-EXT-RF;KIT_RELE_DIN
Tutti i prezzi indicati sono espressi in Euro con IVA e spese di trasporto escluse. I prezzi si riferiscono al singolo pezzo
DescrizioneCodicePrezzo
Per maggiori informazioniUSB Radio Telemetry Module
Composto da due nostri prodotti tradizionali, la seriale Wireless ER400TRS e dal DLP-USB232M Convertitore USB Seriale RF, questa interessante device consente di collegare direttamente ad un computer la Scheda di I/O SX16 senza utilizzare fili!

Prodotto compliant RoHs
USBRF04€ 70.00
Per maggiori informazioniPer maggiori informazioni
Per maggiori informazioniRelè di potenza da barra DIN
Il Kit Relè da barra DIN è la soluzione ideale per controllare carichi con potenza massima di 10A e tensioni fino a 400V tramite le schede: SX16, FLEXOUTPUT e SXPY.

Caratteristiche tecniche:
  • Tensione bobina: 12V c.c.
  • Corrente massima sui contatti: 10A
  • Tensione massima sui contatti: 400V c.a.
  • Resistenza bobina: 300ohm
  • Isolamento bobina - contatto: 6000V c.a.
  • Contatto unipolare COMUNE N.A. N.C.
  • Montaggio: DIN rail socket
  • Dimensioni: 354x158x75


Prodotto compliant RoHs
KIT_RELE_DIN€ 25.00
Per maggiori informazioniPer maggiori informazioni

Rivenditori Social Contatti Condizioni
Area SX s.r.l
Via Stefano Longanesi 25
00146 Roma

Tel: +39.06.99.33.02.57
Fax: +39.06.62.20.27.85
P.IVA 06491151004
Condizioni di vendita
Procedura di rientro in garanzia
Condizioni per i rivenditori