Код Грея (отражённый двоичный код) — способ записи чисел, при котором два соседних числа отличаются ровно одним разрядом. Его запатентовал инженер Bell Labs Фрэнк Грей: заявка подана в 1947 году, патент US 2 632 058 выдан в 1953-м. Сегодня код Грея стоит на дисках абсолютных энкодеров и в указателях асинхронных FIFO.
Как пользоваться
- Выберите разрядность кода — от 1 до 32 бит — и запись числа: двоичную, десятичную или шестнадцатеричную.
- Выберите направление: двоичный → Грей, если известно число (номер положения), или Грей → двоичный, если известен прочитанный код.
- Введите число. При переключении направления результат переносится в поле ввода — так удобно проверять перевод в обе стороны.
Калькулятор показывает результат в двоичном, десятичном и шестнадцатеричном виде, вычисление через XOR, коды соседних позиций и номер бита, который при переходе к ним меняется. Для кода до 8 бит рисуется кодовый диск, до 6 бит — полная таблица; при большей разрядности — 8 позиций до и после выбранной.
Формулы перевода
Пусть bn−1…b1b0 — разряды двоичного числа, gn−1…g0 — разряды кода Грея, разряд 0 младший. Прямой перевод — XOR соседних разрядов:
Обратный перевод идёт от старшего разряда: каждый двоичный разряд — XOR всех разрядов кода от старшего до него самого:
Обе формулы — это формулы (1) и (2) из патента Грея, записанные через XOR вместо сложения по модулю 2. Поразрядный обратный перевод требует n − 1 шагов, но его можно ускорить: после g ^= g >> 1 каждый разряд содержит XOR двух соседних, после g ^= g >> 2 — четырёх, и так далее. Поэтому для 32-битного кода хватает пяти сдвигов, для 8-битного — трёх.
Таблица кода Грея на 4 бита
| Число | Двоичный | Грей | Число | Двоичный | Грей |
|---|---|---|---|---|---|
| 0 | 0000 | 0000 | 8 | 1000 | 1100 |
| 1 | 0001 | 0001 | 9 | 1001 | 1101 |
| 2 | 0010 | 0011 | 10 | 1010 | 1111 |
| 3 | 0011 | 0010 | 11 | 1011 | 1110 |
| 4 | 0100 | 0110 | 12 | 1100 | 1010 |
| 5 | 0101 | 0111 | 13 | 1101 | 1011 |
| 6 | 0110 | 0101 | 14 | 1110 | 1001 |
| 7 | 0111 | 0100 | 15 | 1111 | 1000 |
Видно, откуда название «отражённый»: младшие три разряда второй половины таблицы повторяют первую половину в обратном порядке, а старший разряд становится единицей. Так Грей и строил код — из одноразрядного двухразрядный, из него трёхразрядный и далее. Переход от 15 к 0 тоже меняет один разряд — старший, поэтому код замкнут в кольцо.
Где применяется
Абсолютные энкодеры
Абсолютный энкодер выдаёт код угла сразу, без подсчёта импульсов, и помнит положение после выключения питания. Каждый разряд кода снимается с отдельной дорожки диска. Если бы дорожки несли обычный двоичный код, на границе секторов 7 и 8 одновременно переключались бы четыре контакта, а из-за разброса их срабатывания энкодер на мгновение выдавал бы случайные значения — например, 15 или 0. С кодом Грея на каждой границе переключается одна дорожка.
Пример — механический энкодер TT Electronics EN16AB на 16 положений. В даташите приведены состояния четырёх выводов для трёх вариантов: положения в нём пронумерованы с 1, и в варианте 0 выводы 1–4 дают четырёхразрядный код Грея числа «номер положения − 1»: положение 1 — 0000, положение 16 — 1000 (вывод 1 — младший разряд). В варианте 1 — тот же код с обратным порядком выводов, в варианте 2 — обычный двоичный код того же числа. Функция gray_to_bin() вернёт число от 0 до 15; чтобы получить номер по даташиту, прибавьте 1.
Не все абсолютные энкодеры используют именно отражённый двоичный код. Bourns ACE-128 размещает 128 положений на одной кодовой дорожке: соседние состояния у него тоже различаются одним битом, но это другой код, и номер положения получают по таблице на 256 байт из даташита. Как устроены энкодеры, их сигналы и подключение, разобрано в статье «Энкодеры».
Указатели асинхронного FIFO
В FIFO между двумя тактовыми доменами указатель записи нужно передать в домен чтения, а указатель чтения — в домен записи. Многоразрядный двоичный счётчик для этого не годится: если синхронизатор защёлкнет его как раз во время перехода 0111 → 1000, получится произвольное число. Клиффорд Каммингс в статье для SNUG 2002 разбирает решение, ставшее стандартным: счётчик считает в двоичном коде, а в регистр указателя пишется (bin >> 1) ^ bin, который за такт меняет один бит.
У указателей на один бит больше, чем нужно для адреса памяти. FIFO пуст, когда указатели в коде Грея совпадают полностью. FIFO полон, когда у них различаются два старших бита, а остальные совпадают: из-за отражения код позиции k + 2ⁿ⁻¹ отличается от кода позиции k именно двумя старшими разрядами. Калькулятор это наглядно показывает: в таблице 4-битного кода строки 0 и 8, 1 и 9 и так далее отличаются только двумя старшими разрядами.
Код на C
Функции для кода до 32 бит, лежащего в младших разрядах слова:
#include <stdint.h>
static inline uint32_t bin_to_gray(uint32_t b)
{
return b ^ (b >> 1);
}
static inline uint32_t gray_to_bin(uint32_t g)
{
g ^= g >> 16;
g ^= g >> 8;
g ^= g >> 4;
g ^= g >> 2;
g ^= g >> 1;
return g;
}
Калькулятор выдаёт эти функции под выбранную разрядность: для 8-битного кода — с типом uint8_t и тремя сдвигами. Для энкодера на выводах порта сначала соберите биты в число в правильном порядке (у EN16AB варианта 0 вывод 1 — младший), затем вызовите gray_to_bin() и, если положения в даташите нумеруются с 1, прибавьте единицу. Сами операции XOR и сдвиги разобраны в статье «Битовые операции в C».
Ограничения и типичные ошибки
- Порядок разрядов. Перепутанные выводы энкодера дают не код Грея, а перестановку его разрядов, и переход между соседними положениями уже может менять несколько бит. Сверяйте порядок выводов с таблицей в даташите.
- Арифметика. Коды Грея нельзя складывать и сравнивать как числа: код позиции 7 — 0100 — как число меньше кода позиции 6 — 0101. Для счёта, сравнения и вычисления разности положений переведите код в двоичный — в FIFO так и делают: счётчик двоичный, в код Грея переводится только передаваемое значение.
- Длина цикла. Отражённый код замыкается в кольцо только при числе позиций 2ⁿ. Если сбросить счётчик Грея раньше — например, после 9 для десяти позиций, — переход 9 → 0 изменит больше одного разряда.
- Код Грея не исправляет ошибки. Он гарантирует только, что при правильном переходе меняется один бит; искажённый разряд он не обнаружит. Для защиты данных служат контрольные биты — например, код Хэмминга.
Другие системы счисления и представления того же числа — двоичное, шестнадцатеричное, дополнительный код — показывает конвертер систем счисления, а сложение и вычитание в двоичном виде с флагами процессора — калькулятор двоичной арифметики.
Частые вопросы
Как перевести двоичное число в код Грея?
Сложить число по модулю 2 (XOR) с ним же, сдвинутым вправо на один разряд: g = b ⊕ (b >> 1). Старший разряд кода Грея равен старшему разряду числа, каждый следующий — XOR соседних разрядов числа. Например, 6 = 0110: 0110 ⊕ 0011 = 0101. Пример из патента Грея: 38 = 0100110₂ в семиразрядном коде Грея записывается как 0110101.
Как перевести код Грея обратно в двоичный?
Старший двоичный разряд равен старшему разряду кода, а каждый следующий двоичный разряд — XOR предыдущего двоичного разряда и очередного разряда кода. Иначе говоря, разряд номер k — XOR всех разрядов кода от старшего до k-го. В программе это несколько сдвигов: g ^= g >> 16; g ^= g >> 8; g ^= g >> 4; g ^= g >> 2; g ^= g >> 1 для 32 бит, для более коротких слов хватает меньшего числа сдвигов.
Зачем абсолютным энкодерам код Грея?
Контакты или оптические датчики разных дорожек переключаются не строго одновременно. В двоичном коде при переходе 0111 → 1000 меняются все четыре разряда, и в момент перехода можно прочитать любое из 16 значений. В коде Грея соседние положения отличаются одним разрядом, поэтому на границе читается либо старое, либо новое положение. Например, у абсолютного энкодера TT Electronics EN16AB на 16 положений вариант 0 выдаёт четырёхразрядный код Грея числа «номер положения − 1» (положения в даташите нумеруются с 1).
Почему в асинхронном FIFO указатели передают в коде Грея?
Указатель записи читается в домене другой тактовой частоты через синхронизатор из двух триггеров. Если при этом меняются сразу несколько бит двоичного счётчика, синхронизатор может защёлкнуть часть старых и часть новых бит и получить значение, которого никогда не было. Указатель в коде Грея за такт меняет один бит, поэтому после синхронизации получается либо старое, либо новое значение — так устроен FIFO в статье К. Каммингса (SNUG 2002).
Бывает ли код Грея на 10 или 12 положений?
Отражённый двоичный код из этого калькулятора замыкается в кольцо только при числе положений, равном степени двойки: 2, 4, 8, 16 и так далее. Каммингс отмечает, что последовательности нечётной длины с изменением одного бита не бывает, а счётчики Грея на чётное число шагов, не равное степени двойки, сделать можно, но перевод для них уже не так прост. Энкодеры на другое число положений используют собственные таблицы: у EN16AB на 12 положений своя таблица выходов, а Bourns ACE-128 выдаёт 8-битный код на 128 положений, который переводят в номер положения по таблице на 256 байт.
Источники
- Gray F. Pulse Code Communication. US Patent 2,632,058, подан 13.11.1947, выдан 17.03.1953 — с. 6 PDF — определение: соседние числа отличаются одной позицией, название «reflected binary code»; с. 7 — построение отражением, трёхразрядная таблица и пример: 38 = 0110101; с. 8 — формулы (1) и (2) перевода между кодами по модулю 2 — эталоны тестов
- Cummings C. E. Simulation and Synthesis Techniques for Asynchronous FIFO Design. SNUG San Jose 2002, Rev 1.2 — разд. 2.3 и 3.2 — указатели FIFO в коде Грея меняют один бит за такт; 3.3 — (n − 1)-битный код из n-битного; 5.1 и 5.2 — условия «пусто» и «полно» на указателях с лишним старшим битом; примеры 6 и 7 — (bin >> 1) ^ bin
- TT Electronics / BI Technologies. EN16AB Series 16 mm Absolute Encoder, Rev A 02/2022 — с. 6, «Output Signal Format» — состояния выводов 1–4 по 16 позициям: вариант 0 — четырёхразрядный код Грея, вариант 1 — он же с обратным порядком выводов, вариант 2 — обычный двоичный (эталоны тестов)
- Bourns. EAW — Absolute Contacting Encoder (ACE), K2540 05/26R — с. 1–2 — 128 положений одной кодовой дорожкой, выход — 8-битный код, для перевода в номер положения нужна таблица на 256 байт
Где пригодится
Встроить калькулятор на свой сайт
Скопируйте код и вставьте его в HTML страницы, статьи или вики. Виджет бесплатный, без рекламы, счётчиков и cookie. Условие одно — ссылка на GAW под рамкой остаётся на месте. Подробнее о виджетах
<iframe src="https://gaw.ru/embed/gray-code/" title="Код Грея: калькулятор и таблица" width="100%" height="640" style="border:1px solid #e3e5e9;border-radius:8px" loading="lazy" allow="clipboard-write"></iframe>
<p style="margin:6px 0 0;font-size:14px">Калькулятор: <a href="https://gaw.ru/tools/gray-code/">Код Грея: калькулятор и таблица</a> — GAW.ru</p>Автоподстройка высоты рамки
Если сайт разрешает скрипты, добавьте этот код один раз в любом месте страницы: рамка будет менять высоту вместе с результатом расчёта.
<script>window.addEventListener("message",function(e){if(e.origin!=="https://gaw.ru"||!e.data||e.data.type!=="gaw:embed-height")return;var f=document.querySelectorAll('iframe[src^="https://gaw.ru/embed/"]');for(var i=0;i<f.length;i++)if(f[i].contentWindow===e.source)f[i].style.height=e.data.height+"px"})</script>Обновлено .
Нашли ошибку в расчёте?