Из-за маленького размера платы и особенностей разводки светодиод имеет типоразмер 0201 и не имеет общего минуса или плюса. Он подключен к двум цифровым контактам: PIN_PC2 и PIN_PA3 через резистор. PIN_PC2 является минусом для светодиода, и его всегда нужно конфигурировать как digitalWrite(PIN_PC2, LOW). Вторым контактом уже можно управлять как в ШИМ-режиме с помощью analogWrite(PIN_PA3, i), так и в обычном режиме с digitalWrite(PIN_PA3, HIGH).
Вот два простых примера:
Пример 1
void setup() {
pinMode(PIN_PC2, OUTPUT);
pinMode(PIN_PA3, OUTPUT);
digitalWrite(PIN_PC2, LOW);
}
void loop() {
for(int i=0;i<140;i++) {
analogWrite(PIN_PA3, i);
delay(15);
}
for(int i=140;i>0;i--) {
analogWrite(PIN_PA3, i);
delay(15);
}
}
Пример 2
void setup() {
pinMode(PIN_PC2, OUTPUT);
pinMode(PIN_PA3, OUTPUT);
digitalWrite(PIN_PC2, LOW);
}
void loop() {
digitalWrite(PIN_PA3, HIGH);
delay(100);
digitalWrite(PIN_PA3, LOW);
delay(100);
}
В новой версии Qrduino~ появился втроеный делитель напряжения от 0 до 24 вольт. На кртинке с распиновкой можно заметить контакт "ADC АЦП (0-24v)" это и есть он. Это удобство позволяет напрямую подключать измеряемые напряжения без дополнительных резисторов. Эта обвязка также имеет конденсатор на 100nf для помехоподавления. Делитель подключен к контакту PIN_PA5. При этом сама площадка на стороне "сетки" контактов подключена напрямую, а площадка делителя напряжения(на лийцевой стороне ADC АЦП) подключена через делитель как дополнение.
Тут все работает так же, как и на обычном Arduino. Давайте попробуем считать аналоговой сигнал с фоторезистора. Поскольку мы не можем вывести значения в монитор порта, будем выводить их на OLED дисплей 0.96" 128x64.
Соберем простую схему:
Выглядит примерно так:
Теперь загрузим код в Qrduino:
#include <Wire.h> // Для работы с I2C (OLED)
#include <Adafruit_GFX.h> // Графическая библиотека для OLED
#include <Adafruit_SSD1306.h> // Библиотека для дисплея SSD1306
#define SCREEN_WIDTH 128 // Ширина дисплея OLED
#define SCREEN_HEIGHT 64 // Высота дисплея OLED
#define OLED_RESET -1 // Пин сброса не требуется для этого дисплея
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
void setup() {
// Настройка дисплея
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // 0x3C — I2C-адрес дисплея
while(1); // Если дисплей не найден, программа остановится
}
// Настройка АЦП на пине PA5 с внутренним опорным напряжением 1.5V
analogReference(INTERNAL2V5);
}
void loop() {
int sensorValue = analogRead(PIN_PA5); // Чтение значения с АЦП
// Отображаем результат на OLED-дисплее
display.clearDisplay();
display.setTextSize(5);
display.setCursor(20, 20);
display.setTextColor(SSD1306_WHITE); // Белый цвет текста
display.println(sensorValue);
display.display();
delay(1); // Обновляем показания через определенное время
}
Перед компиляцией, установите соответствующие библиотеки для работы с дисплеем.
Для выбора опорных напряжений АЦП используйте функцию analogReference(INTERNAL2V2); и таблицу:
Итак, наш код, просто показывает на дисплее считаные значения с фоторезистора:
Комнатный свет:
Закрываем пальцем фоторезистор:
А теперь его на яркий свет:
Как видим, значение уменьшается при больше яркости.
Этот код, как и другие в этих примерах – всего лишь демонстрация того, как работать с Qrduino в IDE Arduino.
Этот пример проще с точки зрения кода в IDE Arduino, однако процессы настройки таймера для генерации ШИМ, которые происходят «за кулисами» digitalWrite(PIN_PB2,255) не проще чем настройка ацп. Но при кодировании в IDE Arduino, это знать не нужно, если вы не сталкивайтесь с конфликтами библиотек и т.п.
Итак, соберем простую схему:
В этом примере использованы smd компоненты для компактности, можно использовать и обычные выводные компоненты. Обратите внимание, что вместо минуса для светодиода будем использовать площадку PIN_PB5. За одно посмотрим как работают обычные функции digitalWrite.
Напишем простой пример ШИМ:
void setup() {
pinMode( PIN_PB1, OUTPUT); // Устанавливаем пин как выход это будет вывод ШИМ
pinMode( PIN_PB5, OUTPUT);// Устанавливаем пин как выход это будет минус для светодиода.
digitalWrite(PIN_PB5, LOW); //устанавливаем вывод на минус
}
void loop() {
// Увеличение яркости
for (int i = 0; i<= 255; i++) {
analogWrite(PIN_PB1, i); // Устанавливаем яркость
delay(10); // Небольшая задержка для плавного увеличения
}
// Уменьшение яркости
for (int i = 255; i >= 0; i--) {
analogWrite(PIN_PB1, i); // Устанавливаем яркость
delay(10); // Небольшая задержка для плавного уменьшения
}
}
В результате у нас светодиод будет медленно увеличиваться в яркости и гаснуть:
Этот периферийный блок не часто встретишь в микроконтроллерах. Он позволяет получить на выходе аналоговое напряжение, заданное программой.
Мы знаем из основ устройства микроконтроллеров, что схемотехнически цифровые выводы подключены к так называемой комплементарной паре. Не вдаваясь в подробности, это нам дает знание, что любой цифровой вывод микроконтроллера, когда сконфигурирован на выход, технически, только и умеет подключаться к плюсу питания (VCC) или минусу питания (GND). Но делать он может это разными комбинациями в зависимости от программы, как мы и убедились с примером ШИМ. В предыдущем примере у нас горел светодиод с разной яркостью, но технически пин микроконтроллера не может дать напряжение меньше чем 5 вольт. Поэтому мы использовали прием, который подает эти 5 вольт импульсно, но с разной периодичностью, что и позволяет добиться эффекта уменьшения яркости для восприятия наших глаз. На самом деле, светодиод просто очень быстро мигает.
Но вот другое дело ЦАП. Именно это устройство может сделать на выводе микроконтроллера разные напряжения, написав просто значение в функцию analogWrite. В данном случае ЦАП имеет разрешение 8 бит (0-255 значений). То напряжение, которое будете получать на выходе, зависит от опорного напряжения.
Итак, теперь мы сделаем похожий пример с ШИМ, но только на ЦАПе. То есть наш светодиод будет тоже увеличивать яркость и гаснуть, но уже не импульсно, а линейно (аналогово). В этом ЦАПе есть нюанс по максимальному току всего – 1мА. Это значит, что даже светодиод запитать обычным способом – превысит ток для ЦАП. Поэтому его нужно использовать только как устройство сигнального напряжения. Для таких схем, где этот сигнал будет использован либо для сравнения, или как опорное напряжение, или регулировать что-то (типа переменного резистора в сигнальной схеме), или мы этот сигнал усилим операционным усилителем, транзистором, или операционным усилителем rail-to-rail (регулирует напряжение от 0 до напряжения питания).
Для примера мы возьмем ту же схему из прошлого примера, но поменяем резистор на более высокоомный 4.7кОм, за это мы пожертвуем максимальной яркостью. И переключим на другие пины:
Теперь загрузим такой код:
void setup() {
DACReference(INTERNAL2V5); // Устанавливаем опорное напряжение, оно должно быть меньше напряжения питания на примерно пол вольта.
pinMode( PIN_PC3, OUTPUT); // Устанавливаем пин как выход это будет минус для светодиода.
digitalWrite(PIN_PC3, LOW); //устанавливаем вывод на минус
}
void loop() {
// Увеличение яркости
for (int i = 0; i<= 255; i++) {
analogWrite(PIN_PA6, i); // Устанавливаем яркость
delay(10); // Небольшая задержка для плавного увеличения
}
// Уменьшение яркости
for (int i = 255; i >= 0; i--) {
analogWrite(PIN_PA6, i); // Устанавливаем яркость
delay(10); // Небольшая задержка для плавного уменьшения
}
}
Как видим, тут тоже используется функция analogWrite, но на выводе PIN_PA6(Вывод для ЦАП), где отсутствует ШИМ. Это значит, что в данном случае яркость регулирует именно ЦАП:
Для установки опорных напряжений ЦАП используйте функцию DACReference(INTERNAL2V5); и таблицу:
Библиотека Fab_Led:
Как мы выяснили, не все библиотеки адресных лент будут работать на этом ядре. Но некоторые вполне работают. В этом примере попробуем библиотеку FabLed. Считается продвинутой, энергоэффективной и легкой библиотекой.
Итак, соберем такую схему:
Тепер, нужно настроить частоту на 16мгц:
И очень важно обеспечить эту схему хорошим и стабильным питанием 5 вольт.
Установить эту библиотеку, получиться только путем копирования папки в библиотеки ардуино. Зайдите на репозиторий github.com библиотеки Fab_Led. Там подробная инструкция по установке в Arduino ide.
Теперь напишем такой код:
#include <FAB_LED.h>
// Объявляем протокол управления светодиодной лентой и используемый порт
// В данном случае используется протокол ws2812b и порт A5 на контроллере
ws2812b<A,5> strip;
// Количество пикселей (светодиодов) в ленте, которыми будем управлять
const uint8_t numPixels = 2;
// Максимальная яркость светодиодов (максимум 255, значение 100 - умеренная яркость)
const uint8_t maxBrightness = 100;
// Массив для хранения данных о цветах пикселей
// Каждый элемент массива представляет один пиксель и его цвет в формате GRB (Green-Red-Blue)
grb pixels[numPixels] = {};
// Функция для установки цвета определённого пикселя
// Параметры: номер пикселя (pixel), значения цвета r (красный), g (зелёный), b (синий)
void setPixelColor(int pixel, char r, char g, char b) {
pixels[pixel].r = r; // Устанавливаем уровень красного цвета для пикселя
pixels[pixel].g = g; // Устанавливаем уровень зелёного цвета для пикселя
pixels[pixel].b = b; // Устанавливаем уровень синего цвета для пикселя
}
void setup() {
// Отключаем все светодиоды при запуске программы
// strip.clear() очищает (выключает) заданное количество пикселей
strip.clear(2 * numPixels); // Умножаем на 2 для гарантии полного отключения
}
void loop() {
// Настраиваем первый пиксель на красный цвет, а второй выключаем
setPixelColor(0, maxBrightness, 0, 0); // Устанавливаем первый пиксель на красный
setPixelColor(1, 0, 0, 0); // Отключаем второй пиксель
strip.sendPixels(numPixels, pixels); // Отправляем данные о цвете на светодиодную ленту
delay(1000); // Ждём 1 секунду
// Настраиваем второй пиксель на зелёный цвет, а первый выключаем
setPixelColor(0, 0, 0, 0); // Отключаем первый пиксель
setPixelColor(1, 0, maxBrightness, 0); // Устанавливаем второй пиксель на зелёный
strip.sendPixels(numPixels, pixels); // Отправляем данные о цвете на светодиодную ленту
delay(1000); // Ждём 1 секунду
}
В результате у нас будут перемигиваться два пикселя, один – зеленым, другой - красным. Если мы захотим смешать цвета то надо написать что-то вроде этого: setPixelColor(0, 150, 50, 200); // первый пиксель.
Библиотека Fast_Led:
Эта популярная библиотека тоже запустилась на этом ядре, но не сразу. Пришлось добавить такую конструкцию в начале кода:
void update_millis() {
static unsigned long last_micros = 0;
unsigned long current_micros = micros();
// Если прошло более 1 миллисекунды, увеличиваем счетчик времени
if (current_micros - last_micros >= 1000) {
timer_millis++;
last_micros = current_micros;
}
}
В этом примере использовалась версия библиотеки 3.9.2.
Итак, для примера мы возьмем эту же схему, что собрали.
Запустим теперь код, который будет делать то же самое, что и в предыдущем примере:
#include <FastLED.h>
volatile unsigned long timer_millis = 0;
// Функция обновления миллисекунд
void update_millis() {
static unsigned long last_micros = 0;
unsigned long current_micros = micros();
// Если прошло более 1 миллисекунды, увеличиваем счетчик времени
if (current_micros - last_micros >= 1000) {
timer_millis++;
last_micros = current_micros;
}
}
// Определение количества светодиодов в ленте
#define NUM_LEDS 2
// Определение пина для передачи данных в светодиоды
#define DATA_PIN PIN_PA5
// Массив для хранения состояния светодиодов
CRGB leds[NUM_LEDS];
void setup() {
// Подключение библиотеки FastLED с настройкой для WS2812B
FastLED.addLeds<WS2812B, DATA_PIN, RGB>(leds, NUM_LEDS);
}
void loop() {
// Включаем первый светодиод на красный цвет, затем ждем 1 секунду
leds[0] = CRGB(100, 0, 0); // Устанавливаем цвет красный
FastLED.show(); // Обновляем ленту
delay(1000); // Задержка 1 секунда
// Выключаем первый светодиод
leds[0] = CRGB(0, 0, 0); // Устанавливаем цвет черный (выключено)
FastLED.show(); // Обновляем ленту
// Включаем второй светодиод на зеленый цвет, затем ждем 1 секунду
leds[1] = CRGB(0, 100, 0); // Устанавливаем цвет зеленый
FastLED.show(); // Обновляем ленту
delay(1000); // Задержка 1 секунда
// Выключаем второй светодиод
leds[1] = CRGB(0, 0, 0); // Устанавливаем цвет черный (выключено)
FastLED.show(); // Обновляем ленту
}
Результат будет такой же.
Удивительно, какой маленький контроллер адресной ленты, можно сделать из платы Qrduino.
В этом примере будем использовать стандартную библиотеку servo.h. Но эта библиотека в стандартном виде не совместима с Attiny1616, поэтому в megaTinyCore вместе с установкой ядра автоматически устанавливается подходящая библиотека - Servo_megaTinyCore.h. Это та же самая библиотека servo.h с точно такими же командами, но адаптирована под серию этих микроконтроллеров, выбирая подходящий таймер.
Итак, соберем схему:
И загрузим простой код:
#include <Servo_megaTinyCore.h>
Servo myservo;
void setup() {
myservo.attach(PIN_PA3);
}
void loop() {
myservo.write(90);
delay(1000);
myservo.write(0);
delay(1000);
}
В итоге сервопривод будет просто поворачиваться с нулевого на среднее положение и обратно с периодичностью в секунду: