Modbus Haberleşme Sorunu

Başlatan thenorthstar, 08 Nisan 2011, 14:20:24

thenorthstar

Merhaba arkadaşlar.
18f452 ile Modbus_ Master ve Slave çalışması yapmaya çalışıyorum. Slave kart ile yaptığım çalışmada LM35 ile sıcaklığı okuyup Modbus Poll programı ile slave kart tan bilgileri okuya biliyorum, birde 18f452 ile Master kart yaptım, slave karttan bilgileri alıp Master kart üzerindeki LCD de göstermek istedim fakat değişik değerlergeliyor, bir türlü sağlıklı bilgi alamadım,Bu konuda yardımcı olabilirmisiniz acaba.
Master Code:
#include <18f452.h>
#fuses XT,NOWDT,NOPROTECT,NOBROWNOUT,NOLVP,NOPUT,NOWRT,NODEBUG,NOCPD
#use delay(clock=10000000)
#use fast_io(a)
#use fast_io(d) //Port yönlendirme komutları D portu için geçerli

#define MODBUS_TYPE MODBUS_TYPE_MASTER
#define MODBUS_SERIAL_TYPE MODBUS_RTU
#define MODBUS_SERIAL_RX_BUFFER_SIZE 64
#define MODBUS_SERIAL_BAUD 38400
#define MODBUS_SERIAL_RX_PIN PIN_C7
#define MODBUS_SERIAL_TX_PIN PIN_C6
#define MODBUS_SERIAL_ENABLE_PIN PIN_C5
#define MODBUS_SERIAL_INT_SOURCE MODBUS_INT_RDA

#include <modbus.c>
#define MODBUS_SLAVE_ADDRESS 01
#include "2x16_4x20_LCD.c"


int i;

/*This function may come in handy for you since MODBUS uses MSB first.*/
int8 swap_bits(int8 c)
{
   return ((c&1)?128:0)|((c&2)?64:0)|((c&4)?32:0)|((c&8)?16:0)|((c&16)?8:0)
          |((c&32)?4:0)|((c&64)?2:0)|((c&128)?1:0);
}

void read_all_holding()
{  

if(!(modbus_read_holding_registers(MODBUS_SLAVE_ADDRESS,0,2)))
   {
     /*Started at 1 since 0 is quantity of coils*/
    LCD_gotoxy(1,1);
    printf(lcd_putc,"Modbus OK.....");
    for(i=1; i < (modbus_rx.len); ++i)
    LCD_gotoxy(2,2);
    printf(lcd_putc,"Temp=%3.1u", modbus_rx.data[i]);

   } 
   else
   {
    LCD_gotoxy(2,3);
    printf(lcd_putc,"Modbus Hata");
    LCD_gotoxy(3,4);
    printf(lcd_putc,"Error=%D ", modbus_rx.error);
   }
}

void main()
{
  setup_adc_ports(NO_ANALOGS);
  set_tris_d(0b00000000); 
   
   modbus_init();
   lcd_init();
while ( true )

{

   read_all_holding();

}
}


Slave Code:
//================================================================================

//================================================================================

#include <18F452.h>
#device ADC=10  // 10 bitlik ADC 
#fuses   HS, NOWDT,NOLVP, NOPROTECT,NOBROWNOUT, NOPUT, STVREN, NODEBUG, NOWRT, NOWRTD, NOWRTB, NOWRTC, NOCPD, NOCPB, NOEBTR, NOEBTRB
#use delay(clock=10000000)
#use fast_io(a)
#define MODBUS_TYPE MODBUS_TYPE_SLAVE
#define MODBUS_SERIAL_RX_BUFFER_SIZE 64
#define MODBUS_SERIAL_BAUD 38400
#define MODBUS_SERIAL_RX_PIN PIN_C7
#define MODBUS_SERIAL_TX_PIN PIN_C6
#define MODBUS_SERIAL_ENABLE_PIN PIN_C5
#define MODBUS_SERIAL_RX_ENABLE  PIN_C5            // Controls RE pin for RS485 transceiver
#define MODBUS_SERIAL_INT_SOURCE MODBUS_INT_RDA
#define MODBUS_SERIAL_TYPE       MODBUS_RTU        // use MODBUS_ASCII for ASCII mode
#include <modbus.c>

#define MODBUS_ADDRESS 01
#include "2x16_4x20_LCD.c"

//=============================================================================
#define OUT1 PIN_C0
#define OUT2 PIN_C1
#define OUT3 PIN_E1
#define OUT4 PIN_E2


//=============================================================================
int8 coils = 0b00000000;
int8 inputs = 0b00000000;
int16 hold_regs[] = {0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000};
int16 input_regs[] = {0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000};
int16 event_count = 0;
unsigned long int Ham_Deger,Ham_Deger2;
float Temp,sicaklik,Temp2,sicaklik2;
int32 sayi=0; // Tamsayı tipinde değişken tanımlanıyor
int a,i;

/*This function may come in handy for you since MODBUS uses MSB first.*/
int8 swap_bits(int8 c)
{
   return ((c&1)?128:0)|((c&2)?64:0)|((c&4)?32:0)|((c&8)?16:0)|((c&16)?8:0)
          |((c&32)?4:0)|((c&64)?2:0)|((c&128)?1:0);
}


void LM35_Oku ()
{
      set_adc_channel( 0 );
      delay_us(10);
      Ham_Deger=read_adc();  
      Temp=(0.0048828125*Ham_Deger)*1000;   // Dijitale çevirme işlemine uğrayan sinyalin mV olarak gerilimi hesaplanıyor
      sicaklik=(Temp/10);    // Her 10mV'ta 1 derece artma
      LCD_gotoxy(1,2);                                           // gönderilmek 
      printf(lcd_putc,"Temp1=%5.1f'C",sicaklik); 

      set_adc_channel( 1 );
      delay_us(10);
      Ham_Deger2=read_adc();  
      Temp2=(0.0048828125*Ham_Deger2)*1000;   // Dijitale çevirme işlemine uğrayan sinyalin mV olarak gerilimi hesaplanıyor
      sicaklik2=(Temp2/10);    // Her 10mV'ta 1 derece artma
      LCD_gotoxy(1,3);                                           // gönderilmek 
      printf(lcd_putc,"Temp2=%5.1f'C",sicaklik2); 



}

void LCD_OKU ()
{
   LCD_gotoxy(3,1); 
   printf(lcd_putc,"SLAVE ID=%d",MODBUS_ADDRESS);
}

void main()
{

   setup_adc(adc_clock_div_32);   // ADC clock frekansı fosc/32
   setup_adc_ports(AN0_AN1_AN3);
   delay_ms(10);            //1 sn bekle
   
   modbus_init();
   lcd_init();
  

   while(TRUE)
   {
 
   LM35_Oku ();
   LCD_OKU ();
  // Sicaklik = Sicaklik * 10;
   hold_regs[0]=Sicaklik;
   hold_regs[1]=Sicaklik2;

 
//!   if (INPUT(OUT1) == 1)
//!      bit_set(inputs,0);
//!   else
//!      bit_clear(inputs,0);
   
       if (bit_test(coils,0) == 1)
         OUTPUT_HIGH(OUT1);
      else
         OUTPUT_LOW(OUT1);
         
      if (bit_test(coils,1) == 1)
         OUTPUT_HIGH(OUT2);
      else
         OUTPUT_LOW(OUT2);
         
      if (bit_test(coils,2) == 1)
         OUTPUT_HIGH(OUT3);
      else
         OUTPUT_LOW(OUT3);
         
      if (bit_test(coils,3) == 1)
         OUTPUT_HIGH(OUT4);
      else
         OUTPUT_LOW(OUT4);
   
      while(!modbus_kbhit());
      
      delay_us(50);
      
      //check address against our address, 0 is broadcast
      if((modbus_rx.address == MODBUS_ADDRESS) || modbus_rx.address == 0)
      {
         switch(modbus_rx.func)
         {
            case FUNC_READ_COILS:    //read coils
            case FUNC_READ_DISCRETE_INPUT:    //read inputs
               if(modbus_rx.data[0] || modbus_rx.data[2] ||
                  modbus_rx.data[1] >= 8 || modbus_rx.data[3]+modbus_rx.data[1] > 8)
                  modbus_exception_rsp(MODBUS_ADDRESS,modbus_rx.func,ILLEGAL_DATA_ADDRESS);
               else
               {
                  int8 data;
                  
                  if(modbus_rx.func == FUNC_READ_COILS)
                     data = coils>>(modbus_rx.data[1]);      //move to the starting coil
                  else
                     data = inputs>>(modbus_rx.data[1]);      //move to the starting input

                  data = data & (0xFF>>(8-modbus_rx.data[3]));  //0 out values after quantity

                  if(modbus_rx.func == FUNC_READ_COILS)
                     modbus_read_coils_rsp(MODBUS_ADDRESS, 0x01, &data);
                  else
                     modbus_read_discrete_input_rsp(MODBUS_ADDRESS, 0x01, &data);
                     
                  event_count++;
               }
               break;
            case FUNC_READ_HOLDING_REGISTERS:
            case FUNC_READ_INPUT_REGISTERS:
               if(modbus_rx.data[0] || modbus_rx.data[2] ||
                  modbus_rx.data[1] >= 8 || modbus_rx.data[3]+modbus_rx.data[1] > 8)
                  modbus_exception_rsp(MODBUS_ADDRESS,modbus_rx.func,ILLEGAL_DATA_ADDRESS);
               else
               {
                  if(modbus_rx.func == FUNC_READ_HOLDING_REGISTERS)
                     modbus_read_holding_registers_rsp(MODBUS_ADDRESS,(modbus_rx.data[3]*2),hold_regs+modbus_rx.data[1]);
                  else
                     modbus_read_input_registers_rsp(MODBUS_ADDRESS,(modbus_rx.data[3]*2),input_regs+modbus_rx.data[1]);
                  
                  event_count++;
               }
               break;
            case FUNC_WRITE_SINGLE_COIL:      //write coil
               if(modbus_rx.data[0] || modbus_rx.data[3] || modbus_rx.data[1] > 8)
                  modbus_exception_rsp(MODBUS_ADDRESS,modbus_rx.func,ILLEGAL_DATA_ADDRESS);
               else if(modbus_rx.data[2] != 0xFF && modbus_rx.data[2] != 0x00)
                  modbus_exception_rsp(MODBUS_ADDRESS,modbus_rx.func,ILLEGAL_DATA_VALUE);
               else
               {
                  //coils are stored msb->lsb so we must use 7-address
                  if(modbus_rx.data[2] == 0xFF)
                     bit_set(coils,modbus_rx.data[1]);
                  else
                     bit_clear(coils,modbus_rx.data[1]);

                  modbus_write_single_coil_rsp(MODBUS_ADDRESS,modbus_rx.data[1],((int16)(modbus_rx.data[2]))<<8);
                  
                  event_count++;
               }
               break;
            case FUNC_WRITE_SINGLE_REGISTER:
               if(modbus_rx.data[0] || modbus_rx.data[1] >= 8)
                  modbus_exception_rsp(MODBUS_ADDRESS,modbus_rx.func,ILLEGAL_DATA_ADDRESS);
               else
               {
                                    //the registers are stored in little endian format ///////======///
                  hold_regs[modbus_rx.data[1]] = make16(modbus_rx.data[2],modbus_rx.data[3]);

                  modbus_write_single_register_rsp(MODBUS_ADDRESS,
                               make16(modbus_rx.data[0],modbus_rx.data[1]),
                               make16(modbus_rx.data[2],modbus_rx.data[3]));
               }
               break;
            case FUNC_WRITE_MULTIPLE_COILS:
               if(modbus_rx.data[0] || modbus_rx.data[2] ||
                  modbus_rx.data[1] >= 8 || modbus_rx.data[3]+modbus_rx.data[1] > 8)
                  modbus_exception_rsp(MODBUS_ADDRESS,modbus_rx.func,ILLEGAL_DATA_ADDRESS);
               else
               {
                  int i,j;

                  modbus_rx.data[5] = swap_bits(modbus_rx.data[5]);

                  for(i=modbus_rx.data[1],j=0; i < modbus_rx.data[1]+modbus_rx.data[3]; ++i,++j)
                  {  
                     if(bit_test(modbus_rx.data[5],j))
                        bit_set(coils,7-i);
                     else
                        bit_clear(coils,7-i);
                  }

                  modbus_write_multiple_coils_rsp(MODBUS_ADDRESS,
                                 make16(modbus_rx.data[0],modbus_rx.data[1]),
                                 make16(modbus_rx.data[2],modbus_rx.data[3]));
                  
                  event_count++;
               }
               break;
            case FUNC_WRITE_MULTIPLE_REGISTERS:
               if(modbus_rx.data[0] || modbus_rx.data[2] ||
                  modbus_rx.data[1] >= 8 || modbus_rx.data[3]+modbus_rx.data[1] > 8)
                  modbus_exception_rsp(MODBUS_ADDRESS,modbus_rx.func,ILLEGAL_DATA_ADDRESS);
               else
               {
                  int i,j;

                  for(i=0,j=5; i < modbus_rx.data[4]/2; ++i,j+=2)
                     hold_regs[i] = make16(modbus_rx.data[j],modbus_rx.data[j+1]);

                  modbus_write_multiple_registers_rsp(MODBUS_ADDRESS,
                                 make16(modbus_rx.data[0],modbus_rx.data[1]),
                                 make16(modbus_rx.data[2],modbus_rx.data[3]));
               
                  event_count++;
               }
               break;           
            default:    //We don't support the function, so return exception
               modbus_exception_rsp(MODBUS_ADDRESS,modbus_rx.func,ILLEGAL_FUNCTION);
         }
      }
  }
}

//=====================================================================================


mesela ben burda hold_regs[0] ve hold_regs[1]  adresini okumak istiyorum, fakat birtürlü yapamadım. Okuma ve yazmayı nasıl yapabilirim.
Proteusta yaptığım debug resmi ve proteus resmi bu şekilde. İstediğim adresleri tek tek nasıl okur ve yazabilirim. Virgül kısmınıda yapamıyorum.




Murat Mert

mert07

thenorthstar

A.S Dostum,
Evet okumayı hallettim, fakat hala virgülsüz okuyorum.
void read_all_holding()
{  

if(!(modbus_read_holding_registers(MODBUS_SLAVE_ADDRESS,0,8)))  // Burda tüm word dataları okuyor
   {
     /*Started at 1 since 0 is quantity of coils*/
    LCD_gotoxy(1,1);
    printf(lcd_putc,"Modbus OK.....");
    LCD_gotoxy(2,2);
    printf(lcd_putc,"Temp=%3.1u", modbus_rx.data[2]);  // Burda ise okumak istediğin datanın adresini yazıyorsun, ben şu anda 2. datayı                                 //okuyorum

   } 
   else
   {
    LCD_gotoxy(2,3);
    printf(lcd_putc,"Modbus Hata");
    LCD_gotoxy(3,4);
    printf(lcd_putc,"Error=%D ", modbus_rx.error);
   }
}

Klein

virgülsüzden kasıt nedir?
float değerleri mi okuyamıyorsunuz?

Murat Mert

Alıntı yapılan: thenorthstar - 14 Nisan 2011, 08:55:06
A.S Dostum,
Evet okumayı hallettim, fakat hala virgülsüz okuyorum.
void read_all_holding()
{  

if(!(modbus_read_holding_registers(MODBUS_SLAVE_ADDRESS,0,8)))  // Burda tüm word dataları okuyor
   {
     /*Started at 1 since 0 is quantity of coils*/
    LCD_gotoxy(1,1);
    printf(lcd_putc,"Modbus OK.....");
    LCD_gotoxy(2,2);
    printf(lcd_putc,"Temp=%3.1u", modbus_rx.data[2]);  // Burda ise okumak istediğin datanın adresini yazıyorsun, ben şu anda 2. datayı                                 //okuyorum

   } 
   else
   {
    LCD_gotoxy(2,3);
    printf(lcd_putc,"Modbus Hata");
    LCD_gotoxy(3,4);
    printf(lcd_putc,"Error=%D ", modbus_rx.error);
   }
}


S.A
Şimdi sen burada uarttan gelen high byte yi okudun. Gelen data high byte + low bytedir. yani:
istediğin data = (high byte * 256) + low byte
dir.
mert07

Murat Mert

S.A.

Slave de şöyle bir değişiklik yap
hold_regs[0]=Sicaklik*10;
   hold_regs[1]=Sicaklik2*10;


masterdede:
void read_all_holding()

   { 
   unsigned long int bilgi;
   if(!(modbus_read_holding_registers(MODBUS_SLAVE_ADDRESS,0,8)))  // Burda tüm word dataları okuyor   
   {    
   /*Started at 1 since 0 is quantity of coils*/  
   bilgi=(modbus_rx.data[1]*256)+modbus_rx.data[2];
      LCD_gotoxy(1,1);    
   printf(lcd_putc,"Modbus OK.....");    
   LCD_gotoxy(2,2);   
   printf(lcd_putc,"Dijital=%lu",bilgi);
  // printf(lcd_putc,"Temp=%3.1u", modbus_rx.data[2]);  // Burda ise okumak istediğin datanın adresini yazıyorsun, ben şu anda 2. datayı                                 //okuyorum   
   
   }
   else  
    {    
   LCD_gotoxy(2,3);    
    printf(lcd_putc,"Modbus Hata");   
    LCD_gotoxy(3,4);    
   printf(lcd_putc,"Error=%D ", modbus_rx.error);
   }
 
 }
mert07

Murat Mert

Yazıyı tamamlamadan yolladım ama edit yapamadım neyse :)
CCS C de mutlaka bunun kolay bir yöntemi vardır ama daha yeni başladım :) protonda olsaydı kolaydı

Dim VERI As Word ' 16 bitlik değişken

VERI.Byte0 = modbus_rx.data[1]
VERI.Byte1 = modbus_rx.data[2]

Print At 1,1, "ALINAN:", dec VERI

derdik olay biterdi ama sen halledebilirsin kısa yolunu virgüllü yapmak içinde float bir değişken atarsın mastere olur.
mert07