MSP430 – это мощная микроконтроллерная платформа, разработанная и поддерживаемой компанией Texas Instruments для использования во встраиваемых системах различного назначения. Но в современных сложных системах ни один микроконтроллер не может в одиночку решать все множество задач, стоящих перед системой, ему необходима связь с другими устройствами, помогающими ему в решении этих задач. В настоящее время наиболее популярными коммуникационными интерфейсами во встраиваемых системах являются интерфейсы USART, IIC, SPI и CAN. Каждый из них имеет свои собственные достоинства и недостатки. В данной статье мы рассмотрим использование интерфейса (протокола) I2C в плате MSP430G2.
Ранее на нашем сайте мы рассматривали использование интерфейса I2C в других микроконтроллерах (платах):
Как работает интерфейс I2C
IIC (Inter Integrated Circuits), также известный как I2C или даже как TWI (двухпроводный интерфейс), представляет собой синхронный последовательный протокол связи. Передача данных в данном интерфейсе осуществляется с помощью всего 2-х линий – линия передачи данных и линия синхронизации.
Протокол I2C первоначально был разработан компанией Phillips. Он использует для связи 2 провода, которыми можно соединить два устройства. В этом случае одно из этих устройств будет являться ведущим (master), а второе – ведомым (slave). Ведущее устройство всегда одно, ведомых устройств может быть несколько – это одно из преимуществ протокола I2C по сравнению с более ранними аналогичными протоколами.
Линии в интерфейсе I2C называются соответственно линия синхронизации (Serial Clock, SCL) и линия передачи данных (Serial Data, SDA).
Serial Clock (SCL): передает сигнал синхронизации, формируемый ведущим устройством (master), ведомым устройствам (slave).
Serial Data (SDA): передает данные между ведущим и ведомым устройством.
В любой произвольный момент времени в протоколе I2C только ведущее устройство (master) может инициировать (начать) передачу данных. Поскольку к шине I2C может быть подключено более чем одно ведомое устройство, то ведущее устройство должно обращаться к каждому ведомому устройству используя его уникальный адрес. Когда ведущий передал запрос с указанием адреса ведомого запроса, то только это ведомое устройство должно отвечать ведущему, все остальные ведомые в это время должны “хранить молчание”. Таким образом, появляется возможность использования одной и той же шины для передачи данных между несколькими устройствами.
Уровни напряжений для линий интерфейса I2C жестко не заданы, что означает гибкость интерфейса I2C в этих вопросах – на нем можно использовать, к примеру, как уровни напряжений 5v для устройств запитываемых от 5v, так и уровни напряжений 3v для устройств запитываемых от 3.3v. Но что делать если по интерфейсу I2C необходимо соединить два устройства, одно из которых работает от 5V, а другое – от 3.3V. В этом случае устройства нельзя соединять по шине I2C напрямую, необходимо использовать преобразователи уровня напряжения (voltage shifters).
Для осуществления передачи данных необходимо выполнить ряд условий. Начало передачи осуществляется по падающему фронту линии SDA, что на представленном ниже рисунке обозначено условием ‘START’. В это же самое время ведущее устройство должно поддерживать на линии SCL уровень high.
Как показано на представленном рисунке, падающий край импульса на линии SDA означает условие начала передачи (сигнал START), после его получения все устройства, подключенные к линии, переходят в режим прослушивания (listening mode).
Аналогичным образом, восходящий край импульса (rising edge) на линии SDA будет означать условие окончания передачи – условие ‘STOP’ на представленном выше рисунке. На линии SCL в это время должен быть уровень high.
Структура первого передаваемого байта в протоколе I2C показана на следующем рисунке.
Бит R/W в данном адресе указывает на направление передачи последующих байт. Если он HIGH, то это будет означать что передачу данных будет осуществлять ведомое устройство, а если LOW – ведущее устройство.
Каждый бит передается в своем временном цикле. Таким образом, для передачи одного байта необходимо 8 временных циклов. После каждого переданного или принятого байта в девятом временном цикле передается сигнал подтверждения передачи (ACK/NACK, acknowledged/not acknowledged). В зависимости от ситуации бит подтверждения ACK формируется ведомым или ведущим устройством. Для бита ACK на линии SDA устанавливается уровень low ведущим или ведомым устройством в 9-м временном цикле. Если на этой линии уровень low, то подразумевается бит ACK, иначе – бит NACK.
Где используется протокол I2C
Протокол I2C используется только для связи на короткие расстояния. Наличие линии синхронизации делает передачу данных в данном протоколе достаточно устойчивой. В большинстве случаев данный протокол используется для передачи данных от датчиков или других устройств ведущему устройству. Он очень удобен в случаях когда, к примеру, микроконтроллеру, выполняющему роль ведущего устройства, необходимо обмениваться данными с несколькими ведомыми устройствами, используя для этого минимальное количество проводов. Если для связи на короткие расстояния вам необходима более надежная связь чем в протоколе I2C, используйте протокол SPI, для связи на дальние расстояния используйте протокол RS232.
Использование I2C в MSP430
Для написания кода нашей программы мы будем использовать среду Energia IDE – фактически, это тоже самое что и Arduino IDE. Более подробно про ее установку и работу с ней вы можете прочитать в статье про начало работы с платой MSP430G2.
Для использование протокола I2C в плате MSP430G2 в среде Energia IDE нам необходимо в программе подключить заголовочный файл библиотеки wire.h. Объявление контактов для работы по линиям SDA и SCL уже присутствует внутри библиотеки wire, поэтому у нас не необходимости объявлять их в функции setup.
Примеры для работы с протоколом I2C можно найти в меню с примерами (Example menu) среды Energia IDE. В нашем проекте мы рассмотрим одни из таких примеров, а именно пример управления аналоговыми устройствами с помощью цифрового потенциометра (Digital Potentiometer) AD5171 по синхронному последовательному протоколу I2C. В данном примере с помощью библиотеки I2C Wire цифровой потенциометр будет изменять свое сопротивление по 64 уровням.
Первым делом подключим в программе библиотеку для работы с интерфейсом I2C.
1 |
#include <Wire.h> |
В функции setup мы инициализируем библиотеку wire с помощью функции .begin().
1 2 3 |
void setup() { Wire.begin(); } |
Затем объявим переменную val для хранения значений потенциометра.
1 |
byte val = 0; |
В функции loop мы начнем передачу ведомым устройствам по интерфейсу I2C. В данном случае цифровой потенциометр будет определять адрес устройства, которому будет осуществляться передача.
1 2 |
void loop() { Wire.beginTransmission(44); // transmit to device #44 (0x2c) |
После этого передадим необходимые данные с помощью функции write().
1 2 |
Wire.write(byte(0x00)); // sends instruction byte Wire.write(val); // sends potentiometer value byte |
Закончим передачу данных при помощи вызова функции endTransmission().
1 2 3 4 5 6 7 |
Wire.endTransmission(); // stop transmitting val++; // increment value if (val == 64) { // if reached 64th position (max) val = 0; // start over from lowest value } delay(500); } |
Исходный код программы
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
#include <Wire.h> byte val = 0; void setup() { Wire.begin(); } void loop() { Wire.beginTransmission(44); // будем передавать данные устройству с адресом #44 (0x2c) Wire.write(byte(0x00)); // передаем байт инструкций Wire.write(val); // передаем значение байта потенциометра Wire.endTransmission(); // завершаем передачу val++; // инкрементируем значение if (val == 64) { // если мы достигли 64-й позиции (max) val = 0; // снова начинаем с самого маленького значения } delay(500); } |