Здравствуйте, Дорогие друзья! В этой статье мы с Вами разберемся с тем, как между собой «общаются» электронные компоненты и модули. Речь конечно же пойдёт об программируемых электронных компонентах.
Самый простой способ взаимодействия – передача сообщения в виде короткого импульса от вывода одного компонента на вывод другого:
Основные недостатки данного способа:
- Низкая скорость передачи данных;
- Требуется большое количество выводов для организации линий связи;
- Требуется детальная проработка программного кода с целью организации точного позиционирования импульса во временной области.
Для новичков эти три пункта могут показаться простым набором слов. Поэтому постараюсь объяснить просто и понятно. Разберем первый пункт. Любой электронный компонент имеет в своем составе специальный генератор импульсов или же такой генератор подключается к компоненту через один из его выводов. Задача этого генератора – создавать специальный сигнал: импульсы определенной формы. Амплитуда и период этого сигнала всегда одинаковые. Такой генератор – это личные часы компонента. Для него не существует понятий секунда, минута, час, микросекунда и т.д. Есть только такт, то есть кусочек времени, равный периоду сигнала генератора. На выполнение какой-либо операции компоненту требуется определенное количество тактов. Предположим, что частота генератора будет равна 1МГц, то есть простейшую операцию компонент будет выполнять в течение 1мкс. Также предположим, что нам нужно передать, скажем, 4 байта полезной информации другому компоненту. Для этого нам понадобится задействовать как минимум два вывода каждого компонента. И передача эта будет выглядеть как-то так:
Как видите, всё просто и понятно: первый такт передачи – на время одного такта поднимаем логический уровень на одном из выводов в «единицу», то есть говорим принимающему данные компоненту «сейчас мы начнем передавать тебе информацию, подготовься». Второй такт и последующие – выставляем на втором выводе компонента логические нули и единицы: нашу передаваемую информацию. Делаем это до того, пока все данные не будут переданы. Затем снова подаем команду через первый вывод, но на этот раз она уже будет означать «я передал данные, больше не будет». Ну и где здесь большая затрата времени? А вот где: реализовать подобную схему обмена данными можно, но не в таком виде. Что мы не учли в текущей схеме? Мы, возможно, сможем передавать данные с большой скоростью, но эти нолики и единички – не простой набор символов, и мы передаем их не просто так, а для того, чтобы принимающее устройство с ними что-то сделало. То есть компоненту №2 требуется время на то, чтобы обработать принятые данные, а мы ему этого времени не даём. Из этой ситуации есть два выхода: или снизить скорость передачи данных, или задействовать ещё по одному выводу компонентов, для того, чтобы принимающее устройство могло сказать передающему «я готов принимать дальше, передавай». Тогда схема передачи несколько изменится. Мы сможем разделить передаваемые данные на несколько частей – пакетов, длина которых позволит принимающему устройству качественно выполнять их обработку:
Теперь представьте следующую картину:
Как неожиданно... Мы не только не передали всю информацию, а вообще не получили на приемной стороне даже какую-то белиберду. Почему это произошло? Обратите внимание на сигналы «отправляющее» и «такт» на рисунке 4: первый – это передаваемая информация, третий – сигнал генератора. Они как бы связаны друг с другом: изменение логического уровня на первом происходит точно во время, когда на третьем «единица». Но тогда что произошло с принимающим устройством, почему оно молчит? А вот почему:
В рассматриваемой нами схеме передачи-приема устройства никак между собой по сути не связаны. Да, мы подключили провода к их выводам, соединив их, но при этом сами устройства продолжают существовать обособленно. Да они работают с одной и той же частотой и с одним и тем же напряжением питания и логики, но при этом у каждого свой НЕЗАВИСИМЫЙ генератор. Как исправить то, что получилось на рисунке 5? Очень просто, но в то же время и очень затратно: выделить ещё по одному выводу компонентов на то, чтобы синхронизировать их между собой. Пусть у них будет общий генератор и, лучше всего, пусть это будет не генератор передающего устройства, а некий внешний генератор. Тогда устройства будут работать синхронно и вероятность успешной передачи данных будет высокой. Вот так, решая первую проблему, мы создали вторую: теперь для успешной организации линии связи нам требуется большое количество выводов устройств.
Теперь разберемся с позиционированием. Тут всё вообще просто: расположить управляющие импульсы и импульсы, несущие информацию, таким образом, чтобы принимающее устройство смогло их принять, а передающее передать. То есть необходимо избежать ситуации, когда принимающее устройство ожидает информацию, а передающее и не думает начинать её передавать, либо наоборот, когда передающее устройство начинает передачу, не уведомив об этом принимающее устройство.
Мы рассмотрели последовательный интерфейс передачи данных. То есть способ связи, когда данные передаются последовательно. Я, можно сказать, взял его из головы, чтобы простыми словами объяснить принцип взаимодействия устройств при применении последовательных интерфейсов, так как он отражает суть большинства существующих способов обмена информацией.
Существует ещё один способ передачи данных. Он является самым быстрым и понятным, но в то же время и самым требовательным к свободным выводам элементов.
Конкретного названия данный способ не имеет. Но чаще всего его именуют параллельный интерфейс или “parallel”. Данный способ позволяет передавать одновременно по несколько бит полезной информации, при этом, проводники, используемые для передачи, образуют ШИНУ данных. То есть нечто общее, объединенное, но «многопроводное». Главный и, возможно, единственный существенный недостаток параллельных интерфейсов – для организации линий связи требуется большое количество выводов. Используется данный интерфейс в микросхемах памяти, драйверах сегментных индикаторах, дешифраторах, преобразователях, матрицах и т.д.
Рассмотрим наиболее распространенные последовательные интерфейсы обмена данными. Начнем с самого простого и понятного – SPI. SPI– четырехпроводная шина передачи данных (на самом деле пяти проводная, просто провод GNDне учитывают, подразумевая, что устройства и так соединены им между собой). Передача данных с помощью SPIосуществляется по принципу «Хозяин - Раб». Как по мне, такое название принципа передачи данных искажает его суть, поэтому будем именовать его не менее распространенным названием «Ведущий - Ведомый». Ведущим в этой паре выступает передающее устройство (его принято называть «Master»), а ведомым – принимающее (его называют также «Slave device» или просто «Slave»). Весь смысл интерфейса SPI заключается в том, что к ведущему устройству подключается одно или несколько ведомых. Один из проводов шины служит для односторонней связи ведомого с ведущим(MISO – «Master In Slave Out»), другой – для передачи данных от ведущего к ведомому(MOSI – «Master Out Slave In»). Как я уже сказал, все ведомые и ведущий соединены между собой проводом GND. А теперь самое интересное: как организован обмен данными. Все ведомые получают сигнал тактового генератора от ведущего (тактируются от ведущего). Пятый провод шины, о котором мы ещё ничего не сказали называют CS(«Chip Select»), само это название наталкивает на мысль для чего он нужен. Изначально к данному проводу приложен высокий логический уровень (единица, проще говоря). Перед началом передачи ведущее устройство изменяет значение логического уровня на выводе CSведомого устройства, которому будет передаваться информация, на низкое (из единицы в ноль, то есть, можно сказать, что провод «садят на землю»). Затем выполняется передача данных по проводу MOSI . Если требуется контролировать выполнена ли передача, по проводу MISO ведомое устройство дублирует полученную информацию (обычно передается один байт по MOSI и ведомое возвращает его по MISO). Как только информация будет передана, ведущее устройство «отпускает» провод CS ведомого. Рассмотрим случай, когда имеется одно ведущее и одно ведомое устройство. Пусть от нас требуется передать ведомому 1байт полезной информации:
Количество ведомых устройств, подключаемых по SPIк ведущему может быть сколь угодно большим. Вернее их может быть столько, сколько выводов для CS1, CS2, CS3… мы готовы выделить. Теперь о том, что мы можем передать ведомому: это могут быть обычные данные (полезная информация, которую ведомое должно как-нибудь обработать, например записать в память), либо команда. В последнем случае ведомое устройство должно иметь собственный список команд (мы ведь не можем написать нули и единицы из головы и ждать при этом от ведомого нужной реакции). Например, нам нужно получить информацию от какого-нибудь датчика: ведущее устройство передает ему соответствующую команду по проводу MOSI, а по проводу MISO получает требуемые данные. Не стоит забывать, что универсален только SPI как способ передачи данных, универсальных команд для ведомых устройств нет, команды для того или иного устройства прописываются в его памяти (памяти ведомого) производителем. Для ведомого – это кодовые слова, в то время как для ведущего – обычная полезная информация. Ведомые устройства могут быть подключены между собой по-разному, но об этом мы вспомним, когда будем говорить о топологиях сетей.
Всем удобен SPI: скорость передачи у него высокая, принцип работы понятен, вот только количество выводов, которое нужно задействовать для организации шины связи, немного пугает. Рассмотрим способ связи, в котором для формирования шины нам понадобится всего два провода – I2C или IIC(по факту нам потребуется опять-таки на один провод больше, потому что «умные люди» не любят учитывать общий провод). Итак, как можно добиться обмена данными только по двум проводам? Очень просто: «выбросим» провода CS и найдём эквивалент для проводов MOSI и MISO. То есть связь в I2C организована с применением входов/выходов. Для тех, кто не понял, поясняю: устройство через один из своих выводов отправляет данные, через некоторое время данное устройство через этот же вывод получает данные от других устройств. То есть этот вывод является как выходом, так и входом, поэтому применимо к нему можно сказать, что он является входом/выходом. Провод, по которому передается тактирующий сигнал называют CLK, провод, по которому передаются данные – SDA. С этим понятно. Но как ведомый будет понимать, что ведущий обращается именно к нему, ведь выводы CSмы убрали? Нет ничего более простого: ведущий прямым текстом последовательностью из нескольких бит (чаще всего из 8) говорит об этом. То есть перед началом передачи данных ведущее устройство отправляет по шине информацию ВСЕМ ведомым. Данная информация содержит адрес ведомого (7 бит) и уточняющие данные (1 бит). Адреса для конкретных устройств задаются производителем, но они являются базовыми и могут «сдвигаться» аппаратно или программно. Восьмой бит указывает на то, что ведущему требуется от ведомого, если передан «0», то ведомый должен подготовиться к приему информации, если передана единица – ведомый должен передать ведущему информацию. Теперь об интересной особенности: оба провода шины «подтянуты» к питанию. То есть, для того, чтобы передать единицу устройство должно «дёргать» только за CLK. Сам процесс передачи простой: ведущий передал адрес всем ведомым, выбранный ведомый откликнулся, ведущий НЕ генерирует тактовый сигнал, то есть уровень на выводах CLK высокий, при этом ведущий опускает провод SDAв «0» - это говорит ведомому о начале процесса передачи. Далее выполняется тактирование и передача данных по 1 байту. При этом, после успешного приема каждого байта ведомое устройство отправляет ведущему бит подтверждения. После завершения процесса передачи всех данных устройство должно «отпустить шину», то есть перестать на неё воздействовать, при этом также сообщить о завершении передачи ведомому. Для этого ведущий как бы отзеркаливает стартовый сигнал: на высоком уровне CLKон поднимает уровень на выводах SDAв единицу и больше ими не оперирует. То есть шина возвращается в исходное состояние. На рисунке 8 я показал пример передачи данных.
Таким образом, одни из главных недостатков данного интерфейса – невысокая скорость передачи данных и ограниченное число ведомых (не так уж и критично, мы ведь не собираемся «обвешивать» компонент сотнями ведомых). Достоинства же: низкая требовательность к выводам ведущего, понятность, а также универсальность.
Что ж, мы с Вами рассмотрели общие принципы функционирования последовательных и параллельных интерфейсов, а также поверхностно познакомились с двумя широко распространенными последовательными интерфейсами: SPI и I2C. Надеюсь, что данная статья была Вам полезной. Спасибо, что читаете. Удачи в учебе и труде!