Как перестать бояться и полюбить mbed [Часть 3]

в 10:11, , рубрики: atmel, FT800, HYT, IST, mbed, SiLabs, Wiznet, Блог компании ЭФО, программирование микроконтроллеров, Промышленное программирование, Разработка для интернета вещей, Разработка робототехники

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

Напомню, что речь идет о разработке устройства с сенсорным экраном, которое служит для высокоскоростного измерения температуры и относительной влажности. Самое интересное в этой истории — подход к созданию встроенного ПО. Для написания программы используется онлайн IDE mbed, позволяющая создавать железонезависимый код, который одинаково работает на отладочных платах от SiLabs, Atmel, Wiznet, STM32, NXP и других производителей.

Сегодня подключаем датчик.

Как перестать бояться и полюбить mbed [Часть 3] - 1

Содержание цикла публикаций:

  1. Обзор использованных программных и аппаратных решений.
  2. Начало работы с графическим контроллером FT800. Использование готовых mbed-библиотек для периферийных устройств.
  3. Подключение датчика HYT-271. Создание и публикация в mbed собственной библиотеки для периферийных устройств.
  4. Разработка приложения: Структура программы, работа с сенсорным экраном.
  5. Разработка приложения: Вывод изображений на дисплей, проблемы русификации.
  6. Печать деталей корпуса. Анализ ошибок проектирования и другие выводы.

Третья часть под катом.

Предыдущая статья закончилась описанием проекта, который создан в mbed IDE и реализует вывод счетчика секунд на TFT-дисплей от Riverdi.

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

Формат посылок и пример реализации соответствующих функций на Си подробно описан в этой статье. Сейчас я постараюсь не сильно дублировать уже сказанное и сосредоточусь на вопросах использовании датчика HYT-271* в mbed-проекте.

* серия HYT состоит из трех моделей — HYT-271, HYT-221 и HYT-939. Они отличаются только корпусом, поэтому всё что я пишу о включении HYT-271 актуально и для остальных моделей.

Как перестать бояться и полюбить mbed [Часть 3] - 2

Схема включения


Для подключения датчиков серии HYT обычно используется интерфейс I2C (датчики с SPI доступны под заказ). Соответственно, для подключения датчика нужно четыре линии:

  • Питание (подойдут и 3.3, и 5 В)
  • Земля
  • Линия данных SDA
  • Линия тактирования SLC

Как перестать бояться и полюбить mbed [Часть 3] - 3

Рекомендованный номинал подтягивающих резисторов для линий SDA и SLC — 2.4 кОм.

Порядок опроса датчика


Датчики серии HYT поддерживают несколько типов команд. Для непосредственного опроса датчика служат команды Measuring Request и Data Fetch, а остальные инструкции понадобятся только при необходимости смены стандартного адреса датчика на шине I2C.

Сразу скажу, что в mbed-библиотеке HYT отсутствуют функции для смены I2C-адреса. Причины этого — моя природная лень и отсутствие прямой необходимости, ведь в большинстве случаев на шине висит единственный датчик и для работы достаточно реализовать процедуры опроса и получения результатов измерений.

Как перестать бояться и полюбить mbed [Часть 3] - 4

Итак, по получении команды Measuring Request датчик HYT выходит из режима сна, проводит измерения и формирует посылку с данными о температуре и влажности. Чтобы получить данные, на датчик нужно отправить команду Data Fetch, причем между передачей этих двух команд должна быть предусмотрена задержка в 100 мс, т.к. именно столько времени требуется датчику для измерений и формирования посылки.

Measuring Request — это пакет, состоящий только из заголовочного байта — адреса датчика и флага записи. Соответствующая функция MRCommand() осуществляет отправку на I2C пустого пакета.

Команда Data Fetch — это заголовочный байт с флагом чтения и четыре байта данных, которые контроллер получает с датчика.

Как перестать бояться и полюбить mbed [Часть 3] - 5

Первый бит первого байта — служебный CMode bit. Если он установлен в «1», то датчик находится в специальном режиме работы, в котором можно сменить его адрес на шине.

Второй бит первого байта — служебный Stale bit. Если он установлен в «1», значит после выполнения очередного цикла измерений получены те же значения температуры и влажности, что и в предыдущем цикле.

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

Соответствующая функция DFCommand() осуществляет передачу соответствующего пакета на I2C и декодирование полученных с датчика данных. Значения относительной влажности и температуры вычисляются по следующим формулам:

RH [%] = (100 / (214 — 1)) * RHвх
T [°C] = (165 / (214 — 1)) * Tвх — 40

Таким образом, библиотека опроса датчика HYT должна реализовывать две функции — MRCommand() и DFCommand().

Создание и публикация библиотеки в mbed


Напомню, что mbed поддерживает различные ARM-платформы и сопряженные устройства (компоненты) — дисплеи, приводы, датчики, приемопередатчики и так далее.

Естественно, поддержку новой отладочной платы может обеспечить только производитель микроконтроллеров, а вот с поддержкой новых периферийных компонентов всё обстоит интереснее. Ещё пару месяцев назад новые устройства мог добавлять любой пользователь и над списком поддерживаемых компонентов висела кнопка Add new component. Сейчас ARM меняет политику: любой зарегистрированный пользователь может опубликовать библиотеку и описание для нового компонента, однако для того чтобы добавить свой драйвер в список поддерживаемых компонентов требуются расширенные права (у меня такие теперь есть, хи-хи-хи).

Все mbed-библиотеки для периферийных устройств представляют собой С++ классы, содержащие необходимые для работы с устройством функции. Как правило, конструктор такого класса принимает в качестве аргументов линии ввода/вывода, к которым подключается компонент. Если при подключении устройства требуется некая процедура инициализации, то эту процедуру тоже логично включить в конструктор класса. Примером библиотеки, содержащей процедуру инициализации, служит библиотека графического контроллера FT800, подробное описание которой приводилось в предыдущей статье.

В случае с датчиком HYT всё гораздо проще: инициализации датчика не требуется, а для получения результатов измерений необходимо всего две функции.

Файл HYT.h

#define HYT_ADDR 0x50 // 01010000
 
class HYT
{
public:
    /**
     * HYT constructor.
     *
     * @param   sda mbed pin to use for SDA line of I2C interface.
     * @param   scl mbed pin to use for SCL line of I2C interface.
     * 
     * Remember about pull-up resistors on sda and scl. Recommended value is 2.4 kΩ
     */
    HYT(PinName sda, PinName scl);
    /**
     * @brief   The totals (temperature in Celsius, relative humidity in percentages)
     */
    float humidity;
    float temperature;
    /**
     * @brief   Send "Measuring Request" command
     * @details Initiates a measuring cycle of HYT sensor
     * @details More information: http://www.ist-ag.com/eh/ist-ag/resource.nsf/imgref/Download_AHHYTM_E2.2.5.pdf/$FILE/AHHYTM_E2.2.5.pdf
     */     
    void MRCommand(void);
    /**
     * @brief   Send "Data Fetch" command & processing the data
     * @details Fetch the last measured value of humidity and temperature from sensor
     * @details Calculate values of temperature in Celsius, relative humidity in percentages
     * @details More information: http://www.ist-ag.com/eh/ist-ag/resource.nsf/imgref/Download_AHHYTM_E2.2.5.pdf/$FILE/AHHYTM_E2.2.5.pdf
     * @returns 0 if no errors, -1 if no new value received from sensor.
     */    
     int DFCommand(void);
private:
    I2C _i2c;
};

Файл HYT.cpp

#include "HYT.h"
#include "mbed.h"
 
HYT::HYT(PinName sda, PinName scl) : _i2c(sda, scl)
{
}
 
/*************************************************************************************************************************/
void HYT::MRCommand(void)
{
    _i2c.write(HYT_ADDR, 0, 0);
}
 
/*************************************************************************************************************************/
int HYT::DFCommand(void)
{
    char    dataI2C[4];
    int     stateBit;
    int     humidityRaw;
    int     temperatureRaw;
 
    _i2c.read(HYT_ADDR, dataI2C, 4);
 
    stateBit = (dataI2C[0] & 0x40) >> 6;
    if (stateBit == 0) {
        humidityRaw = ((dataI2C[0] & 0x3F) << 8) | dataI2C[1];
        temperatureRaw = ((dataI2C[2] << 8) | dataI2C[3]) >> 2;
        if (temperatureRaw < 0x3FFF && humidityRaw < 0x3FFF) {
            temperature = ((float)(temperatureRaw) * 165.0f / 16383.0f) - 40.0f;
            humidity = (float)humidityRaw * 100.0f / 16383.0f;
        } else {   // sensor returns wrong data (1111...11)
            return -1;
        }
    } else {   // no new value received from sensor
        return 0;    
    } 
    return 0;
}

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

Как перестать бояться и полюбить mbed [Часть 3] - 6

При публикации mbed-библиотеки для нового компонента полагается не только создать и должным образом задокументировать код. Помимо этого желательно снабдить библиотеку описанием аппаратного модуля, типовой схемой включения устройства и Hello World program — простым примером использования библиотеки. Для создания такого примера я снова использую проект-заготовку из первой статьи данного цикла публикаций.

Напомню, что проект-заготовка - это простая программа, выводящая счетчик секунд на последовательный интерфейс (на виртуальный COM-порт)

#include "mbed.h"

Serial              pc(USBTX, USBRX);
Ticker              timeKeeping;
volatile uint64_t     seconds = 0;

void secondsCallback(void) {
    pc.printf("Number of seconds: %xrn", seconds);
    seconds ++;
}
 
int main() {
    timeKeeping.attach(&secondsCallback, 1.0f);
    while(1) {}
}

Как перестать бояться и полюбить mbed [Часть 3] - 7

Подключаем к проекту-заготовке библиотеку HYT и вносим нехитрые изменения:

  • создаем объект SENSOR класса HYT, передавая в качестве аргументов называния выводов, на которых доступен интерфейс I2C
  • добавляем функцию опроса датчика dataUpdate() и вызываем её в бесконечном цикле
  • вместо счетчика секунд выводим на последовательный интерфейс полученные данные о температуре и относительной влажности

Таким образом получаем демо-пример для созданной библиотеки:

#include "mbed.h"
#include "HYT.h"
 
Serial              pc(USBTX, USBRX);
Ticker              timeKeeping;

HYT                 SENSOR (PD6, PD7); // sda, scl [SLSTK3400A]
//HYT               SENSOR (D14, D15); // sda, scl [WIZwiki-W7500P]
//HYT               SENSOR (PA08, PA09); // sda, scl [ATSAMD21-XPRO]
 
// HYT sensor polling cycle
void dataUpdate(void)
{
    SENSOR.MRCommand();
    wait_ms(100);
    SENSOR.DFCommand();
}
 
void secondsCallback(void) {
    pc.printf("Humidity level: %.1frn%", SENSOR.humidity);
    pc.printf("Temperature level: %.1frn%", SENSOR.temperature);
    pc.printf("-------------------------------rn%", SENSOR.temperature);
}
 
int main()
{
    timeKeeping.attach(&secondsCallback, 1.0f);
    while(1) {
        dataUpdate();
    }
}

Проект доступен по ссылке и корректно работает на разных отладочных платах, которые поддерживаются в ARM mbed.

Как перестать бояться и полюбить mbed [Часть 3] - 8

На публикации примера использования процесс создания библиотеки для датчиков температуры и относительной влажности серии HYT заканчивается. Получив соответствующие права, я добавила новый компонент и в базу поддерживаемых в mbed датчиков.

Использование библиотеки в собственном проекте


Теперь можно вернуться к нашему основному проекту, будем выводить на сенсорный TFT-дисплей не счетчик секунд, а данные, полученные с датчика HYT-271.

Как перестать бояться и полюбить mbed [Часть 3] - 9

Для этого создаем в mbed новый проект и импортируем туда библиотеки HYT и FT800_2.
Затем создаем объекты классов HYT и FT800, используя в качестве аргументов названия линий ввода/вывода, на которых доступны интерфейсы I2C и SPI соответственно:

HYT SENSOR (PD6, PD7); // sda, scl [SLSTK3400A]
FT800 TFT (PE10, PE11, PE12, PE13, PB11, PD4); // mosi, miso, sck, ss, int, pd [SLSTK3400A]
//HYT SENSOR (D14, D15); // sda, scl [WIZwiki-W7500P]
//FT800 TFT (D11, D12, D13, D10, D9, D8); // mosi, miso, sck, ss, int, pd [WIZwiki-W7500P]
//HYT SENSOR (PA08, PA09); // sda, scl [ATSAMD21-XPRO]
//FT800 TFT (PA18, PA16, PA19, PA17, PA20, PA21); // mosi, miso, sck, ss, int, pd [ATSAMD21-XPRO]

Добавляем функцию опроса датчика:

void dataUpdate(void)
{
    SENSOR.MRCommand();
    wait_ms(100);
    SENSOR.DFCommand();
}

Добавляем функцию, формирующую и загружающую на графический контроллер дисплей-лист:

  • Начало дисплей-листа, установка белого цвета как цвета по умолчанию
  • Установка черного цвета, вывод двух текстовых строк
  • Установка темно-зеленого цвета, вывод графического примитива «Прямоугольник»
  • Установка белого цвета, вывод текстовой строки и числа (значения относительной влажности)
  • Установка темно-синего цвета, вывод графического примитива «Прямоугольник»
  • Установка белого цвета, вывод текстовой строки и числа (значения температуры)
  • Установка черного цвета, вывод текстовой строки
  • Вывод графического примитива «Прямая линия»
  • Конец дисплей-листа, загрузка картинки на дисплей

void drawTimeScreen(void)
{
    TFT.DLstart();
    TFT.DL(CLEAR_COLOR_RGB(255, 255, 255));
    TFT.DL(CLEAR(1, 1, 1));

    TFT.DL(COLOR_RGB(0, 0, 0));
    TFT.Text(11, 15, 30, 0, "Demo-project for habrahabr.ru");
    TFT.Text(13, 15 + 40, 28, 0, "Using FT800 library and HYT library");

    TFT.DL(COLOR_RGB(9, 40, 3));
    TFT.DL(BEGIN(RECTS));
    TFT.DL(VERTEX2II(11, 105, 0, 0));
    TFT.DL(VERTEX2II(11 + 222, 105 + 100, 0, 0));

    TFT.DL(COLOR_RGB(255, 255, 255));
    TFT.Text(11 + 10, 105 + 10, 28, 0, "Relative humidity, %");
    TFT.Number(11 + 10, 105 + 10 + 30, 31, 0, SENSOR.humidity);

    TFT.DL(COLOR_RGB(9, 3, 40));
    TFT.DL(BEGIN(RECTS));
    TFT.DL(VERTEX2II(11 + 222 + 14, 105, 0, 0));
    TFT.DL(VERTEX2II(11 + 222 + 14 + 222, 105 + 100, 0, 0));

    TFT.DL(COLOR_RGB(255, 255, 255));
    TFT.Text(11 + 222 + 14 + 10, 105 + 10, 28, 0, "Temperature, C");
    TFT.Number(11 + 222 + 14 + 10, 105 + 10 + 30, 31, 0, SENSOR.temperature);
    
    TFT.DL(COLOR_RGB(0, 0, 0));
    TFT.Text(300, 105 + 100 + 35, 28, 0, "e-mail: xk@efo.ru");
    
    TFT.DL(BEGIN(LINES));
    TFT.DL(LINE_WIDTH(8));
    TFT.DL(VERTEX2II(11, 15 + 40 + 30, 0, 0));
    TFT.DL(VERTEX2II(460, 15 + 40 + 30, 0, 0));

    TFT.DL(DISPLAY());
    TFT.Swap();
}

И непрерывно обновляем и выводим данные:

int main()
{
    while(1) {
        dataUpdate();
        drawTimeScreen();
    }
}

Проект доступен по ссылке.

Как и на остальных этапах разработки проекта, я запускаю полученную программу на трех разных платах — SLSTK3400A от SiLabs, ATSAMD21-XPRO от Atmel и WIZwiki-W7500P от Wiznet.

Как перестать бояться и полюбить mbed [Часть 3] - 10

В прошлой статье, когда мы рассматривали демо-пример для вывода информации на TFT-дисплей, для перехода с одной платы на другую потребовалось:

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

Переход, как помнит читатель, прошел гладко и mbed-овская программа с ходу заработала на всех трех платах.

Для новой программы понадобится также:

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

Вот при подключении датчика наконец-то начали вылезать различия отладочных плат.

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

Как перестать бояться и полюбить mbed [Часть 3] - 11

Данные с платы SiLabs удалось получить даже без использования дискретных резисторов. Дело в том, что все GPIO микроконтроллеров EFM32 имеют встроенные подтягивающие резисторы, при работе в десктопной IDE Simplicity Studio режим работы каждой линии (open-drain push-pull и т.д.) настраивается вручную. Судя по всему, mbed автоматически подтянул к питанию те линии, на которых реализованы SDA и SCL.

Как перестать бояться и полюбить mbed [Часть 3] - 12

Слабым звеном сегодня объявляем Atmel — на плате ATSAMD21-XPRO интерфейс I2C (он же TWI) доступен на линиях, которые как-то использует отладчик Atmel Embedded Debugger. Я не разбиралась в этом вопросе подробно, но факт остается фактом: при питании платы от USB прием данных по I2C прекращается через 2-3 секунды. Если же подать питание на отдельный разъем 5.0V IN, то вся программа работает корректно.

Как перестать бояться и полюбить mbed [Часть 3] - 13

Однако нужно признать, что по работе софта нареканий так и не возникло, а значит имеет смысл продолжить разработку с использованием mbed.

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

Заключение


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

Автор: ЭФО

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js