Что такое манчестерский код
Перейти к содержимому

Что такое манчестерский код

  • автор:

Манчестерский код (Manchester)

Манчестерский код относится к самосинхронизирующимся импульсным кодам и имеет два уровня, что обеспечивает хорошую помехозащищенность. Каждый такт (битовый интервал) делится на две части. Информация кодируется перепадами потенциала, происходящими в середине каждого такта.

Единица кодируется перепадом от высокого уровня сигнала к низкому, а ноль — обратным перепадом. В начале такта может происходить служебный перепад сигнала (при передаче несколько единиц или нулей подряд).

Рассмотрим частные случаи кодирования, как в предыдущих случаях.

При манчестерском кодировании обязательное изменение сигнала в середине каждого битового интервала позволяет легко выделить тактовый синхросигнал. Поэтому манчестерский код обладает хорошими самосинхронизирующимися свойствами.

Сигнал не содержит постоянную составляющую, частота основной гармоники сигнала находится в интервале от fо=N/2 Гц до fо=N Гц, изменяясь в зависимости от вида битового потока.

Манчестерское кодирование использовалось в ранних версиях технологии Ethernet со скоростью передачи 10 Мбит/с.

Дифференциальный манчестерский код (Differential Manchester)

Логические значения «0» и «1» передаются соответственно наличием или отсутствием смены уровня сигнала в начале тактового (битового) интервала. В середине битового интервала имеет место обязательная смена значения сигнала.

Дифференциальное манчестерское кодирование

Этот код обладает теми же самыми преимуществами и недостатками, что и манчестерский.

Из всех рассмотренных нами кодов манчестерское кодирование обладает лучшей самосинхронизацией, поскольку перепад сигнала происходит минимум один раз за такт.

Манчестерский код используется в сетях Ethernet со скоростью передачи 10 Мбит/с (10Bаsе-Т). Дифференциальный манчестерский код – в сетях с технологией Token Ring.

В настоящее время разработчики пришли к выводу, что во многих случаях рациональнее применять потенциальное кодирование, ликвидируя его недостатки с помощью, так называемого логического кодирования (см. ниже в этом разделе).

Код с возвратом к нулю rz (Return to Zero)

Бит «1» — импульс одной полярности в первой половине битового интервала, во второй половине битового интервала сигнал имеет нулевой потенциал.

Бит «0» – импульс другой полярности в первой половине битового интервала, во второй половине битового интервала сигнал имеет нулевой потенциал. Код имеет хорошие синхронизирующие свойства.

Для этого кода битовый интервал .

Код с инверсией кодовых значений cmi.

При этом методе передачи бит 1 представляется по правилам квазитроичного кодирования, а бит 0 — в виде двух импульсов противоположной полярности со сменой знака посередине. Код также обладает хорошими синхронизирующими свойствами.

Потенциальный код 2b1q

Это потенциальный код с четырьмя уровнями сигнала для кодирования данных. Название отражает суть кодирования – каждые два бита () передаются за один такт сигналом определенного уровня (1Q). Линейный сигнал имеет четыре состояния. Другими словами, скорость передачи информации N при этом методе кодирования в два раза больше скорости модуляции В.

Сигнал в коде 2B1Q

На рисунке изображен сигнал, соответствующий последовательности бит: 01 01 10 00. Основная частота сигнала в коде 2B1Q не превышает значения fо=N/4 Гц.

Однако для реализации этого метода кодирования мощность передатчика должна быть выше, чтобы четыре значения потенциала четко различались приемником на фоне помех.

Код MLT3 (Multi Level Transmission — 3).

Используются три уровня передачи: «-1», «0», «+1».

Единице соответствует обязательный переход с одного уровня сигнала на другой на границе тактового интервала.

Нулю соответствует отсутствие изменения уровня линейного сигнала.

При передаче последовательности единиц период изменения уровня сигнала включает четыре бита. В этом случае fо=N/4 Гц. Это максимальная основная частота сигнала в коде MLT-3. В случае чередующейся последовательности нулей и единиц основная гармоника сигнала находится на частоте fо=N/8 Гц, что в два раза меньше чем у кода NRZI.

Сигнал в коде MLT-3

Логическое кодирование

Логическое кодирование выполняется передатчиком до физического кодирования, рассмотренного выше, средствами канального или физического уровня. На этапе логического кодирования борются с недостатками методов физического цифрового кодирования отсутствие синхронизации, наличие постоянной составляющей. Таким образом, сначала с помощью средств логического кодирования формируются исправленные битовые последовательности, которые потом с помощью простых методов физического кодирования передаются по линиям связи.

Логическое кодирование подразумевает замену бит исходной информационной последовательности новой последовательностью бит, несущей ту же информацию, но обладающей, кроме этого, дополнительными свойствами, например возможностью для приемной стороны обнаруживать ошибки в принятых данных или надежно поддерживать синхронизацию с поступающим сигналом.

Различают два метода логического кодирования:

кодирование избыточным кодом;

скремблирование.

Избыточные коды (табличные коды) основаны на разбиении исходной последовательности бит на группы и последующей замене каждой исходной группы кодовым словом в соответствии с таблицей. Кодовое слово всегда содержит большее количество бит, чем исходная группа.

Логический код 4В/5В заменяет исходные группы длиной в 4 бита кодовыми словами длиной в 5 бит. В результате общее количество возможных битовых комбинаций для них (2 5 =32) больше, чем для исходных групп (2 4 =16). Поэтому в кодовую таблицу можно включить 16 таких комбинаций, которые не содержат более двух нулей подряд, и использовать их для передачи данных. Код гарантирует, что при любом сочетании кодовых слов на линии не могут встретиться более трех нулей подряд.

Остальные комбинации кода используются для передачи служебных сигналов (синхронизация передачи, начало блока данных, конец блока данных, управление передачей на канальном уровне). Неиспользуемые кодовые слова могут быть задействованы приемником для обнаружения ошибок в потоке данных. Цена за полученные достоинства при таком способе кодирования данных — снижение скорости передачи полезной информации на 25%.

Линейный код

Исходная группа

Логическое кодирование 4В/5В используется в сетях Ethernet со скоростью передачи 100МБит/с:

  • в сочетании с кодом NRZI (спецификация 100Base FX, среда передачи — оптоволокно);
  • в сочетании с кодом MLT-3 (спецификация 100Base TX, среда передачи UTP Cat 5e).

Имеются также коды и с тремя состояниями сигнала, например, в коде 8В/6Т для кодирования 8 бит исходной информации используются кодовые слова троичного кода из 6 элементов. Каждый элемент может принимать одно из трех значений (+1, 0, -1). Избыточность кода 8В/6Т выше, чем кода 4В/5В, так как на 2 8 =256 исходных символов приходится 36=729 результирующих кодовых слов. Этот метод кодирования используется в спецификации 100Base T4 – при организации 100Мбит/с Ethernet по кабелю UTP Cat3 (устаревшая спецификация). Здесь для передачи битового потока одновременно используются 3 витые пары. Скорость передачи информации по каждой паре составляет N=100 Мбит/с / 3 = 33,3 Мбит/с, скорость модуляции линейного сигнала равна 25 М Бод (8:6=1,33; 33,3:1,33=25), что позволяет использовать неэкранированную витую пару UTP Cat3. В коде8B/10В каждые 8 бит исходной последовательности заменяются десятью битами кодового слова. При этом на 256 исходных комбинаций приходится 1024 результирующих комбинаций. При замене в соответствии с кодовой таблицей соблюдаются следующие правила:

    1. ни одна результирующая комбинация (кодовое слово) не должна иметь более 4-х одинаковых бит подряд;
    2. ни одна результирующая комбинация не должна содержать более 6 нулей или 6 единиц;

Код 8B/10В(+NRZI) используется в стандарте Gigabit Ethernet 1000Base-Х (когда в качестве среды передачи данных используется оптоволокно). Осуществляют логическое кодирование сетевые адаптеры. Поскольку, использование таблицы перекодировки является очень простой операцией, метод логического кодирования избыточными кодами не усложняет функциональные требования к этому оборудованию. Для обеспечения заданной пропускной способностиNБит/с передатчик, использующий избыточный код, должен работать с повышенной тактовой частотой. Так, для передачи сигнала в коде 4В/5В со скоростью передачи информации N=100 Мбит/с, передатчик должен работать с тактовой частотой 125 МГц (то естьB=125МБод). При этом спектр линейного сигнала расширяется. Тем не менее, спектр сигнала избыточного потенциального кода оказывается уже спектра сигнала в манчестерскомкоде, что оправдывает дополнительный этап логического кодирования, а также работу приемника и передатчика на повышенной тактовой частоте. Скремблирование представляет собой такое «перемешивание» исходной битовой последовательности, при котором вероятность появления единиц и нулей на входе модуля физического кодирования становится близкой 0,5. Устройства (или программные модули), выполняющие такую операцию, называются скремблерами (scramble — свалка, беспорядочная сборка). Схема включения скремблера в канал связи Скремблер в передатчике выполняет преобразование структуры исходного цифрового потока. Дескремблер в приемнике восстанавливает исходную последовательность бит. Практически единственной операцией, используемой в скремблерах и дескремблерах, является XOR — «побитное исключающее ИЛИ» (сложение по модулю 2). Основная часть скремблера и дескремблера – это генератор псевдослучайной последовательности (ПСП) в виде К-разрядного регистра сдвига с обратными связями. Различают 2 основных типа пар скремблеров – дескремблеров:

  1. самосинхронизирующиеся;
  2. с начальной установкой (аддитивные).

Самосинхронизирующиеся схемы управляются скремблированной последовательностью. Эти схемы имеют недостаток – размножение ошибок. Влияние ошибочного символа проявляется столько раз, сколько обратных связей имеется в схеме. Вариант реализации скремблирования в самосинхронизирующейся схеме. Пусть, например, скремблер реализует соотношение Вi=Ai+Bi-5+Bi-7. Здесь Bi – двоичная цифра результирующего кода, полученная на i-м такте работы скремблера; Ai – двоичная цифра исходного кода, поступающая в передатчике на вход скремблера на i-м такте; Bi-5 и Bi-7 – двоичные цифры результирующего кода, полученные на предыдущих тактах работы скремблера, соответственно на «i-5» и «i-7» тактах. Дескремблер в приемнике восстанавливает исходную последовательность, используя соотношение Ci=Bi+Bi-5+Bi-7=(Ai+Bi-5+Bi-7 )+Bi-5+Bi-7=Ai В аддитивных схемах скремблированная последовательность не поступает на вход регистров сдвига, размножение ошибок отсутствует, но требуется синхронизация работы пары скремблер-дескремблер.

Манчестерский код для чайников

Манчестерский Код — это самосинхронизирующийся двоичный код без постоянной составляющей, в котором значение каждого передаваемого бита определяется направлением смены логического уровня в середине обусловленного заранее временного интервала. Поскольку логических уровней у самой маленькой единицы информации (бит) на данный момент известно всего два (1 и 0), вариантов тут немного: либо смена 1 => 0 либо 0 => 1. Согласно общепринятым стандартам для Манчестерского кода переход от нуля к единице считается 1, а если наоборот, то 0. На самом деле последнее утверждение — это просто формальность — вопрос в том, с какой стороны посмотреть 😉 Главное, чтобы и приёмник и передатчик смотрели на жизнь одинаково.

Код Манчестер

Введите число и нажмите «Encode Manchester!«:

Теперь давайте внимательно посмотрим на картинку и попробуем проанализировать и перечислить основные преимущества и недостатки преобразования данных в Манчестерский Код:

  • Pазмер данных увеличивается вдвое — это негативно сказывается на скорости передачи
  • Kоличество логических нулей всегда равно количеству логических единиц, соответственно у такого сигнала не будет постоянной составляющей — это крайне важно для электрических цепей и радиоволн
  • Комбинация логических уровней 11 однозначно говорит о последнем принятом 0, а комбинация 00, соответственно, говорит о 1. Таким образом после одной из них приёмник синхронизируется
  • Не может идти последовательно более двух одинаковых логических уровней, т.е. комбинация типа 111 или 000 невозможна
  • В начале данных и в конце не может быть двух одинаковых логических уровней — только 10 или 01

Сначала пишем тест

О пользе тестов можно почитать тут. В контексте решения текущей задачи будет использоваться техника Mock-объектов, поэтому для тестирования используется связка gtest (Google Test) + gmock (Google Mocking Framework). Всё это добро поставляются в исходниках, поэтому единственное требование к системе — совместимый C / C++ компилятор, например gcc g++ для Linux или Visual Studio C++ для Windows. Так выглядит простое консольное приложение, которое будет собираться вместе с тестами и запускать их:

#include "gtest/gtest.h" int main(int argc, char* argv[])  testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); > 

Теперь сами тесты. Более простой задачей является преобразование данных в Манчестерский Код (encode), поэтому с неё, пожалуй, и начнём:

#include  #include  extern "C"  #include "../../../../manchester/src/tx/Man_Encode.c" > class IManEncode  public: virtual void Man_Encode_One() = 0; virtual void Man_Encode_Zero() = 0; >; /* Mock implementation */ ACTION_P2(Act_Inc_1, T, V)  ON_CALL(*T, Man_Encode_One()) .WillByDefault(Act_Inc_1(T, testing::ByRef(++V))); > ACTION_P2(Act_Inc_0, T, V)  ON_CALL(*T, Man_Encode_Zero()) .WillByDefault(Act_Inc_0(T, testing::ByRef(++V))); > class ManEncodeMock : public IManEncode  public: MOCK_METHOD0(Man_Encode_One,void()); MOCK_METHOD0(Man_Encode_Zero,void()); ManEncodeMock()  _total_1 = _total_0 = 0; ON_CALL(*this, Man_Encode_One()) .WillByDefault(Act_Inc_1(this, testing::ByRef(_total_1))); ON_CALL(*this, Man_Encode_Zero()) .WillByDefault(Act_Inc_0(this, testing::ByRef(_total_0))); > void Expect_Total_1_And_0_Eq(int total)  EXPECT_EQ(_total_1, total); EXPECT_EQ(_total_0, total); > private: int _total_1, _total_0; >; /* Fixture class for each test */ class ManEncodeTest_F : public testing::Test  public: static ManEncodeMock* getMock()  return _ManEncodePtr; > protected: virtual void SetUp()  _ManEncodePtr = &_ManEncode; > private: ManEncodeMock _ManEncode; static ManEncodeMock* _ManEncodePtr; >; ManEncodeMock* ManEncodeTest_F::_ManEncodePtr; /* Man_Encode externs (events) */ void On_Man_Encode_One()  ManEncodeTest_F::getMock()->Man_Encode_One(); > void On_Man_Encode_Zero()  ManEncodeTest_F::getMock()->Man_Encode_Zero(); > /* 0 => 1010101010101010(manchester) */ TEST_F(ManEncodeTest_F, Send_0)  testing::InSequence s; for (int i = 0; i  8; i++)  EXPECT_CALL(*getMock(), Man_Encode_One()); // MSB EXPECT_CALL(*getMock(), Man_Encode_Zero()); > Man_Encode(0); getMock()->Expect_Total_1_And_0_Eq(8); > /* 255(dec) => 11111111(bin) => 0101010101010101(manchester) */ TEST_F(ManEncodeTest_F, Send_255)  testing::InSequence s; for (int i = 0; i  8; i++)  EXPECT_CALL(*getMock(), Man_Encode_Zero()); // MSB EXPECT_CALL(*getMock(), Man_Encode_One()); > Man_Encode(255); getMock()->Expect_Total_1_And_0_Eq(8); > /* 170(dec) => 10101010(bin) => 0110011001100110(manchester) */ TEST_F(ManEncodeTest_F, Send_170)  testing::InSequence s; EXPECT_CALL(*getMock(), Man_Encode_Zero()); // MSB for (int i = 0; i  3; i++)  EXPECT_CALL(*getMock(), Man_Encode_One()).Times(2); EXPECT_CALL(*getMock(), Man_Encode_Zero()).Times(2); > EXPECT_CALL(*getMock(), Man_Encode_One()).Times(2); EXPECT_CALL(*getMock(), Man_Encode_Zero()); Man_Encode(170); getMock()->Expect_Total_1_And_0_Eq(8); > /* 85(dec) => 01010101(bin) => 1001100110011001(manchester) */ TEST_F(ManEncodeTest_F, Send_85)  testing::InSequence s; EXPECT_CALL(*getMock(), Man_Encode_One()); // MSB for (int i = 0; i  3; i++)  EXPECT_CALL(*getMock(), Man_Encode_Zero()).Times(2); EXPECT_CALL(*getMock(), Man_Encode_One()).Times(2); > EXPECT_CALL(*getMock(), Man_Encode_Zero()).Times(2); EXPECT_CALL(*getMock(), Man_Encode_One()); Man_Encode(85); getMock()->Expect_Total_1_And_0_Eq(8); > /* 84(dec) => 01010100(bin) => 1001100110011010(manchester) */ TEST_F(ManEncodeTest_F, Send_84)  testing::InSequence s; EXPECT_CALL(*getMock(), Man_Encode_One()); // MSB for (int i = 0; i  3; i++)  EXPECT_CALL(*getMock(), Man_Encode_Zero()).Times(2); EXPECT_CALL(*getMock(), Man_Encode_One()).Times(2); > EXPECT_CALL(*getMock(), Man_Encode_Zero()); EXPECT_CALL(*getMock(), Man_Encode_One()); EXPECT_CALL(*getMock(), Man_Encode_Zero()); Man_Encode(84); getMock()->Expect_Total_1_And_0_Eq(8); > 

Все тесты помещены в макрос TEST_F() . В начале теста с помощью EXPECT_CALL() необходимо установить ожидаемое поведение. В процессе преобразования 0 => 1010101010101010 и при условии, что старший бит идёт первым (MSB), ожидается последовательный вызов методов On_Man_Encode_One() и On_Man_Encode_Zero() и так восемь раз. После того, как ожидаемое поведение описано, необходимо вызвать проверяемый метод Man_Encode() . Если реальное поведение отличается от ожидаемого, в процессе выполнения тестов будет сообщено об ошибке. В конце каждого теста также выполняется проверка условия, что количество нулей равно количеству единиц.

Преобразовать данные в Манчестерский Код очень легко:

#include "Man_Encode.h" /******************************************************************** * Function Name: Man_Encode * * Return Value: no * * Parameters: character to transmit * * Description: Convert char to Manchester Code (2 chars) * * MSB is first to convert * ********************************************************************/ void Man_Encode(register char character)  register unsigned char bitcount = 8; while (bitcount--)  if (character & 0x80)  On_Man_Encode_Zero(); On_Man_Encode_One(); > else  On_Man_Encode_One(); On_Man_Encode_Zero(); > character  1; > > 

Реализация обратной задачи — декодирования данных из Манчестерского Кода в оригинальный несколько сложнее. Перед началом передачи данных необходимо синхронизироваться с приёмником сиигнала. В реализации тестов нас особо не интересует как именно приёмник синхронизируется и в какой последовательности будут вызваны(если вообще будут) On_Man_Decode_Add_1() и On_Man_Decode_Add_0() — для этой цели обозначим предварительные ожидания как testing::AtMost(1) . После синхронизации процесс декодирования можно точно спрогнозировать и описать соответствующие ожидания с помощью EXPECT_CALL() . Также как и в предыдущем случае в конце каждого теста проверяется отсутствие постоянной составляющей (количество нулей и единиц должно совпадать).

#include  #include  extern "C"  #include "../../../../manchester/src/rx/Man_Decode.c" > class IManDecode  public: virtual void Man_Dec_Add_1() = 0; virtual void Man_Dec_Add_0() = 0; >; /* Mock implementation */ class ManDecodeMock : public IManDecode  public: MOCK_METHOD0(Man_Dec_Add_1,void()); MOCK_METHOD0(Man_Dec_Add_0,void()); >; /* Fixture class for each test */ class ManDecodeTest_F : public testing::Test  public: static ManDecodeMock* getMock()  return _ManDecodePtr; > protected: virtual void SetUp()  _total_1 = _total_0 = 0; _ManDecodePtr = &_ManDecode; > void Expect_Total_1_And_0_Eq(int total)  EXPECT_EQ(_total_1, total); EXPECT_EQ(_total_0, total); > void Perform_Stable_Zero(unsigned char periods)  _total_0 += periods; Man_Decode_Stable_Zero(periods); > void Perform_Stable_One(unsigned char periods)  _total_1 += periods; Man_Decode_Stable_One(periods); > private: ManDecodeMock _ManDecode; static ManDecodeMock* _ManDecodePtr; int _total_1, _total_0; >; ManDecodeMock* ManDecodeTest_F::_ManDecodePtr; /* Man_Decode externs (events) */ void On_Man_Decode_Add_1()  ManDecodeTest_F::getMock()->Man_Dec_Add_1(); > void On_Man_Decode_Add_0()  ManDecodeTest_F::getMock()->Man_Dec_Add_0(); > /* Helpers for TEST_F */ #define EXPECT_MAN_SYNCH(x,y) \ EXPECT_CALL(*getMock(), Man_Dec_Add_##x()) \ .Times(testing::AtMost(1)); /* Clay? */ \ EXPECT_CALL(*getMock(), Man_Dec_Add_##y()) \ .Times(testing::AtMost(1)); /* Clay? */ \ EXPECT_CALL(*getMock(), Man_Dec_Add_##x()); /* Sync */ \ EXPECT_CALL(*getMock(), Man_Dec_Add_##y()) /* Sync */ \ #define PERFORM_MAN_SYNCH(x,y) \ Perform_Stable_##x(1); /* Clay balance (1 - 1 = 0) */ \ Perform_Stable_##y(2); /* Sync balance (2 - 2 = 0) */ \ Perform_Stable_##x(2); /* Sync */ \ Perform_Stable_##y(1) /* Clay */ \ /* 1010101010101010(manchester) => 0 */ TEST_F(ManDecodeTest_F, Decode_0)  testing::InSequence s; EXPECT_MAN_SYNCH(1,0); EXPECT_CALL(*getMock(), Man_Dec_Add_0()).Times(8); PERFORM_MAN_SYNCH(One, Zero); for (int i = 0; i  8; i++)  Perform_Stable_One(1); Perform_Stable_Zero(1); > Expect_Total_1_And_0_Eq(11); // Sync(3) + Byte(8) > /* 0101010101010101(manchester) => 11111111(bin) => 255(dec) */ TEST_F(ManDecodeTest_F, Decode_255)  testing::InSequence s; EXPECT_MAN_SYNCH(0,1); EXPECT_CALL(*getMock(), Man_Dec_Add_1()).Times(8); PERFORM_MAN_SYNCH(Zero, One); for (int i = 0; i  8; i++)  Perform_Stable_Zero(1); Perform_Stable_One(1); > Expect_Total_1_And_0_Eq(11); // Sync(3) + Byte(8) > /* 0110011001100110(manchester) => 10101010(bin) => 170(dec) */ TEST_F(ManDecodeTest_F, Decode_170)  testing::InSequence s; EXPECT_MAN_SYNCH(0,1); for (int i = 0; i  4; i++)  EXPECT_CALL(*getMock(), Man_Dec_Add_1()); EXPECT_CALL(*getMock(), Man_Dec_Add_0()); > PERFORM_MAN_SYNCH(Zero, One); Perform_Stable_Zero(1); for (int i = 0; i  3; i++)  Perform_Stable_One(2); Perform_Stable_Zero(2); > Perform_Stable_One(2); Perform_Stable_Zero(1); Expect_Total_1_And_0_Eq(11); // Sync(3) + Byte(8) > /* 1001100110011001(manchester) => 01010101(bin) => 85(dec) */ TEST_F(ManDecodeTest_F, Decode_85)  testing::InSequence s; EXPECT_MAN_SYNCH(1,0); for (int i = 0; i  4; i++)  EXPECT_CALL(*getMock(), Man_Dec_Add_0()); EXPECT_CALL(*getMock(), Man_Dec_Add_1()); > PERFORM_MAN_SYNCH(One, Zero); Perform_Stable_One(1); for (int i = 0; i  3; i++)  Perform_Stable_Zero(2); Perform_Stable_One(2); > Perform_Stable_Zero(2); Perform_Stable_One(1); Expect_Total_1_And_0_Eq(11); // Sync(3) + Byte(8) > /* 1001100110011010(manchester) => 84(dec) => 01010100(bin) */ TEST_F(ManDecodeTest_F, Decode_84)  testing::InSequence s; EXPECT_MAN_SYNCH(1,0); for (int i = 0; i  3; i++)  EXPECT_CALL(*getMock(), Man_Dec_Add_0()); EXPECT_CALL(*getMock(), Man_Dec_Add_1()); > EXPECT_CALL(*getMock(), Man_Dec_Add_0()).Times(2); PERFORM_MAN_SYNCH(One, Zero); Perform_Stable_One(1); for (int i = 0; i  3; i++)  Perform_Stable_Zero(2); Perform_Stable_One(2); > Perform_Stable_Zero(1); Perform_Stable_One(1); Perform_Stable_Zero(1); Expect_Total_1_And_0_Eq(11); // Sync(3) + Byte(8) > 

Предположительная реализация процесса декодирования Манчестерского кода:

#include "Man_Decode.h" static bool ds_LB; /******************************************************************** * Function Name: Man_Decode_Stable_Zero * * Return Value: no * * Parameters: Stable digital input periods. Ideal 1 or 2 * * Description: Convert signal from Manchester Code. * * Fire according On_Man_Decode_Add_1() * * callback event. * ********************************************************************/ void Man_Decode_Stable_Zero(register unsigned char periods)  if ( periods )  if ( !--periods )  if ( ds_LB )  On_Man_Decode_Add_1(); ds_LB = 1; > > else if ( !--periods )  On_Man_Decode_Add_1(); ds_LB = 1; > > > /******************************************************************** * Function Name: Man_Decode_Stable_One * * Return Value: no * * Parameters: Stable digital input periods. Ideal 1 or 2 * * Description: Convert signal from Manchester Code. * * Fire according On_Man_Decode_Add_0() * * callback event. * ********************************************************************/ void Man_Decode_Stable_One(register unsigned char periods)  if ( periods )  if ( !--periods )  if ( !ds_LB )  On_Man_Decode_Add_0(); ds_LB = 0; > > else if ( !--periods )  On_Man_Decode_Add_0(); ds_LB = 0; > > > 

Сборка и запуск тестов

Если Вы работаете в связке Windows + Visual Studio, необходимо выполнить следующее:

@set GTEST_HOME=gtest-1.6.0 @set GMOCK_HOME=gmock-1.6.0 cl /EHsc /I%GTEST_HOME% /I%GTEST_HOME%/include -I%GMOCK_HOME% ^ -I%GMOCK_HOME%/include main.cpp src/manchester/Man_Encode.cpp ^ src/manchester/Man_Decode.cpp %GTEST_HOME%/src/gtest-all.cc ^ %GMOCK_HOME%/src/gmock-all.cc main.exe

Windows Скриншот

При использовании Linux + gcc g++:

GTEST_HOME=gtest-1.6.0 GMOCK_HOME=gmock-1.6.0 g++ -g -I$GTEST_HOME -I$GTEST_HOME/include -I$GMOCK_HOME \ -I$GMOCK_HOME/include -pthread main.cpp src/manchester/Man_Encode.cpp \ src/manchester/Man_Decode.cpp $GTEST_HOME/src/gtest-all.cc \ $GMOCK_HOME/src/gmock-all.cc ./a.out

Linux Скриншот

Тестов много не бывает. Например, было бы неплохо добавить проверку для последовательности из двух байт и более, или проверку условия отсутствия невозможных для Манчестерского Кода комбинаций — например 111 или 000. Чем больше терпения и выдержки на этом этапе разработки — тем крепче будет сон после её сдачи в эксплуатацию.

Практика

Тесты это хорошо, но пока что всё это больше похоже на теорию — а теория без практики, как известно, скучна. Поэтому, если Вы дочитали до этого момента, милости прошу посетить следующий пост, в котором в качестве приёмника и передатчика используются два микроконтроллера, а сам процесс эмулируется в виртуальной среде, которая умеет моделировать поведение электрических цепей.

Исходники к текущему посту на GitHub.

Манчестерский код. Синхронизация, приём и декодирование

Итак, для начала поговорим о том, что представляет собой «манчестерское» кодирование.

В «манчестерском» коде единица кодируется переходом сигнала в середине битового интервала из состояния «OFF» в состояние «ON», а ноль — наоборот, переходом сигнала в середине
битового интервала из состояния «ON» в состояние «OFF».

Что такое состояния «ON» и «OFF»?
Состояния сигнала «ON» и «OFF» — это логические состояния. В общем случае «OFF» — это неактивное состояние, такое же, как при отсутствии какого-либо обмена вообще, а «ON» — это активное состояние, то есть такое, которое как-либо отличается от неактивного. Поэтому, несмотря на то, что на картинке справа состояние сигнала «ON» показано высоким уровнем сигнала, а состояние «OFF» показано низким уровнем, это не нужно понимать буквально (просто с высоким и низким уровнем картинка привычнее и нагляднее). На самом деле состояния «ON» и «OFF» могут быть закодированы совершенно по-разному. Например, ИК-пульты кодируют эти состояния наличием или отсутствием импульсов на определённой частоте, интегральные фотоприёмники (у которых чаще всего неактивным является высокий уровень сигнала на выходе) выдают код, в котором «ON» закодировано низким уровнем, а «OFF» — высоким и т.д.

Длительность нуля и единицы в манчестерском кодировании одинаковая, то есть длина сообщения не зависит от того, сколько в сообщении нулей или единиц, а зависит только от общего количества бит.

Ключевым свойством «манчестерского» кодирования является то, что при передаче каждого бита обязательно присутствуют оба состояния сигнала: «ON» и «OFF» (ещё раз смотрим на рисунок вверху). То есть, во время передачи каждого бита сигнал должен хотя бы раз изменить своё состояние. То есть «манчестерский» код может состоять только из интервалов одинарной, если соседние биты одинаковые, и двойной, если соседние биты отличаются, длительности (это продемонстрировано на рисунке слева).

Описанное свойство позволяет дополнительно синхронизировать приёмник с передатчиком при приёме каждого бита, определять — может ли вообще принимаемый код быть «манчестерским», диагностировать конец сообщения или «потерю» сигнала передатчика.

Скажем, если предположить, что частота передатчика не может скачком измениться более чем в 1,5 раза, то отсутствие изменения состояния сигнала в течении 3-х полубит можно смело трактовать как конец сообщения или «потерю» сигнала передатчика (если мы заранее знаем длину сообщения). Или, например, при исследовании какого-то неизвестного кода, если мы видим, что в коде присутствует более двух вариантов интервалов между состояниями «ON» и «OFF», то можно однозначно сделать заключение о том, что исследуемый код не «манчестерский».

Надеюсь, с тем, что такое «манчестерский» код, всё более или менее понятно, поэтому переходим к следующему вопросу — как этот код принимать и декодировать.

Ну, очевидно, что определить начало передачи данных можно по изменению состояния сигнала, воспринимаемого приёмником, с «OFF» на «ON». Однако тут есть один нюанс. Поскольку передача единицы тоже начинается с состояния «OFF», то при первом изменении сигнала из «OFF» в «ON» мы совершенно никак не сможем диагностировать что это — середина передачи единицы или начало передачи нуля. Единственное, что тут можно сделать — это заранее условиться, какой бит должен передаваться первым (то есть ввести специальный старт-бит, значение которого будет всегда строго определено).

