Общие сведения
Набор Сделай сам №10 - «Механический циферблат» — набор для сборки электромеханической семисегментной цифры. Может быть использован как в одиночном экземпляре, так и в составе из нескольких штук. В наборе есть всё необходимое для сборки одной семисегментной цифры, которую можно подключить либо напрямую к Aruduino, либо при помощи модулей Расширителей выводов
Для подключения сервоприводов дополнительно понадобится:
Оборудование:
- 1x Piranha UNO
- 2x Trema-модуль Расширитель выводов, FLASH-I2C
- 1x i2c hub
- Провода мама-мама
Библиотеки:
Подключение сервоприводов
Установим 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); } }
Обсуждение