Modbus Slave (server) por USB

Estoy jugando con Modbus en Arduino e hice una pequeña aplicación en C para leer datos del arduino conectado por USB.

Del lado server o slave hay que descargar Libreria para el Arduino e instalarla

El código del arduino es una modificación del ejemplo que viene con la librería, solo agregue una señal analógica de un potenciómetro.

#include <modbus.h>
#include <modbusDevice.h>
#include <modbusRegBank.h>
#include <modbusSlave.h>


//Setup the brewtrollers register bank
//All of the data accumulated will be stored here
modbusDevice regBank;
//Create the modbus slave protocol handler
modbusSlave slave;
const int analogInPin = A0;  // Analog input pin that the potentiometer is attached to
int sensorValue = 0;        // value read from the pot


void setup()
{   

  
//Assign the modbus device ID.  
  regBank.setId(1);



//Add Analog Output registers 40001-40020 to the register bank
  regBank.add(40001);  
  regBank.add(40002);  
 
  slave._device = &regBank;  

// Initialize the serial port for coms at 9600 baud  
  slave.setBaud(9600);   
}

void loop()
{

  
 while(1)
  {
     sensorValue = analogRead(analogInPin);
     regBank.set(40001, (word) sensorValue);
     slave.run();  
  }
}

En el lado del cliente o master (PC) hay que descargarse la Libreria libmodbus e instalarla (depende del sistema operativo y compilador que se use)

#include <stdio.h>
#include <modbus.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <termios.h>
uint16_t tab_reg[32];// array global donde se almacenan los datos obtenidos por modbus
int main()
{
int i;
/* Se abre el puero y se setea (no necesario en windows */
open("/dev/ttyACM0", O_RDWR | O_NOCTTY);
/* Setup estructura de  control  */
 struct termios toptions;
/* Wait for the Arduino to reset */
 usleep(1000*1000);
for(i=1;i<200;i++){
   //creacion de contexto modbus.En windows hay que colocar COM1, COM2 o donde se encuentre el Arduino
    modbus_t *mb;
    mb = modbus_new_rtu("/dev/ttyACM0",9600 , 'N', 8, 1);
    if (mb == NULL) {
    fprintf(stderr, "imposible crear contexto modbus\n");
          return -1;
     }
   modbus_set_slave(mb,1); //setea el numero de esclavo a consultar. El arduino tiene que estar seteado igual
   modbus_connect(mb);//Conecta al contexto creado
   modbus_read_registers(mb,0,2, tab_reg);// lee 2 registros a partir del registro "0"y los almacena en tab_reg
   printf(" Registro potenciometro %u\n     ",tab_reg[0]);// imprime en pantalla el valor leído
   modbus_free(mb);// libera el contexto
   modbus_close(mb);// cierra la coneccion
  }
 return 1;
}

Moviendo el potenciómetro se obtendría la siguiente salida

     Registro potenciometro 354
      Registro potenciometro 390
      Registro potenciometro 444
      Registro potenciometro 481
      Registro potenciometro 524
      Registro potenciometro 563
      Registro potenciometro 595
      Registro potenciometro 630
      Registro potenciometro 651
      Registro potenciometro 679
      Registro potenciometro 705
      Registro potenciometro 735
      Registro potenciometro 758
      Registro potenciometro 783
      Registro potenciometro 795
      Registro potenciometro 817
      Registro potenciometro 826
      Registro potenciometro 841
      Registro potenciometro 835
      Registro potenciometro 839
      Registro potenciometro 838
      Registro potenciometro 841
      Registro potenciometro 839
      Registro potenciometro 843
      Registro potenciometro 843
      Registro potenciometro 836
      Registro potenciometro 831
      Registro potenciometro 834
      Registro potenciometro 831
      Registro potenciometro 831
      Registro potenciometro 831
      Registro potenciometro 831
      Registro potenciometro 830
      Registro potenciometro 839
      Registro potenciometro 829
      Registro potenciometro 827
      Registro potenciometro 831
      Registro potenciometro 832
      Registro potenciometro 830
      Registro potenciometro 833
     martin@casa:~/Escritorio$

Algunos Avances

Agregue una función que inserta los datos obtenidos del potenciómetro en una base de datos MySQL.
Para que funcione hay que tener una base de datos llamada data_logger con una tabla llamada Potenciometro que consta de dos campos
Uno es un TIMESTAMP,currenttime, que la misma base de datos se encargara de llenar y otro llamado Lectura_potenciometro donde insertaremos el valor MODBUS

#include <stdio.h>
#include <modbus.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <termios.h>
#include <mysql/mysql.h>

#define Host "localhost" //lugar donde se encuentra localizada la base de datos
#define User "root" // Usuario con privilegios para guardar datos
#define pass "XXXXXXX" //clave del usuario
#define DB "data_logger"  //nombre de la base de datos
#define slave_modbus "/dev/ttyACM0" //en windosw probablemente COMX Donde X es donde se encuentra el arduino
#define slave_modbus_id 1

uint16_t tab_reg[32];// array global donde se almacenan los datos obtenidos por modbus


//***********************************************************************
int genera_consulta_modbus(){
int i;
/* Se abre el puero y se setea (no necesario en windows */
open(slave_modbus, O_RDWR | O_NOCTTY);
/* Setup estructura de  control  */
 struct termios toptions;
/* Wait for the Arduino to reset */
 usleep(1000*1000);

   //creacion de contexto modbus.En windows hay que colocar COM1, COM2 o donde se encuentre el Arduino
    modbus_t *mb;
    mb = modbus_new_rtu(slave_modbus,9600 , 'N', 8, 1);
    if (mb == NULL) {
    fprintf(stderr, "imposible crear contexto modbus\n");
          return -1;
     }
   modbus_set_slave(mb,slave_modbus_id); //setea el numero de esclavo a consultar. El arduino tiene que estar seteado igual
   modbus_connect(mb);//Conecta al contexto creado
   modbus_read_registers(mb,0,2, tab_reg);// lee 2 registros a partir del registro "0"y los almacena en tab_reg
   modbus_free(mb);// libera el contexto
   modbus_close(mb);// cierra la coneccion
}
//***************************************************************************


int Consulta_evento() //Colocar la condicion para que genere un evento
{
    return 1; //retorna 1 si se produjo un evento

}
//*****************************************************************************

int registra_dato_en_Mysql()
{
char consulta[1024];

MYSQL *con; //puntero a la coneccion Mysql
con=mysql_init(NULL); //inicilaiza la coneccion si no esta conectado
  if(!mysql_real_connect(con,Host,User,pass,DB,3303,NULL,0))
  {
     fprintf(stderr,"%s\n",mysql_error(con)); //imprime error si no se produce la coneccion
  return 1;



  }

sprintf(consulta,"INSERT INTO Potenciometro (Lectura_potenciometro) VALUES ('%u') ",tab_reg[0]);//construye le texto de la consulta
//printf(consulta);
 mysql_query(con,consulta); //consulta
mysql_close(con); //cierra coneccion

}

//****************************************************************************


int main()
    {
    int a=0;
    while(a==0)
        {
        if (Consulta_evento()==1)
            {
            genera_consulta_modbus();
            registra_dato_en_Mysql();
            }
   printf(" Registro potenciometro %u\n     ",tab_reg[0]);// imprime en pantalla el valor leido

        }
 return 1;
}

En breve me llega mis módulos RS485 y te sigo.

surbyte:
En breve me llega mis módulos RS485 y te sigo.

No estoy utilizando módulos RS485, estoy usando el USB del Arduino. Precisamente por eso encare este mini-proyecto casi toda la información de web sobre Modbus y Arduino hace referencia a RS485 o TCP/IP.

Saludos

Ahhh te mal entendí para variar jajaja.
Entonces si puedo probarlo.

Releyendo me acabo de dar cuenta que no lo puse en ningún lado.

Estou com um sensor de corrente elétrica e queria receber os resultados no scadabr alguém pode ajudar com este código tenho um exemplo mas não sei programa para Modbus serial.
EmonLibrary examples openenergymonitor.org, Licence GNU GPL V3
#include "EmonLib.h" // Include Emon Library
EnergyMonitor emon1; // Create an instance

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

emon1.current(1, 111.1); // Current: input pin, calibration.
}

void loop()
{
double Irms = emon1.calcIrms(1480); // Calculate Irms only

Serial.print(Irms*230.0); // Apparent power
Serial.print(" ");
Serial.println(Irms); // Irms
}

Estou com um sensor de corrente elétrica e queria receber os resultados no scadabr alguém pode ajudar com este código tenho um exemplo mas não sei programa para Modbus serial.
EmonLibrary examples openenergymonitor.org, Licence GNU GPL V3
#include "EmonLib.h" // Include Emon Library
EnergyMonitor emon1; // Create an instance

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

emon1.current(1, 111.1); // Current: input pin, calibration.
}

void loop()
{
double Irms = emon1.calcIrms(1480); // Calculate Irms only

Serial.print(Irms*230.0); // Apparent power
Serial.print(" ");
Serial.println(Irms); // Irms
}

No hay problema, abrí un nuevo post y lo charlamos.

Saludos

Agregue la función evento

#include <stdio.h>
#include <modbus.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <termios.h>
#include <mysql/mysql.h>
#include <time.h>

#define Host "localhost" //lugar donde se encuentra localizada la base de datos
#define User "root" // Usuario con privilegios para guardar datos
#define pass "fiorentina" //clave del usuario
#define DB "data_logger"  //nombre de la base de datos
#define slave_modbus "/dev/ttyACM0" //en windosw probablemente COMX Donde X es donde se encuentra el arduino
#define slave_modbus_id 1
 int tipo_de_evento =1;


 uint16_t  lapso=10; //lapso de tiempo de muestreo en segundos

uint16_t tab_reg[32];// array global donde se almacenan los datos obtenidos por modbus


//***********************************************************************
int genera_consulta_modbus(){
int i;
/* Se abre el puero y se setea (no necesario en windows */
open(slave_modbus, O_RDWR | O_NOCTTY);
/* Setup estructura de  control  */
 struct termios toptions;
/* Wait for the Arduino to reset */
 usleep(1000*1000);

   //creacion de contexto modbus.En windows hay que colocar COM1, COM2 o donde se encuentre el Arduino
    modbus_t *mb;
    mb = modbus_new_rtu(slave_modbus,9600 , 'N', 8, 1);
    if (mb == NULL) {
    fprintf(stderr, "imposible crear contexto modbus\n");
          return -1;
     }
   modbus_set_slave(mb,slave_modbus_id); //setea el numero de esclavo a consultar. El arduino tiene que estar seteado igual
   modbus_connect(mb);//Conecta al contexto creado
   modbus_read_registers(mb,0,2, tab_reg);// lee 2 registros a partir del registro "0"y los almacena en tab_reg
   modbus_free(mb);// libera el contexto
   modbus_close(mb);// cierra la coneccion
}
//***************************************************************************


int Consulta_evento(int tipo_de_evento, uint16_t lapso, uint16_t Dato_a_comparar ){

//si tipo_de evento =0 muestrea de forma continua
//si tipo_de evento =1 se muestrea lapso de tiempo
//si tipo_de evento =2 se muestrea por cambio de una variable
int32_t static valor_anterior_tiempo;
int32_t static valor_anterior_variable;

//------obtencion del tiempo del sistema en segundos (entero)-------
       time_t tempo_segundos;
       int32_t tiempo_calculo;
        struct tm * timeinfo;
       tzset ();
       tempo_segundos = time ( NULL );
       tiempo_calculo= (int32_t)tempo_segundos; //casting para convertilo en un entero

//--------------------------------------



switch(tipo_de_evento){




      case 0 :


         return 1;


      case 1 :// muestrea lapso de tiempo
                if (tiempo_calculo-valor_anterior_tiempo>=lapso ){
                valor_anterior_tiempo=tiempo_calculo;
                return 1;
                 }

      case 2 :
                if (valor_anterior_variable != Dato_a_comparar){
                valor_anterior_variable = Dato_a_comparar;
                return 1;
                }



return 0 ;
}
//-------------------------------


    return 1; //retorna 1 si se produjo un evento

}
//*****************************************************************************

int registra_dato_en_Mysql()
{
char consulta[1024];

MYSQL *con; //puntero a la coneccion Mysql
con=mysql_init(NULL); //inicilaiza la coneccion si no esta conectado
  if(!mysql_real_connect(con,Host,User,pass,DB,3303,NULL,0))
  {
     fprintf(stderr,"%s\n",mysql_error(con)); //imprime error si no se produce la coneccion
  return 1;



  }

sprintf(consulta,"INSERT INTO Potenciometro (Lectura_potenciometro) VALUES ('%u') ",tab_reg[0]);//construye le texto de la consulta
//printf(consulta);
 mysql_query(con,consulta); //consulta
mysql_close(con); //cierra coneccion

}


//****************************************************************************

int main()
    {
    int a=0;
    while(a==0)
        {
        if (Consulta_evento(tipo_de_evento,lapso,0)==1)
            {
            genera_consulta_modbus();
            registra_dato_en_Mysql();
            printf(" Registro potenciometro %u\n     ",tab_reg[0]);// imprime en pantalla el valor leido
            }


        }
	return 1;
}