danjperron
Posts: 2667
Joined: Thu Dec 27, 2012 4:05 am
Location: Québec, Canada

Multi-function RS-485 remote sensor

Mon Apr 21, 2014 3:52 am

This is a sequel of my water detect modbus system.

Sometimes we need to have sensors away of the raspberry PI and we need to connect them without too many wires.

I decide to use a small cpu like the PIC12F1840 which will have only 2 IO but could be daizy chain up to 127 modules using a simple RJ11 cable system. This is the same plug we use to connect telephone.

I was able to set different type of operation using the same binary code. This way we could set them online.
But since modbus protocol need to have a different slave address for each module, we need to set the address one by one.

This is the primary documentation about it

https://docs.google.com/document/d/1Nex ... sp=sharing

it is base on my preliminary water detect module

https://docs.google.com/document/d/1YN4 ... sp=sharing


The document explain acces via minimalmodbus in python.

But it is possible to use libmodbus in C. In my test , python will gives you around 20 transactions per second
but libmodbus will be around 200 with a Baud Rate of 57600.


This is the configuration application in C to select Slave address and IO configuration

you will need to install libmodbus

Code: Select all

sudo apt-get install libmodbus5 libmodbus-dev
and compile the code

Code: Select all

gcc -I /usr/include/modbus configPIC.c -o configPIC  -l modbus
And the configPIC.c code

Code: Select all

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <termios.h>

#include <modbus.h>

typedef struct
{
unsigned short     mode;
unsigned char * asciiMode;
}IOConfigStruct;

char device[256];
int Baud = 57600;

unsigned char scanOnly=0;
unsigned char CurrentSlaveAddress=255;

int IsModuleFound(modbus_t * mb, unsigned char  SlaveAddress);
unsigned char selectModule(modbus_t * mb);


IOConfigStruct  configInfo[]={
  {  0, "ANALOGVDD"},
  {  1, "ANALOG1V"},
  {  2, "ANALOG2V"},
  {  3, "ANALOG4V"},
  {  4, "INPUT"},
  {  5, "INPUT PULLUP"},
  {  6, "OUTPUT"},
  {  8, "CAP SENSE OFF"},
  {  9, "CAP SENSE LOW"},
  { 10, "CAP SENSE MEDIUM"},
  { 11, "CAP SENSE HIGH"},
  { 16, "DHT11"},
  { 17, "DHT22"},
  { 32, "DS18B20"},
  { 64, "R/C SERVO"},
  {128, "COUNTER"},
  {65535, NULL}};


int IsConfigModeValid(int mode)
{
  int loop;

  for(loop=0;;loop++)
   {
     if(configInfo[loop].mode==65535) break;
     if(configInfo[loop].mode==mode) return 1;
   }

 return 0;
}

char * configModeInText(int IOConfigMode)
{
   int loop;

   for(loop=0;;loop++)
    {
      if(configInfo[loop].mode==65535)
         break;
      if(configInfo[loop].mode== IOConfigMode) 
         return configInfo[loop].asciiMode;
    }

   return "???";
}


void decodeArg(int argc, char * argv[])
{
  int loop;

  for(loop=1;loop<argc;loop++)
   {
    if(strcasecmp(argv[loop],"-scan")==0)
      scanOnly=1;
    if(strcmp(argv[loop],"-d")==0)
      {
       loop++;
       strcpy(device,argv[loop]);
      }
    if(strcmp(argv[loop],"-b")==0)
      {
        loop++;
        Baud=atoi(argv[loop]);
      }
    if(strcmp(argv[loop],"--help")==0)
      {
        printf("usage:\nconfigPIC  [-scan][-d DeviceName][-b BaudRate]\n");
        exit(0);
      }
  }
}


void changeAddress(modbus_t * mb)
{

  int  new_Address;

  printf("\n=======Change Address\n");





  if(CurrentSlaveAddress == 255)
     selectModule(mb);
  else
     if(!IsModuleFound(mb,CurrentSlaveAddress))
       selectModule(mb);

  if(CurrentSlaveAddress==255) return;


   printf("\nEnter new Slave Address for this module (1..127) ?");

   if(scanf("%d",&new_Address)!=1)
      printf("Invalid value!  configuration not change.\n");
   else
     {
       if(new_Address>0)
        if(new_Address<128)
        {
          if(IsModuleFound(mb,new_Address))
          {
      	   modbus_set_slave(mb,CurrentSlaveAddress);
           printf("Address already used!\nConfiguration not changes.\n");
          }
          else
          {
   	   modbus_set_slave(mb,CurrentSlaveAddress);
           modbus_write_register(mb,160,new_Address);
           printf("Module is now on Address %d\n",new_Address);
           CurrentSlaveAddress=new_Address;
          }
        }
      else
       printf("Invalid value!  configuration not change.\n");
     }
   usleep(1000000); // delay needed to store data into eerom
   IsModuleFound(mb,CurrentSlaveAddress);

}


unsigned short  getConfigMode(modbus_t * mb, int Pin)
{
     uint16_t MB_Register;
     if( modbus_read_registers(mb,0x100+Pin,1,&MB_Register) < 0)
        return 65535;
     return MB_Register;
}

int IsModuleFound(modbus_t * mb, unsigned char  SlaveAddress)
{
   uint16_t MB_Register;
   int rcode;

   if(SlaveAddress >127) return 0;

   modbus_set_slave(mb,SlaveAddress);
   if (modbus_read_registers(mb,251,1,&MB_Register) <0) return 0;
   if(MB_Register != 0x6532)
     return 0;
   return 1;
}


unsigned char selectModule(modbus_t * mb)
{
   char buffer[256];
   int SlaveAddress;
   int rcode;
   uint16_t MB_Register;
   CurrentSlaveAddress=255;

   printf("Select Module\nEnter Slave Address ?");

   if(scanf("%d",&SlaveAddress)==1)
      if(SlaveAddress>0)
       if(SlaveAddress<128)
         if(IsModuleFound(mb,SlaveAddress))
           CurrentSlaveAddress=SlaveAddress;

  printf("\n");fflush(stdout);
  return SlaveAddress;
}



void changeConfigMode(modbus_t * mb,int Pin)
{
  
  int loop;
  unsigned short  mode;
  unsigned char  module;
  int  new_mode;
  uint16_t MB_mode;

  printf("\n=======  Change  IO%d mode\n",Pin);




  if(CurrentSlaveAddress == 255)
     selectModule(mb);
  else
     if(!IsModuleFound(mb,CurrentSlaveAddress))
       selectModule(mb);

  if(CurrentSlaveAddress==255) return;

  for(loop=0;;loop++)
    {

      if(configInfo[loop].mode==65535) break;

      if(loop%3==0)
        printf("\n");
      printf("%3d) %-20s",configInfo[loop].mode, configInfo[loop].asciiMode);
    }

   mode=getConfigMode(mb,Pin);
   printf("\n\nSlave address %d  current IO%d mode is %d : %-20s\n",CurrentSlaveAddress,Pin,mode,configModeInText(mode));

   printf("\nEnter new configuration ?");

   if(scanf("%d",&new_mode)!=1)
      printf("Invalid value!  configuration not change.\n");
   else
     {
      if(IsConfigModeValid(new_mode))
        {
          MB_mode= new_mode;
          modbus_write_register(mb,0x100+Pin,MB_mode);
         printf("Module %d  IO%d set to %d: %s\n",CurrentSlaveAddress,Pin,MB_mode,configModeInText(MB_mode));
        }
      else
       printf("Invalid value!  configuration not change.\n");
     }
   usleep(1000000); // delay needed to store data into eerom
}

void scanBus(modbus_t * mb)
{
  int loop,io;
  int rcode;
  uint16_t  MB_Register;



//set 1/100th of second response time
   struct timeval response;
   response.tv_sec=0;
   response.tv_usec=10000;
 modbus_set_response_timeout(mb, &response);


  printf("\n==== Scanning MODBUS\n");fflush(stdout);

  for(loop=1;loop<128;loop++)
  {

   if(IsModuleFound(mb,loop))
   {
    printf("%d : %-20s",loop,"PIC Multi-Purpose");

    for(io=0;io<2;io++)
    {
      printf("IO%d: ",io);
      printf("%-20s",configModeInText(getConfigMode(mb,io)));
    }
    printf("\n");
   }
 }
}


unsigned char ReadOneKey(void)
{
  char c;
  struct termios term,term_orig;

  // put keyboard in raw mode

  tcgetattr(0,&term_orig);
  memcpy(&term,&term_orig,sizeof(struct termios));
  term.c_lflag &= ~(ICANON | ECHO);
  term.c_cc[VTIME] =0;
  term.c_cc[VMIN]=1;
  tcsetattr(0,TCSANOW, &term);

  while(read(0, &c,1)!=1);

  tcsetattr(0,TCSANOW,&term_orig);
  fflush(stdin);
  return c;
}



void Menu(modbus_t * mb)
{
char  rcode;

 printf("\nPIC multi-purpose I/O  MODBUS configuration\n");
 printf("Version 1.0 (c) Daniel Perron, April 2014\n");
 printf("device:%s Baud Rate:%d\n",device,Baud);
 while(1)
  {
    // print menu
    printf("\n\n\nM) MODBUS scan \n");
    printf("S) Select Slave Module\n");
    printf("A) Change Slave Address\n");
    printf("0) Set IO0 mode\n");
    printf("1) Set IO1 mode\n");
    printf("Q) Quit\n");


    printf("\nSelected module :");

    if(CurrentSlaveAddress == 255)
     printf("None\n");
    else
     printf("%d\n",CurrentSlaveAddress);

    fflush(stdout);

    rcode= toupper(ReadOneKey());
    fflush(stdin);
    switch(rcode)
    {
     case 'M':  scanBus(mb);break;
     case 'S':  selectModule(mb);break;
     case 'A':  changeAddress(mb);break;
     case '0':  changeConfigMode(mb,0);break;
     case '1':  changeConfigMode(mb,1);break;
     case 'Q':  return;
    }
  }

}






int main(int argc, char * argv[])
{

   modbus_t *mb;

  strcpy(device,"/dev/ttyAMA0");

  decodeArg(argc,argv);

   mb = modbus_new_rtu(device,Baud,'N',8,1);
   modbus_connect(mb);

if(scanOnly==1)
  scanBus(mb);
else
   Menu(mb);

 modbus_close(mb);
 modbus_free(mb);
 return 0;
}
This http://www.ostafichuk.com/modbus-on-the ... c-example/ is a good link for libmodbus

Daniel

danjperron
Posts: 2667
Joined: Thu Dec 27, 2012 4:05 am
Location: Québec, Canada

Re: Multi-function RS-485 remote sensor

Wed Apr 23, 2014 4:05 am

This is an example of auto scanning the modbus and figure it out the sensor


First I set each module IOs to their corresponding sensor
M) MODBUS scan
S) Select Slave Module
A) Change Slave Address
0) Set IO0 mode
1) Set IO1 mode
Q) Quit

Selected module :None

==== Scanning MODBUS
1 : PIC Multi-Purpose IO0: CAP SENSE HIGH IO1: INPUT
2 : PIC Multi-Purpose IO0: DHT22 IO1: ANALOG1V
3 : PIC Multi-Purpose IO0: DS18B20 IO1: DS18B20
I made a small example program to scan all the possible address et return data from each remote sensor
pi@WebPi ~/MultiModbus $ ./test
23:59:57
Module[ 1]
IO0 CAP SENSE [0 (0x0000)] [13816 (0x35F8)]
IO1 DIGITAL [0 (0x0000)]
Module[ 2]
IO0 DHT22 Temp: 21.1 Celsius Humidity: 36.6%
IO1 ANALOG 1V TMP35 Temp: 18.8 Celsius
Module[ 3]
IO0 DS18B20 Temp: 20.2 Celsius
IO1 DS18B20 Temp: 20.1 Celsius
23:59:59
Module[ 1]
IO0 CAP SENSE [0 (0x0000)] [13814 (0x35F6)]
IO1 DIGITAL [0 (0x0000)]
Module[ 2]
IO0 DHT22 Temp: 21.1 Celsius Humidity: 36.5%
IO1 ANALOG 1V TMP35 Temp: 18.8 Celsius
Module[ 3]
IO0 DS18B20 Temp: 20.2 Celsius
IO1 DS18B20 Temp: 20.1 Celsius
And this is the source code for test.c

Code: Select all

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <time.h>
#include <modbus.h>


#define IOCONFIG_ANALOGVDD 0
#define IOCONFIG_ANALOG1V  1
#define IOCONFIG_ANALOG2V  2
#define IOCONFIG_ANALOG4V  3
#define IOCONFIG_INPUT     4
#define IOCONFIG_INPUT_PULLUP 5
#define IOCONFIG_OUTPUT    6

#define IOCONFIG_CAP_SENSE_OFF    8
#define IOCONFIG_CAP_SENSE_LOW 	  9
#define IOCONFIG_CAP_SENSE_MEDIUM 10
#define IOCONFIG_CAP_SENSE_HIGH   11


#define IOCONFIG_DHT11     16
#define IOCONFIG_DHT22     17
#define IOCONFIG_DS18B20   32
#define IOCONFIG_SERVO     64
#define IOCONFIG_COUNTER   128

void  ReadDHT22(modbus_t * mb,int _io)
{
    float Factor,Temperature,Humidity;
    static char status[256];
  uint16_t  MB_Register[3];

    printf("%-20s","DHT22");

    if(modbus_read_input_registers(mb,_io*16,3,MB_Register)>=0)
       {
         if(MB_Register[0]==0)
          {
            printf("Buzy"); 
          }
         else if (MB_Register[0]==1)
         {
           if(MB_Register[2] & 0x8000)
             Factor = (-0.1);
        else
             Factor = (0.1);
        Temperature = (MB_Register[2] & 0x7fff) * Factor;
        Humidity = (MB_Register[1] * 0.1);
        printf("Temp: %5.1f Celsius   Humidity: %5.1f%%",
          Temperature,Humidity);     
         }
         else printf("Error");
       }
     else
      printf("Unable to read DHT22 Sensor");
    printf("\n"); 
}

void ReadDS18B20(modbus_t * mb,int _io)
{
    float Factor,Temperature;
    int mask;
    short Temp;
    uint16_t  MB_Register[3];

    printf("%-20s","DS18B20");

    if(modbus_read_input_registers(mb,_io*16,3,MB_Register)>=0)
       {
         if(MB_Register[0]==0)
          {
            printf("Buzy"); 
          }
         else if (MB_Register[0]==1)
         {
           mask = MB_Register[2] & 0x60;
           switch(mask)
           {
            case 0 :   Factor = 0.0625/8.0;break;
            case 0x20: Factor = 0.0625/4.0;break;
            case 0x40: Factor = 0.0625/2.0;break;
            default:   Factor = 0.0625;
           }
           Temperature = Factor * ((short)MB_Register[1]);
           printf("Temp: %5.1f Celsius",Temperature);
         }
         else printf("Error");
       }
     else
      printf("Unable to read  Sensor");
     printf("\n");
}

