Добрий час доби!
Хочу реалізувати протокол передачі даних в якому дані будуть передаватися через uart однієї 9-бітової посилкою.
Структура посилки повинні бути наступною:
0 - стартовий біт
5. 7 - три біта даних
8 - стоповий біт
Як краще реалізувати?
Тоді не з'явиться чергова тема типу "чому приймаю не те, що посилаю"
Ну народ стверджує що такі речі так не робляться. Так що я тепер в замішанні :)
Звичайно можна спробувати, по ганяю дані по шині і.т.д. може й справді в 1 байт зможу вкластися. Для налагодження "не стандартного рішення" у мене є лог.аналізатор.
На самому початку я дійсно ступив, думаючи що стартовий і стоповий біт повинен міститися всередині посилки (даних): rolleyes:
Це дозволить в майбутньому (а швидше за все це і виникне) змінити кількість команд до слейв, і можливо захочеться передати відповідь від слейв.
Чому 8бітних, а не 9-ти? Її простіше відловлювати "звичайним когось портом компа", а необхідність така швидше за все виникне.
Разом вам протокол:
передача від майстра до слейв
1й байт -
2й байт -
.
Nй байт -
відповідь від слейв до майстра точно такий же (якщо з'явиться необхідність)
1й байт -
2й байт -
.
Nй байт -
в цій структурі можна і "нормальні" дані передавати (short, long) - запакувавши їх більшу кількість байт (тут теж є варіанти, можна зрушувати дані, можна старші біти упакувати в останній байт даних).
На рахунок даних, виділень даних і байт на сі:
є така річ як структура (struct) і об'єднання (union).
У вашому випадку її можна записати як:
struct
usigned char Addr. 4;
usigned char Data. 4;
> Pac;
// звернення до полів:
Pac.Addr = 0;
Pac.Data = 5;
В моєму випадку:
#define DATA_LEN 1
struct
unsiged char Addr;
unsiged char Data [DATA_LEN];
unsiged char DataLen; // кількість прийнятих даних
> Pac;
У моєму варіанті ускладниться прийом і обробка. якщо вам це не треба - зупиняйтеся на своєму первісному варіанті.
PS студенту респект, не кожному дипломникові (початківцю інженеру) попадається таке завдання.
Добре, що все так випадково збіглося, як раз те, що потрібно ТС. І надійність перевірена на мільйонах зразків, і імператор галактики навіть сертифікував все це справа. І купити готове рішення можна;) А ми тут мозок напружуємо. Я ж казав, що там, де хохол пройшов, єврею робити нічого. І сайт український виявився. ) Молодці.
Добре, що все так випадково збіглося, як раз те, що потрібно ТС. І надійність перевірена на мільйонах зразків, і імператор галактики навіть сертифікував все це справа. І купити готове рішення можна;) А ми тут мозок напружуємо. Я ж казав, що там, де хохол пройшов, єврею робити нічого. І сайт український виявився. ) Молодці.
Не розумію до чого тут приналежність до будь-якої національності. Сайт привів, так як опис на доступній мові, що простіше до поняття. Без всяких думок де він знаходиться, є сайт і добре.
Сертифікація тут при чому. Яким вона боком стосується теми.
Хто говорив про продаж або купівлю?
А то що багато обладнання працює по цьому протоколу, так таки да, так воно і є.
Ніхто ТЗ не змушує, "передирати" протокол, або застосовувати, але ідею щось запозичити можна, тим більше "2. Всі вже розведено / закуплено."
1. Всі девайси на одній платі.
2. Всі вже розведено / закуплено.
3. Можна робити без підтвердження
Це дозволить в майбутньому (а швидше за все це і виникне) змінити кількість команд до слейв, і можливо захочеться передати відповідь від слейв.
Чому 8бітних, а не 9-ти? Її простіше відловлювати "звичайним когось портом компа", а необхідність така швидше за все виникне.
Щодо 8 бітової передачі згоден, хоча якщо мені не зраджує пам'ять 9-бітовий режим прийому / передачі так-же можна включити в параметрах той-же FT232 (usb-uart). Ось тільки 9-бітовий режим мені не потрібен :) Я просто не розумів на початку структуру пакетів і думав що стартовий і стоповий біт входить в ці 8-9 біт разом з інформацією знаходиться в посилці (в байті): o
А ось в необхідності 2 і більше байт я все-таки не впевнений. По-перше у мене кількість пристроїв на шині буде більше 16, а по-друге 16 команд буде більш ніж достатньо для настільки не тривіальним завдання.
По суті від master мені необхідно відправляти наступний набір команд:
1 [111] - встановити на RC2 високий рівень тобто включити канал
2 [000] - встановити на RC2 низький рівень тобто вимкнути канал
3 [001] - подати на RC1 імпульс довжиною 10ms
4 [011] - подати на RC1 імпульс довжиною 50ms
5 [100] - запросити стан RC1
6 [101] - запросити стан RC2
7 [110] - впустити пристрій в сон до перезавантаження тобто вимкнути канал і не отримувати команди.
У свою чергу slave відправлятимуть на master наступний набір відповідей;
I [111] - канал успішно включений (позитивну відповідь на команду 1)
II [000] - канал успішно вимкнений (позитивну відповідь на команду 2)
III [001] - випромінює імпульс поданий (позитивну відповідь на команди 3, 4)
IV [011] - перевантаження по току! (Негативну відповідь на команди 1, 2, 3, 4)
V [100] - вкл (відповідь на команди 5, 6)
VI [101] - викл (відповідь на команди 5, 6)
Власне я не бачу сенсу в 2 і більше байтах, алгоритм роботи системи простий і не вимагає передачі важкої інформації.
При такій надмірності, немає сенсу в контрольній сумі, можна просто повторити повідомлення. Ну звичайно перевірка правильності пакету з боку приймача - дуже добре.
Працювати це все буде так:
Припустимо необхідно включить канал на четвертому slave-устройсва (0100 - ID = 4).
Для цього з майстер пристрою відправляється посилка з наступним змістом:
Слідом за цією посилкою йде ще одна з контрольною сумою, для підрахунку контрольної суми вважаємо в першій посилці все 1 і множимо їх на 3, в результаті отримане десяткове число кодируем в десятеричная.
У нашому випадку друга посилка набуде вигляду:
11110000
[01234567]
де
0. 3 - 15 в бінарній системі (5 * 3)
7 - прапор рівний 0 (позначення байта з контрольною сумою)
Тепер у мене є 2 питання до Вас:
1. я ідіот?
2. Як це реалізувати на Сі? Конкретно я не розумію як отриману посилку можна розбити на біти?
У мене є ось така реалізація коду, але вона дозволяє відправляти / отримувати через uart символи і рядки.
#include
#include
#define BAUD 9600
#define FOSC 4000000L
#define _XTAL_FREQ 4000000
#define NINE_BITS 0
#define SPEED 0x4
#define DIVIDER ((int) (FOSC / (16UL * BAUD) -1))
#define LED_RED RA4
#define LED_GREN RA5
#define on_off RC2
#define ground RC1
__CONFIG (FOSC_INTOSC WDTE_ON PWRTE_OFF MCLRE_OFF CP_OFF BOREN_OFF CLKOUTEN_OFF IESO_OFF FCMEN_OFF);
__CONFIG (WRT_OFF PLLEN_OFF STVREN_OFF BORV_LO LVP_OFF);
void usart_init (void);
void usart_putch (unsigned char c);
// ------------------------------------------------ -
void usart_init (void) SPBRG = DIVIDER;
RCSTA = (NINE_BITS | 0x90);
TXSTA = (SPEED | NINE_BITS | 0x20);
>
void putch (unsigned char byte) while (! TXIF)
continue;
TXREG = byte;
>
unsigned char getch () while (! RCIF)
continue;
return RCREG;
>
unsigned char getche (void) unsigned char c;
putch (c = getch ());
return c;
>
.
void main (void) OSCTUNE = 0b00000000;
OSCCON = 0b01101010;
TRISA = 0b11001111;
TRISC = 0b11111001;
PORTA = 0b00000000;
ground = 0;
on_off = 0;
LED_RED = 1;
LED_GREN = 1;
char comand;
char addr;
char byte;
while (1) // тут я намагаюся маніпулювати з вмістом посилки
byte = getch ();
addr = byte&0x0F;
if (addr == 1 101)/проверка принадлежности посылки к sale-устройству
comand = (byte0xF0) >> 4;
.
>
Або пост №10, яку посаду №29.
Працювати це все буде так:
Припустимо необхідно включить канал на четвертому slave-устройсва (0100 - ID = 4).
Для цього з майстер пристрою відправляється посилка з наступним змістом:
Слідом за цією посилкою йде ще одна з контрольною сумою, для підрахунку контрольної суми вважаємо в першій посилці все 1 і множимо їх на 3, в результаті отримане десяткове число кодируем в десятеричная.
У нашому випадку друга посилка набуде вигляду:
11110000
[01234567]
де
0. 3 - 15 в бінарній системі (5 * 3)
7 - прапор рівний 0 (позначення байта з контрольною сумою)
Тепер у мене є 2 питання до Вас:
1. я ідіот?
2. Як це реалізувати на Сі? Конкретно я не розумію як отриману посилку можна розбити на біти?
У мене є ось така реалізація коду, але вона дозволяє відправляти / отримувати через uart символи і рядки.
#include
#include
#define BAUD 9600
#define FOSC 4000000L
#define _XTAL_FREQ 4000000
#define NINE_BITS 0
#define SPEED 0x4
#define DIVIDER ((int) (FOSC / (16UL * BAUD) -1))
#define LED_RED RA4
#define LED_GREN RA5
#define on_off RC2
#define ground RC1
__CONFIG (FOSC_INTOSC WDTE_ON PWRTE_OFF MCLRE_OFF CP_OFF BOREN_OFF CLKOUTEN_OFF IESO_OFF FCMEN_OFF);
__CONFIG (WRT_OFF PLLEN_OFF STVREN_OFF BORV_LO LVP_OFF);
void usart_init (void);
void usart_putch (unsigned char c);
// ------------------------------------------------ -
void usart_init (void) SPBRG = DIVIDER;
RCSTA = (NINE_BITS | 0x90);
TXSTA = (SPEED | NINE_BITS | 0x20);
>
void putch (unsigned char byte) while (! TXIF)
continue;
TXREG = byte;
>
unsigned char getch () while (! RCIF)
continue;
return RCREG;
>
unsigned char getche (void) unsigned char c;
putch (c = getch ());
return c;
>
.
void main (void) OSCTUNE = 0b00000000;
OSCCON = 0b01101010;
TRISA = 0b11001111;
TRISC = 0b11111001;
PORTA = 0b00000000;
ground = 0;
on_off = 0;
LED_RED = 1;
LED_GREN = 1;
char comand;
char addr;
char byte;
while (1) // тут я намагаюся маніпулювати з вмістом посилки
byte = getch ();
addr = byte&0x0F;
if (addr == 1 101)/проверка принадлежности посылки к sale-устройству
comand = (byte0xF0) >> 4;
.
>
RS485, на такому залізі, дійсно не потрібен. З "підтяжкою" в 470 Ом буде працювати як з гармати. А бітову еквілібристику в обміні краще відкинути Не освоївши: D Я чому про фіксовану довжину говорив. Є таймер перезапускати з будь-якого прийнятого байта (прямо в перериванні приймача), є лічильник байт. Якщо лічильник дотікал - таймер зупиняється і виполнет перевірка CRC. Ві, таки, здивуєтеся як просто і швидко вона виконується (якщо правильно робити, а як правильно - на цьому тільки форумі вагон прикладів). Треба тільки пам'ятати, що CRC від всієї посилки (з CRC) має дорівнювати нулю. Якщо "0" можна парсити посилку, якщо вона коротка і дії по виконанню короткі теж - то прямо з переривання.
Якщо таймер дотікал раніше, таймер зупиняється і сбрасивиется лічильник байт. ффсё. У реалізації - простіше нікуди.
Вимог щодо обов'язкової обв'язки пакета Xon / Xoff, адже, немає, чай, не в Німеччині живемо
Кожен бачить те, що хоче побачити.
І не тільки те, що хоче, а й те, що може. Чим вище рівень інтелекту, тим складніший марення винахідництва може бути.
(Прим. Гравіцаппа - фантастичне пристрій, зображене у фільмі "Кін-дза-дза". Будучи встановленим в двигун пепелаца - міжзоряного карабля - дозволяє здійснювати практично миттєві міжпланетні, міжзоряні і навіть міжгалактичні перельоти). :)
Я ж казав, що там, де хохол пройшов, єврею робити нічого.
зразок цей вислів приписують К.Марксом. Правда, звучало як "там де російський купець пройшов, там трьом євреям робити нічого". З українцями - перебір.
Зовсім забув відписатися тут :)
Загалом проект вийшов, дана реалізація зарекомендувала себе цілком непогано. Помилкових спрацьовувань не відбувається, дані не б'ються.
По секрету кажучи, комплекс з 16 slave плат і одним master'ом вже пів року торохтить в реакторному цеху однієї АЕС;)
По суті завдання slave-пристроїв - просто міняти стан вихідного напівмоста :)
Тепер про програмну реалізації:
struct unsigned char cmd. 4; // Command addressed to device (4-bits)
unsigned char dev. 4; // Address of the recipient (4-bits)
>;
> Pack_in;
struct unsigned char current. 2;
unsigned char ground_key. 1;
unsigned char power_key. 1;
unsigned char dev. 4;
>;
> Pack_out;
У відповідь посилці 2 біта відведені для зворотного зв'язку по струму споживаються навантаженням. Простіше кажучи, якщо навантаження споживає менше 0,12А - значить на лінії обрив, або записується платою пристрій вийшов з ладу. Якщо споживає не більше 0,2 А і не меньше 0,12А - все працює як треба. А ось якщо струм прівищает 200 мА (КЗ), то значить щось трапилося нештатное і slave-пристрій тут-же відключає живлення від навантаження.
Чекаю критики і зауважень :)