Сообщество EasyElectronics.ru
Яндекс.Директ
отрицательна.
→
счётчике СОЭ-55 МЗЭП 23 Блог им. toxin65
Именно этой разностью потенциалов и передается сигнал. Такой способ передачи trengtor → Макетирование на Veroboard
обеспечивает высокую устойчивость к синфазной помехе. Синфазной называют →
stripboard и на простых stripboard 105
Технологии
помеху, действующую на оба провода линии одинаково. К примеру,
электромагнитная волна, проходя через участок линии связи, наводит в обоих Vga → DDS синтезатор AD9833 83 → Блог
проводах потенциал. Если сигнал передается потенциалом в одном проводе им. grand1987
относительно общего, как в RS-232, то наводка на этот провод может исказить сигнал Vga → Delphi. Определение разрешения
относительно хорошо поглощающего наводки общего («земли»). Кроме того, на видеофайла формата MP4 прямым парсингом
сопротивлении длинного общего провода будет падать разность потенциалов →
без использования кодеков. 20 Алгоритмы и
программные решения
земель — дополнительный источник искажений. А при дифференциальной передаче
искажения не происходит. В самом деле, если два провода пролегают близко друг к __bl__→ Передача данных в устройство
другу, да еще перевиты, то наводка на оба провода одинакова. Потенциал в обоих →
через COM-порт 5 LabView
Contemplator →
Все о модуле
распознавания голоса EasyVR (ex VRbot) 81 →
Деталька
Mihail →
Стек для W5200 без циклов
задержек + STM32F103 14 STM32 →
Vga →
Доработка напильником
→
мультиметра UT61E 139 Блог им. ACE
(0x10) — запись значений в несколько регистров хранения (Preset Multiple Registers) Деталька 23.24
(0x16) — запись в один регистр хранения с использованием маски «И» и маски «ИЛИ»
(Mask Write Register). Схемотехника 18.15
(0x18) — Чтение данных из очереди (Read FIFO Queue) Умный дом 17.75
(0x14) — Чтение из файла (Read File Record)
MSP430 17.13
(0x15) — Запись в файл (Write File Record)
(0x08) — Диагностика (Diagnostic) LPC1xxx 14.79
(0x0B) — Чтение счетчика событий (Get Com Event Counter)
Все блоги
(0x0C) — Чтение журнала событий (Get Com Event Log)
(0x11) — Чтение информации об устройстве (Report Slave ID)
(0x2B) — Encapsulated Interface Transport
Обработка ошибок
Ведущий отправляет запрос к Ведомому, в котором в поле «код функции» указывает
ему на необходимое действие.
Байты данных содержат информацию, необходимую для выполнения данной
функции.
Ведомый, в случае удачного выполнения этой функции, повторяет код функции в
ответе.
При возникновении ошибки, код функции в ответе модифицируется — старший бит
выставляется в 1.
В байтах данных передается причина ошибки. Например при исполнении Ведомым
функции 0x0F возникла ошибка, тогда он ответит Ведущему полем функции равным
0x8F.
В дополнении к изменению кода функции, Ведомый размещает в поле данных
уникальный код, который указывает на тип и причину ошибки.
и Табличный
const uint8_t auchCRCHi[256]=
{
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0
0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00
0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40
0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1
0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40
0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0
0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00
0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40
0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81
0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0
0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40
0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0
0x40
};
if (len>256U)
{
return (0);
}
n = (uint8_t)len;
do
{
uint8_t i = crc_hi ^ *p++; // will index into CR
crc_hi = crc_lo ^ (uint8_t)(&auchCRCHi[i]); // calcu
crc_lo = (uint8_t)(&auchCRCLo[i]);
}
while (--n); // pass through message buffer (max 2
return ((crc_hi << 8) | crc_lo);
}
Как указано в даташите на ADM485, для работы на прием выводы RE-DE-DI должны
быть в 0,
тогда на выводе RO появляются принятые данные.
Для работы на передачу — все противоположно, но данные следует слать на DI.
Простая функция приема
void USART1_IRQHandler(void)
{ uint16_t temp;
if((Modbus_Progress_Status == M_STAT_REC_ON)|| (Modbus_Pro
{
Modbus_Data[Modbus_Count_Byte] = USART1->DR;
Modbus_Count_Byte ++;
if(Modbus_Count_Byte >= LENGTH_PACK)
{
if(Modbus_Data[0] == MY_ID)
{
temp = Modbus_Data[7];
temp = temp<<8;
temp |= Modbus_Data[6];
if(CRC_calc(Modbus_Data,9)==temp)
{
Modbus_Progress_Status = M_STAT_TRAN_ON;
Modbus_Count_Byte =0;
USART1->CR1 &=~ USART_CR1_RE;
USART1->CR1 &=~ USART_CR1_RXNEIE;
Modbus_Send();
};
}}}}
void Modbus_Send(void)
{
uint16_t crc;
uint8_t i;
USART1->CR1 &=~ USART_CR1_RE;
USART1->CR1 &=~ USART_CR1_RXNEIE;
Modbus_DataTX[0]= ID;
Modbus_DataTX[1]= COMMAND_READ;
Modbus_DataTX[2]= LENGTH_REDE;
Modbus_DataTX[3]= Param1L;
Modbus_DataTX[4]= Param1H;
Modbus_DataTX[5]= Param2L;
Modbus_DataTX[6]= Param1H;
....
Modbus_DataTX[21]= Param21L;
Modbus_DataTX[22]= Param21H;
crc = CRC(Modbus_DataTX, 23);
Modbus_DataTX[23]= (crc & 0x00FF);
Modbus_DataTX[24]= (crc >>8);
Modbus_Transmit_Select();
for(i=0; i<LENGTH_PACK_REDE; i++)
{
USART_Transmit(Modbus_DataTX[i]);
}
USART1->CR1 &=~ USART_CR1_TE;
Modbus_Receive_Select();
// Тут очищаем флаги если есть
Modbus_Data_TransLength = 0;
Modbus_Progress_Status = M_STAT_CLEAR;
Modbus_Progress_Status = 0;
Modbus_Count_Byte = 0;
Modbus_Count_TransByte =0;
USART1->CR1 |= USART_CR1_RE;
USART1->CR1 |= USART_CR1_RXNEIE;
}
Рекомендуется к прочтению:
Спецификация Modbus Link
RS-485 для чайников — Link
Modbus в Википедии Link
Modbus протокол Link
modbus, RS-485
Комментарии (27)
RSS свернуть / развернуть
khomin
25 октября 2013, 03:41
khomin
25 октября 2013, 08:14
GYUR22
25 октября 2013, 12:19 ↑
вообще то да, но с учетом старых трансиверов на полную нагрузку — 32 0
устройства на сегмент (а есть 1/2, 1/4) и 3 последовательных сегмента (но можно
древовидную стрктуру), но много нодов и длинные шланги это ад и сотона в поле,
поэтому надо подходить разумно.
GYUR22
25 октября 2013, 12:51 ↑
Papandopala
25 октября 2013, 12:57 ↑
Papandopala
25 октября 2013, 12:38
khomin
25 октября 2013, 13:33 ↑
Ну и рассчет CRC
uint16_t CRC16(uint8_t *p, uint16_t len)
{
uint8_t crc_hi;
uint8_t crc_lo;
uint8_t n;
if (len>256U)
{
return (0);
}
n = (uint8_t)len;
do
{
uint8_t i = crc_hi ^ *p++; // will ind
crc_hi = crc_lo ^ (uint8_t)pgm_read_byte(&auc
crc_lo = (uint8_t)pgm_read_byte(&auc
}
while (--n); // pa
return ((crc_hi << 8) | crc_lo);
}
/*
Вызов функции в программе.
unsigned char mess[3] = {1,108,8};
volatile unsigned short res1 = CRC16(&mess[0],3);
res1 будет равен 0СС6 при подстановке в конце команды менять
старший и младший байты не надо. Эта функция при занесении зн
res1 автоматически меняет местами старший и младший байты.
Papandopala
25 октября 2013, 13:49 ↑
добавил, спасибо 0
khomin
25 октября 2013, 14:43 ↑
Так а зачем таблицу в озу перенес, убрав PROGMEM? Она ж у тебя вся 0
будет висеть в оперативке, памяти столько не напасешься.
Papandopala
25 октября 2013, 15:02 ↑
khomin
25 октября 2013, 15:07 ↑
Papandopala
25 октября 2013, 15:09 ↑
Vga
25 октября 2013, 16:12 ↑
Насколько я вижу, под видом двух методов расчета CRC в статье приведены два 0
куска одного, табличного. MakeCRC16Table считает табличку (uint16_t
crctable[256]), GetCRC16 считает CRC для блока. Первую функцию нужно вызвать
один раз для инициализации.
Vga
25 октября 2013, 16:07 ↑
Коллега, имя массива — это есть адрес первого его элемента. Таким образом, можно и
лучше написать более прозрачный код — CRC16(mess,3);
zhevak
26 октября 2013, 00:36
И еще! +2
zhevak
26 октября 2013, 00:42 ↑
0
У инициализированных массивов размер можно не указывать
В более общем случае это нужно:
unsigned char mess[100] = {1,108,8};
Logic
27 октября 2013, 18:46 ↑
zhevak
27 октября 2013, 19:27 ↑
khomin
27 октября 2013, 12:54
+1
Шахматов и библиотекаршей.
EW1UA
27 октября 2013, 18:17 ↑
kalobyte-ya
27 октября 2013, 20:56 ↑
16-ти канальный логический анализатор прямо «из коробки» умеет парсить MODBUS? 0
Logic
27 октября 2013, 18:51
да, все Saleae распознают — Последовательный интерфейс, SPI, I2C, DMX, i-wire, 0
CAN
khomin
27 октября 2013, 19:45 ↑
romanetz
02 августа 2016, 22:45
Dimaster
18 октября 2016, 15:09
EagleSha
29 ноября 2016, 20:21
(uint8_t)pgm_read_byte(&auchCRCHi[i]);
e_mc2
30 ноября 2016, 15:58 ↑