void ReadTMP35(modbus_t * mb,int _io)
{
  uint16_t Temp;

    printf("%-20s","ANALOG 1V TMP35");
    if(modbus_read_input_registers(mb,_io*16,1,&Temp)>=0)
      printf("Temp: %5.1f Celsius\n",0.1 * Temp);
    else
      printf("Unable to read  input register\n");


}


void RawData(modbus_t * mb, unsigned char _io, char * Label, unsigned char Size)
{
  uint16_t MB_Register[3];
  int loop;
    printf("%-20s",Label);
  if(modbus_read_input_registers(mb,_io*16,Size,MB_Register)<0)
     printf("Unable to read\n",Label);
  else
  {
    
    for(loop=0;loop<Size;loop++)
      printf("[%d (0x%04X)] ",MB_Register[loop],MB_Register[loop]);
    printf("\n");
  }
}



void PrintModule(modbus_t * mb,unsigned char _module)
{
   uint16_t MB_Register[3];
   uint16_t ModeIO[2];
   int _io;
   int Flag=1;
   printf("     Module[%3d]",_module);

   // Set Slave module
     modbus_set_slave(mb,_module);

   // Get COnfiguration
     if(modbus_read_registers(mb,0x100,1,&ModeIO[0])<0)
       Flag=0;
     if(modbus_read_registers(mb,0x101,1,&ModeIO[1])<0)
       Flag=0;
  
     if(Flag)
        printf("\n");
     else
        {
         printf("Unable to read module\n");
         return;
        }

   for(_io=0;_io<2;_io++)
   {

     printf("%12s IO%d :"," ",_io);

     switch(ModeIO[_io])
      {
       case IOCONFIG_ANALOGVDD: RawData(mb,_io,"ANALOG Vref=VDD",1);break;
       case IOCONFIG_ANALOG1V:  ReadTMP35(mb,_io);break;
       case IOCONFIG_ANALOG2V:  RawData(mb,_io,"ANALOG Vref=2.048V",1);break;
       case IOCONFIG_ANALOG4V:  RawData(mb,_io,"ANALOG Vref=4.096V",1);break;

       case IOCONFIG_INPUT:     
       case IOCONFIG_INPUT_PULLUP:
       case IOCONFIG_OUTPUT:     RawData(mb,_io,"DIGITAL",1);break;

       case IOCONFIG_CAP_SENSE_OFF:
       case IOCONFIG_CAP_SENSE_LOW:
       case IOCONFIG_CAP_SENSE_MEDIUM:
       case IOCONFIG_CAP_SENSE_HIGH:  RawData(mb,_io,"CAP SENSE",2);break;


       case IOCONFIG_DHT11:       RawData(mb,_io,"DHT11",3);break;
       case IOCONFIG_DHT22:       ReadDHT22(mb,_io);break;
       case IOCONFIG_DS18B20:     ReadDS18B20(mb,_io);break;
       case IOCONFIG_SERVO:       RawData(mb,_io,"R/C SERVO",1);break;
       case IOCONFIG_COUNTER:    RawData(mb,_io,"COUNTER",3);break;
      }

 }

}




int main(int argc, char * argv[])
{
  time_t now;
  struct tm tmnow;
  int module,io;
  uint16_t  MB_Register[3];



   modbus_t *mb;

   mb = modbus_new_rtu("/dev/ttyAMA0",57600,'N',8,1);
   modbus_connect(mb);


   // Fset time out to 1/100 of second
   struct timeval response;
   response.tv_sec=0;
   response.tv_usec=10000;
   modbus_set_response_timeout(mb, &response);


    for(;;)
   {
       now = time(NULL);
       tmnow = *localtime(&now);

       printf("%2d:%02d:%02d\n",
       tmnow.tm_hour,tmnow.tm_min,tmnow.tm_sec);



       for(module=1;module<128;module++)
         {
           // check for release version
           modbus_set_slave(mb,module);
           if(modbus_read_registers(mb,251,1,MB_Register)<0)
              continue;

           PrintModule(mb,module);

         }


 usleep(1000000);
  }

 modbus_close(mb);
 modbus_free(mb);
 return 0;
}
and this is the schematic of the small board
Image

Daniel

danjperron
Posts: 2667
Joined: Thu Dec 27, 2012 4:05 am
Location: Québec, Canada

Re: Multi-function RS-485 remote sensor

Thu Apr 24, 2014 12:10 am

I put the source code of the remote sensor

in github.

https://github.com/danjperron/PicMultiPurpose.git


Now I will fix the documentation and make a very small pcb with RJ11 connector has soon I received the usb to RS-485 adapter. I need to verify which pins the adapter use on RJ11. I want to match the connection pin to pin.


Daniel

MariaLemone
Posts: 2
Joined: Thu Apr 24, 2014 5:14 pm

Re: Multi-function RS-485 remote sensor

Thu Apr 24, 2014 5:31 pm

Here are some other Modbus RTU based remote data acquisition devices for taking 4-20mA, 0-10V, +/-10V, Temperature, Thermocouple, RTD, Thermistor, digital, analog and other measurements.

http://www.icpdas-usa.com/m7000_analog_digital.php

Maria Lemone
ICP DAS USA
http://www.icpdas-usa.com
1-310-517-9888 ext 105

danjperron
Posts: 2667
Joined: Thu Dec 27, 2012 4:05 am
Location: Québec, Canada

Re: Multi-function RS-485 remote sensor

Fri Apr 25, 2014 5:02 pm

Wow

Couple of hundred dollars versus something around $10.


Obviously we are not on the same league and we won't be on the same market. They are more like industrial and with multi io on the same spot. My remote sensor is more like one or two sensors with a long distance range.

Daniel

danjperron
Posts: 2667
Joined: Thu Dec 27, 2012 4:05 am
Location: Québec, Canada

Re: Multi-function RS-485 remote sensor

Mon May 19, 2014 2:12 pm

This is a new version with 10 IO pins configurable.

The protocol is ModBus , the same than the 2 I/O version.

Image

The source code is on github

https://github.com/danjperron/PIC_MULTI_10_IO.git

The code has been modified to minimize impact of interrupt routine ( a lot of assembly code and use of method to disperse priority). The DHT sensor and the R/C servo are the problematic ones. I still have a tiny little glitch o the R/C servo since the PWM for servo are in software. I also double check the DHT-22.


You could use Rs-485 or by removing the Rs-485 driver connect the module directly to the TTY of the Raspberry Pi, like the picture of the prototype. Also it is possible to use a bluetooth serial adapter, a XBee module or simply an usb to serial ttl adapter (like the one to program the arduino mini).

But only the RS-485 will allow to put more than one module together. With bluetooth and XBee is possible to communicate with more than one but is more complicated.

In the Github you will have two application in C.

configPIC -> Tool to set each IO pin mode.
test -> This application scan all 127 address of modbus and display each IO values.


This is the output of the application test with the current setup (Same has the image above).

Code: Select all

pi@WebPi ~/MultiModbus $ ./test
10:10:01
     Module[127] ID:653A  Version: 1.00  VDD:  5.02V 
             IO0 :PWM                 [666 (0x029A)]
             IO1 :DS18B20             Temp:  17.6 Celsius
             IO2 :COUNTER             Count:   20280217   Pulse/sec: 492
             IO3 :DHT22               Temp:  18.0 Celsius   Humidity:  33.3%
             IO4 :DIGITAL             [1 (0x0001)] 
             IO5 :DS18B20             Temp:  17.7 Celsius
             IO6 :DIGITAL             [0 (0x0000)] 
             IO7 :ANALOG Vref=1.024V  [156 (0x009C)] 
             IO8 :DIGITAL             [0 (0x0000)] 
             IO9 :R/C SERVO           [2000 (0x07D0)]

I'm on the PCB right now . I will add the XBee adapter.


Daniel
Last edited by danjperron on Sun Mar 19, 2017 3:26 pm, edited 1 time in total.

danjperron
Posts: 2667
Joined: Thu Dec 27, 2012 4:05 am
Location: Québec, Canada

Re: Multi-function RS-485 remote sensor

Tue May 20, 2014 3:14 am

I modified the protoboard and added a XBee adapter. I'm still using the modbus protocol but I need to increase the timeout delay.

This way I was able to use the module in wireless mode.


On the Raspberry Pi I used the Xbee with the DFRobot usb to Xbee adapter. It could be used also like an usb to ttl serial adapter.

Image

I also use a usb battery pack to show that it is completely wireless.

This is a small video to demonstrate how easy it is to configure the module.

I set the ds18b20 , the dht22 sensor. I also set the R/C Servo with some values and finally change the pwm output signal to a led.

https://www.dropbox.com/s/gd6305alstmj9 ... e.mp4?dl=0


Daniel
Last edited by danjperron on Sun Mar 19, 2017 3:29 pm, edited 1 time in total.

danjperron
Posts: 2667
Joined: Thu Dec 27, 2012 4:05 am
Location: Québec, Canada

Re: Multi-function RS-485 remote sensor

Sat Jun 14, 2014 12:56 am

I just received my orders with three different type of RS-485 adapters.

They all works except they are connected differently.


The first one is the USB to 485 adapter. Really simple to implement and no handshake needed since it is done automatically.

The adapter , when it is connected, will simply add a serial device into the Raspberry. (/dev/ttyUSB0)

Image

The two others devices are shields, 5V and 3.3V adapter which you connect using the GPIO RX/TX pins. (/dev/ttyAMA0)

On both devices you need to take care of the received/transmit handshake. For this reason I use my rs485 switcher program with the PIC12F1840 cpu. This is a very simple solution to deal with the handshake. I don't have to implement it into the Rpi.

On the 5V adapter, you need to take care of the RO signal by reducing the maximum current it delivers to the gpio. A simple 4k7 resistor in serie will limit the current to prevent the 3.3V to increase.

Image

The 3.3V adapter is directly connected , with my cpu handshake handler, to the GPIO.
But we need to get 3.3V not from the RPI since there is only 30ma available.

Image

My cpu code for the Receive/transmit handshake is in the github .

https://github.com/danjperron/NoContactWaterDetect.git

I like the USB!
It is simple and very clean to install, except no hole to mount it.

Daniel
Last edited by danjperron on Sun Mar 19, 2017 3:31 pm, edited 1 time in total.

caglar
Posts: 13
Joined: Tue Apr 08, 2014 11:15 am

Re: Multi-function RS-485 remote sensor

Tue Jul 08, 2014 10:27 am

Hi Daniel,

I just got this USB to serial (RS-485) dongle http://www.ebay.com/itm/K1BO-USB-to-RS4 ... 3f31761ce9 and I would like to send commands to a particle counter's registers. I can see the dongle for the output of lsusb and it is attached to ttyUSB0 (output from dmesg). Since the module has its driver that is installed to Rpi I suppose I don't need an another CPU for handshake right ?. I installed pymodbus but I see that you've been using minimalmodbus so I can swap the library if its necessary. What I don't know is how to send data to a specifıc register with modbus RTU.

So to start with, I set up the parameters for serial comm as shown below.

Code: Select all

USBPort = serial.Serial(
                               "/dev/ttyUSB0",
                                baudrate = 57600,
                                parity = serial.PARITY_NONE,
                               stopbits = serial.STOPBITS_ONE,
                               bytesize = serial.EIGHTBITS,
                               writeTimeout = 0,
                               timeout = 5,
                               rtscts = False,
                               dsrdtr = False,
                               xonxoff = False)

data = bytes([0x0c])
USBPort.write(data)
                                
As you can see, I did not specify the register. When I run this, I do not see anything on osciloscope.

Best Wishes

Caglar Sekmen

danjperron
Posts: 2667
Joined: Thu Dec 27, 2012 4:05 am
Location: Québec, Canada

Re: Multi-function RS-485 remote sensor

Tue Jul 08, 2014 11:48 am

I'm on vacation right now.
I only have my tablet with me.

Did you check my code in the github.

Using python or C, is a question of taste but ultimately on speed.

If you use python, You should check my github and the file

https://github.com/danjperron/PIC_MULTI ... cModule.py

Try to read or write to a register instead. Don't forget that the signal is in differential mode . Did you check the signal after the receiver? or just at the transmitter?

The problem with ebay post is there gone fast. I can't read your ebay link! Then I don't know what you bought. :-/

But if it is usb, the handshake is buil-in.

If you have more question please free to ask.

Have fun to decode my python code :-)

From Barcelona,
Daniel

caglar
Posts: 13
Joined: Tue Apr 08, 2014 11:15 am

Re: Multi-function RS-485 remote sensor

Tue Jul 22, 2014 8:58 am

Hi Daniel,

I am still not sure which library to use (pymodbus, or minimalmodbus). Also, the configuration for the connection is an another issue. I have seen plenty of examples for pymodbus but all seem like for server based communication. I will keep digging it :) .. in the mean time do you have anything useful for pymodbus over serial line ?

Regards

Caglar Sekmen

danjperron
Posts: 2667
Joined: Thu Dec 27, 2012 4:05 am
Location: Québec, Canada

Re: Multi-function RS-485 remote sensor

Tue Jul 22, 2014 10:51 am

Modbus protocol is a master/slave protocol. The Raspberry Pi will be the master.

Both works well but I prefer minimal modbus libmodbus because of speed issue.

For PymodbusThis is an example with minimal modbus you need to open the port , Specify the slave address and send the read or write information.

something like this

Code: Select all

#!/usr/bin/python3.2
import minimalmodbus
module = minimalmodbus.Instrument('/dev/ttyUSB0',1)
module.serial.baudrate= 9600
module.serial.timeout=0.02
module.serial.flushInput()

register1 = module.read_register(1,0,4)
holdingregister = module.read_register(1,0,3)

...
...

I don't use Pymodbus!
I correct this post. I didn't have my coffee when I started to write this morning ;-)


http://web.eecs.umich.edu/~modbus/docum ... US_300.pdf

Daniel

danjperron
Posts: 2667
Joined: Thu Dec 27, 2012 4:05 am
Location: Québec, Canada

Re: Multi-function RS-485 remote sensor

Tue Jul 22, 2014 9:33 pm

Hi Caglar,


I did check pymodbus. Works fine but I had to enable the ctsrts handshake.

This is my demo code, on one of my MultiIO module, with pymodbus using rtu on an usb rs-485 adapter.

Code: Select all

#!/usr/bin/python2.7

from pymodbus.client.sync import ModbusSerialClient as ModbusClient
client = ModbusClient(method='rtu', port='/dev/ttyUSB0', 
                      stopbits=1, bytesize=8, timeout=0.3, 
                      baudrate=57600)
client.connect()

#enable hardware handshake IMPORTANT
client.socket.rtscts=True

#specify which slave you want to talk to 
myUnit=127

#read  module Identification
reg = client.read_holding_registers(251,1, unit=myUnit)
print "Module Id = {}".format(hex(reg.registers[0]))

#read  Version
reg = client.read_holding_registers(250,1, unit = myUnit)
print "Version {}.{}".format(reg.registers[0]>>8, (reg.registers[0] & 0xff))

#read I/2 DHT22 temperature

reg = client.read_input_registers(32,4, unit = myUnit)
print "I/O 2   DHT22 :  {} Celsius,  {} % Humidity".format(reg.registers[2]/10.0, reg.registers[1]/10.0)

client.close()
This is the output of the executable

Code: Select all

pi@WebPi ~ $ ./pymodtest.py
Module Id = 0x653a
Version 1.0
I/O 2   DHT22 :  24.8 Celsius,  39.7 % Humidity
pi@WebPi ~ $ 
I did'n add any check or retry commands.

Daniel

danjperron
Posts: 2667
Joined: Thu Dec 27, 2012 4:05 am
Location: Québec, Canada

Re: Multi-function RS-485 remote sensor

Wed Jul 23, 2014 10:48 am

After playing with the pymodbus, I found out that it is waiting for the timeout and I can't put it very short.

Then minimal modbus is faster in python.


And this is the usb to RS-485 I was using (http://www.dx.com/p/296620). At this price, It is cost effective to use the usb instead of a I.C. convert to the 3.3 V TTL uart. (ttyAMA0).

Daniel

danjperron
Posts: 2667
Joined: Thu Dec 27, 2012 4:05 am
Location: Québec, Canada

Re: Multi-function RS-485 remote sensor

Thu Sep 25, 2014 3:21 am

I finally received my pcb.

Image

This is seven working modules on test using the raspberry pi.
Image

The configPIC application was able to see them without a glitch.

I update the Github and add the Gerber file if somebody interested. The cost of the pcb, was around $20 US for 10 pcbs, including the transport.

Still have to modify the Boxes which are the 1591ASFLBK from Hammond.

And of course I need to make the documentation

Daniel
Last edited by danjperron on Sun Mar 19, 2017 3:33 pm, edited 2 times in total.

danjperron
Posts: 2667
Joined: Thu Dec 27, 2012 4:05 am
Location: Québec, Canada

Re: Multi-function RS-485 remote sensor

Sat Sep 27, 2014 6:39 pm

I got a small problem with the Xbee. I had to cut a trace and replace one capacitor by a 10uF otherwise the XBee power was too noisy.

This is a small demo of 3 modules using Xbee series 1 with only one 9V battery.

The first module has 2 servos. The second one reads a DHT22 and a DS18B20. And the Third one toggles relay and reads water level from a bottle using the capacitive sensor build-in the cpu.

The main module is attached to the Raspberry PI with a USB adapter. it is transmitting in broadcast mode,to all. All the other xbee are set to transmit to the Raspberry Pi Xbee.

https://www.dropbox.com/s/26hh9hzdx66ro ... 2.mp4?dl=0

I will modify the gerber and the schematic. Now I need to create the C++ classe to implement all the sensor.

I know that Xbee is more expensive than some other RF transmitter but it has encryption possibilities and for me this is very important.

Daniel
Last edited by danjperron on Sun Mar 19, 2017 3:33 pm, edited 1 time in total.

Apnea
Posts: 2
Joined: Sun Nov 16, 2014 5:11 am

Re: Multi-function RS-485 remote sensor

Sun Nov 16, 2014 5:33 am

Hi Daniel,

I have a small project I want to try do for a friend. I plan to use a RPI as a data logger for a VSD (ABB ACS550). From some of your posts and others I have decided to go with a USB-485 device from DX.

I have read through your different projects and stages. I am a little confused as to what I should use, pymodbus, minimalmobus or libmodbus. Then there is .py and .c code. I really struggle with the code side of things.

Do you have sample code I could use and expand on just for the usb-4485 device?

Thanks in advance..

Cheers,
AP

danjperron
Posts: 2667
Joined: Thu Dec 27, 2012 4:05 am
Location: Québec, Canada

Re: Multi-function RS-485 remote sensor

Sun Nov 16, 2014 1:56 pm

Hi,

I quickly read the ACS550 manual and it should be possible to communicate with it.

First you need to set the protocol ,the baud rate and the modbus address (from page 199, 212 )

I.M.O. I will use python since you will be able to communicate on the fly with the instrument.


First install python-pip and minimalmodbus

Code: Select all

sudo apt-get install python-pip
sudo pip install -U minimalmodbus
The usb adapter should be /dev/ttyUSB0 if you have no other serial adapter interface connected to it. I assuming Raspbian OS.

Open Python and try to communicate with the instrument

Code: Select all

>>> import minimalmodbus
>>> motor = minimalmodbus.Instrument('/dev/ttyUSB0', 1)
>>> motor.serial.baurate=9600
>>> motor.serial.stopbits=2
>>> motor.read_bit(0)
This should read the "stop" input from the unit if you didn't change all default to the instrument. Be sure that it is on modbus at 9600 baud and set the parity and stop bit correctly.

The rest is up to you. Be familiar with python.
Please read the modbus pdf document and the minimalmodbus.

http://web.eecs.umich.edu/~modbus/docum ... US_300.pdf
http://minimalmodbus.sourceforge.net


Daniel

Apnea
Posts: 2
Joined: Sun Nov 16, 2014 5:11 am

Re: Multi-function RS-485 remote sensor

Mon Nov 17, 2014 9:52 am

Thanks for the quick reply Daniel. I will have a go later this week to setup the basics, but will have to wait until the usb units come.

I'll let you know how I go.

Cheers

webzterd
Posts: 15
Joined: Sun Dec 07, 2014 8:47 am

Re: Multi-function RS-485 remote sensor

Sun Dec 21, 2014 9:43 am

First I apologise, I have done an amount of scan reading last coding etc. but I was hoping you could consolidate into an answer for me:

I think I undertsand that this offers input/output by a remote board that can be daisy chained together, but how many inputs/outputs does each board offer?

and would the outputs be able to drive relay boards?

I know most of this is in there already but from the first IO mentions there are a number of developments made in your design that the skim reading haven't fully picked up on

webzterd
Posts: 15
Joined: Sun Dec 07, 2014 8:47 am

Re: Multi-function RS-485 remote sensor

Sun Dec 21, 2014 10:22 am

^^^ ignore me, had some breakfast, took the dog for a walk and re-read it :)

danjperron
Posts: 2667
Joined: Thu Dec 27, 2012 4:05 am
Location: Québec, Canada

Re: Multi-function RS-485 remote sensor

Sun Dec 21, 2014 2:31 pm

Hi webzterd,

This board have 10 I/Os which could be set to all output.

In the end of my document , sorry it is in french, there is code on how to create a webiopi server with three modules all connected to a 8 relays board. This way you have a simple interface web page to enable or disable appliances.

https://docs.google.com/document/d/1JIR ... sp=sharing

Image

Since I have a Xbee socket on the board I will eventually post code for android , using bluetooth, to control them. The code is on is way but I have some contract to do before returning to this project.
Image

A bluetooth adapter could be inserted instead of a Xbee module.(J4 need to be removed and don't put the RS-485 I.C.)
Image


If you want to create a setup like that. Use a 12V power supply with 12V relay board. This way you reduce the current load on the cable. A cable with 4 wires will drive serial signal and power signal. Two wires for RS-485 , one for ground and one for 12V.

This is a crude setup on how I test the webiopi server. Since then I bought 8 relays modules at 12V. My nephew is currently doing the three modules setup to powered an gagdet panel display.

Image




Daniel
Last edited by danjperron on Sun Mar 19, 2017 3:35 pm, edited 1 time in total.

danjperron
Posts: 2667
Joined: Thu Dec 27, 2012 4:05 am
Location: Québec, Canada

Re: Multi-function RS-485 remote sensor

Fri Dec 26, 2014 9:22 pm

This is a preliminary translation of my french document about this module.

https://docs.google.com/document/d/1lXs ... sp=sharing


Daniel

Asad masood
Posts: 2
Joined: Mon Jan 05, 2015 11:04 am

Re: Multi-function RS-485 remote sensor

Mon Jan 05, 2015 12:04 pm

sir
i am planning to use Xbee for connecting my PIR and temperature sensor to rpi
but i want that if PIR sensor detects anything it will generate an interrupt in code which i am running in rpi
Can you help me with that
i am New with python :cry:

Best regards
Asad Masood

danjperron
Posts: 2667
Joined: Thu Dec 27, 2012 4:05 am
Location: Québec, Canada

Re: Multi-function RS-485 remote sensor

Mon Jan 05, 2015 12:24 pm

There is two mode with the Xbee.

One mode looks like you have a single serial communication.

The other use a protocol to get information about the Xbee. You should read about that one.

You could use one of the Xbee Pin directly connected to your PIR. No need for other processor just the Xbee by itself.

A Xbee to USB adapter will be the best since you could use it to program the Xbee. Way simpler with a PC.

After that link both Xbee together and made a small program to read the specific Xbee IO pin every second. It is quit simple In Python.

Could you make a new post about that issue! I wall be glad to help you a some people search for xbee in the forum title could give you more hint.

It has nothing to do with RS-485 or multi-function remote.


B.T.W.

Return to “Interfacing (DSI, CSI, I2C, etc.)”

Who is online

Users browsing this forum: No registered users and 12 guests