Ви не увійшли.
Всім доброго дня та з Новим Роком! Допоможіть розібратись з кодом. Зробили з сином Led Cub 4*4*4. Куб працює, все добре. Програму взяли з GitHub, також все працює добре. Але хочемо створювати свої ефекти. По маленьку щось виходить, разом вчимо програмування ))). Стикнулись з таким. Два ефекти. Один (randomRain_v2) - рандомне заповнення одного стовпчика з низу до верху, Другий (randomRain_v3) навпаки - рандомне заповнення одного стовпчика з верху до низу. У першому випадку все добре, у другому сам ефект працюе, але чомусь спрацьовує ще один стовпчик. Буду дуже вдячний за допомогу та роз'яснення.
#include <avr/wdt.h>
//initializing and declaring led rows
int column[16]={13,12,11,10,9,8,7,6,5,4,3,2,1,0,A5,A4};
//initializing and declaring led layers
int layer[4]={A3,A2,A1,A0};
void setup() {
//настройка колонок для вывода
for(int i = 0; i<16; i++)
{
pinMode(column[i], OUTPUT);
}
//настройка слоев для вывода
for(int i = 0; i<4; i++)
{
pinMode(layer[i], OUTPUT);
}
//seeding random for random pattern
randomSeed(analogRead(10));
}
void loop() {
//randomRain_v2();
randomRain_v3();
//onCube();
//reboot();
}
void reboot() { // перезагрузка платы
wdt_disable();
wdt_enable(WDTO_1S);
while (1) {}
};
void offCube() { // выключение куба
for (int i = 0; i < 16; i++) {
for (int j = 0; j < 4; j++) {
digitalWrite (column[i] , 1);
digitalWrite (layer[j] , 0);
}
}
}
void onCube() { // включение куба
for (int i = 0; i < 16; i++) {
for (int j = 0; j < 4; j++) {
digitalWrite (column[i] , 0);
digitalWrite (layer[j] , 1);
}
}
}
void randomRain_v2(){
offCube();
for(int i = 0; i!=60; i+=2)
{
int randomColumn = random(0,16);
digitalWrite(column[randomColumn], 0);
for(int i = 4; i >= 0; i--) {
digitalWrite(layer[i], 1);
delay(50);
}
delay(300);
for(int j = 0; j <= 4; j++) {
digitalWrite(layer[j], 0);
delay(300);
}
digitalWrite(column[randomColumn], 1);
}
}
void randomRain_v3(){
offCube();
for(int i = 0; i!=60; i+=2)
{
int randomColumn = random(0,16);
digitalWrite(column[randomColumn], 0);
for(int i = 0; i <= 4; i++) {
digitalWrite(layer[i], 1);
delay(100);
}
delay(300);
for(int i = 4; i >= 0; i--) {
digitalWrite(layer[i], 0);
delay(100);
}
digitalWrite(column[randomColumn], 1);
}
}
Неактивний
Honey пише:Вилазите за межі масива
i=4 замінити на i=3
i<=4 замінити на i<4Дякую! Працює )))
Підкажіть будь ласка ще, як реалізувати поступове заповнення всього куба по одному стовпчику. Так як в прикладах вище, але щоб поступово рандомно кожен стовпчик заповнився з верху до низу і так у весь куб
Неактивний
Зробіь масив int random_index[16]; спочатку заповніть його числами від 0 до 15, а потім їх перетасуйте (google: shuffle), з масиву послідовно берете індекс і заповнюєте цей стовпчик
Дякую! Але моїх знань ще замало щоб це все зрозуміти та зробити) Чи можете Ви допомогти та зробити приклад? Дуже вдячний за допомогу та розуміння
Неактивний
Чи можете Ви допомогти та зробити приклад?
Оголошуєм константу з розміром масиву та сам масив:
const size_t N = 16;
uint8_t cols[N];
Набираєм ентропію для генерації випадкових чисел. Достатньо один раз на початку, десь в setup():
unsigned long seed = 0;
for (size_t i = 0; i < sizeof(seed)*8; i++) {
seed <<= 1;
seed |= analogRead(10) & 1;
}
randomSeed(seed ? seed : 1);
Заповнюємо масив послідовними значеннями:
for (size_t i = 0; i < N; i++) {
cols[i] = i;
}
і перемішуємо:
for (size_t i = 0; i < N-1; i++) {
size_t j = random(i, N);
auto tmp = cols[i];
cols[i] = cols[j];
cols[j] = tmp;
}
Далі можете послідовно вибирати значення з масиву і робити з ними, що вам там потрібно. Наприклад, вивод в послідовний порт:
Serial.println();
for (auto i : cols) {
Serial.print("X: ");
Serial.print(i % 4);
Serial.print(", Y: ");
Serial.print(i / 4);
Serial.println();
}
Якщо потрібна ще одна випадкова перестановка, можна не заповнювати послідовними значеннями заново, а лише перемішати існуючу.
Неактивний
У цьому алгоритмі, мені здається, є недолік. Деякі перестановки можуть не спрацювати, тому що j може виявитись рівним i.
Можна придумати таку ідею:
- згенерувати N пар виду (I(0..N-1), random(maxint))
- відсортувати отриманий масив за зростанням другого елемента пари
- перші елементи - рандомно переставлені числа 0..N-1
Ідеально підходить сортування вставкою.
Недолік - потрібно в 2 рази більше пам'яті.
У цьому алгоритмі, мені здається, є недолік. Деякі перестановки можуть не спрацювати, тому що j може виявитись рівним i.
Випадкова перестановка на те і випадкова, що елемент може залишитись на своєму місці з ймовірністю 1/N.
Он в Енігмі, наприклад, вхідна літера теж ніколи не транслювалась сама в себе
Можна придумати таку ідею
Такий алгоритм теж існує. Тільки він вимагає, щоб допоміжні елементи були унікальними, інакше розподіл вже не буде випадковим. А генерація випадкових унікальних елементів потребує випадкової перестановки
Недолік - потрібно в 2 рази більше пам'яті.
І алгоритмічна швидкодія обмежена обраним алгоритмом сортування. Для сортування вставкою найгірший випадок О(n²).
А результат такий самий: елемент також із ймовірністю 1/N може залишитись на своєму місці.
Інша справа, що ардуінівска random(long) реалізована некоректно і не дає рівномірного розподілу. Але якщо не потрібна криптографічна надійність, то для невеликих діапазонів цей ефект не дуже суттєвий.
Остання редакція dimich (2025-01-03 10:44:12)
Неактивний
Імовірність перестановки в початку і в кінці масиву відрізняється. Так що непогано було б прогнати цикл перестановок N раз, із зсувом масиву на 1 позицію.
Так, для міні-куба це не актуально. Але краще старатися робити красиво; як попало воно само вийде
Наприклад, мій електрокамін. В ньому є імітація потріскування дров, але зробили її як попало. На слух помітні паттерни що повторюються. Бісить
Імовірність перестановки в початку і в кінці масиву відрізняється.
Не відрізняється.
Ймовірність, що 0-й елемент залишиться на своєму місці: 1/N.
Ймовірність, що 1-й елемент залишиться на своєму місці після першого кроку: (N-1)/N, на другому кроці: 1/(N-1).
Тобто після двох кроків його шанс залишитись на своєму місці: ((N-1)/N) * (1/(N-1) = 1/N.
Для 2-го елемента ймовірність залишитить на своєму місці після 1-го кроку: (N-1)/N, після другого кроку: (N-2)/(N-1), на третьому кроці: 1/(N-2). Після всіх трьох кроків: ((N-1)/N) * ((N-2)/(N-1)) * (1/(N-2)) = 1/N.
Далі за індукцією.
Якщо не довіряєте аналітичним методам, можете самі написати програмку та прогнати результати через статистичні тести.
Так що непогано було б прогнати цикл перестановок N раз, із зсувом масиву на 1 позицію.
І що це дасть?
Але краще старатися робити красиво; як попало воно само вийде
Саме так. Тільки "молоді та амбітні" не хотять красиво, хотять "%#як-%#як, і в продакшн".
Остання редакція dimich (2025-01-03 18:45:33)
Неактивний
Filaka пише:Чи можете Ви допомогти та зробити приклад?
Оголошуєм константу з розміром масиву та сам масив:
const size_t N = 16; uint8_t cols[N];
Набираєм ентропію для генерації випадкових чисел. Достатньо один раз на початку, десь в setup():
unsigned long seed = 0; for (size_t i = 0; i < sizeof(seed)*8; i++) { seed <<= 1; seed |= analogRead(10) & 1; } randomSeed(seed ? seed : 1);
Заповнюємо масив послідовними значеннями:
for (size_t i = 0; i < N; i++) { cols[i] = i; }
і перемішуємо:
for (size_t i = 0; i < N-1; i++) { size_t j = random(i, N); auto tmp = cols[i]; cols[i] = cols[j]; cols[j] = tmp; }
Далі можете послідовно вибирати значення з масиву і робити з ними, що вам там потрібно. Наприклад, вивод в послідовний порт:
Serial.println(); for (auto i : cols) { Serial.print("X: "); Serial.print(i % 4); Serial.print(", Y: "); Serial.print(i / 4); Serial.println(); }
Якщо потрібна ще одна випадкова перестановка, можна не заповнювати послідовними значеннями заново, а лише перемішати існуючу.
Дуже дякую за допомогу та пояснення! Але мені ще поки що складно було розібратись в коді та синтаксису Інтернет моцна штука, допоміг! Спробував виводити у Монітор Порта Arduino, щоб зрозуміти що тут відбувається. Але поки що не зрозумів як це все реалізувати у своєму проєкт Куба. Та поєднати з :
digitalWrite (column[i] , 1);
digitalWrite (layer[j] , 0);
Можливо я не так пояснив свій задум, ось посилання на приклад. Куб повинен повністю заповнитись.
https://drive.google.com/file/d/1bFwaPj … drive_link
Неактивний
Filaka пише:Чи можете Ви допомогти та зробити приклад?
Оголошуєм константу з розміром масиву та сам масив:
const size_t N = 16; uint8_t cols[N];
Набираєм ентропію для генерації випадкових чисел. Достатньо один раз на початку, десь в setup():
unsigned long seed = 0; for (size_t i = 0; i < sizeof(seed)*8; i++) { seed <<= 1; seed |= analogRead(10) & 1; } randomSeed(seed ? seed : 1);
Заповнюємо масив послідовними значеннями:
for (size_t i = 0; i < N; i++) { cols[i] = i; }
і перемішуємо:
for (size_t i = 0; i < N-1; i++) { size_t j = random(i, N); auto tmp = cols[i]; cols[i] = cols[j]; cols[j] = tmp; }
Далі можете послідовно вибирати значення з масиву і робити з ними, що вам там потрібно. Наприклад, вивод в послідовний порт:
Serial.println(); for (auto i : cols) { Serial.print("X: "); Serial.print(i % 4); Serial.print(", Y: "); Serial.print(i / 4); Serial.println(); }
Якщо потрібна ще одна випадкова перестановка, можна не заповнювати послідовними значеннями заново, а лише перемішати існуючу.
Дуже дякую за допомогу та пояснення! Але мені ще поки що складно було розібратись в коді та синтаксису Інтернет моцна штука, допоміг! Спробував виводити у Монітор Порта Arduino, щоб зрозуміти що тут відбувається. Але поки що не зрозумів як це все реалізувати у своєму проєкт Куба. Та поєднати з :
digitalWrite (column[i] , 1);
digitalWrite (layer[j] , 0);
Можливо я не так пояснив свій задум, ось посилання на приклад. Куб повинен повністю заповнитись.
drive.google.com/file/d/1bFwaPjvazLKD6y … drive_link
Неактивний
Добрий вечір! Другий день намагаюсь написати повідомлення і не виходить. Пишу через "Цитувати", едине що то це додаю посилання на файл. Якщо зайти у "Цитувати" або "Відповісти", то там вже два моїх повідомлення, а у темі їх немає. Чому так?
Неактивний
Добрий вечір! Другий день намагаюсь написати повідомлення і не виходить. Пишу через "Цитувати", едине що то це додаю посилання на файл. Якщо зайти у "Цитувати" або "Відповісти", то там вже два моїх повідомлення, а у темі їх немає. Чому так?
А на головній сторінці та в темі відображається, що є нове повідомлення, а заходиш - немає. Хто зна, може через посилання спрацьовує якийсь антиспам захист. Через "Відповісти", дійсно, побачив.
Але поки що не зрозумів як це все реалізувати у своєму проєкт Куба.
Наскільки можна здогадатись по коду, куб реалізовано підключенням світлодіодів секціями зі спільним анодом. Якщо так, то для відображення довільного стану вам потрібна динамічна індикація. Це окрема задача, не повʼязана з випадковим заповненням, але необхідна для його для реалізації.
Потрібно перебирати секції по одній (прохід по вашому масиву layer) і вмикати світлодіоди в ній на певний час. Бажано з частотою більше 60 Гц, щоб не було помітне мерехтіння. При 4 секціях це десь на 4 мілісекунди.
Це можна реалізувати "в лоб": на перший погляд здається простіше, але чим складніше буде логіка заповнення, тим заплутанішим ставатиме код. Правильніше буде розділити: код індикації окремо, логіка заповнення окремо.
Звісно, середній струм через діоди, і як наслідок, яскравість, зменшаться в 4 рази. Щоб яскравість була така ж як зараз, без динамічної індикації, потрібно буде зменшити номінал резисторів в 4 рази. У вас же, сподіваюсь, по резистору на кожний стовпчик, а не на секцію?
Щоби порадити щось детальніше, потрібно хоча би побачити схему.
Як запрацює динамічна індикація, тоді можна думати і про різні варіанти ефектів.
Остання редакція dimich (2025-01-10 03:28:49)
Неактивний
Чому так?
Походу движок форума глючить. Занадто часто, як для форума, де нове повідомлення раз на тиждень. Напишіть адмінам.
Але поки що не зрозумів як це все реалізувати у своєму проєкт Куба. Куб повинен повністю заповнитись.
Якщо здогадки про вашу схему підключення вірні, то ось така наївна реалізація може запрацювати:
// Абстрактний клас періодичної задачі
template <unsigned int Period>
class task
{
protected:
unsigned long last;
virtual void process() = 0;
public:
task() : last { -Period } // дозволимо перший виклик одразу, без очікування
{}
void loop(unsigned long now)
{
if (now - last >= Period) {
last = now;
process();
}
}
};
// Клас динамічної індикації
template <byte Segments, byte Layers, byte FPS = 60>
class matrix: public task<1000/FPS/Layers>
{
const byte *segment_pins;
const byte *layer_pins;
static constexpr auto seg_size = (Segments+7)/8;
// Кожний біт в масиві визначає стан окремого світлодіода
byte leds[Layers][seg_size];
byte active_layer;
void process() override
{
// Вимикаємо поточний шар
digitalWrite(layer_pins[active_layer], LOW);
// Беремо наступний шар за активний
if (++active_layer == Layers) {
active_layer = 0;
}
// Оновлюємо стан світлодіодів.
// Перемикання світлодіодів по одному дуже повільне, але керування
// декількома пінами одночасно ставить певні вимоги до схемотехніки
// та не буде крос-платформенним.
const byte *pin = segment_pins;
const uint8_t *bits = leds[active_layer];
byte mask = 1;
for (byte i = Segments;;) {
digitalWrite(*pin++, (*bits & mask) ? LOW : HIGH);
if (!--i) {
break;
}
if ((mask <<= 1) == 0) {
mask = 1;
bits++;
}
}
// Вмикаємо поточний шар
digitalWrite(layer_pins[active_layer], HIGH);
}
public:
matrix(const byte *segment_pins_, const byte *layer_pins_)
: segment_pins(segment_pins_), layer_pins(layer_pins_),
active_layer( Layers-1 )
{}
void begin()
{
// початковий стан: все вимкнено
for (const byte *pin = layer_pins; pin < layer_pins + Layers; pin++) {
pinMode(*pin, OUTPUT);
digitalWrite(*pin, LOW);
}
for (const byte *pin = segment_pins; pin < segment_pins + Segments; pin++) {
pinMode(*pin, OUTPUT);
}
}
void set(byte segment, byte layer, bool on)
{
byte mask = 1 << (segment % 8);
byte *addr = &leds[layer][segment / 8];
if (on) {
*addr |= mask;
} else {
*addr &= ~mask;
}
}
void clear()
{
memset(leds, 0, sizeof(leds));
}
void fill()
{
memset(leds, 0xff, sizeof(leds));
}
};
// для номера піна достатньо байта
const byte column[16]= { 13,12,11,10,9,8,7,6,5,4,3,2,1,0,A5,A4 };
const byte layer[4]= { A3,A2,A1,A0 };
#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x)))
matrix<ARRAY_SIZE(column), ARRAY_SIZE(layer)> cube(column, layer);
/* Клас анімації */
template <byte Cols, byte Height>
class animation: public task<100> // квант 1/10 секунди
{
byte cols[Cols];
byte col_idx;
byte col_state;
unsigned int pause;
bool wait;
unsigned int update(void)
{
if (wait) {
wait = false;
cube.clear();
return 20; // пауза після очищення куба
}
cube.set(cols[col_idx], col_state, true);
if (++col_state < Height) { // ще не заповнили стовпчик?
return 2; // пауза після проміжного світлодіода в стопчику
}
col_state = 0;
// вибираєм наступний стовпчик
if (++col_idx < Cols) { // ще не заповнили всі ?
return 6; // пауза після останнього світлодіода в стопчику
}
shuffle();
col_idx = 0;
wait = true;
return 20; // пауза після заповнення всього куба
}
void process() override
{
for (;;) {
// дециматор
if (pause) {
--pause;
return;
}
pause = update();
}
}
void shuffle()
{
for (size_t i = 0; i < Cols-1; i++) {
size_t j = random(i, Cols);
auto tmp = cols[i];
cols[i] = cols[j];
cols[j] = tmp;
}
}
public:
void begin()
{
for (size_t i = 0; i < Cols; i++) {
cols[i] = i;
}
shuffle();
col_idx = 0;
col_state = 0;
pause = 0;
wait = false;
}
};
animation<ARRAY_SIZE(column), ARRAY_SIZE(layer)> anim;
void setup()
{
// Набираєм ентропію для генерації випадкових чисел
// до того як перемкнули пін 10 в output
{
const byte rnd_pin = 10;
pinMode(rnd_pin, INPUT);
unsigned long seed = 0;
for (size_t i = 0; i < sizeof(seed)*8; i++) {
seed <<= 1;
seed |= analogRead(rnd_pin) & 1;
}
randomSeed(seed ? seed : 1);
}
cube.begin();
anim.begin();
}
void loop()
{
auto now = millis();
cube.loop(now);
anim.loop(now);
}
Не перевіряв, бо світлодіодного куба не маю. Так що на свій страх і ризик.
Неактивний
Filaka пише:Але поки що не зрозумів як це все реалізувати у своєму проєкт Куба. Куб повинен повністю заповнитись.
Якщо здогадки про вашу схему підключення вірні, то ось така наївна реалізація може запрацювати:
// Абстрактний клас періодичної задачі template <unsigned int Period> class task { protected: unsigned long last; virtual void process() = 0; public: task() : last { -Period } // дозволимо перший виклик одразу, без очікування {} void loop(unsigned long now) { if (now - last >= Period) { last = now; process(); } } }; // Клас динамічної індикації template <byte Segments, byte Layers, byte FPS = 60> class matrix: public task<1000/FPS/Layers> { const byte *segment_pins; const byte *layer_pins; static constexpr auto seg_size = (Segments+7)/8; // Кожний біт в масиві визначає стан окремого світлодіода byte leds[Layers][seg_size]; byte active_layer; void process() override { // Вимикаємо поточний шар digitalWrite(layer_pins[active_layer], LOW); // Беремо наступний шар за активний if (++active_layer == Layers) { active_layer = 0; } // Оновлюємо стан світлодіодів. // Перемикання світлодіодів по одному дуже повільне, але керування // декількома пінами одночасно ставить певні вимоги до схемотехніки // та не буде крос-платформенним. const byte *pin = segment_pins; const uint8_t *bits = leds[active_layer]; byte mask = 1; for (byte i = Segments;;) { digitalWrite(*pin++, (*bits & mask) ? LOW : HIGH); if (!--i) { break; } if ((mask <<= 1) == 0) { mask = 1; bits++; } } // Вмикаємо поточний шар digitalWrite(layer_pins[active_layer], HIGH); } public: matrix(const byte *segment_pins_, const byte *layer_pins_) : segment_pins(segment_pins_), layer_pins(layer_pins_), active_layer( Layers-1 ) {} void begin() { // початковий стан: все вимкнено for (const byte *pin = layer_pins; pin < layer_pins + Layers; pin++) { pinMode(*pin, OUTPUT); digitalWrite(*pin, LOW); } for (const byte *pin = segment_pins; pin < segment_pins + Segments; pin++) { pinMode(*pin, OUTPUT); } } void set(byte segment, byte layer, bool on) { byte mask = 1 << (segment % 8); byte *addr = &leds[layer][segment / 8]; if (on) { *addr |= mask; } else { *addr &= ~mask; } } void clear() { memset(leds, 0, sizeof(leds)); } void fill() { memset(leds, 0xff, sizeof(leds)); } }; // для номера піна достатньо байта const byte column[16]= { 13,12,11,10,9,8,7,6,5,4,3,2,1,0,A5,A4 }; const byte layer[4]= { A3,A2,A1,A0 }; #define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x))) matrix<ARRAY_SIZE(column), ARRAY_SIZE(layer)> cube(column, layer); /* Клас анімації */ template <byte Cols, byte Height> class animation: public task<100> // квант 1/10 секунди { byte cols[Cols]; byte col_idx; byte col_state; unsigned int pause; bool wait; unsigned int update(void) { if (wait) { wait = false; cube.clear(); return 20; // пауза після очищення куба } cube.set(cols[col_idx], col_state, true); if (++col_state < Height) { // ще не заповнили стовпчик? return 2; // пауза після проміжного світлодіода в стопчику } col_state = 0; // вибираєм наступний стовпчик if (++col_idx < Cols) { // ще не заповнили всі ? return 6; // пауза після останнього світлодіода в стопчику } shuffle(); col_idx = 0; wait = true; return 20; // пауза після заповнення всього куба } void process() override { for (;;) { // дециматор if (pause) { --pause; return; } pause = update(); } } void shuffle() { for (size_t i = 0; i < Cols-1; i++) { size_t j = random(i, Cols); auto tmp = cols[i]; cols[i] = cols[j]; cols[j] = tmp; } } public: void begin() { for (size_t i = 0; i < Cols; i++) { cols[i] = i; } shuffle(); col_idx = 0; col_state = 0; pause = 0; wait = false; } }; animation<ARRAY_SIZE(column), ARRAY_SIZE(layer)> anim; void setup() { // Набираєм ентропію для генерації випадкових чисел // до того як перемкнули пін 10 в output { const byte rnd_pin = 10; pinMode(rnd_pin, INPUT); unsigned long seed = 0; for (size_t i = 0; i < sizeof(seed)*8; i++) { seed <<= 1; seed |= analogRead(rnd_pin) & 1; } randomSeed(seed ? seed : 1); } cube.begin(); anim.begin(); } void loop() { auto now = millis(); cube.loop(now); anim.loop(now); }
Не перевіряв, бо світлодіодного куба не маю. Так що на свій страх і ризик.
Дуже дякую! Все саме так як і хотів. Зараз буду розбиратись у самому коді
Неактивний
Звісно, середній струм через діоди, і як наслідок, яскравість, зменшаться в 4 рази. Щоб яскравість була така ж як зараз, без динамічної індикації, потрібно буде зменшити номінал резисторів в 4 рази. У вас же, сподіваюсь, по резистору на кожний стовпчик, а не на секцію?
Щоби порадити щось детальніше, потрібно хоча би побачити схему.Як запрацює динамічна індикація, тоді можна думати і про різні варіанти ефектів.
Так, після послідовного вмикання світлодіодів, яскравість поступово падає. Спробую окремо подавати живлення.
Резистори стоять на шари(4шт. анод), по одному резистору номіналом 100Ом. Катод на стовпчики(16шт. без резистора)
Остання редакція Filaka (2025-01-12 14:11:12)
Неактивний
Так, після послідовного вмикання світлодіодів, яскравість поступово падає.
Що ж, не бачачи схеми можна й не вгадати.
Спробую окремо подавати живлення.
Це не допоможе.
Резистори стоіть на шари(4шт. анод), по одному резистору номіналом 100Ом. Катод на стовпчики(16шт. без резистора)
Поставте резистори на кожний стовпчик (16 штук, на кожний пін із column), а з пінів layers приберіть.
Звісно, можна залишити схему як є, а поміняти місцями column і layer в програмі. Але тоді коефіцієнт заповнення зміниться з 1/4 до 1/16 і загальна яскравість впаде ще в 4 рази. І час світіння кожного сегмента зменшиться з 4 мс до 1 мс, що вже може впертись в швидкодію ардуіни.
По-хорошому, динамічну індикацію треба вішати на переривання по таймеру. Тільки фреймворк ардуіно не надає для цього крос-платформенних функцій, і це зовсім інша тема.
Неактивний
по одному резистору номіналом 100Ом.
Якого кольору ваші світлодіоди? При 100 омах втікаючий в катодні піни струм перевищуватиме допустимий, коли світитиметься весь шар. Також загальний струм через сам контроллер вже може бути завеликий. По-хорошому, таку кількість світлодіодів потрібно комутувати через буферні каскади. Або обмежити струм збільшенням резисторів, хоча б до 470 Ом.
Неактивний
Filaka пише:по одному резистору номіналом 100Ом.
Якого кольору ваші світлодіоди? При 100 омах втікаючий в катодні піни струм перевищуватиме допустимий, коли світитиметься весь шар. Також загальний струм через сам контроллер вже може бути завеликий. По-хорошому, таку кількість світлодіодів потрібно комутувати через буферні каскади. Або обмежити струм збільшенням резисторів, хоча б до 470 Ом.
Колір фіолетовий - 3,1V. Я думаю спробувати поставити на анод по мосфету та окремо подавати живлення, що скажете?
Неактивний
Не бажаєте схему показати?
Вам потрібно, щоб струм через світлодіоди був стабільний, без залежності скільки їх ввімкнено? тоді на кожен led в групі - окремий резистор (16 шт). І порахуйте який потрібен струм, може mosfet лишній.
Якщо 1 резистор на групу з 16 led - в залежності від кількості ввімкнених led яскравість буде мінятися.Можна спробувати скомпенсувати часом експозиції - підібрати резистор, щоб нормально світились всі 16, а коли менше - зменшувати час, але це буде багато веселих дослідів
Неактивний
Колір фіолетовий - 3,1V.
В поточній схемі струм з піна (5-3.1)/100 = 19 мА - в межах допустимого. При одному увімкненому світлодіоді він весь тече через нього. При всіх 16 увімкнених світлодіодах він розподіляється між ними, так що через кожний світлодіод тече всього 1.1 мА.
При 100 омах втікаючий в катодні піни струм перевищуватиме допустимий
Тут я мав на увазі витікаючий струм з анодних пінів. (Нескладно заплутатись, не маючи схеми перед очима )
Я думаю спробувати поставити на анод по мосфету та окремо подавати живлення, що скажете?
Без переміщення резисторів з анодних пінів (4 шт) на катодні (16 шт)? Цим ви вирішите проблему перевищення допустимого струму, якщо вона є. На ефект падіння яскравості по мірі вмикання світлодіодів це ніяк не вплине, тому що програма перебирає шари (4 штуки), в кожен момент часу вмикаючи світлодіоди одного шару. Щоб яскравість не залежала від кількості увімкнених у шарі світлодіодів, кожен із них потрібно живити через окремий резистор.
Ще раз, є два варіанта.
Або: Прибираєте 4 резистора з анодних пінів. Ставите 16 резисторів в катодні піни.
Щоби при всіх увімкнених у шарі світлодіодах з анодного піна не витікало більше 40 мА, струм через кожний світлодіод не має перевищувати 2.5 мА. Якщо яскравість при такому струмі вас задовільняє, тоді мосфетів і окремого живлення не потрібно. Номінал катодних резисторів при цьому має бути не менше (5-3.1)/0.0025 = 760 Ом.
Але документація атмеги не зазначає, чи 40 mA absolute maximum rating - це для середнього струму, чи імпульсного. Враховуючи, що кожний шар активний лише 1/4 періоду, то можна ризикнути і зменшити резистори до 470 Ом. Тоді струм світлодіода збільшиться до 4 мА, а струм з піна при всіх увімкнених збільшиться до 64 мА.
Програма при цьому залишається як є.
Якщо хочете збільшити струм понад 2.5 мА, але не хочете ризикувати, тоді має сенс ставити мосфети. Тільки я би для зручності перевернув полярність діодів та інвертував сигнали, щоб використовувати N-мосфети, а не P.
Або: схема залишається як є. В програмі міняєте місцями column і layer для динамічної індикації:
matrix<ARRAY_SIZE(layer), ARRAY_SIZE(column)> cube(layer, column);
а також міняєте HIGH на LOW і навпаки скрізь у digitalWrite() у функціях класу matrix.
Тільки це може призвести до небажаних ефектів, про які писав вище. Все ж таки при динамічній індикації намагаються зробити сегментів більше, а секцій менше. Щоб яскравість не залежала від кількості одночасно увімкнених сегментів, живлення кожного сегмента має бути через окремий резистор.
Остання редакція dimich (2025-01-12 17:14:34)
Неактивний