Главная chevron_right Наши уроки chevron_right Arduino chevron_right Электромеханическая семисегментная цифра

Электромеханическая семисегментная цифра

Собираем электромеханическую семисегментную цифру из набора «Механический циферблат». Подключаем сервоприводы к Piranha UNO через расширители выводов и пишем скетч для отображен...

Видео-обложка запускается при наведении

Общие сведения

Набор Сделай сам №10 - «Механический циферблат» — набор для сборки электромеханической семисегментной цифры. Может быть использован как в одиночном экземпляре, так и в составе из нескольких штук. В наборе есть всё необходимое для сборки одной семисегментной цифры, которую можно подключить либо напрямую к Arduino, либо при помощи модулей Расширителей выводов

Для подключения сервоприводов дополнительно понадобится:

Оборудование:

Библиотеки:

Подключение сервоприводов

Установим Trema Shield на Piranha UNO

Подключим модули

Подключим сервоприводы согласно следующей таблице:

СегментРасширительВывод
Aнечет1
Bнечет2
Cчет0
Dчет1
Eчет2
Fнечет0
Gнечет3

Для удобства сборки рекомендуем подписать сервоприводы соответствующими буквами

Сборка механики

Перед установкой сервоприводов необходимо запустить калибровочный скетч.

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

// Подключаем библиотеку для работы с аппаратной шиной I2C, до подключения библиотеки iarduino_I2C_Expander.
#include <Wire.h>
// Подключаем библиотеку для работы с модулями расширителей выводов.
#include <iarduino_I2C_Expander.h>

// Подключаем файл с объектом механических часов.
#include <MechaClock.h>

// Создаём массив объектов библиотеки расширителя выводов, указывая адреса
// (не забудьте устонавить адреса расширителей)
iarduino_I2C_Expander gpio[2]{9, 10};

/* Сегменты

      _a
    f|_|b
    e|g|c
     d^
 */

/* Калибровка сервоприводов */

//!!! Сегменты E и B работают в обратном направлении !!!

// Положение ВКЛ. сегментов
uint8_t ON[DIGITS][SEGMENTS] {
    {
    //  g   f   e   d   c   b   a
        90, 10, 90, 10, 10, 90, 10
    }
};

// Положение ВЫКЛ. сегментов
uint8_t OFF[DIGITS][SEGMENTS] {
    {
    //  g   f   e   d   c   b   a
        10, 90, 10, 90, 90, 10, 90
    }
};

Digit myDigit;

// Функция очистки буфера последовательного порта
void discardSerial()
{
    while(Serial.available())
        Serial.read();
}

void setup()
{
    Serial.begin(9600);
    delay(500);

    Serial.println(F("Скетч калибровки сервоприводов механических часов."));
    Serial.println();
    Serial.println(F("Адреса расширителей выводов в десятеричной системе:"));

    bool flag = false;
    for (auto& i:gpio) {

        if(i.begin()) {

            Serial.print(i.getAddress());
            Serial.print("\t");
        }
        else {

            Serial.print("failed");
            Serial.print("\t");
            flag = true;
        }
    }

    Serial.println();

    if (flag) {
        Serial.println(
                F("Один из расширителей не обнаружен."
                " Проверьте подключение и адрес "
                "модуля и запустите скетч заново.")
                  );
        goto exit;
    }

    myDigit = Digit(gpio, 0);
    myDigit.set('8');

    Serial.println(
            F("Все сервоприводы сегментов установлены в положение\r\n"
            "ВКЛ. Если вы уже выполняли это шаг, пропустите его\r\n"
            ", если нет, отключите питание и установите качалки\r\n"
            "сервоприводов и сегменты цифр. Качалки должны\r\n"
            "\"смотреть\" на сколько это возможно вверх от \r\n"
            "оснований (цифры показывают восьмёрки)")
            );

    delay(1000);

    Serial.println();

    Serial.println(F("Карта сегментов:"));
    Serial.println();

    Serial.println(F("      A"));
    Serial.println(F("    #####"));
    Serial.println(F("   #     #"));
    Serial.println(F(" F #     # B"));
    Serial.println(F("   #  G  #"));
    Serial.println(F("    #####"));
    Serial.println(F("   #     #"));
    Serial.println(F(" E #     # C"));
    Serial.println(F("   #  D  #"));
    Serial.println(F("    #####"));
    Serial.println();

    Serial.println(
            F("Для продолжения введите любой символ в поле ввода"
            " и нажмите \"Отправить\" или <Enter>.")
              );

    while(!Serial.available());

    Serial.println(F("Начинаем процесс калибровки. Для выхода из калибровки"
            " введите \"exit\" и нажмите <Enter> или \"Отправить\""));

    Serial.println(F("Для дострочного вывода углов сервоприводов и выхода"
            " введите \"printout\" и нажмите <Enter> или \"Отправить\""));

    delay(2000);

    uint8_t dig = 0;
    uint8_t seg = SEGMENTS;

    char current_seg = 'A';

    do {
        Serial.println("Калибруем сегмент"
                + String(current_seg) + " "
                + String(dig+1)
                + "-й цифры");

        uint8_t on_deg = 0;

        if (current_seg == 'B' || current_seg == 'E')

            Serial.println(F("Угол сервопривода этого сегмента должен"
                    "быть ближе к 90 градусам в положении ВКЛ."));

        else

            Serial.println(F("Угол сервопривода этого сегмента должен"
                    "быть ближе к 0 градусам в положении ВКЛ."));

        Serial.print(F("текущее значение: "));
        Serial.println(ON[dig][seg-1]);

        Serial.println(
                F("Введите новое значение... (если калибровка"
                " текущего сегмента закончена, введите \"n\""
                " и нажмите <Enter> или \"Отправить\")")
                  );

        // Опустошаем буфер последовательного порта
        discardSerial();

        // Ждём ввода пользователя
        while(!Serial.available());

        // Читаем введённые данные
        String s = Serial.readStringUntil('\n');

        // Удаляем непечатные символы
        s.trim();

        // Выходим из калибровки по желанию
        if (s == "exit")

            goto exit;

        // Переходим к следующему сегменту
        else if (s == "n") {

            seg--;
            current_seg++;
        }

        else if (s == "printout")

            goto printout;

        // Записываем новые показания в массив
        else {
            on_deg = uint8_t(s.toInt());
            ON[dig][seg-1] = on_deg;
            myDigit.set('8');
        }

        if (seg == 0) {
            dig++;
            seg = SEGMENTS;
            current_seg = 'A';
        }

    } while(dig != 1);

printout:

    Serial.println();
    Serial.println(F("Калибровка завершена."));
    Serial.println();

    Serial.println(F("Замените следующие данные в скетче"
               " управления одной цифрой:"));
    Serial.println();

    Serial.println(F("uint8_t ON[DIGITS][SEGMENTS] {"));
    Serial.println(F("\t{"));

    //int k = 1;

    Serial.println(F("\t//\tg    f    e    d    c    b    a"));
    Serial.print("\t\t");

    bool first_seg = true;
    for (auto& j:ON[0]) {
        if (!first_seg)
            Serial.print(",  ");
        first_seg = false;
        Serial.print(j);
    }

    Serial.println();
    Serial.println("\t}");
    Serial.println("};");

exit:
    Serial.println();
    Serial.println(F("Выходим из калибровки."));

    // "Отпускаем все серво"
    myDigit.release();
}

void loop()
{
    delay(1000);
}

Сборка корпуса

Установите все сервоприводы в раму, как показано на рисунке:

После установки сервоприводов, установите раму на основание и соберите корпус:

Примеры

Скетч для одной цифры

Данный скетч выводит цифры от 0 до 9 на электромеханическую цифру.

// Подключаем библиотеку для работы с аппаратной шиной I2C, до подключения библиотеки iarduino_I2C_Expander.
#include <Wire.h>
// Подключаем библиотеку расширителей выводов
// (Она должна быть подключена до бибилотеки механических часов!)
#include <iarduino_I2C_Expander.h>

// Подключаем библоитеку механических часов
#include <MechaClock.h>

// Создаём массив объектов расширителей выводов, указывая их адреса
iarduino_I2C_Expander gpio[]{9, 10};

// Создаём объект цифры
Digit myDigit;

// Положение ВКЛ. сегментов. Сюда необходимо вставить результат калибровки
uint8_t ON[DIGITS][SEGMENTS] {
    {
    //  g   f   e   d   c   b   a
        90,  5,  92,  2,  0,  98, 10
    }
};

// Положение ВЫКЛ. сегментов
uint8_t OFF[DIGITS][SEGMENTS] {
    {
    //  g   f   e   d   c   b   a
        20, 90, 10, 90, 90, 10, 90
    }
};

void setup()
{
    // Инициируем расширители выводов
    for (auto& i:gpio) {
        i.begin();
    }

    /* Инициируем объект цифры передавая указатель на массив объектов
     * расширителей выводов в первом параметре и номер цифры. В данном
     * случае у нас одна цифра, поэтому её порядковый номер 0.
     */
    myDigit = Digit(gpio, 0);
}

void loop()
{
    for (size_t i = 0; i < 10; i++) {
        myDigit.set('0' + i);
        delay(1000);
    }
}

Скетч для нескольких цифр

Скетч выводит секунды до 99 с момента перезагрузки микроконтроллера

#include <Wire.h>
#include <iarduino_I2C_Expander.h>
#include <MechaClock.h>

// Интервал переключения сегментов в мс
#define INTERVAL 0

// количество цифр
#define DIG_NUM 2

// Создаём массив объектов расширитерей выводов, указывая адреса в десятиричной
// системе счисления
iarduino_I2C_Expander gpio[]{9, 10, 11, 12};

// Если у вас три цифры - установите соответсвующие адреса на дополнительных расширителях выводов
// и укажите их при создании объектов, например:
// iarduino_I2C_Expander gpio[]{9, 10, 11, 12, 13, 14};

// Положение ВКЛ. сегментов
uint8_t ON[DIGITS][SEGMENTS] {
    { // Углы сервоприводов первой цифры
    //  g   f   e   d   c   b   a
        10, 10, 90, 10, 10, 90, 10
    },
    { // Углы сервоприводов второй цифры
    //  g   f   e   d   c   b   a
        10, 10, 90, 10, 10, 90, 10
    }
};

// Положение ВЫКЛ. сегментов
uint8_t OFF[DIGITS][SEGMENTS] {
    {
    //  g   f   e   d   c   b   a
        90, 90, 10, 90, 90, 10, 90
    },
    {
    //  g   f   e   d   c   b   a
        90, 90, 10, 90, 90, 10, 90
    }
};

Display myDisp(gpio, INTERVAL, DIG_NUM);

void setup()
{
    Serial.begin(9600);

    while(!Serial);

    for (auto& i:gpio) {
        i.begin();
    }
}

void loop()
{
    // Выводим цифры раз в секунду...
    for (size_t i = 0; i < 100; i++) {

        /* Если у Вас меньше 4-х цифр, в функцию print необходимо
           передать второй параметр. В случае с двумя цифрами это
           POS2, в случае с тремя - POS3. Если Вы используете 4
           цифры, то можно не передавать второй параметр. Если
           Вам необходимо использовать больше 4-х цифр -
           свяжитесь с нами: [email protected] */
        myDisp.print(i, POS2);

        delay(1000);
    }
}

Ссылки

Комплект для повторения проекта

Что понадобится

Это быстрый ориентир по основным модулям и деталям. Полный список для повторения проекта смотрите в самой статье.

5 позиций
Все уроки Arduino