Contoh Code Slave Modbus dengan Microcontroller AVR Atmega8535 dgn bahasa C codevision

Pada Artikel ini saya mencoba  membuat Slave  untuk protokol Modbus dengan microcontroller Atmega8535 dengan bahasa C CodeVision.  Saya berharap bagi anda yang sudah mengerti atau  pernah membuat , bisa memberikan masukannya demi kemajuan kita semua.

Untuk mengerti  tentang modbus RTU atau ASCII anda sebaiknya sudah mengerti pemrograman RS232 /  RS485 . anda bisa baca pada artikel lainya pada blog ini.

Kita akan membuat  Slave dengan function Code 03 dan 04 yaitu   fungsi untuk membaca data (register)  pada slave ,  sebagai masternya  adalah program di PC dengan C# .

Untuk versi awal ini saya tidak menggunakan timeout spt yg dipersyaratkan oleh Modbus , untuk menghindari kerumitan.

Konsep dasar  modbus RTU.

master-slave-modbus

master-slave-modbus function code 03 atau 04

Program Master Pada PC

Slave Modbus hanya bersifat menungu perintah dari master , maka  sebelumnya kita harus membuat program sbagai Master  pada PC untk mengirim query /perintah. Perintah master disebut query dan jawaban slave disebut respon.

Program pd PC akan kita buat dgn C#, program ini  akan berfungsi:

1. Mengirim Perintah (query)  ke Slave.

2. Menerima Respon dari Slave.

Berikut ini contoh kode program mengirim perintah/query dengan C# :

pembahasan contoh  master RTU lengkapnya bisa baca di artikel ini

private SerialPort serialcomm1 = new SerialPort();

private void open_com_Click()
{
                serialcomm1.PortName = "COM1";
                serialcomm1.BaudRate = 9600;
                serialcomm1.DataBits = 8;
                serialcomm1.Parity = Parity.None;
                serialcomm1.StopBits = StopBits.One;

                serialcomm1.ReadTimeout = 1000;
                serialcomm1.WriteTimeout = 1000;
                serialcomm1.Open();
}
private void KirimPerintah(ref byte[] framedata)
        {

            byte[] CRC = new byte[2];
            ushort alamat _awal = Convert.ToUInt16(txtAlamat_Awal_Register.Text)
            ushort jumlah_register = Convert.ToUInt16(txtJumlah_Register.Text);
                //Clear  buffers:
                serialcomm1.DiscardOutBuffer();
                serialcomm1.DiscardInBuffer();
                //Perintah Function Code 03 selalu  8 byte:
                byte[] framedata = new byte[8];

            framedata[0] =Convert.ToByte(txtAlamatSlave.Text);
            framedata[1] = 0x03 ; //FuctionCode
            framedata[2] = (byte)(alamat_awal >> 8);    // MSB starting address
            framedata[3] = (byte)alamat_awal;           // LSB
            framedata[4] = (byte)(jumlah_register >> 8);  //MSB
            framedata[5] = (byte)jumlah_register;         //LSB
            GetCRC(framedata, ref CRC);
            framedata[framedata.Length - 2] = CRC[0];
            framedata[framedata.Length - 1] = CRC[1];

             //kirim perintah/query  ke slave
                    serialcomm1.Write(framedata, 0, framedata.Length);

            }

//fungsi menghitung Error Check ( CRC16 )
 private void GetCRC(byte[] framedata, ref byte[] CRC)
        {

            ushort CRCFull = 0xFFFF;
            byte CRCHigh = 0xFF, CRCLow = 0xFF;
            char CRCLSB;

            for (int i = 0; i < (message.Length) - 2; i++)
            {
                CRCFull = (ushort)(CRCFull ^ message[i]);

                for (int j = 0; j < 8; j++)
                {
                    CRCLSB = (char)(CRCFull & 0x0001);
                    CRCFull = (ushort)((CRCFull >> 1) & 0x7FFF);

                    if (CRCLSB == 1)
                        CRCFull = (ushort)(CRCFull ^ 0xA001);
                }
            }
            CRC[1] = CRCHigh = (byte)((CRCFull >> 8) & 0xFF);
            CRC[0] = CRCLow = (byte)(CRCFull & 0xFF);
        }

Anda bisa juga membuat program mengirim data tetap buat testing saja
contoh data :

  • 01 05 00 01 00 02 CB  1D    //data ini a kan memberi memberi fuction eror
  • 01 03 00 01 00 02   CB 95  // data yg ok FC=03

data data tsb akan ditampilkan di LCD2x16 dlm bentuk desimal.

private void button2_Click(object sender, EventArgs e)       
 {

            byte[] message = new byte[9]; 

            message[0] = 0x01; //address;
            message[1] = 0x03;//FC03;

            message[2] = 0x00;//START ADRESS MSB ;
            message[3] = 0x01;  //START ADRESS LSB;

            message[4] = 0x00;  //QTY REGISTER MSB;
            message[5] = 0x02;  //QTY REGISTER LSB;

            message[6] = 0x95; //   CRC LOW             
            message[7] = 0xCB; //   CRC High

           serialcomm1.Write(message, 0, message.Length);
                    }

Berikut ini contoh program untuk Microcontroller Atmega8535 dgn C codevision:  (maaf  belum selesai)

/*

fungsi usart_rx_isr()   -> untuk menerima data dan simpan di rx_buffer

fungsi kirim_data_isr()   -> untuk mengirim data array di tx_buffer

fungsi main()    -> fungsi  utama terus menerus mengecek data rx_buffer yg datang.

fungsi  checkframedata()   -> fungsi  yg  memeriksa  alamat , fungsi 03 dan crc

fungsi baca_register()   -> fungsi untuk membaca  alamat  register yg dituju

fungi get_crc();    -> fungsi untuk menghitung nilai CRC dari frame datang atau yg akan dikirim.

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

Date    : 6/30/2011
Author  : PCCONTROL.WORDPRESS.COM
Company :
Comments: Slave Modbus RTU 

Chip type           : ATmega8535
Program type        : Application
Clock frequency     : 4.000000 MHz
Memory model        : Small
External SRAM size  : 0
Data Stack size     : 256
*****************************************************/

#include <mega8535.h>
#include <math.h>
#include <delay.h>
// Alphanumeric LCD Module functions
#asm
   .equ __lcd_port=0x15 ;PORTC
#endasm
#include <lcd.h>
#include <string.h>
#include <stdio.h>

#define RXB8 1
#define TXB8 0
#define UPE 2
#define OVR 3
#define FE 4
#define UDRE 5
#define RXC 7

#define FRAMING_ERROR (1<<FE)
#define PARITY_ERROR (1<<UPE)
#define DATA_OVERRUN (1<<OVR)
#define DATA_REGISTER_EMPTY (1<<UDRE)
#define RX_COMPLETE (1<<RXC)

unsigned char	sendBuf[32],localAddr = 0x1;
// USART Receiver buffer
#define RX_BUFFER_SIZE 30
unsigned char rx_buffer[RX_BUFFER_SIZE],rx_counter;

//char tampung3[16]; 

unsigned char CRC[2],CRCLow,CRCHigh;
unsigned char tampung1[10];
unsigned char tampung2[10];
unsigned char tampung3[10];
unsigned char data0[10];
unsigned char data1[10];
unsigned char data2[10];
unsigned char data3[10];
unsigned char data4[10];
unsigned char data5[10];
unsigned char data6[10];
unsigned char data7[10];
//unsigned char data8[10];

unsigned char r_ready; 

void GetCRC(char message[], char panjangdata);
unsigned char rx_wr_index,tx_wr_index;

void checkframedata();
void readRegisters();
int getRegisterVal(int addr,int *tempData);
int testRegister; 