Всё, теперь, если мы знаем с какого бита посылка начинается, знаем длительности интервалов состояний «ON» и «OFF», наш приёмник обладает точным, стабильным генератором и мы
точно знаем сколько хотим принять бит, то можно составить первый простейший алгоритм восстановления исходной, закодированной «манчестерским» кодом посылки:

  1. — по изменению состояния сигнала с «OFF» на «ON» определяем начало передачи
  2. — отсчитываем четверть длительности бита (чтобы попасть в середину полубита)
  3. — начинаем записывать значение сигнала. С этого момента и далее через интервалы, равные длительности бита. И так — до получения необходимого количества бит.

Вариант второй. Мы знаем с какого бита посылка начинается, знаем длительности интервалов «ON» и «OFF», наш приёмник обладает стабильным генератором, но мы ничего не знаем о длине сообщения. В этом случае можно воспользоваться тем свойством манчестерского кода, что сигнал не может оставаться постоянным в течении 3-х и более полубит. То есть, момент, когда сигнал в течении 3-х полубит остаётся в состоянии «OFF» можно считать концом сообщения. Алгоритм восстановления исходного кода в этом случае может выглядеть так:

  1. — по изменению состояния сигнала с «OFF» на «ON» определяем начало передачи
  2. — отсчитываем четверть длительности бита (чтобы попасть в середину полубита)
  3. — с этого момента (пусть это будет момент номер 1) и далее, через интервалы, равные длительности полубита, анализируем значение сигнала. Как только
    случится такое, что сигнал в трёх последних замерах будет в состоянии «OFF» — это будет сигнализировать об окончании сообщения. Кроме того, записывая значение сигнала во все моменты с нечетными номерами, кроме последнего, — мы восстановим исходное сообщение.

Вариант третий. Мы знаем с какого бита посылка начинается, но не знаем длительности интервалов, в течении которых сигнал находится в состоянии «ON» и «OFF». Что нам делать в
этом случае? Если вы по счастливой случайности знаете значение не только первого бита, но и второго, — значит вам точно известно, через какие интервалы (через целый бит или через половину)
произойдут первые 2 переключения и вы с лёгкостью можете необходимые интервалы засечь или, научно выражаясь, — синхронизировать приёмник с передатчиком.
(Ага, вот мы и раскусили зачем у RC-5 целых 2 стартовых бита. Кстати, в сетях ethernet, где тоже используется «манчестерское» кодирование, для начальной синхронизации используется целая 56-битная преамбула).
Далее можно легко воспользоваться первым или вторым из приведённых выше алгоритмов.

Ну и, предположим, ещё один вариант. Мы знаем первые два бита посылки, но наш генератор — полное говно, хотя и работает (или, говоря научными терминами, мы можем гарантировать, что за время, равное длительности полубита, частота генератора не может измениться в 1,5 раза и более). Тут-то как быть?

Да просто надо по каждому новому фронту заново вычислять значения длительности полубита и целого бита. То есть, другими словами, нужно синхронизировать приёмник с передатчиком не один раз в самом начале, а по каждому новому фронту (под фронтом будем понимать переключения между состояниями «ON»/»OFF»), благо при манчестерском кодировании у нас новый фронт присутствует в каждом передаваемом бите.

Короче говоря, рассматривать разные комбинации можно долго, запомните главное преимущество, за которое «манчестерский» код всем так полюбился: при передаче каждого бита существует изменение состояния «ON»/»OFF», которое даёт возможность синхронизировать передатчик и приёмник.

Кроме описанного выше, существует ещё, так называемое, «разностное» или «дифференциальное» «манчестерское» кодирование. В данном случае при передаче нуля битовый интервал начинается с изменения состояния сигнала на противоположное, а при передаче единицы — состояние сигнала в начале битового интервала не изменяется. В остальном всё так же, как и в обычном «манчестерском» кодировании — в середине битового интервала состояние сигнала обязательно меняется на противоположное (смотрим рисунок слева).

Самодельные ИК-пульты и приёмники сигналов дистанционного управления

Понравилась статья? Поделись с друзьями!

16. Манчестерский код.

Манчестерский код. В локальных сетях Ethernet и Token Ring.он является самым распространенным методом кодирования. В нем для кодирования единиц и нулей используется перепад потенциала. При кодировании каждый такт делится на две части. Первая часть используется для передачи значения бита, а вторая – противоположным значением (перепадом потенциала). Так как сигнал изменяется по крайней мере один раз за такт передачи одного бита данных, то манчестерский код обладает хорошими самосинхронизирующими свойствами. Полоса пропускания манчестерского кода уже, чем у биполярного импульсного. Манчестерский код имеет еще одно преимущество перед биполярным импульсным кодом: в нем используются не три уровня сигнала, а два.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *