- PVSM.RU - https://www.pvsm.ru -
Эта статья описывает библиотеку MRAA, которая может существенно упростить работу с различными типами устройств, использующими:
[1]
Вместо примеров с полными программами, мы рассмотрим небольшие фрагменты на языке C, которые покажут основные принципы MRAA API. Чтобы получить больше информации из этой статьи, вы должны знать следующие вещи:
В этой статье не объясняется, как выполнить компиляцию, сборку программы и установку приложений на данную платформу.
MRAA (произносится «эм-ра») это низкоуровневая библиотека, написанная на языке C. Она предназначена для абстрагирования от деталей, связанных с доступом и управлением вводом-выводом на платформе, такой как Intel Galileo или Intel Edison, при помощи введения одного небольшого API.
Пакет MRAA уже установлен на Intel Galileo и Intel Edison и может быть подключен к вашему коду как будет показано ниже. Последнюю версию исходных кодов можно также загрузить из репозитория Intel.
Документация на API доступна по адресу http://iotdk.intel.com/docs/master/mraa/ [2]
В этой статье есть различные «пины». На аппаратные пины обычно ссылаются по номеру. Номер пина также может начинаться с буквы «D» для цифрового типа и буквы «A» для аналогово типа. Например, «D0» будет указывать на цифровой пин №0, а «A3» на аналоговой входной пин №3. Пин также может быть указан как GPIO6, т.е. это GPIO-пин номер 6, без указания его типа «D» или «A», т.е. он может быть и цифровым и аналоговым.
При компиляции прилинковывайте библиотеку командой –lmraa, например:
gcc -g blink.c -o blink -lmraa
Перед написанием кода помните следующее.
1. В начале программы MRAA должна быть проинициализирована следующим образом:
mraa_result_t rv;
rv = mraa_init();
if (rv != MRAA_SUCCESS)
сообщение об ошибке
. . .
2. Многие MRAA функции возвращают результат типа mraa_result_t. Очень важно убедиться, что вызов функции произошел без ошибок.
3. Примеры в данной статье не выполняют проверку ошибок, но всё же очень рекомендуется это делать.
4. После инициализации надо указать MRAA, каким способом вы хотите использовать пин (ввод/вывод, цифровой/аналоговый/ШИМ/AURT). Ниже будет показано, как это сделать.
5. Когда работа закончена (например, в конце программы), надо сказать MRAA освободить занимаемые пины, чтобы она сбросила все внутренние состояния и настройки. Ниже будет показано, как это сделать.
Главный подключаемый файл MRAA это mraa.h. Он подключается вместе с другими аппаратно-зависимыми заголовочными файлами. Например:
Код для аналогового устройства должен подключать:
#include <mraa.h>
#include <mraa/aio.h>
Код для цифрового устройства должен подключать:
#include <mraa.h>
#include <mraa/gpio.h>
Аналоговое устройство, это такое устройство, которое получает данные, измеряя значение напряжения на пине, меняющееся от 0 до максимально поддерживаемого. Это максимальное значение напряжения называется опорным напряжением (AREF – Analog Reference Voltage). Например, аналоговый сенсор давления может выдавать значение напряжения, начинающееся с 0 (соответствует отсутствию давления), и увеличивающееся при возрастании давления. Это напряжение на сенсоре переводится в число устройством, которое называется АЦП (Аналогово-цифровой преобразователь, ADC – analog-to-digital converter). Программа, которая работает с сенсором, считывает это число, выдаваемое с АЦП.
Опорное напряжение обычно составляет 3.3 В или 5.0 В постоянного тока. Тем не менее, опорное напряжение может отличаться, так как некоторые платформы, например Intel Edison, позволяет устанавливать другое значение опорного напряжения вместо использования встроенного значения. Следовательно, надо знать точное значение опорного напряжения перед тем, как получать данные с устройства.
Разрядность АЦП очень важна, так как она определяет точность ваших измерений. Все АЦП, которые используются на платформе Intel, имеют разрядность 10 бит (1024 значения). И по крайней мере в случае с Intel Edison 12 бит (4096 значений).
Вы можете определить примерный шаг точности измерения напряжения, разделив значение опорного напряжения на количество доступных значений. Это значение потом можно использовать в приложении. Например, при опорном напряжении 5 В и разрядности 10 бит, получаем, что шаг АЦП равен примерно 5 мВ. Т.к. 5.0 / 1024 = 0.00488 В
Использую ранее описанную информацию, вы можете определить примерное напряжение, которые находится на аналоговом пине. При большей разрядности АЦП можно измерять напряжение с большей точностью.
Датчик влажности от Grove [3] это пример простого аналогово устройства. Это просто резистор, который изменяет уровень напряжения на аналоговом входе в соответствии с тем, какой уровень влажности был определен. Следующий пример показывает, как работает сенсор при подключении его к пину A0. В программе видно как инициализировать MRAA и пин A0, считать значение, распечатать его и затем освободить пин.
int main()
{
/* initialize MRAA */
mraa_init();
/* create an MRAA analog context */
mraa_aio_context m_aio;
/* initialize A0 for use as an analog input */
m_aio = mraa_aio_init(0);
/* read the value, an integer */
int value;
value = mraa_aio_read(m_aio);
/* print the value */
printf(“The value returned was: %dn”, value);
/* now release (close) the pin and exit */
mraa_aio_close(m_aio);
return(0) ;
}
С АЦП разрядностью 10 бит, возвращаемое значение будет от 0 до 1023. Как интерпретировать значение, зависит от устройства сенсора. Для сенсора Grove и разрядностью АЦП 10 бит, документация даёт следующие диапазоны для состояния сухо, влажно и сыро.
Важно помнить, что все сенсоры различны, и их значения бывает сложно декодировать. Учитывайте следующее:
1. У некоторых сенсоров есть джиттер (дрожание сигнала). В таком случае надо получить несколько последовательных значений с сенсора и найти среднее значение.
2. Если вы пишете MRAA драйвер для использования на различных платформах, важно, чтобы вы правильно указывали опорное напряжение и разрешение АЦП, которые будет использованы в вычислениях. Иначе получаемые данные могут быть бесполезны. В предыдущем примере нам не надо было знать опорное напряжение, но это не относится к другим более сложным аналоговым устройствам. На некоторых устройствах точное значение опорного напряжения и разрешение АЦП требуется, чтобы определить значение, получаемое с сенсора.
3. Значение на сенсоре не всегда бывает линейно связано с измеряемым параметром. В таком случае надо смотреть в документацию за формулами перевода значений или воспользоваться дополнительными библиотеками, например, UPM.
Цифровые устройства имеют дело с высоким и низким значением сигнала. Используются только эти два значения. Например, в системе работающей при напряжении 5 В, низкий уровень может соответствовать 0 В, а высокий 5 В. Обычно высокий уровень обозначается 1, а низкий 0.
Цифровые устройства могут быть настроены на ввод и вывод. Для использования в качестве входного устройства, вам надо использовать MRAA для чтения с цифрового пина и возвращать значение, показывающее каким было напряжение, высоким или низким.
MRAA предоставляет API для чтения и записи состояния цифрового пина. Дополнительно, можно подключить обработчик прерывания на цифровом входе. Для использования возможностей цифрового ввода и вывода в MRAA, надо подключить заголовочный файл.
#include <mraa/gpio.h>
Для примера возьмем простое цифровое устройство, кнопку. Когда кнопка не нажата, на ней высокое напряжение, при нажатии низкое.
int main()
{
/* initialize MRAA */
mraa_init();
/* create an MRAA digital context */
mraa_ai o_context m_aio;
/* initialize D2 for use as a digital pin */
m_gpio = mraa_gpio_init(2);
/* configure the digital pin as an input */
mraa_gpio_dir(m_gpio, MRAA_GPIO_IN);
/* read the value into an integer */
int value = mraa_gpio_read(m_gpio);
/* print the value */
if (value != 0)
printf(“The button is being pushedn”);
else
printf(“The button is not being pushedn”);
/* now release (close) the pin and exit */
mraa_gpio_close(m_gpio);
return(0);
}
Как вы можете видеть, всё достаточно просто. Обратите внимание как мы указываем MRAA настроить пин на ввод с использованием функции mraa_gpio_dir(). Цифровые пины могут быть использованы и на ввод и на выход, в отличие от аналоговых, которые могут работать только на ввод.
Иногда не хочется повторять чтение значения на пине, чтобы определить изменение его состояния. Возьмем для примера сенсор, который подключен к мотору, чтобы подсчитывать число оборотов в минуту. В данном случае было бы неразумно постоянно продолжать чтение состояния пина для определения изменений.
MRAA предлагает возможность создать обработчик прерывания и соединить его с пином. В таком случае MRAA гарантирует, что ваша функция будет вызвана всякий раз, когда произойдет заданное изменение состояния пина (с 0 на 1 или с 1 на 0).
Используя такую возможность, легко написать функцию подсчета, и сказать MRAA, чтобы она вызывала её при изменении состояния. Ниже приведён простой пример подсчета числа переходов с высокого состояния сигнала на низкое.
/* first, create our counting variable */
volatile int counter = 0;
/* Now our simple counting function. */
/* This will be our interrupt handler. */
void intrHandler(void *arg)
{
counter++;
}
/* now in our main() function */
int main()
{
/* initialize MRAA */
mraa_init();
/* create an MRAA digital context */
mraa_aio_context m_aio;
/* initialize D2 for use as digital pin */
m_gpio = mraa_gpio_init(2);
/* configure the digital pin as an input */
mraa_gpio_dir(m_gpio, MRAA_GPIO_IN);
/* now, setup an interrupt handler. */
/* Our function (intrHandler()) above will */
/* be called whenever the pin goes from */
/* HIGH to LOW */
*/
mraa_gpio_isr(m_gpio, MRAA_GPIO_EDGE_FALLING, intrHandler, NULL);
/* sleep for 5 seconds, and then print out the current */
/* value of counter */
sleep(5);
printf(“Counter = %dn”, counter);
/* now, stop the interrupt handler and cleanup */
mraa_gpio_isr_exit(m_gpio);
/* now release (close) the pin and exit */
mraa_gpio_close(m_gpio);
return(0);
}
Обратите внимание на следующее в этом примере:
Использовать цифровой выход достаточно просто. Следующий пример меняет сигнал с высокого (1) на низкий (0) на цифровом выходе с периодом в 1 секунду. Нечто подобное можно использовать, чтобы помигать светодиодом, подключенным к пину.
int main()
{
/* initialize MRAA */
mraa_init();
/* create an MRAA digital context */
mraa_aio_context m_aio;
/* initialize D13 for use as a digital pin */
m_gpio = mraa_gpio_init(13);
/* configure the digital pin as an output */
mraa_gpio_dir(m_gpio, MRAA_GPIO_OUT);
/* now run in a loop 10 times, blinking the output each second */
int i;
for (i=0; i<10; i++)
{
/* turn output on (HIGH) */
mraa_gpio_write(m_gpio, 1);
sleep(1);
/* turn output off (LOW) */
mraa_gpio_write(m_gpio, 0);
sleep(1);
}
/* now release (close) the pin and exit */
mraa_gpio_close(m_gpio);
return(0);
}
Как вы можете видеть, с MRAA очень просто использовать цифровой ввод-вывод. Обработка прерываний немного посложнее, но тут главное аккуратно использовать ключевое слово volatile для переменных, с которыми работаете вне прерывания.
Широтно-импульсная модуляция (ШИМ, PWM — Pulse-width modulation) это тип цифрового вывода. ШИМ задается двумя параметрами, периодом и коэффициентом заполнения:
Например, если вы установите период в 2 мс, а коэффициент заполнения 50%, тогда вы получите повторяющиеся изменения: 1 мс значение сигнала будет высоким и 1 мс – низким. Изменение коэффициента заполнения может быть использовано для различных функций, например, управление яркостью светодиода или скоростью вращения мотора.
#include <mraa/pwm.h>
В следующем примере будем изменять яркость светодиода. Мы сделаем это, установив период в 10 мс и будем увеличивать и уменьшать коэффициент заполнения каждые 100 мс.
int main()
{
/* initialize MRAA */
mraa_init();
/* create an MRAA PWM context */
mraa_pwm_context m_pwm;
/* initialize D3 for use as a digital pin */
m_pwm = mraa_gpio_init(3);
/* set the period to 10ms */
mraa_pwm_period_ms(m_pwm, 10);
/* set the initial duty cycle to 0 */
mraa_pwm_write(m_pwm, 0.0);
/* enable PWM output */
mraa_pwm_enable(m_pwm, 1);
/* now run in a loop 10 times, dimming or brightening /*
/* the LED every 100ms */
int i;
float duty = 0.0;
for (i=0; i<10; i++)
{
/* first, start at 0% duty cycle and increase to 100% */
for (duty= 0.0; duty < 1.0; duty+=0.1)
{
mraa_pwm_write(m_pwm, duty);
usleep(100000);
}
sleep(1);
/* now decrease it to 0% */
for (duty= 1.0; duty > 0.0; duty-=0.1)
{
mraa_pwm_write(m_pwm, duty);
usleep(100000);
}
sleep(1);
}
/* disable PWM output and clean up */
mraa_pwm_enable(m_pwm, 0);
mraa_pwm_close(m_pwm);
return(0);
}
Обратите внимание на следующее в этом примере:
Используя I2C, помните следующее:
#include <mraa/i2c.h>
В следующем примере мы будем работать с I2C-часами реального времени (DS1307) и считывать значение из регистра секунд. Мы установим контекст I2C MRAA на I2C-шине 0, используя адрес 0x68, и прочитаем секундный регистр. Полученное значение будем печатать каждые 10 секунд.
Важно помнить, что многие I2C устройства имеют различные требования, например, как данные должны быть записаны или считаны. Поэтому подробности работы уточняйте в документации.
int main()
{
/* initialize MRAA */
mraa_init();
/* create an MRAA I2C context */
mraa_i2c_context m_i2c;
/* initialize I2C on bus 0 */
m_i2c = mraa_i2c_init(0);
/* now run in a loop 10 times, reading the seconds */
/* register and printing it.*/
int i;
for (i=0; i<10; i++)
{
char buf;
/* always specify the address */
mraa_i2c_address(m_i2c, 0x68);
/* read in 1 byte. mraa_i2c_read() always reads */
/* starting at register 0x00 */
mraa_i2c_read(m_i2c, &buf, 1);
printf(“The seconds returned was: %dn”, buf);
sleep(1);
}
mraa_i2c_stop(m_pwm);
return(0);
}
Посмотрите пример выше:
#include <mraa/uart.h>
В следующем примере мы используем вымышленный сенсор на основе UART, подключенный к D0 и D1. Он будет обозначаться UART 0.
Важно, чтобы после открытия устройства были правильно изменены настройки, которые были сделаны автоматически ядром Linux. Мы добавили функцию setupTTY() которая выполняет эти действия после открытия TTY устройства.
int setupTTY(int fd, speed_t baud)
{
if (fd < 0)
return 0;
struct termios termio;
/* get current modes */
tcgetattr(fd, &termio);
/* setup for a 'raw' mode. 8bit, 1 stop bit, no parity, */
/* no echo or special character handling, */
/* no flow control or line editing semantics. */
cfmakeraw(&termio);
// set our baud rates
cfsetispeed(&termio, baud);
cfsetospeed(&termio, baud);
// make it so
if (tcsetattr(fd, TCSAFLUSH, &termio) < 0)
{
fprintf(stderr, “%sn”, “tcsetattr failed”);
return 0;
}
return 1;
}
/* now our main function */
int main()
{
/* initialize MRAA */
mraa_init();
/* create an MRAA UART context */
mraa_uart_context m_uart;
/* initialize UART 0 (pins D0 and D1 used for TX and RX) */
m_uart = mraa_uart_init(0);
/* now that we have our context, query MRAA */
/* to get the file name of the TTY device we need to open. */
char *devPath = mraa_uart_get_dev_path(m_uart);
/* if this fails, we can go no further */
if (!devPath)
{
fprintf(stderr, “%sn”, “Could not get device path”);
return 0;
}
/* now that we have a device path, open it and set it up */
int fd;
if ((fd = open(devPath, O_RDWR)) == -1)
{
fprintf(stderr, “%sn”, “Could not open device path”);
return 0;
}
/* now we are almost ready, call setupTTY() and from then on */
/* we can read/write to the device normally. */
/* We assume a baud rate of 9600/ */
if (!setupTTY(fd, B9600))
{
fprintf(stderr, “%sn”, “Could not setup TTY port”);
return 0;
}
/* now we can use standard read and write calls */
/* read(fd, ...) or write(fd, …) */
/* when we are done, close the device and exit */
close(fd);
return(0);
}
Посмотрите предыдущий пример:
Библиотека MRAA упрощает процесс доступа и управления основными возможностями ввода-вывода на платформе Intel Galileo и Intel Edison. Мощная библиотека, MRAA предлагает последовательный подход для использования аналоговых, цифровых, ШИМ, I2C и UART устройств на этих и подобных платформах. Это дополнительный ключ к ящику с инструментами для интернета вещей.
Автор: varerysan
Источник [4]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/diy-ili-sdelaj-sam/97253
Ссылки в тексте:
[1] Image: http://geektimes.ru/company/intel/blog/260998/
[2] http://iotdk.intel.com/docs/master/mraa/: http://iotdk.intel.com/docs/master/mraa/
[3] Датчик влажности от Grove: http://www.seeedstudio.com/depot/Grove-Moisture-Sensor-p-955.html
[4] Источник: http://geektimes.ru/post/260998/
Нажмите здесь для печати.