// USART Receiver interrupt service routine
interrupt [USART_RXC] void usart_rx_isr(void)
{
char status,data;
status=UCSRA;
data=UDR;
if ((status & (FRAMING_ERROR | PARITY_ERROR | DATA_OVERRUN))==0)
   {
      if(rx_wr_index <= 7)  // 0 sampai 7
      {  

      rx_buffer[rx_wr_index]=data;
      rx_wr_index++;
      }
      else
      {
       lcd_clear();
       sprintf(tampung3,"%i",rx_wr_index);
       lcd_gotoxy(15,1);
       lcd_puts(tampung3); 

       GetCRC(rx_buffer,rx_wr_index-2);

       rx_wr_index=0;
       r_ready=1;
       UCSRB.7=0;
      }

   };
}

void main(void)
{

// USART initialization
// Communication Parameters: 8 Data, 1 Stop, No Parity
// USART Receiver: On
// USART Transmitter: On
// USART Mode: Asynchronous
// USART Baud rate: 9600
UCSRA=0x00;
UCSRB=0x98;
UCSRC=0x86;
UBRRH=0x00;
UBRRL=0x19;

// LCD module initialization
lcd_init(16);
lcd_gotoxy(0,0);
lcd_putsf("MODBUS SLAVE FC3");
// Global enable interrupts
#asm("sei")

 r_ready=0;
 rx_wr_index=0;
 UCSRB.7=1;  

while (1)
      {
      // Place your code here

        //ambil parameter
        if(r_ready==1)  //==============
           {  

             checkframedata(); 

           } 

      }; //end of while(1)
}     //end of main

        void GetCRC(char message[], char panjangdata)
       // unsigned  int GetCRC(char message[], char panjangdata)
        {
            //Function expects a modbus message of any length as well as a 2 byte CRC array in which to
            //return the CRC values:
           unsigned char i,j;
            unsigned int  CRCFull = 0xFFFF;
         //  unsigned char CRCHigh = 0xFF, CRCLow = 0xFF;
           unsigned  char CRCLSB;

            for (i = 0; i < (panjangdata) ; i++)
            {
                CRCFull = (CRCFull ^ message[i]);

                for ( j = 0; j < 8; j++)
                {
                    CRCLSB = (CRCFull & 0x0001);   //ambil LSB
                    CRCFull = ((CRCFull >> 1) & 0x7FFF);  // geser 

                    if (CRCLSB == 1)
                        CRCFull = CRCFull ^ 0xA001;
                }
            }
            CRC[1] = CRCHigh = ((CRCFull >> 8) & 0xFF);
            CRC[0] = CRCLow = (CRCFull & 0xFF); 

           return ;//0 ; //CRCFull;
        }

  void checkframedata()
  {  

      //untuk mendebug tampilkan Data di baris pertama dan CRC di baris ke dua  LCD 2x16
        sprintf(data0,"%i",rx_buffer[0]); //01
        lcd_gotoxy(0,0);
        lcd_puts(data0); 

        sprintf(data1,"%i",rx_buffer[1]); //03
        lcd_gotoxy(3,0);
        lcd_puts(data1);

        sprintf(data2,"%i",rx_buffer[2]); //00
        lcd_gotoxy(6,0);
        lcd_puts(data2);

        sprintf(data3,"%i",rx_buffer[3]); //01
        lcd_gotoxy(9,0);
        lcd_puts(data3);

        sprintf(data4,"%i",rx_buffer[4]); //00
        lcd_gotoxy(12,0);
        lcd_puts(data4);

        sprintf(data5,"%i",rx_buffer[5]); //02
        lcd_gotoxy(14,0);
        lcd_puts(data5);
        // tampilkan nilai CRC kiriman dari PC

        sprintf(data6,"%i",rx_buffer[6]); //123
        lcd_gotoxy(0,1);
        lcd_puts(data6);

        sprintf(data6,"%i",rx_buffer[7]); //123
        lcd_gotoxy(3,1);
        lcd_puts(data6);

        //Tampilkan Nilai CRC hasil hitungan Microcontroller
        sprintf(tampung1,"%i",CRC[1]);
        lcd_gotoxy(7,1);
        lcd_puts(tampung1);  

        sprintf(tampung2,"%i",CRC[0]);
        lcd_gotoxy(10,1);
        lcd_puts(tampung2);  

	if(rx_buffer[0]==0x01)  // alamat slave ini = 01
	 {
	  if(CRC[1] == rx_buffer[7] && CRC[0]==rx_buffer[6])
	{
	  	if(rx_buffer[1] == 0x03)
	  	{
	  	 lcd_gotoxy(14,1);
	         lcd_putsf("ok");
	        readRegisters();
		}
		 else if(rx_buffer[1] != 3)
		 {
		 lcd_gotoxy(0,1);
		 lcd_putsf("Fuction Error ");
		 }
	  }
         else
          {
          lcd_gotoxy(0,1);
	  lcd_putsf("CRC error    ");
          }

         }											

   r_ready=0;
   rx_wr_index=0;
   UCSRB.7=1;
  }       

void readRegisters(void)
{
	unsigned char addr;
	unsigned char tempAddr;

	unsigned int crcData;
	unsigned char readCount;
	unsigned char byteCount;

	unsigned int i;
	unsigned int tempData = 0;	

	//addr = (receBuf[2]<<8) + receBuf[3];
	//tempAddr = addr & 0xfff;
	addr = rx_buffer[3];
	tempAddr = addr;

	//readCount = (receBuf[4]<<8) + receBuf[5];	//?????
	readCount = rx_buffer[5];

	byteCount = readCount * 2;

	for(i=0;i<byteCount;i++)
	{     tempAddr++;
		getRegisterVal(tempAddr,&tempData);
		sendBuf[2*i+3] = tempData >> 8;
		sendBuf[2*i+4] = tempData & 0xff;
	}

	sendBuf[0] = localAddr;
	sendBuf[1] = 3;
	sendBuf[2] = byteCount;
	byteCount = byteCount + 3;
	GetCRC(sendBuf,byteCount);;
	sendBuf[byteCount] = crcData >> 8;
	byteCount++;
	sendBuf[byteCount] = crcData & 0xff;

	tx_wr_index = byteCount + 1;
	//beginSend();
}//void readRegisters(void)

int getRegisterVal(int addr,int *tempData)
{
	 int result = 0;

	switch(addr & 0xff)
	{
		case 0:
		        	*tempData = testRegister;
				break;
		case 1:
				break;

		default:
				break;
	}

	return result;
}

tobe continue….

referensi:

http://chinahack.com

http://www.modbus.pl/Microchip.html

Advertisements

About pccontrol

Berisi Tutorial Menggunakan PC untuk mengontrol Peralatan dengan cara mudah & praktis.

Posted on 29/07/2011, in Contoh-contoh Aplikasi, Menengah-3. Bookmark the permalink. 7 Comments.

  1. Buat program modbus sendiri from scratch, bikin pusing juga yak wkwkwk
    Ane lagi coba bikin sendiri,, masalah ada pada timing sering miss yang nunggu 3.5 frame..

  2. Mas . apakah ada tutorial tentang koneksi program [aplikasi] ke hardware ? kalau bisa saya contohkan : antara teknologi sollar cell yang berkonfigurasi ke aplikasi,

  3. aku ada problem ni mas,,, tolong dipecahin yah mas,, sebelumyna terima kasih…

    aku mau buat tugas ni mas, mendeteksi orang di pintu pake “satu laserldr”,

    “satu laserldr” ini nanti akan mendeteksi keberadaan orang di depan pintu,,

    begini ceritanya mas…

    pas ada 2 orang yag lewat pintu dhitung sama si ldr trus disimpan hasilnya,
    kemudian ada 3 orang lagi yang lewat pada ldr yang sama dan hasilnya disimpan juga,,
    kemudian kedua hasil itu dibandingkan,jumlah orang yang lebih banyak akan lebih ditumakan untuk membuka pintu terlebih dahulu
    aku bingungnya pas nyimpan hasilnya itu mas dan membandingkan jumlah orangnya.,,

    gimana ya mas??

    tolong dibalas ya mas ke mail aku “sogiaras@yahoo.com”

    thanks mas…

  4. thanks infonya mas. bisa tanya mas, ini program bisa dikembangkan agar membaca ADC ga mas??

  5. apakah program diatas sudah komplit,mas?

Komentar ,Saran atau Pertanyaan

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: