Программируем микроконтроллер PIC в качестве ведомого устройства I2C для пользовательского датчика и интерфейса ввода/вывода

Добавлено 6 мая 2018 в 21:21

У датчика нет интерфейса I2C? Нет проблем. Запрограммируйте микроконтроллер PIC в качестве ведомого устройства I2C для пользовательского датчика и интерфейса ввода/вывода. Для примера мы используем три датчика DHT22 на одном интерфейсе I2C.

Шина I2C (Inter-Integrated Circuit) – это распространенная и удобная технология для подключения устройств к встраиваемым контроллерам. Этот популярный протокол последовательного интерфейса позволяет микроконтроллерной плате, такой как Arduino UNO, взаимодействовать с периферийным устройством, например, с датчиком, используя два провода связи, тактовый и данные (SCL и SDA), и два провода питания (Vcc и GND). Каждое периферийное устройство I2C имеет адрес, что позволяет подключать несколько устройств к тем же соединениям I2C, и что является основной причиной популярности данной шины.

Но что вы будете делать, если необходимое вам периферийное устройство не использует протокол связи I2C? Одним из решений является разворачивание вами собственного интерфейса I2C. Данный проект представляет собой относительно простой и недорогой способ сделать это.

В частности, мы будем использовать экономичную микросхему PIC12F1840 в качестве ведомого устройства I2C, которое будет взаимодействовать с Arduino UNO, а также с большинством любых других микроконтроллерных плат, использующих I2C схему «один ведущий / несколько ведомых».

Схема проекта на макетной плате
Схема проекта на макетной плате

Чтобы проиллюстрировать данную методику так, чтобы была хоть какая-то польза, микроконтроллер PIC будет взаимодействовать с тремя датчиками температуры и влажности DHT22 (он же AM2302). Конечным результатом является простой способ развертывания всех трех датчиков с использованием одной шины I2C. Эту методику можно расширить, включив сюда другие пользовательские датчики, а также пользовательские расширения ввода/вывода и их комбинации.

Аппаратное обеспечение

Схема состоит из интерфейса I2C на PIC и трех датчиков DHT22. PIC интерфейс I2C содержит микросхему 12F1840, несколько вспомогательных компонентов, разъем/перемычку (JP1) для подключения платы к ведущему устройству и три дополнительных разъема/перемычки для подключения трех плат датчиков. Четыре контакта на J1 для подключения к Arduino UNO – это +5V, GND, SDA и SCL, линии которых доступны на разъемах платы Arduino. 12F1840 имеет 6 выводов ввода/вывода. Два из этих выводов, RA1 и RA2, образуют линии SDA и SCL для связи по I2C. К этим линиям я подключил подтягивающие резисторы по 10 кОм (R1 и R2), и всё работает хорошо; для своего приложения вы можете подобрать номиналы этих резисторов. Кроме того, может потребоваться полностью убрать эти резисторы, если у вас в вашей системе уже есть подтягивающие резисторы на линиях I2C.

Три вывода ввода/вывода, RA0, RA4 и RA5, подключаются к линиям данных датчиков DHT22 #1, #2 и #3 соответственно. Оставшийся вывод (RA3) не используется и остается неподключенным. При использовании дополнительных схем расширения этот вывод может быть задействован как вход общего назначения или для включения аппаратного сброса (MCLR).

Схема для платы PIC I2C
Схема для платы PIC I2C
Перечень элементов для платы PIC I2C
КомпонентОписание
U1PIC 12F1840
C1Конденсатор 0,1 мкФ
R1, R2Резистор 10 кОм
J1, DHT1-34-пиновый разъем/перемычка
Кабели3 x 4-пиновый

Каждый из датчиков монтируется на отдельной плате с намерением разместить их на некотором расстоянии друг от друга и подключить к плате I2C с помощью 4-контактных кабелей. Поскольку на DHT22 можно использовать только 3 из 4 контактов, вы можете использовать 3-контактные кабели и разъемы.

Датчик температуры и влажности воздуха DHT22 или AM2302. Выводы: 1 – Vdd, 2 – данные, 3 – не подключен, 4 – GND.
Датчик температуры и влажности воздуха DHT22 или AM2302. Выводы: 1 – Vdd, 2 – данные, 3 – не подключен, 4 – GND.

Платы датчиков также относительно просты, содержат только датчик DHT22, подтягивающий резистор на линии данных и конденсатор развязки на линиях питания.

Схема платы одного датчика DHT22. Для каждого из трех датчиков требуется отдельная плата
Схема платы одного датчика DHT22. Для каждого из трех датчиков требуется отдельная плата
Перечень элементов для платы датчика
КомпонентОписание
DHT22Датчик DHT22
C1Конденсатор 0,1 мкФ
R1Резистор 4,7 кОм
J14-пиновый разъем/перемычка

Данный проект разрабатывался для работы с напряжением 5 вольт, но я также протестировал его при питании от 3,3 вольт, и всё отлично работало, поскольку это напряжение находится в рабочем диапазоне как микроконтроллера PIC, так и DHT22.

Реализация пользовательского датчика I2C

PIC12F1840 является примером усовершенствованной 8-разрядной архитектуры среднего класса от Microchip. Это 8-выводный микроконтроллер, который включает в себя большое число функций периферийного устройства. Главной из этих функций периферийного устройства, для данного проекта, является модуль синхронного последовательного интерфейса MSSP (Master Synchronous Serial Port). Эта функция позволяет нам реализовать интерфейс I2C таким образом, что чип будет работать как ведомое устройство I2C. Возможно, самое главное, что программное обеспечение уже сделано для нас в примечании к применению (AN734C). Код из этого примечания к применению составляет основу нашего средства I2C. Он управляется прерываниями и позволит чипу, по сути, работать в качестве 32-байтового массива памяти, позволяющего совершать между ведущим и ведомым устройствами двунаправленные чтение и запись. Прилагаемая программа включает в себя код из примечания к применению, немного измененный для использования на 12F1840.

Ведущее устройство I2C (в этом примере Arduino UNO) будет выдавать команды ведомому устройству I2C путем записи в выбранное место в массиве памяти. PIC, как ведомое устройство I2C, будет выполнять команды (т.е. считывать показания датчиков DHT22) и отправлять назад информацию о состоянии и информацию с датчиков через массив памяти. Затем устройство-мастер считывает массив памяти для извлечения показаний датчиков.

Карта памяти

Мы будем говорить о 32-байтном массиве памяти как о значениях от Array[0] до Array[31]. Array[0] служит местом, куда мастер (Arduino) выдавать команду, и где ведомый (PIC) будет сообщать о состоянии, которое будет считываться мастером. В этом отношении PIC вернет одно из трех значений, описанных в таблице ниже. Эти значению указывают включенное состояние, успешность выполнения допустимой команды и получение недопустимой или неизвестной команды.

Значения состояния
Статус Array[0] – значение устанавливается микроконтроллером PIC для сообщения о состоянии
0x00Устройство включено. Кроме того, данное значение устанавливается при программном сбросе микроконтроллера.
0x01Последняя команда была выполнена успешно.
0xF1Была запрошена недопустимая (неизвестная) команда.

Arduino будет записывать в Array[0] значение одной из четырех возможных команд, описанных ниже. Они указывают PIC микроконтроллеру о необходимости либо прочитать показания одного из датчиков DHT, либо перезагрузиться.

Значения команд
Команда Array[0] – значение устанавливается платой Arduino для выдачи команды
0x02Прочитать показания датчика DHT #1
0x03Прочитать показания датчика DHT #2
0x04Прочитать показания датчика DHT #3
0x10Выполнить программную перезагрузку PIC микроконтроллера

Когда команда о считывании показаний датчика была получена, путем записи в Array[0] значения 0x02, 0x03 или 0x04, и PIC микроконтроллер вернул статус об успешном выполнении, путем записи в Array[0] значения 0x01, данные будут доступны для Arduino путем считывания массива памяти.

DHT22 возвращает 5 байтов, чтобы показать влажность (относительную влажность воздуха или RH) и температуру (в градусах Цельсия) следующим образом: RH целая часть, RH часть после десятичной запятой, температура целая часть, температура часть после десятичной запятой и контрольная сумма, которая представляет собой сумму всех четырех байтов AND 255. Эти 5 байтов будут записаны в разные ячейки в памяти PIC микроконтроллера после команд чтения датчиков. Ячейки Array[16]Array[31] не используются, и свободная память в них доступна для пользовательского использования.

Карта хранения информации данных датчиков
Распределение места в Array – значения устанавливаются микроконтроллером PIC для чтения платой Arduino
Array[1]Array[5]Датчик DHT #1: RH целая часть, RH часть после десятичной запятой, температура целая часть, температура часть после десятичной запятой и контрольная сумма
Array[6]Array[10]Датчик DHT #2: RH целая часть, RH часть после десятичной запятой, температура целая часть, температура часть после десятичной запятой и контрольная сумма
Array[11]Array[15]Датчик DHT #3: RH целая часть, RH часть после десятичной запятой, температура целая часть, температура часть после десятичной запятой и контрольная сумма
Array[16]Array[31]Доступно для использования

И последняя команда, 0x10, вызывает программную перезагрузку микроконтроллера PIC12F1840. Обычно в использовании данной команды нет необходимости, но она может быть полезна в случае неожиданных ситуаций.

Чтение показаний датчика влажности и температуры DHT22

Работа по считыванию показаний датчиков DHT22 и хранение их в массиве памяти также ложится на микроконтроллер PIC. Низкая цена, доступность и относительная надежность DHT22 сделали его использование повсеместным. Однако последовательный протокол, который используется этим чипом, требует очень точной временно́й работы. Эти требования к синхронизации могут стать проблемой для систем, использующих относительно медленный ввод/вывод, и для систем (например, микросхем систем на кристалле, SoC), чьи многочисленные высокоприоритетные функции могут сделать требуемые выделения времени неудобными. В этом отношении имеет смысл «разгрузить» работу на отдельную микросхему.

Связь с датчиком осуществляется через специальный «однопроводный» последовательный протокол, который не следует путать с однопроводным протоколом от Dallas/Maxim semiconductor – они совершенно разные. В данной связи задействованы три соединения (Vcc, GND и данные). Вывод данных – это место, где происходят все манипуляции, и тщательное прочтение технического описания даст более подробную информацию.

Вкратце, следующие шаги описывают взаимодействие со стороны PIC микроконтроллера, необходимое для считывания датчика, а прилагаемая программа MPASM была подробно прокомментирована для облегчения прослеживания действий программы:

  1. Установить линию данных в режим выхода, установить на ней низкий уровень и ждать 18 микросекунд.
  2. Установить на линии данных высокий уровень на 30 микросекунд.
  3. Установить линию данных в режим входа и мониторить её состояние. DHT22 должен установить на ней низкий уровень на 80 микросекунд, а затем высокий уровень на 80 микросекунд.
  4. Шаги 1-3 являются преамбулой к потоку данных. Затем DHT22 установит на линии данных низкий уровень на 50 микросекунд, что сигнализирует о старте бита данных.
  5. Теперь всё становится немного сложнее. После времени стартового бита DHT22 установит на линии данных высокий уровень либо на ~27 микросекунд, либо на 70 микросекунд. Первый сигнал соответствует биту данных '0', а второй сигнал – биту данных '1'.
  6. После передачи бита данных (шаг 5 выше) DHT22 перейдет к следующему 50-микросекундному стартовому биту, за которым следует следующий бит данных (либо '0', либо '1', как описано в шаге 5), и эта последовательность повторяется для 40 битов, составляющих 5 байтов данных датчика (влажность целая часть, влажность часть после десятичной запятой, температура целая часть, температура часть после запятой и контрольная сумма).

Вы можете видеть, что протокол требует точной синхронизации, и что время считывания датчика является переменным значением в том смысле, что оно зависит от количества битов '0' и '1' в чтении. Одна из стратегий состоит в том, чтобы измерить каждый из интервалов и затем решить, соответствует ли бит данных интервалу '0' или '1'. Я выбрал другую стратегию, описанную ниже, которая менее требовательна и очень надежна.

Стратегия распознавания битов '0' и '1' в последовательном потоке
Стратегия распознавания битов '0' и '1' в последовательном потоке

После преамбулы мы ждем окончания времени стартового бита, затем ждем около 43 микросекунд, после чего считываем состояние линии данных. Если на линии данных уровень низкий, то бит был равен '0', и мы находимся во времени передачи следующего стартового бита. В этом случае мы записывает бит как '0' и ждем окончания времени стартового бита перед чтением следующего бита данных. Если на линии данных уровень высокий, то бит был равен '1', и мы всё еще находимся во времени передачи бита данных. В этом случае, мы записываем бит как '1' и ждем начала времени следующего стартового бита, затем ждем окончания времени стартового бита перед чтением следующего бита данных.

Когда PIC микроконтроллер закончит считывание запрошенного датчика DHT22, данные будут доступны для чтения через интерфейс I2C. В этом случае Array[0] будет считан как 0x01, что указывает на успешное завершение последней команды.

Получение данных датчика на Arduino UNO

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

Во-первых, для использования библиотеки I2C вам необходим оператор:

#include <Wire.h>

Затем вам необходим I2C адрес PIC микроконтроллера. Он программно установлен в коде MPASM для PIC микроконтроллера в строке:

#define I2C_ADDRESS  0x32    ; Адрес ведомого

Этот адрес должен быть сдвинут вправо на один бит, чтобы сформировать адрес, который будет использоваться Arduino. Те, кто знаком с 7-разрядной адресацией I2C, узнают этот часто неудобный шаг. Смещение 0x32 вправо даст нам 0x19, и это будет адрес I2C, который используется Arduinio. Конечно, вы можете установить этот адрес в коде MPASM в любое доступное значение для адреса I2C, которое у вас есть.

Чтобы начать обмен, используйте:

Wire.begin();    // подключается к шине в качестве мастера, обычно выполняется в setup()

Ниже в качестве примера приведены шаги для выдачи команды считывания датчика #2 (значение переменной address было установлено в 0x19):

Wire.beginTransmission(address);
Wire.write(0); // индекс в буфере
Wire.write(3); // байт команды (3 = прочитать DHT22 #2)
Wire.endTransmission();

delay(50);     // ждем выполнения команды - для начала 50 миллисекунд

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

На этом этапе данные от датчика DHT22 #2 должны быть в Array[6]-Array[11]. Чтобы запросить данные, используем следующее:

Сначала прочитаем байт статуса в Array[0].

Wire.beginTransmission(address);
Wire.write(0); // индекс в буфере
Wire.endTransmission();
Wire.requestFrom(address, 1);

// обновить байт статуса
DHT[0]=Wire.read();

Проверим, равен ли байт статуса (теперь в DHT[0]) 0x01, что указывает на успешность выполнения команды. Затем получим 5 байтов данных DHT (из Array[6]-Array[11]) с помощью следующего кода:

Wire.beginTransmission(address);
Wire.write(6); // индекс в буфере (указывает на данные для DHT #2)
Wire.endTransmission();
Wire.requestFrom(address, 5);

После того, как мы поместили эти данные в программный массив DHT[6]-DHT[10], мы преобразуем данные во влажность (RH) и температуру и, наконец, проверим совпадает ли контрольная сумма:

// Влажность
RHz2 = DHT[6];
RHz2 *= 256;
RHz2 += DHT[7];
RHz2 /= 10;

// Температура
TempCz2 = DHT[8] & 0x7f;
TempCz2 *= 256;
TempCz2 += DHT[9];
TempCz2 /= 10;

if(DHT[8]&0x80)
{
  TempCz2*=-1;
}

TempFz2=TempCz2 * 9 / 5 +32;  


// Контрольная сумма
if ((DHT[6]+DHT[7]+DHT[8]+DHT[9] & 255) != DHT[10])
{
  Serial.print(" *** BAD CRC! ***  "); 
}    
else
{
  Serial.print(" CRC is good  ");
}

Два других датчика DHT22 считываются таким же образом, используя соответствующие коды команд.

Приведенный ниже код скетча примера для Arduino просто считывает все три датчика каждые 5 секунд и отображает данные в мониторе последовательного порта.

Вывод на экран в результате работы тестового скетча Arduino
Вывод на экран в результате работы тестового скетча Arduino

Запуск

Программное обеспечение, необходимое для работы схем, приведено ниже и состоит из исходного кода MPASM для 12F1840, HEX файла для 12F1840 и тестового скетча для Arduino. Вам нужно будет запрограммировать микроконтроллер PIC12F1840. Если вы раньше использовали PIC-контроллеры, это не должно быть сложным. Если вы не знакомы с PIC-контроллерами, то это может показаться сложной задачей. Однако есть много недорогих программаторов, в том числе несколько самодельных разработок, которые получили большую поддержку. Ассемблер MPASM доступен бесплатно от Microchip.

Кроме того, начиная с мелкого PIC-контроллера, такого как 12F1840, задача становится менее сложной, чем может показаться. Вы можете собрать приведенный исходный код MPASM для программирования, как есть, или внести изменения, такие как адрес I2C. В качестве альтернативы, большинство программаторов позволит вам напрямую использовать HEX файл для программирования микроконтроллера.

Заключение

Данный проект призван обеспечить полезное дополнение к более крупному проекту на встраиваемом контроллере. В частности, он хорошо подходит для тех проектов, где вам необходимо контролировать влажность и температуру в нескольких зонах. Он также является отправной точкой для использования шины I2C в пользовательских приложениях. Хотя 12F1840 дешев и подходит для этого проекта, расширения могут быть реализованы на более крупных PIC-микроконтроллерах, которые содержат требуемый функционал MSSP и обеспечивают большее количество выводов ввода/вывода общего назначения. Таким образом, вполне возможно реализовать недорогие комбинации интерфейсов датчиков и расширения ввода/вывода на базе I2C.


На сайте работает сервис комментирования DISQUS, который позволяет вам оставлять комментарии на множестве сайтов, имея лишь один аккаунт на Disqus.com.


Сообщить об ошибке