
- •Завдання
- •Основні теоретичні відомості
- •Вимірювання температури
- •Методи вимірювання температури і температурних шкал
- •Input Registers - 16-бітовий знаковий або беззнакових тип, доступний тільки для читання;
- •Принцип роботи modbus
- •Пакет Modbus pdu
- •Модель даних
- •Стандартні функції протоколу Modbus. Читання даних.
- •Контроль помилок у протоколі Modbus rtu
Контроль помилок у протоколі Modbus rtu
Під час обміну даними можуть виникати помилки двох типів: помилки, пов'язані із спотвореннями при передачі даних та логічні помилки. Помилки першого типу виявляються за допомогою фреймів символів, контролю парності і циклічної контрольної суми CRC16 (використовується число-поліном 0xA001). При цьому молодший байт передається першим, на відміну від байтів адреси і значення регістра в PDU
У RTU режимі повідомлення повинно починатися і закінчуватися інтервалом тиші - часом передачі не менше 3,5 символів при даній швидкості в мережі. Першим полем потім передається адреса пристрою. Слідом за останнім переданим символом також має бути інтервал тиші тривалістю не менш як 3,5 символів. Нове повідомлення може починатися після цього інтервалу. Фрейм повідомлення передається безперервно. Якщо інтервал тиші тривалістю 1,5 виник під час передачі кадру, приймаючий пристрій повинен ігнорувати цей фрейм як неповний. Таким чином, нове повідомлення повинно починатися не раніше 3,5 інтервалу, тому що в цьому випадку встановлюється помилка.
Для повідомлень про помилки другого типу (логічні помилки) протокол Modbus RTU передбачає, що пристрої можуть відсилати відповіді, що свідчать про помилкову ситуації. Ознакою того, що відповідь містить повідомлення про помилку, є встановлений старший біт коду команди. Приклад кадру при виявленні помилки веденим пристроєм, у відповідь на запит наведено в табл..
Робота пристрою Slave за різних випадків роботи:
1. Якщо Slave приймає коректний запит і може його нормально опрацювати, то повертає нормальну відповідь.
2. Якщо Slave не приймає жодного значення, ніякої відповіді не відправляється. Master діагностує помилку по тайм-ауту.
3. Якщо Slave приймає запит, але виявляє помилку (parity, LRC, або CRC), жодної відповіді не відправляється. Master діагностує помилку по тайм-ауту.
4. Якщо Slave приймає запит, але не може його опрацювати (звернення до неіснуючого регістру і т. д.), відправляється відповідь, яка містить в собі дані про помилку.
Кадр відповіді (Slave→Master) при виникненні помилки Мodbus
Напрям передачі |
Адреса Slave |
Номер функції |
Дані або код помилки |
CRC |
Master→Slave |
0x01 |
0x77 |
0xDD |
0xC7 0xA9 |
Slave→Master |
0x01 |
0xF7 |
0xEE |
0xE6 0x7C |
Стандартні коди помилок
01 – Прийнятий код функції не може бути опрацьований.
02 – Адреса даних, вказана у запиті, недоступна даному Slave.
03 – Значення, що міститься в полі даних запиту, є неприпустимою для Slave.
04 – Мала місце невідновлювана помилка, поки Slave намагався сформувати пакет-відповідь.
05 – Slave прийняв запит і опрацьовує його, але це вимагає багато часу. Ця відповідь оберігає Master від генерації помилки тайм-ауту.
06 – Slave зайнятий опрацюванням іншої команди. Master повинен повторити повідомлення пізніше, коли Slave звільниться.
07 – Slave не може виконати програмну функцію, прийняту в запиті. Цей код повертається для невдалого програмного запиту, який використовує функції з номерами 13 або 14. Master повинен запросити діагностичну інформацію або інформацію про помилки від Slave.
08 – Slave намагається читати розширену пам'ять, але виявив помилку паритету. Master може повторити запит, але звичайно в таких випадках потрібно проводити діагностику обладнання та ремонт.
Обчислення контрольної суми CRC16. Контрольна сума CRC16 обчислюють з використанням всіх байтів пакету даних DATA за таким алгоритмом:
Присвоїти змінній CRC, яка є типу __int16 (шістнадцяти бітне число) значення 0xFFFF.
Виконати з першим байтом DATA0 пакету даних таку операцію: CRC = CRC XOR DATA0 (додавання за модулем 2).
Зсунути CRC на один біт вправо.
Якщо вихідний біт (той що вийшов за межі числа CRC) дорівнює 1, виконати таку операцію: CRC = CRC XOR 0xA001. Якщо вихідний біт дорівнює 0, нічого не робити.
Виконати 8 разів пункти 3, 4 (з усіма бітами молодшого байту числа CRC, до якого було додано за модулем 2 байт DATA0).
Виконати з усіма наступними байтами (DATA1, DATA2 і т.д.) пакету даних пункти 2, 3, 4, 5
Отримане значення контрольної суми CRC16 додається в кінці пакету даних у такому порядку: спочатку молодший, а потім старший байти (на відміну від інших даних, що містяться в пакеті, який сформовано за протоколом Modbus – спочатку старший, а потім молодший байти).
Алгоритм обміну даними представлено на рисунку:
Алгоритм обміну даними для приладу та комп’ютера
Код програми прийому-передачі комп’ютера:
//---------------------------------------------------------------------------
#include <vcl.h>
#include "comm.h"
#pragma hdrstop
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
TCommPort *Serial1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
Serial1=new TCommPort;
Serial1->OpenCommPort("COM1");
Serial1->SetBaudRate(CBR_9600);
Serial1->SetStopBits(ONESTOPBIT);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
Adr1Slov=20;
Serial1->PutByte(10);
Serial1->PutByte(3);
Serial1->PutByte(0);
Serial1->PutByte(Adr1Slov);
Serial1->PutByte(0);
Serial1->PutByte(10);
Serial1->PutByte(0);
Serial1->PutByte(0); }
//---------------------------------------------------------------------------
#ifndef Unit1H
#define Unit1H
//---------------------------------------------------------------------------
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
#include <ExtCtrls.hpp>
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published: // IDE-managed Components
TButton *Button1;
TMemo *Memo1;
TTimer *Timer1;
TButton *Button2;
void __fastcall Button1Click(TObject *Sender);
private: // User declarations
public: // User declarations
__int8 a,i,Adr1Slov;
unsigned char Data[100];
__fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif