вопрос программирования от чайника

vitmish
Offline
Зарегистрирован: 06.02.2017

Есть желание автоматизировать работу вентилятора в ванной. Задача в принципе тривиальная, несмотря на отсутствие опыта в программировании - есть готовые решения, которые можно скопировать и адаптировать под себя.
Я же хочу добиться следующего - кроме банального включения вентилятора по достижению параметра влажности вывести ещё индикацю влажности на базе ленты ws2811 - 7-8 диодов, больше смысла не вижу.
Работать примерно так - 55-60% горит один зелёный, с увеличением влажности кол-во диодов увеличивается и меняется их свет.
Когда включается вент - можно поставить мигание либо змейку.
Проблема для меня на текущий момент в том, что в одном loop у меня либо идёт отслеживание и работа по силовой части скетча, а лента горит с одним из значений... Либо я работаю слентой, а алгоритм работы включения не фунциклирует.
Какие функции копать, чтобы один массив данных ( в моём случае влажность) мог в одном loop мог управлять несколькими действиями?

Mr.Privet
Mr.Privet аватар
Offline
Зарегистрирован: 17.11.2015

Loop у Вас один, в нем должны быть вызовы функций "мигания", "управления", а также функции "чтения датчиков". Также глобальная переменная влажности, которую видят все функции. Избавляемся от делаев и loop пробегает достаточно быстро, "чтение" вызываем раз в 1-2 сек. если влажность меняется и перескакивает пороговые значения уже из loop вызываем нужные функци.
P.s. если приведете скетч можно будет поговорить более конкретно

vitmish
Offline
Зарегистрирован: 06.02.2017
Если я в loop ставлю через if режимы работы светодиодов в зависимости от уровня влажности, то .... четкой работы добиться не удалось - либо горят постоянно при инициации,
т.е. было на начальном этапе 75%, зажглись 3 диода, так и горят.
Либо удалось скомпилировать один из вариантов скетча, где гас диод, но при этом не работало включение
Меня в основном интересует, как в этом дне сурка при изменении влажности отрабатывали алгоритмы изменения светодиодов и на пороговом значении отработало реле и более не беспокоило до понижения уровня влажности.
Вернее - так, можно ли из данного loop вытащить текущие значения H и отдельным адгоритмом отработать режим светодиодов
Но, судя по всему, мне надо более вдумчиво курить алгоритм if/else

#include <Adafruit_NeoPixel.h>


#include "DHT.h"
#include <adafruit_NeoPixel.h>
#define DHTPIN 4     // what pin we're connected to
#define PIN 3
#define NUM_LEDS 7
#define BRIGHTNESS 30
Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUM_LEDS, PIN, NEO_GRBW + NEO_KHZ800);

int gamma[] = {
    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  1,  1,  1,
    1,  1,  1,  1,  1,  1,  1,  1,  1,  2,  2,  2,  2,  2,  2,  2,
    2,  3,  3,  3,  3,  3,  3,  3,  4,  4,  4,  4,  4,  5,  5,  5,
    5,  6,  6,  6,  6,  7,  7,  7,  7,  8,  8,  8,  9,  9,  9, 10,
   10, 10, 11, 11, 11, 12, 12, 13, 13, 13, 14, 14, 15, 15, 16, 16,
   17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 24, 24, 25,
   25, 26, 27, 27, 28, 29, 29, 30, 31, 32, 32, 33, 34, 35, 35, 36,
   37, 38, 39, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 50,
   51, 52, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 66, 67, 68,
   69, 70, 72, 73, 74, 75, 77, 78, 79, 81, 82, 83, 85, 86, 87, 89,
   90, 92, 93, 95, 96, 98, 99,101,102,104,105,107,109,110,112,114,
  115,117,119,120,122,124,126,127,129,131,133,135,137,138,140,142,
  144,146,148,150,152,154,156,158,160,162,164,167,169,171,173,175,
  177,180,182,184,186,189,191,193,196,198,200,203,205,208,210,213,
  215,218,220,223,225,228,231,233,236,239,241,244,247,249,252,255 };

#define DHTTYPE DHT11   // DHT 11 
//#define DHTTYPE DHT22   // DHT 22  (AM2302)
//#define DHTTYPE DHT21   // DHT 21 (AM2301)



DHT dht(DHTPIN, DHTTYPE);
int rele = 10;
int x = 0;
int y = 0;
void setup() {
  Serial.begin(9600); 
  Serial.println("DHT test!");
strip.begin();
strip.show();
strip.setBrightness(BRIGHTNESS);
  dht.begin();
}

void loop() {
  pinMode (rele, OUTPUT);
 strip.begin();
  // Reading temperature or humidity takes about 250 milliseconds!
  // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
  float h = dht.readHumidity();
  float t = dht.readTemperature();

  // check if returns are valid, if they are NaN (not a number) then something went wrong!
  if (isnan(t) || isnan(h)) {
    Serial.println("Failed to read from DHT");
  } else {
    x=x+1;
    Serial.print("Humidity: "); 
    Serial.print(h);
    Serial.print(" %\t");
    Serial.print("Temperature: "); 
    Serial.print(t);
    Serial.println(" *C");
    Serial.print(x);
 
  if(h < 70 and x > 600)digitalWrite(rele, HIGH);
  else digitalWrite(rele, LOW);
  
  if(h > 70 and x > 600) x=420;

    
  }

}

 

Mr.Privet
Mr.Privet аватар
Offline
Зарегистрирован: 17.11.2015

Сейчас Ваш скетч подшаманю...

vitmish
Offline
Зарегистрирован: 06.02.2017

мне бы удочку,

рыбы я сам наловлю.

В планах (было) умный дом на даче инсталлировать. Но сейчас как то пыл подугас, если на такой элементарной задаче завис на пару вечеров....

Mr.Privet
Mr.Privet аватар
Offline
Зарегистрирован: 17.11.2015
#include <Adafruit_NeoPixel.h>
#include "DHT.h"
#include <adafruit_NeoPixel.h>
#define DHTPIN 4     // пин датчика
#define PINRELAY 10     // так "кошернее"
#define PIN 3
#define NUM_LEDS 7
#define BRIGHTNESS 30
Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUM_LEDS, PIN, NEO_GRBW + NEO_KHZ800);
#define DHTTYPE DHT11   // DHT 11
DHT dht(DHTPIN, DHTTYPE);
float h=0;                                           // до loop и setup задаются "глобалы"
unsigned long m=0; // переменная для таймера времени
float read_hum ();{//эта функция возвращает значение влажности в float (но можно и в int), ее мы быдем вызывать из loop раз в 2 секунды
                return dht.readHumidity();
}
void serial_ptint();{//Эта функция выводит в сириал значение h(от t я отказался, так как она не используется у нас, можно сделать по аналогии с h)
                Serial.print("Humidity: ");
    Serial.print(h);
    Serial.println(" %\t");
}
void pixelmode(float h){
                for (int i=0;i<map(h,50,100,0,NUM_LEDS);i++)strip.setPixelColor(i,0,255,0);                     // этот кусок домашнее задание на изучение.
                for (int i=map(h,50,100,0,NUM_LEDS);i<NUM_LEDS);i++)strip.setPixelColor(i,0,0,0);
                strip.show();
}
void setup() {//здесь указваем все что нужно сделать 1 раз!
                Serial.begin(9600);
                Serial.println("DHT test!");
                strip.begin();
                strip.setBrightness(BRIGHTNESS);
                strip.show();
                dht.begin();
                pinMode (PINRELAY, OUTPUT);              
}
void loop() {
  if (millis()-m>2000){// если прошло 2 секунды    
                m=millis();                          // обновляем счетчик
                h=read_hum();                               // читаем влажность
                pixelmode(h);
                if(h>80)digitalWrite(rele, HIGH); // здесь закладываем логику включения/выключения вентелятора, я сделал чтобы вент включался при влажности
                                                                                                                                             // больше 80 и выключался при влажности меньше 60, можно подставить таймер чтобы он не молотил постоянно
                                                                                                                                             //если влажность не удалось понизить
                if(h<60)digitalWrite(rele, LOW);
  }
}

Должно компилироваться, не проверял, если что подправьте. А по опыту могу сказать что начинать нужно как тут все советуют с учебника Кернигана и Ритчи по С++, лучше уж пару вечеров на него убить, хотя бы первые 2 главы.

Удачной ловли

vitmish
Offline
Зарегистрирован: 06.02.2017

Спасибо.

Судя по всему, оно может и заработает, но не совсем так, как хочется.

Но для этого изготовлю большой шероховатый напильник.

там напрягло сразу то, что h присвоено значение 0 и далее пока не вижу, как оно будет меняться. Хотя - увидел.

Домашнее задание - это алгоритм работы диодов, только что есть map? - прописано в библиотеке, видимо. Сначала один цвет, по достижению map меняет цвет (0,0,0) - черный/белый?

Подумаю, может процент влажности привять к номеру горящего диода - округлять до целого числа и вычитать константу.

Черт, кажется тут так и прописано, опять таки надо смотреть что такое map.

В общем, это уже все фигня, пройдусь по циклу с карандашом. Главное - я цикл увидел и как он работает.

Спасибо еще раз большое, а то, глядя на чужие скетчи, трудно уловить чужую мысль. Со своей задачей, зная свой алгоритм - читать скетч гораздо проще . Почему то ))

Пару глав придется освоить, а то и больше. Не смогу доверить управление вентилятором, а тем более дачей тому, что не буду знать достаточно хорошо.

Еще раз спасибо, сэкономили мне минимум пару вечеров, воткнули крылья в спину и туда же вставили руки.

vitmish
Offline
Зарегистрирован: 06.02.2017
//Как то странно получается.
Ну - вернее как. Не совсем понял, как значение влажности будет бегать по кругу, поэтому закомментил его.
Печать решил поставить в цикл, чтобы видеть текущие значения.
ну - исправил те ругательства, которыми меня обложила программа. Долго пытался понять, в каких местах все эти недочеты, потом сообразил привязать цифры ошибок к строкам - стало значительно легче ))
И когда ушла последняя ошибка - скомпилировалось таки.
И это было хорошо. Но не совсем.
с функцией map разобрался, обязательно буду пользовать во всех возможных местах. Главу из книги только одну прочитал.
Вот с цветом диодов что-то не задалось.
По идее - индикация должна быть одна для первого ряда, один цвет задан. Для второго ряда - радикально чОрный, тут нет вопросов.
Но у меня цвета пляшут и средний диод не горит.
Это я так, в жилетку поплакаться. Надо бы для чистоты экспериметра запитать ленту от отдельного источника, но вряд ли в этом проблема.
В общем - все работает.
Планы на будущее - выкурить бибилиотеку Неопикселей, может раскроются чакры, освободится сознание и наступит прозрение.
Если здоровья хватит //

#include <Adafruit_NeoPixel.h>
#include "DHT.h"
#include <adafruit_NeoPixel.h>
#define DHTPIN 4     // пин датчика
#define PINRELAY 10     // так "кошернее"
#define PIN 3
#define NUM_LEDS 7
#define BRIGHTNESS 30
Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUM_LEDS, PIN, NEO_GRBW + NEO_KHZ800);
#define DHTTYPE DHT11   // DHT 11
DHT dht(DHTPIN, DHTTYPE);
float h=0;                                           // до loop и setup задаются "глобалы"
unsigned long m=0; // переменная для таймера времени
//float dht.readHumidity ();{//эта функция возвращает значение влажности в float (но можно и в int), ее мы быдем вызывать из loop раз в 2 секунды
           //     return dht.readHumidity();
//}
//void Serial.begin (9600) {
//Serial.begin(9600);  //Эта функция выводит в сириал значение h(от t я отказался, так как она не используется у нас, можно сделать по аналогии с h)
    //            Serial.print("Humidity: ");
  //  Serial.print(h);
  //  Serial.println(" %\t");
//}
void pixelmode(float h)
{
                for (int i=0;i<map(h,50,100,0,NUM_LEDS);i++)strip.setPixelColor(i,0,255,0);                     // этот кусок домашнее задание на изучение.
                for (int i=map(h,50,100,0,NUM_LEDS);i<(NUM_LEDS);i++)strip.setPixelColor(i,0,0,0);
                strip.show();
}
void setup() {//здесь указваем все что нужно сделать 1 раз!
                Serial.begin(9600);
                Serial.println("DHT test!");
                strip.begin();
                strip.setBrightness(BRIGHTNESS);
                strip.show();
                dht.begin();
                pinMode (PINRELAY, OUTPUT);              
}
void loop() {
  if (millis()-m>2000){// если прошло 2 секунды    
                m=millis();                          // обновляем счетчик
                h=dht.readHumidity();                               // читаем влажность
                pixelmode(h);
                if(h>80)digitalWrite(PINRELAY, HIGH); // здесь закладываем логику включения/выключения вентелятора, я сделал чтобы вент включался при влажности
                                                                                                                                             // больше 80 и выключался при влажности меньше 60, можно подставить таймер чтобы он не молотил постоянно
                                                                                                                                             //если влажность не удалось понизить
                if(h<60)digitalWrite(PINRELAY, LOW);
               // Serial.begin(9600);  //Эта функция выводит в сириал значение h(от t я отказался, так как она не используется у нас, можно сделать по аналогии с h)
                Serial.print("Humidity: ");
    Serial.print(h);
    Serial.println(" %\t");
  }
}

 

SLKH
Offline
Зарегистрирован: 17.08.2015

vitmish пишет:

Спасибо.

Судя по всему, оно может и заработает, но не совсем так, как хочется.

Но для этого изготовлю большой шероховатый напильник.

там напрягло сразу то, что h присвоено значение 0 и далее пока не вижу, как оно будет меняться. Хотя - увидел.

Домашнее задание - это алгоритм работы диодов, только что есть map? - прописано в библиотеке, видимо. Сначала один цвет, по достижению map меняет цвет (0,0,0) - черный/белый?

Подумаю, может процент влажности привять к номеру горящего диода - округлять до целого числа и вычитать константу.

Черт, кажется тут так и прописано, опять таки надо смотреть что такое map.

Надо. Я даже подскажу, где: на этой странице вверху есть слово "Программирование". Там внутри и map, и много ещё интересного.

vitmish
Offline
Зарегистрирован: 06.02.2017

тем более что с утра перезапустил схему - не заработала.

А алгоритм диодов вроде бы разгадал, пока пытался уснуть  - параметр i указывает, в какой цветовой гамме работает диод, тогда на 4-м диоде получатся пресловутые 0,0,0

хотя в описании функции все было совсем по другому.

но работающая схема у меня была.....

 

Mr.Privet
Mr.Privet аватар
Offline
Зарегистрирован: 17.11.2015

setPixelColor (номер пикселя, красный,зеленый,синий)

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

vitmish пишет:

Но для этого изготовлю большой шероховатый напильник.

У В.Высоцкого это "РАШПИЛЬ"

vitmish
Offline
Зарегистрирован: 06.02.2017

да я ради чистоты эксперимента ставил setPixelColor(i,255,255,255)

чтобы светился белым.

Один черт, разноцветные пиксели. Но средний пиксель загорелся таки.

Вечером (либо вечерами) буду допиливать. Нестабильно работает, надо смотреть привязку к мониторингу dht, ставить паузы перед запуском, таймеры на отключение, поиграться с индикацией.

Сыроват пока бифштекс, крови много.

Mr.Privet
Mr.Privet аватар
Offline
Зарегистрирован: 17.11.2015

Если лампочки светятся не так как надо значит у Вас плохой контакт сигнального провода на лампочки. Попробуйте запустить скетч из библеотеки. Если к лампам просто подключить питание, повесить провод и теребить его пальцем, без ардуины вообще то будет рандомная дискотека. Смотрите контакт...

vitmish
Offline
Зарегистрирован: 06.02.2017

да, скорее всего.

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

библиотечный скетч уже запускал - но запускал для того, чтобы проверить негорящий средний диод, на правильности цветопередачи как то не акцентировался, хотя опять таки что-то напрягло в выводе цветов.

vitmish
Offline
Зарегистрирован: 06.02.2017

все немного проще оказалось.

Указал другой тип ленты - RGB и белое стало белым, синее-синим и.... китайцы знают несколько тысяч оттенков красного

Теперь буду пытаться при достижении порога включения заставить диоды не просто светитьсЯ, а менять цвет и моргать (как минимум) при работе вентилятора.

Нестабильно работает, может не запуститься, может зависнуть. Держу рашпиль под рукой ))

У меня еще в планах ребенку переделать подсветку лисапеда с обычных лент на WS2811 и RGB/ Бибика, поворотники, ближний/дальний свет, можно цветомузыку сделатЬ, поэтому adafruite изучать по любому

Mr.Privet
Mr.Privet аватар
Offline
Зарегистрирован: 17.11.2015

Вот вам в помощь скетч для светомузыки, мой вольный перевод, делал для себя

//Звуковой и Музыкальный визуализатор ленты с пиксельной адресацией Arduino скетч для обучения Мишеля Бартлетта

/*
 принятые обозначения:
пиксель - физическая LED диод на ленте
точка - объект в программе который может двигаться, менять цвет, появляться исчезать итд. то есль виртуальный, а не физический объект в отличии от пикселя
бам - удар или бит в музыке, вычисляестя в программе момент наступления, периодичность
*/
//БИБЛИОТЕКИ

#include <Adafruit_NeoPixel.h>  
#ifdef __AVR__
#include <avr/power.h>   
#endif   

#define DEMO  						//режим демо, бит и звук генерируются программно.  
#define DEBUG	            		//режим дебаг, выводит в сириал основные параменты звука определяемые программой раз в секунду(замедляет работу)

//КОНСТАНТЫ

#define LED_PIN   A5				// пин для управляющего сигнала ленты.
#define LED_TOTAL 58				// количество ламп в ленте.
#define LED_HALF  LED_TOTAL/2		// половина ламп
#define VISUALS   6					// количество эффектов в Visualize()
#define AUDIO_PIN A0				// пин для звукового детектора
#define KNOB_PIN  A1				// пин для подстойки яркости
#define BUTTON_1  6					// кнопка 1 переключение палитр
#define BUTTON_2  5					// кнопка 2 переключение режимов
#define BUTTON_3  4					// кutton 3 включение "случайного режима"
#ifdef DEBUG
#define PERIOD	1000				// Период вывода в сириал
#endif


// ниже представлены некоторые константы вынесенные из первоначального скетча для удобства автором перевода

#define SILENCE_LVL	15				// уровень шумового фильтра
#define AVGBUMP_LVL 10				// чувствительность к изменению громкости
#define LOOP_DELAY	30				// задержка в цикле
#define SHUFFLE_TIME 30				// Интервал случайного перехода
#define PULSE_FADE 	0.75			// затухание в эффекте Pulse()
#define TRAFF_FADE  0.8				// затухание в эффекте Traffic()(хвостики)
#define SNAKE_FADE	0.975			// затухание в эффекте Snake()
#define DANCE_FADE	0.8				// затухание в эффекте PalleteDance()
#define PAINT_FADE 	0.99			// затухание в эффекте Paintball()

//////////<ГЛОБАЛЬНЫЕ ПЕРЕМЕННЫЕ>

//  Эти переменные нужно помнить от прохода к проходу loop() или нужно использовать в нескольких функциях,
//  поэтому сделаем их глобальными

Adafruit_NeoPixel strand = Adafruit_NeoPixel(LED_TOTAL, LED_PIN, NEO_GRB + NEO_KHZ800);  //Объект ленты

uint16_t gradient = 0; 				// используется для перебора и циклического прохода каждого цвета палитры 
/*
  АХТУНГ!
  Этот массив содержит пороговые значения каждой функции цвета(т.е. максимальное значения которые они принимают перед проходом)
  Значения находятся в том же порятке что в блоке case функции ColorPalette()(Rainbow() первая итд).
  Это простой способ защитить "gradient" от переполняемости, сами цветовые функции могут принимать любые положительные значения.
  На пример наибольшее значения Rainbow() принимает перед циклом 1529, так что "gradient" должен пересчитаться после 1529, как это указано.
  Убедитесь что вы добввили/удалили переменные в соответствии с изменением в блоке case функции ColorPalette().
*/
uint16_t thresholds[] = {1529, 1019, 764, 764, 764, 1274,764};

uint8_t palette = 0;  // содержит текущий цвет палитры
uint8_t visual = 0;   // содержит текущий эффект
uint8_t volume = 0;   // содержит уровень звука, который считывается с датчика звука.
uint8_t last = 0;     // содержит уровень звука с предыдущего прохода loop().

float maxVol = 15;    // содержит самый громкий уровень на данный момент для пропроциональности регулирования отзывчивости визуализации.
float knob = 1023.0;  // содержит процентовку подкрученности подстройки. Используется для настройки максимальной яркости.
float avgBump = 0;    // содержит "среднее" изменение громкости чтобы зафиксировать "бам"
float avgVol = 0;     // содержит "средний" уровень громкости чтобы пропорционально настроить эффект.
float shuffleTime = 0;// содержит сколько секунд назад запущен последний случайный эффект (когда включен случайный режим)

/*
Заметка:	Причина, по которой "среднее" заключено в ковычки потому что это не совсем среднее арифметическое.
То что я использую называется "упорядоченным средним", что более применительно чем просто среднее значение.
Разница в том что упорядоченное среднее не испольует весь набор значений записанных перед этим,
а скорее среднее между последним средним и текущим значением (последовательно) на пример:

     Обычное среднее: (1 + 2 + 3) / 3 = 2
     Упорядоченное среднее: (1 + 2) / 2 = 1.5 --> (1.5 + 3) / 2 = 2.25  (если 1, 2, 3 были получены в таком порядке)

Все "средние в программе расчитаны по этому методу. Разница не большая, но смысл в том, что упорядоченные средние
более адаптированы для изменения звуков. Другими словами если есть переход от громкого к тихому звуку упорядоченные
средние более точно и пропрорционально покажут это.
*/

bool shuffle = false;			// переключатель случайного режима
bool bump = false;				// используется для передачи, если был "бам" в звуке

//для эффекта Traffic()
int8_t pos[LED_TOTAL] = { -2};	// сохраняет позиции пикселей в ленте.
uint8_t rgb[LED_TOTAL][3] = {0};// сохраняет конкретное значение цвета каждого пикселя.

//для эффекта Snake()

bool left = false;				// определяет направление итерации. Изменяется в PaletteDance()
int8_t dotPos = 0;				// содержит какой пиксель в ленте где расположен. Изменяется во многих других эффектах.
float timeBump = 0;				// содержит время (в секундах) когда произошел последний "бам".
float avgTime = 0;				// содержит "среднее" время между "бамами" (используется для стимуляции движения точек).

#ifdef DEMO
uint8_t demoPeak=50;					// пик синусойды звука при ДЕМО режиме
uint8_t demoOldPeak;					// предыдущий пик
uint16_t demoLenght=1000;				// временной промежуток между двумя пиками в ДЕМО
uint32_t demoTime;						// переменная для времени в ДЕМО 
#endif

#ifdef DEBUG
uint32_t debugTime;						// переменная для посекундного вывода в Serial
#endif

//////////</ГЛОБАЛЬНЫЕ ПЕРЕМЕННЫЕ>

//////////<СТАНДАРТНЫЕ ФУНКЦИИ>

void setup() {	//Как говорится, Сетап всему голова

#ifdef DEBUG
  Serial.begin(115200);			// включаем сириал со скоростью 9600.
#endif

  // определяем кнопки на вход
  pinMode(BUTTON_1, INPUT); 
  pinMode(BUTTON_2, INPUT); 
  pinMode(BUTTON_3, INPUT);

  // включаем подтяжку кнопок.
  digitalWrite(BUTTON_1, HIGH); 
  digitalWrite(BUTTON_2, HIGH); 
  digitalWrite(BUTTON_3, HIGH);

  strand.begin(); 				// инициация объекта ленты
  strand.show();  				// показываем пустую ленту, чтобы приготовить пиксели к использованию.
}

void loop() {	// вот где происходит магия. Этот цикл производит каждый кадр эффектов
// прописываем ДЕМО режим, в нем звук будет генерироваться волнами со случайным периодом и пиками
#ifdef DEMO
if (millis()-demoTime>demoLenght)
{
	demoLenght=random(500,3000);		// здесь настраиваем период случайных колебаний
	demoTime=millis();
	demoOldPeak=demoPeak;
	demoPeak=random(150);				// здесь задаем "высоту" сулучайных колебаний
}
volume=demoOldPeak+((demoPeak-demoOldPeak)*(millis()-demoTime)) 
#else
  volume = analogRead(AUDIO_PIN);       // записываем уровень звука с датчика звука
#endif
  knob = analogRead(KNOB_PIN) / 1023.0; // записываем положение подстройки яркости

  // выставляем порог громкости
  // на практике я обноружил что шум может достигать 15, так что если уровень ниже 15 визуализатор думает что это тишина
  // также если громкость меньше чем "средняя" / 2 (в основном средняя с 0), это тоже считается тишиной
  
  if (volume < avgVol / 2.0 || volume < SILENCE_LVL) volume = 0;

  else avgVol = (avgVol + volume) / 2.0; // если не ноль, то берем "среднюю" от громкости

  // если текущая громкость громче чем максимальная ранее, перезаписываем максимальную
  if (volume > maxVol) maxVol = volume;

  // настройте Cycle* функции для конкретных значений, если вы не используете кнопки в вашем проекте.
  
  ////////////////////////////////////////////////////////////////////////////////////////////////////
  
  #ifdef DEBUG
  SerialListing ();//Вывод в сириал если включен ДЕБАГ
  #endif 
 
  CyclePalette();  // меняет палитру в случайном режиме или по нажатию кнопки

  CycleVisual();   // меняет эффект в случайном режиме или по нажатию кнопки

  ToggleShuffle(); // переклчение случайного режима. Удалите это если Вы не используете кнопки
  
  ////////////////////////////////////////////////////////////////////////////////////////////////////

  //Здесь градиент проверяется для предотвращения переполнения.
  
  if (gradient > thresholds[palette]) 
  {
    gradient %= thresholds[palette] + 1;
	
    // после пересчета палитры самое время пересчитать максимальный звук, 
    // на тот случай если песня станет тише, и если вдруг будет какой то один 
	// громкий звук он не должен повлиять на общую яркость 
	
    maxVol = (maxVol + volume) / 2.0;
  }

  // если есть значительное изменение громкости с последнего прохода, усредняем его в "avgBump"
  
  if (volume - last > AVGBUMP_LVL) avgBump = (avgBump + (volume - last)) / 2.0;

  // если есть заметное изменение громкости, фиксируем "бам"
  // avgbump немного понижаем для того чтобы сделать эффект немного чувствительнее.
  bump = (volume - last > avgBump * .9);  
  // если "бам" зафиксирован, усредняем время между ударами
  if (bump) {
    avgTime = (((millis() / 1000.0) - timeBump) + avgTime) / 2.0;
    timeBump = millis() / 1000.0;
  }

  Visualize();   		// вызывает соответствующий эффект по глобальным переменным.
  
  gradient++;    		// увеличивает градиент
  
  last = volume; 		// записывает текущую громкость для следующего прохода
  
  delay(LOOP_DELAY);    // делает эффекты более медленными для того чтобы Вы успели ими насладиться
}

//////////</СТАНДАРТНЫЕ ФУНКЦИИ>

//////////<ЭФФЕКТЫ>

// это функция вызывает соответствующий эффект на основе значения "visual"

void Visualize() {
  switch (visual) {
    case 0: return Pulse();
    case 1: return PalettePulse();
    case 2: return Traffic();
    case 3: return Snake();
    case 4: return PaletteDance();
    case 5: return Glitter();
    case 6: return Paintball();
    default: return Pulse();
  }
}

/*
АХТУНГ! Лента понимает цвет как 32 битное положительное целое значение значение(uint32_t), вот почему ColorPalette()
		и все связанные фукнции возвращают тип uint32_t. Это значение состоит из 3 положительных 8-битных
		целых значений(uint8_t) (0-255 для каждого красного, зеленого и синего цвета).
		Вы заметите функцию split() (описанную ниже) которая используется для раскладки 32 битной переменной на 8-ми бинтые
*/

//Эта функция вызывает соответствующую цветвоую палитру на основе переменной "palette"
//Если передано отрицательное значение возворащает соостветствующую палитру с "градиетном"
//В противном случае возвращает цветовую палитру переданного значения(удобно для установки всей палитры на ленту).

uint32_t ColorPalette(float num) {
  switch (palette) {
    case 0: return (num < 0) ? Rainbow(gradient) 	: Rainbow(num);
    case 1: return (num < 0) ? Sunset(gradient) 	: Sunset(num);
    case 2: return (num < 0) ? Ocean(gradient) 		: Ocean(num);
    case 3: return (num < 0) ? PinaColada(gradient) : PinaColada(num);
    case 4: return (num < 0) ? Sulfur(gradient) 	: Sulfur(num);
    case 5: return (num < 0) ? NoGreen(gradient) 	: NoGreen(num);
	case 6: return (num < 0) ? RUS(gradient) 		: RUS(num);
    default: return Rainbow(gradient);
  }
}

/*
Заметка:    Во всех этих эффектах есть аспект, который влияет на яркость основываюсь на громкости по отношению к
            maxVol, так что чем громче тем ярче будет всетиться лента. Первоначально я сделал простые пропорции(volume/maxvol),
            но я обнаружил что они визуально не четкие. Потом я попробывал экспоненциальный метод (повышение значения
            мощности звука/maxvol). Это было более красивше, и я выбрал баланс между двумя способами. Вы заметите
            что то вроде pow(volume/maxVol, 2.0) в фунциях ниже. Это просто квадрат отношения громкости к 
            maxVol для достижения более экспонентной кривой, но которая не преувеличивают актуальную експонентную криваю.
            По сути, это делает громкие звуки ярче, а тихие более тусклыми, чтобы они визуально отличались.
*/
//ПУЛЬСАЦИЯ  (от центра ленты)

void Pulse() {

  fade(PULSE_FADE);   //Описана ниже, это функция просто немного приглушает цвета каждый проход loop()

  //Увеличивает палитру до следующего заметного цвета если есть "бам"
  if (bump) gradient += thresholds[palette] / 24;

  //Если тихо, то мы хотим чтобы затухающий эффект закончился
  if (volume > 0) {
    uint32_t col = ColorPalette(-1); //Наш полученный 32-бинтый цвет (напоминаю, если передаем отрицательное значение то возвращает палитру по градиетну

    //Эти переменные определяют где начинать и заканчивать импульс, так как он начинается с середины ленты.
    //Велечины хранятся в переменных так, что они вичисляются один раз(плюс мы используем их в цикле).
    int start = LED_HALF - (LED_HALF * (volume / maxVol));
    int finish = LED_HALF + (LED_HALF * (volume / maxVol)) + strand.numPixels() % 2;
    // Перечисленные выше LED_HALF это просто половина диодов в Вашей ленте. 	  ↑ Эта часть регулирует при нечетном количестве.

    for (int i = start; i < finish; i++) {

    // "damp" создает затухающий эффект дальних от центра точек
    // он возвращает значение между 0 и 1, где 1 это центр ленты а 0 это концы
      float damp = sin((i - start) * PI / float(finish - start));
    // возведем "damp" в квадрат, чтобы сделать более различную яркость
    damp = pow(damp, 2.0);
	//получаем цвет текущего пикселя, как мы можем видить если он достаточно тусклый для перезаписи.
      uint32_t colFact = strand.getPixelColor(i);

    // Возьмем значение яркости из ленты, чтобы сделать следующее:
    // отрегулируем яркость этого пискеля используя его положение в ленте, громкость и подстройку
    // Возьмем среднее значение расчетной и существующей яркости и сравним их
      uint8_t colors[3];													// создаем массив из 3 цветов
      float avgColIter = 0, avgColFact = 0;									// создаем переменные для средних значений яркости
      for (int k = 0; k < 3; k++) {											// перебираем 3 цвета
        colors[k] = split(col, k) * damp * knob * pow(volume / maxVol, 2);	// каждый цвет равен разложенному цвету из палитры * на damp,
																			// * на подстройку и * на квадрат отношения звука к максимальному звуку
        avgColIter += colors[k];											// avgColIter сумма полученных цветов (сумма цветов = яркость)
        avgColFact += split(ColFact, k);									// avgColFact яркость фактического цвета пикселя из ленты полученная выше
      }
      avgColIter /= 3.0, avgColFact /= 3.0;		//ДМ переделать флот в инт, убрать деление

      //Сравним средние величины яркостей. Перезапишем только тусклые цвета чтобы эффект затухания был более заметен
      if (avgColIter > avgColFact) strand.setPixelColor(i, strand.Color(colors[0], colors[1], colors[2]));
    }
  }
  //Эта команда показывает цвета. если Вы будете делать новый эффект не забудьте про это.
  strand.show();
}


//ПУЛЬСАЦИЯ ПАЛИТРЫ
// тоже что и Pulse(), но разукрашивает всей палитрой вместо одного сплошного цвета
// ДМ рассмотреть возмжность объединения с Pulse();
void PalettePulse() {
  fade(PULSE_FADE);
  if (bump) gradient += thresholds[palette] / 24;
  if (volume > 0) {
    int start = LED_HALF - (LED_HALF * (volume / maxVol));
    int finish = LED_HALF + (LED_HALF * (volume / maxVol)) + strand.numPixels() % 2;
    for (int i = start; i < finish; i++) {
      float damp = sin((i - start) * PI / float(finish - start));
      damp = pow(damp, 2.0);

      // это едитственное отличие от Pulse(). Цвет для каждого пикселя не тот же самый, но скорее всего
      // весь градиент устанавливается на распостранение импульса, с некоторым смещением от "gradient"
      int val = thresholds[palette] * (i - start) / (finish - start);
      val += gradient;
      uint32_t col = ColorPalette(val);

      uint32_t col2 = strand.getPixelColor(i);
      uint8_t colors[3];
      float avgCol = 0, avgCol2 = 0;
      for (int k = 0; k < 3; k++) {
        colors[k] = split(col, k) * damp * knob * pow(volume / maxVol, 2);
        avgCol += colors[k];
        avgCol2 += split(col2, k);
      }
      avgCol /= 3.0, avgCol2 /= 3.0;
      if (avgCol > avgCol2) strand.setPixelColor(i, strand.Color(colors[0], colors[1], colors[2]));
    }
  }
  strand.show();
}

// ТРАФИК
// точки гоняют друг к другу
void Traffic() {

  //fade() создает след за каждой точкой, очень важно его использовать
  fade(TRAFF_FADE);

  // точка появится "бам" обноружен
  
  if (bump) {

/*АХТУНГ! ДМ так, тут у нас массив pos[] который содержит позиции в ленте движущихся точек, максимальная длинна которого 
это длинна ленты. То есть 1 элемент массива это позиция первой движущийся точки и т.д. Изначально 1 элемент равен -2, остальные нули. 
sizeof(pos) это количество движущихся точек. Нижеописанным цыклом мы ищем куда забубенить новую точку в момент "бам", перебирая уже существующие.
*/
   
    int8_t slot = 0;							//slot - место рождения новой точки
    for (slot; slot < sizeof(pos); slot++) { 	//перебираем slot на длинну массива pos[](количество движущихся точек)
      if (pos[slot] < -1) break; 				//если находим меньше -1 то выходим из цыкла, 
      else if (slot + 1 >= sizeof(pos)) {		//иначе если не нашли свободное место в существующих и перебрали уже все то текущий слот равен -3
        slot = -3;
        break;
      }
    }

    //Если есть свободный слот устанавливаем его начальное положение в ленте
	
    if (slot != -3) {

      //Если идем на право, разница идти налево, так что если начинаем с 0, разница на наибольшую позицию. ? Evens go right, odds go left, so evens start at 0, odds at the largest position.
	  //slot у нас вылетит из цыкла выше там где в pos[slot] будет меньше -1
	  // позиция будет равна -1 если slot четный и равна длинне ленты если slot не четный ????
      pos[slot] = (slot % 2 == 0) ? -1 : strand.numPixels();		//если слот не равен -3 то
      //Даем цвет на основе значения "gradient" когда он родился.
      uint32_t col = ColorPalette(-1);
      gradient += thresholds[palette] / 24;		//скачек текущего градиента палитры
      for (int j = 0; j < 3; j++) {				//цикл для записи цвета
        rgb[slot][j] = split(col, j);			//записываем цвет в массив rgb, где каждый записан каждый цвет каждого пикселя
      }
    }
  }

  //Опять же если тишина мы хотим чтобы цвета потухли.
  if (volume > 0) {

  //Если есть звук то просчитываем каждую точку вдоль нити.
    for (int i = 0; i < sizeof(pos); i++) {		//перебираем все движущиеся точки

      //Если точка -2, это значит что сводобный слот для другой точки, который можно занять. !!! 							//If a dot is -2, that means it's an open slot for another dot to take over eventually.
      if (pos[i] < -1) continue;

      //Как указано выше, ровное движение вправо (+1) и возможное движение влево (-1) !!! 									//As above, evens go right (+1) and odds go left (-1)
      pos[i] += (i % 2) ? -1 : 1;

      //Коэффициенты достигают -2 вычитанием, но если даже точка выходит за пределы ленты она будет удалена. !!! 			//Odds will reach -2 by subtraction, but if an even dot goes beyond the LED strip, it'll be purged.
      if (pos[i] >= strand.numPixels()) pos[i] = -2; // если позиция точки вышла за длинну ленты то возвращаем ее в начало

      //Устанавливаем точку на ее новую позицыю и соответствующего цвета !!! 												//Set the dot to its new position and respective color.
      //Цвет, который на старой позиции будет постепенно исчезать из-за fade(), оставляя след за собой. 					//I's old position's color will gradually fade out due to fade(), leaving a trail behind it.
      strand.setPixelColor( pos[i], strand.Color(
                              float(rgb[i][0]) * pow(volume / maxVol, 2.0) * knob,
                              float(rgb[i][1]) * pow(volume / maxVol, 2.0) * knob,
                              float(rgb[i][2]) * pow(volume / maxVol, 2.0) * knob)
                          );
    }
  }
  strand.show(); //Снова не забудьте показать актуальные точки!
}


//ЗМЕЙКА
//Точки мечутся вперед и назад под бит
void Snake() {
  if (bump) {

    //Немного поменяем цвет при баме
    gradient += thresholds[palette] / 30;

    //Изменим направление движениея точки чтобы создать иллюзию танца
    left = !left;
  }

  fade(SNAKE_FADE); //Оставим хвост за точкой.

  uint32_t col = ColorPalette(-1); //Получим цвет в текущем "gradient."

  //Точки должны двигаться только если есть звук                        															//The dot should only be moved if there's sound happening.
  // Однако когда звук появился и они движутся они появятся телепортом  															//Otherwise if noise starts and it's been moving, it'll appear to teleport.
  if (volume > 0) {

    //Настроим точку подходящим цветом и яркостью                       															//Sets the dot to appropriate color and intensity
    strand.setPixelColor(dotPos, strand.Color(
                           float(split(col, 0)) * pow(volume / maxVol, 1.5) * knob,
                           float(split(col, 1)) * pow(volume / maxVol, 1.5) * knob,
                           float(split(col, 2)) * pow(volume / maxVol, 1.5) * knob)
                        );

    //  Теперь "avgTime" вступает в игру                                                                                            //  This is where "avgTime" comes into play.
    //  эта переменная "среднее" значение между каждым "бамом"                                                                     	//  That variable is the "average" amount of time between each "bump" detected.
    //  Так что мы можем использовать ее чтобы определить, как быстро точки должны двигаться, то есть в темп музыки                 //  So we can use that to determine how quickly the dot should move so it matches the tempo of the music.
    //  С нормальной скоростью лупа точка движется слишком быстро, так что максимальная скорость бедет если avgTime<0.15 секунды    //  The dot moving at normal loop speed is pretty quick, so it's the max speed if avgTime < 0.15 seconds.
    //  Замедляем по причине того, что цвет нужно обновить, но только изменить позицию каждый новый проход loopа                    //  Slowing it down causes the color to update, but only change position every other amount of loops.
    if (avgTime < 0.15)                                               dotPos += (left) ? -1 : 1;
    else if (avgTime >= 0.15 && avgTime < 0.5 && gradient % 2 == 0)   dotPos += (left) ? -1 : 1;
    else if (avgTime >= 0.5 && avgTime < 1.0 && gradient % 3 == 0)    dotPos += (left) ? -1 : 1;
    else if (gradient % 4 == 0)                                       dotPos += (left) ? -1 : 1;
  }

  strand.show(); // Показать пиксели                        //Display the lights

  //проверяем позицыю точки на выход из динии               //Check if dot position is out of bounds.
  if (dotPos < 0)    dotPos = strand.numPixels() - 1;
  else if (dotPos >= strand.numPixels())  dotPos = 0;
}


//ТАНЕЦ ПАЛИТРЫ                         																					//PALETTEDANCE
//Проектируется вся палитра которая качается под бит, аналогично змейке, но весь градиент а не 1 точка.						//Projects a whole palette which oscillates to the beat, similar to the snake but a whole gradient instead of a dot
void PaletteDance() {
  //Это наиболее вычислительная визуализация, поэтому она не нуждается в delayях											//This is the most calculation-intensive visual, which is why it doesn't need delayed.

  if (bump) left = !left; // Изменяем направления вычислений при "баме"														//Change direction of iteration on bump

  //Показваем только если есть звук																							//Only show if there's sound.
  if (volume > avgVol) {
/*
		Эта следубщая часть извилистая, сдесь я подытожу что происходит                                                     //This next part is convoluted, here's a summary of what's happening:
		Сначала функция sin волты вводит изменения яркости всех пикселей (хранится в "sinVal")                              //First, a sin wave function is introduced to change the brightness of all the pixels (stored in "sinVal")
		Это делает эффект танца более очевидным. Фишка в том, что сдвиг sin волны с цветом весь появится                    //This is to make the dancing effect more obvious. The trick is to shift the sin wave with the color so it all appears
		в одном объекте, один "бугор" цвета. "dotPos" добавлена здесь для достижения этого эффекта                          //to be the same object, one "hump" of color. "dotPos" is added here to achieve this effect.
		Во вторых вся текущая палитра пропорционально по всей длинне ленты (хранится в "val" для каждого пикселя) 			//Second, the entire current palette is proportionally fitted to the length of the LED strand (stored in "val" each pixel).
		Это сделано при помощи умножения соотножения позиции всей длинны ленты и пределов палитры							//This is done by multiplying the ratio of position and the total amount of LEDs to the palette's threshold.
		В третьих Когда палитра "сдвинута" добавлением "dotPos" 															//Third, the palette is then "shifted" (what color is displayed where) by adding "dotPos."
        "dotPos" добавлена в позицию перед разделением, так что это матеметический сдвиг. , однако область "dotPos" не 		//"dotPos" is added to the position before dividing, so it's a mathematical shift. However, "dotPos"'s range is not
        такая же как область величин позиции, поэтому используется функция map(). Это основной способ сделать 				//the same as the range of position values, so the function map() is used. It's basically a built in proportion adjuster.
		пропорциональные построения. Наконец, все умноженное вместе дает правильный цвет, интенсивность и положение. 		//Lastly, it's all multiplied together to get the right color, and intensity, in the correct spot.
		"gradient" также добавлен для замедления сдвига цветов во времени													//"gradient" is also added to slowly shift the colors over time.
	*/
    for (int i = 0; i < strand.numPixels(); i++) {

      float sinVal = abs(sin(
                           (i + dotPos) *
                           (PI / float(strand.numPixels() / 1.25) )
                         ));
      sinVal *= sinVal;
      sinVal *= volume / maxVol;
      sinVal *= knob;

      unsigned int val = float(thresholds[palette] + 1)
                         // map берет величину между -LED_TOTAL и +LED_TOTAL и возвращает между 0 и LED_TOTAL 				//map takes a value between -LED_TOTAL and +LED_TOTAL and returns one between 0 and LED_TOTAL
                        * (float(i + map(dotPos, -1 * (strand.numPixels() - 1), strand.numPixels() - 1, 0, strand.numPixels() - 1))
                            / float(strand.numPixels()))
                         + (gradient);

      val %= thresholds[palette]; //make sure "val" is within range of the palette

      uint32_t col = ColorPalette(val); //get the color at "val"

      strand.setPixelColor(i, strand.Color(
                             float(split(col, 0))*sinVal,
                             float(split(col, 1))*sinVal,
                             float(split(col, 2))*sinVal)
                          );
    }

    // После всего, перенесем "dotPos"								//After all that, appropriately reposition "dotPos."
    dotPos += (left) ? -1 : 1;
  }

  // Если нет звука затухаем 										//If there's no sound, fade.
  else  fade(DANCE_FADE);

  strand.show(); //Показать точки									//Show lights.

  //закольцовываем "dotPos" если она за приеделами связей			//Loop "dotPos" if it goes out of bounds.
  if (dotPos < 0) dotPos = strand.numPixels() - strand.numPixels() / 6;
  else if (dotPos >= strand.numPixels() - strand.numPixels() / 6)  dotPos = 0;
}


//СВЕРКАНИЕ
//Создает белые искры на цветной палитре под бит
void Glitter() {

  // Этот эффект помещает всю палитру на всю ленту										//This visual also fits a whole palette on the entire strip
  // Это делате палитру цикличной более быстро, так что это выглядит красивее			//This just makes the palette cycle more quickly so it's more visually pleasing
  gradient += thresholds[palette] / 204;
  //"val" используется стова как пропроциональное значение чтобы заполнить всю палитру	//"val" is used again as the proportional value to pass to ColorPalette() to fit the whole palette.
  for (int i = 0; i < strand.numPixels(); i++) {
    unsigned int val = float(thresholds[palette] + 1) *
                       (float(i) / float(strand.numPixels()))
                       + (gradient);
    val %= thresholds[palette];
    uint32_t  col = ColorPalette(val);
  //мы хотим чтобы искры были яркие, так что мы затемняем задние цвета					//We want the sparkles to be obvious, so we dim the background color.
    strand.setPixelColor(i, strand.Color(
                           split(col, 0) / 6.0 * knob,
                           split(col, 1) / 6.0 * knob,
                           split(col, 2) / 6.0 * knob)
                        );
  }

  //Создаем искры каждый бит															//Create sparkles every bump
  if (bump) {

    //Генератору случайных чисел нужна основа, а micros() дает большой спектр значений 	//Random generator needs a seed, and micros() gives a large range of values.
    // micros() это количество миллисекунд со времени начала программы					//  micros() is the amount of microseconds since the program started running.
    randomSeed(micros());

    //берем случайную точку на ленте
    dotPos = random(strand.numPixels() - 1);
	//Рисуем искру на случайной позиции, с подходящей яркостью.							//Draw  sparkle at the random position, with appropriate brightness.
	
    strand.setPixelColor(dotPos, strand.Color(
                           255.0 * pow(volume / maxVol, 2.0) * knob,
                           255.0 * pow(volume / maxVol, 2.0) * knob,
                           255.0 * pow(volume / maxVol, 2.0) * knob
                         ));
  }
  bleed(dotPos);
  strand.show(); //показать точки														//Show the lights.
}


//ПИНБОЛ
//Переработанный Glitter() со случайной позицией; симулирующий "пинбол" цветных точек
//  случайно разбрызгивающихся на лените и сочащихся всесте
void Paintball() {

  //Если среднее время между "бамами" дважды привысилость то начинаем затухать 							//If it's been twice the average time for a "bump" since the last "bump," start fading.
  if ((millis() / 1000.0) - timeBump > avgTime * 2.0) fade(PAINT_FADE);

  //Цвета сочатся вместе. Операция схожа с затуханием. Для большей информации смотрите описание ниже 	//Bleeds colors together. Operates similarly to fade. For more info, see its definition below
  bleed(dotPos);

  //Создаем новый пинбол если есть "бам" (как искры в Clitter()											//Create a new paintball if there's a bump (like the sparkles in Glitter())
  if (bump) {

    //Генератор случайных значений нуждается в основе, а micros() дает большой спектр значений			//Random generator needs a seed, and micros() gives a large range of values.
    //micros() это количество микросекунд с начала работы программы										//micros() is the amount of microseconds since the program started running.
    randomSeed(micros());

    //Даем случайную позицию в ленте. рандом уже переоснован, так что не нужно это делать снова			//Pick a random spot on the strip. Random was already reseeded above, so no real need to do it again.
    dotPos = random(strand.numPixels() - 1);

    // Берем случайный цвет с палитры																	//Grab a random color from our palette.
    uint32_t col = ColorPalette(random(thresholds[palette]));

	//массив для конечного хранения RGB значений														//Array to hold final RGB values
    uint8_t colors[3];

    //Выставляем яркость цвета по отношению звука и показаний потенциометра								//Relates brightness of the color to the relative volume and potentiometer value.
    for (int i = 0; i < 3; i++) colors[i] = split(col, i) * pow(volume / maxVol, 2.0) * knob;

    // Разбрызгиваем пинболы на случайных позициях														//Splatters the "paintball" on the random position.
    strand.setPixelColor(dotPos, strand.Color(colors[0], colors[1], colors[2]));

    //Эта часть дужна для того чтобы уменьшить яркость того же цвета слева и справа от позиции пинбола,	//This next part places a less bright version of the same color next to the left and right of the
    // так что сочащийся эффект сильнее и цвета более трепещущие										//original position, so that the bleed effect is stronger and the colors are more vibrant.
    for (int i = 0; i < 3; i++) colors[i] *= .8;
    strand.setPixelColor(dotPos - 1, strand.Color(colors[0], colors[1], colors[2]));
    strand.setPixelColor(dotPos + 1, strand.Color(colors[0], colors[1], colors[2]));
  }
  strand.show(); //показать точки																		//Show lights.
}


/////////////////////////////////////////////////////////////////////////////////////////////////////
//ДЕБАГ КРУГ
//Без реакции на звук, просто чтобы показать градиент цвета палитры 
//НЕ активен в коде, но легко включем в блике свитч.
void Cycle() {
  for (int i = 0; i < strand.numPixels(); i++) {
    float val = float(thresholds[palette]) * (float(i) / float(strand.numPixels())) + (gradient);
    val = int(val) % thresholds[palette];
    strand.setPixelColor(i, ColorPalette(val));
  }
  strand.show();
  gradient += 32;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////

//////////</ЭФФЕКТЫ>


//////////<ВСПОМОГАТЕЛЬНЫЕ ФУНКЦИИ>

void CyclePalette() {

  //ВАЖНО: Удалите этот иф блок если вы не используете кнопки

  //Если кнопка 1 нажата, считывание получает "false" результат
  if (!digitalRead(BUTTON_1)) {

    palette++;     //Эта кнопка меняет цветовую палитру

    //Если палитра больше чем количество элементов thresholds[], начинаем с нуля
    //Вот почему важно добавлять ограничения в массив палитр при добавлении новой палитры, 
	//иначе наша программа вернется на Rainbow() не дойдя до новой палитры
    
    if (palette >= sizeof(thresholds) / 2) palette = 0;

    gradient %= thresholds[palette]; //Изменяет градиет от переполнения в зависимости от выбранной палитры

    //У меня кнопки расположены близко к микрофону, так что звук нажатия слишком громкие для звукового датчика.
    //визуально это выглядит как громкий звук, так что задержка помогает избежать этого
    delay(350);

    maxVol = avgVol;  //Выставляем максимальный звук на средний															//Set max volume to average for a fresh experience.
  }
  ///////////////////////////////////////////////////////////////////////////////////////////////////

  //Если включен случайный ражим, и прошло SHUFFLE_TIME секунд с последнего переключения 								//If shuffle mode is on, and it's been 30 seconds since the last shuffle, and then a modulo
  //  и модуль градиента получемт случайное решение между палитрой или визуальным эффектомof							//of gradient to get a random decision between palette or visualization shuffle
  if (shuffle && millis() / 1000.0 - shuffleTime > SHUFFLE_TIME && gradient % 2) {

    shuffleTime = millis() / 1000.0; //Записываем время когда случился случайный переход								//Record the time this shuffle happened.

    palette++;
    if (palette >= sizeof(thresholds) / 2) palette = 0;
    gradient %= thresholds[palette];
    maxVol = avgVol;  //Выставляем максимальный звук на средний															//Set the max volume to average for a fresh experience.
  }
}
//выводим в сириал необходимые данные
void SerialListing () {
	
if(millis()-debugTime>PERIOD){
	debugTime=millis();
	Serial.print("grad");
	Serial.print(gradient);
	Serial.print(" vol");
	Serial.print(volume);
	Serial.print(" last");
	Serial.print(last);
	Serial.print(" maxV");
	Serial.print(maxVol);
	Serial.print(" bump");
	Serial.print(bump);
	Serial.print(" avgB");
	Serial.print(avgBump);
	Serial.print(" avgV");
	Serial.print(avgVol);
	Serial.print(" timeB");
	Serial.print(timeBump);
	Serial.print(" avgT");
	Serial.print(avgTime);
	Serial.print(" dotP");
	Serial.println(dotPos);
	}
}

void CycleVisual() {

  //Важно: Удалите этот иф блок если вы не используете кнопки															//Delete this whole if-block if you didn't use buttons//////////////////////////////////
  if (!digitalRead(BUTTON_2)) {

    visual++;    // Назначение этой кнопки переключать визуальные эффекты												//The purpose of this button: change the visual mode

    gradient = 0; //сбрасываем градиент																					//Prevent overflow

    //Защита от переполнеия "visual"																					//Resets "visual" if there are no more visuals to cycle through.
   if (visual > VISUALS) visual = 0;
    //Вот почему нужно изменять VISUAL когда добавляете эффект, иначе программа до него не дойдет						//This is why you should change "VISUALS" if you add a visual, or the program loop over it.

    //Переписывает позиции всех точек на пустые (-2) если вы переходите на эффект Traffic()								//Resets the positions of all dots to nonexistent (-2) if you cycle to the Traffic() visual.
    if (visual == 1) memset(pos, -2, sizeof(pos));

    //Дает эффектам Snake() и PaletteDance() случайнуж точку начала если переключили на них								//Gives Snake() and PaletteDance() visuals a random starting point if cycled to.
    if (visual == 2 || visual == 3) {
      randomSeed(analogRead(0));
      dotPos = random(strand.numPixels());
    }

    // Как и раньше, эта задержка защищает "maxVol" от скачка при нажатии кнопки										//Like before, this delay is to prevent a button press from affecting "maxVol."
    delay(350);

    maxVol = avgVol; //Выставляем максимальный звук на средний
  }
/* Если случайный режим включен и прошло SHUFFLE_TIME секунд с последнего переключения и модуль градиента со знаком ! 
переключаем визуальный эффект
ДМ Градиент нужен чтобы гарантировать только одно переключение
  
  */
  if (shuffle && millis() / 1000.0 - shuffleTime > 30 && !(gradient % 2)) {

    shuffleTime = millis() / 1000.0; //Записываем время когда случился случайный переход								//Record the time this shuffle happened.

    visual++;
    gradient = 0;
    if (visual > VISUALS) visual = 0;
    if (visual == 1) memset(pos, -2, sizeof(pos));
    if (visual == 2 || visual == 3) {
      randomSeed(analogRead(0));
      dotPos = random(strand.numPixels());
    }
    maxVol = avgVol;
  }
}


//ВАЖНО: Удалите эту функцию если вы не используете кнопки
void ToggleShuffle() {
  if (!digitalRead(BUTTON_3)) {

    shuffle = !shuffle; // Эта кнопка включение и выключения случайного режима 											//This button's purpose: toggle shuffle mode.

    // Эта задержка обеспечивает защиту от повторного чтения кнопки пока вы ее нажали									//This delay is to prevent the button from taking another reading while you're pressing it
    delay(500);

    //Reset these things for a fresh experience.
    maxVol = avgVol;
    avgBump = 0;
  }
}
//////////////////////////////////////////////////////////////////////////////////////////////////////


//Затемняет пиксели умножая их на число от 0 до 1 каждый проход loop()											//Fades lights by multiplying them by a value between 0 and 1 each pass of loop().
void fade(float damper) {

  // "damper" должен быть между 0 и 1, иначе у вас будет засветка цветов или ничего не будет делаться			//"damper" must be between 0 and 1, or else you'll end up brightening the lights or doing nothing.

  for (int i = 0; i < strand.numPixels(); i++) {

    // чтение цвета на текущей позиции																			//Retrieve the color at the current position.
    uint32_t col = strand.getPixelColor(i);

    // если цвет черный то нельзя его еще больше затемнить 														//If it's black, you can't fade that any further.
    if (col == 0) continue;

    float colors[3]; //массив из 3 RGB цветов																	//Array of the three RGB values

    //Умножаем каждое значение на "damper"																		//Multiply each value by "damper"
    for (int j = 0; j < 3; j++) colors[j] = split(col, j) * damper;

    //Возвращаем все цвета на из места																			//Set the dampened colors back to their spot.
    strand.setPixelColor(i, strand.Color(colors[0] , colors[1], colors[2]));
  }
}


//"сочащиеся" цвета устанавливаются в ленте усреднением из заданной "точки" 									//"bleeds" colors currently in the strand by averaging from a designated "Point"
void bleed(uint8_t Point) {
  for (int i = 1; i < strand.numPixels(); i++) {

    //Начинаем с пискселей слева и справа от заданной точки														//Starts by look at the pixels left and right of "Point"
    //затем медленно двигаемся дальше																			//then slowly works its way out
    int sides[] = {Point - i, Point + i};

    for (int i = 0; i < 2; i++) {

      // Для каждых Point+i и Point-i пиксели слева и справа складываются и усредняются друг с другом			//  For each of Point+i and Point-i, the pixels to the left and right, plus themselves, are averaged together.
      // Главное это взяв 1 пиксель и усреднить его соседей, начав слева и справа								//  Basically, it's setting one pixel to the average of it and its neighbors, starting on the left and right
      // от заданной точки и двигаться к концам ленты															//  of the starting "Point," and moves to the ends of the strand
      int point = sides[i];
      uint32_t colors[] = {strand.getPixelColor(point - 1), strand.getPixelColor(point), strand.getPixelColor(point + 1)  };

      //Устаеавомваем новые усредненные значения только на центральную точку, а не слева и справа				//Sets the new average values to just the central point, not the left and right points.
      strand.setPixelColor(point, strand.Color(
                             float( split(colors[0], 0) + split(colors[1], 0) + split(colors[2], 0) ) / 3.0,
                             float( split(colors[0], 1) + split(colors[1], 1) + split(colors[2], 1) ) / 3.0,
                             float( split(colors[0], 2) + split(colors[1], 2) + split(colors[2], 2) ) / 3.0)
                          );
    }
  }
}


//	Как описано выше, split() дает 8-ми битное значение цвета					 		//As mentioned above, split() gives you one 8-bit color value
//	сдвигая 32-битное с которым работает NeoPixel										//from the composite 32-bit value that the NeoPixel deals with.
//	это достигается сдвигом бита вправо оператором ">>"									//This is accomplished with the right bit shift operator, ">>"
uint8_t split(uint32_t color, uint8_t i ) {

  //0 = Red, 1 = Green, 2 = Blue

  if (i == 0) return color >> 16;
  if (i == 1) return color >> 8;
  if (i == 2) return color >> 0;
  return -1;
}

//////////</Вспомогательные функции>


// Наборы политр с плавными переходами цветов

uint32_t Rainbow(unsigned int i) {
  if (i > 1529) return Rainbow(i % 1530);
  if (i > 1274) return strand.Color(255, 0, 255 - (i % 255));   //фиолетовый    ->  красный
  if (i > 1019) return strand.Color((i % 255), 0, 255);         //синий         ->  фиолетовый
  if (i > 764) return strand.Color(0, 255 - (i % 255), 255);    //морской       ->  синий
  if (i > 509) return strand.Color(0, 255, (i % 255));          //зеленый       ->  морской
  if (i > 255) return strand.Color(255 - (i % 255), 255, 0);    //желтый        ->  зеленый
  return strand.Color(255, i, 0);                               //красный       ->  желтый
}

uint32_t Sunset(unsigned int i) {
  if (i > 1019) return Sunset(i % 1020);
  if (i > 764) return strand.Color((i % 255), 0, 255 - (i % 255));          //синий     ->  красный
  if (i > 509) return strand.Color(255 - (i % 255), 0, 255);                //пурпур    ->  синий
  if (i > 255) return strand.Color(255, 128 - (i % 255) / 2, (i % 255));    //оранжевый ->  пурпур
  return strand.Color(255, i / 2, 0);                                       //красный   ->  ораньжевый
}

uint32_t Ocean(unsigned int i) {
  if (i > 764) return Ocean(i % 765);
  if (i > 509) return strand.Color(0, i % 255, 255 - (i % 255));  //синий   ->  зеленый
  if (i > 255) return strand.Color(0, 255 - (i % 255), 255);      //морской ->  синий
  return strand.Color(0, 255, i);                                 //зеленый ->  морской
}

uint32_t PinaColada(unsigned int i) {
  if (i > 764) return PinaColada(i % 765);
  if (i > 509) return strand.Color(255 - (i % 255) / 2, (i % 255) / 2, (i % 255) / 2);  //красный   ->  полубелый
  if (i > 255) return strand.Color(255, 255 - (i % 255), 0);                            //желтый    ->  красный
  return strand.Color(128 + (i / 2), 128 + (i / 2), 128 - i / 2);                       //полубелый ->  желтый
  }

uint32_t Sulfur(unsigned int i) {
  if (i > 764) return Sulfur(i % 765);
  if (i > 509) return strand.Color(i % 255, 255, 255 - (i % 255));   //морской  ->  желтый
  if (i > 255) return strand.Color(0, 255, i % 255);                 //зеленый  ->  морской
  return strand.Color(255 - i, 255, 0);                              //желтый   ->  зеленый
}

uint32_t NoGreen(unsigned int i) {
  if (i > 1274) return NoGreen(i % 1275);
  if (i > 1019) return strand.Color(255, 0, 255 - (i % 255));         //фиолетовый  ->  красный
  if (i > 764) return strand.Color((i % 255), 0, 255);                //голубой     ->  фиолетовый
  if (i > 509) return strand.Color(0, 255 - (i % 255), 255);          //морской     ->  желтый
  if (i > 255) return strand.Color(255 - (i % 255), 255, i % 255);    //желтый      ->  морской
  return strand.Color(255, i, 0);                                     //красный     ->  желтый
}

uint32_t RUS(unsigned int i) {
  if (i > 764) return RUS(i % 765);
  if (i > 509) return strand.Color(128, 128, 128);  //белый
  if (i > 255) return strand.Color(0, 0, 255);  	//синий
  return strand.Color(255, 0, 0);                   //красный
}
 return strand.Color(255 - i, 255, 0);                              //желтый   ->  зеленый
}

uint32_t NoGreen(unsigned int i) {
  if (i > 1274) return NoGreen(i % 1275);
  if (i > 1019) return strand.Color(255, 0, 255 - (i % 255));         //фиолетовый  ->  красный
  if (i > 764) return strand.Color((i % 255), 0, 255);                //голубой     ->  фиолетовый
  if (i > 509) return strand.Color(0, 255 - (i % 255), 255);          //морской     ->  желтый
  if (i > 255) return strand.Color(255 - (i % 255), 255, i % 255);    //желтый    

 

vitmish
Offline
Зарегистрирован: 06.02.2017

твою же ж....

мне пачку карандашей нужно для анализа.

Пока могу сказать, что только что закончил установку супермегаумной гипермашины по запуску вентилятора )

Выкинул из кода все, что можно. Ибо судя по тому, как программа зависала в неопределенные моменты - сделал вывод, что программа пытается выдать инфу о состоянии влажности в порт, порт не подключен, буфер переполняется, программа тормозит.

мониторинг не нужен, для этого индикация есть - комментим. Чуть по цвету исправил, хотел поиграться с миганием, разноцветием, но.... пока оставил так - брутальненько и памяти меньше займет, потом хочу Нано заказать и на нее поставить, там программа копейки весит, для Uno черезчур.

Может еще поставлю датчик СО2 для анализа уровня вони в туалете и на отдельный пиксель выведу индикацию данного датчика.

Спасибо еще раз, минимум неделю сэкономили и главное - появилась уверенность. А то смотришь на чужие простыни кода и думаешь "Данунах"

#include <Adafruit_NeoPixel.h>
#include "DHT.h"
#include <adafruit_NeoPixel.h>
#define DHTPIN 4     // пин датчика
#define PINRELAY 10     // так "кошернее"
#define PIN 3
#define NUM_LEDS 7
#define BRIGHTNESS 70
Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUM_LEDS, PIN, NEO_GRB + NEO_KHZ800);
#define DHTTYPE DHT11   // DHT 11
DHT dht(DHTPIN, DHTTYPE);
 int  h=0;                                       // до loop и setup задаются "глобалы"
unsigned long m=0; // переменная для таймера времени
//int h=dht.readHumidity;{//эта функция возвращает значение влажности в float (но можно и в int), ее мы быдем вызывать из loop раз в 2 секунды
           //     return dht.readHumidity();
//}
//void Serial.begin (9600) {
//Serial.begin(9600);  //Эта функция выводит в сириал значение h(от t я отказался, так как она не используется у нас, можно сделать по аналогии с h)
    //            Serial.print("Humidity: ");
  //  Serial.print(h);
  //  Serial.println(" %\t");
//}
void pixelmode(int h)
{
    if (h<=67){ //до  70% не моргает, индикация одним цветом
            for (int i=0;i<map(h,40,90,0,NUM_LEDS);i++)strip.setPixelColor(i,0,255,0);                     // этот кусок домашнее задание на изучение.
                for (int i=map(h,40,90,0,NUM_LEDS);i<(NUM_LEDS);i++)strip.setPixelColor(i,0,0,50);
                strip.show();
}
    else { //меняем цвет диодов после 70%
            for (int i=0;i<map(h,40,90,0,NUM_LEDS);i++)strip.setPixelColor(i,255,0,0);                     // этот кусок домашнее задание на изучение.
                for (int i=map(h,40,90,0,NUM_LEDS);i<(NUM_LEDS);i++)strip.setPixelColor(i,50,0,50);
               
                strip.show();
    }}
void setup() {//здесь указваем все что нужно сделать 1 раз!
               // Serial.begin(9600);
               // Serial.println("DHT test!");
                strip.begin();
                strip.setBrightness(BRIGHTNESS);
                strip.show();
                dht.begin();
                pinMode (PINRELAY, OUTPUT);              
}
void loop() {
  if (millis()-m>2000){// если прошло 2 секунды    
                m=millis();                          // обновляем счетчик
                h=dht.readHumidity();                               // читаем влажность
                pixelmode(h);
                if(h>75)digitalWrite(PINRELAY, HIGH); // здесь закладываем логику включения/выключения вентелятора, я сделал чтобы вент включался при влажности
                                                                                                                                             // больше 80 и выключался при влажности меньше 60, можно подставить таймер чтобы он не молотил постоянно
                                                                                                                                             //если влажность не удалось понизить
                if(h<65)digitalWrite(PINRELAY, LOW);
               // Serial.begin(9600);  //Эта функция выводит в сириал значение h(от t я отказался, так как она не используется у нас, можно сделать по аналогии с h)
              //  Serial.print("Humidity: ");
   // Serial.print(h);
   // Serial.println(" %\t");
  }
}

 

Mr.Privet
Mr.Privet аватар
Offline
Зарегистрирован: 17.11.2015

vitmish пишет:

Спасибо еще раз, минимум неделю сэкономили и главное - появилась уверенность. А то смотришь на чужие простыни кода и думаешь "Данунах"

Данунах это моя будующая метеостанция http://arduino.ru/forum/proekty/meteostantsiya-danunakh Вам про нее еще думать рано )))

vitmish
Offline
Зарегистрирован: 06.02.2017

Гыгым. Мне пока хватает ткнуть в экран дроида, актуализировать местоположение и изучить метеосводку.

А вот снять показания со стратегического погреба, в коем хранятся не менее стратегические запасы картофеля бронебойного, закатки слюновыделительной и прочих разносолов....

Следующий проект будет - замена готовой схемы от дядюшки Ляо с индикацией температуры и исполнительным реле для включения приборов термостатных - на свое рукожопное творение с мониторингом заповедного пространства, проветриванием и подогревом поляны. Но хотелось бы, конечно, сидючи в теплом доме, видеть на мониторе температуру и влажность подпола, далее - на андроиде, далее - управлять всей этой махиной удаленно.

В идеале конечно - говоришь в пустоту "Ардуинка, сделай красиво" а в ответ глухим голосом "Бу сделано, хозяин" и оно как то волшебным образом красивеет. А, самогонный аппарат надо подключить в систему.

kvadro8
Offline
Зарегистрирован: 17.02.2017

Привет всем. Не знаю правильно ли залез в ветку, но требуется помощь. Со скетчами у меня туговато, но стараюсь вникать.

Есть такая задача

Создать бюджетный лабораторный комплекс ALL in 1.

1 Совместить три скетча в одном с возможностью выбора через меню

(соответственно указав все требуемые библиотеки и шаблоны и т.д. )

2 каждый скетч отдельный прибор 1 тестер ECR и полупроводников 2 осцилограф и 3 генератор сигналаов

3 Использование дисплея LCD 320 х 240 ( китай ) с SD картой( как буфер обмена) по шине I2C

( освобождаем кол-во портов )

Вопрос, 1 какая нибудь плата(ы) из ардуино или STM потянут такое ?

2 Можно это реализовать и как. Если можно с примеро скетча.

Я конечно особо не искал в сети такую вещь но как вариант пришёл на этот форум, здесь как рас обсуждают все три проекта,

которые мне нужны для реализации моего.

Буду признателен за развёрнутый ответ на почту msbu2015@yandex.ru (gmail.com)

 

andriano
andriano аватар
Онлайн
Зарегистрирован: 20.06.2015

1. Первое, без чего Вы не сможете сделать ни один проект, это научиться правильно писать на языке, который используете. Будь то Си, Джава и русский.

2. Совмещение тестера с генератором/осциллографом мне кажется нецелесообразным. Лучше к генератору/осциллографу добавить еще частотомер, а тестер сделать отдельно.

3. Полноцветный дисплей на I2C мне кажется сомнительной затеей. Вы арифметику в школе изучали? Сколько времени займет однократное обновление экрана?

4. Просить на форуме связаться по почте - дурной тон. Единственное, где это простительно, - в разделе "Ищу исполнителя".

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

andriano пишет:

1. Первое, без чего Вы не сможете сделать ни один проект, это научиться правильно писать на языке, который используете. Будь то Си, Джава и русский.

2. Совмещение тестера с генератором/осциллографом мне кажется нецелесообразным. Лучше к генератору/осциллографу добавить еще частотомер, а тестер сделать отдельно.

3. Полноцветный дисплей на I2C мне кажется сомнительной затеей. Вы арифметику в школе изучали? Сколько времени займет однократное обновление экрана?

4. Просить на форуме связаться по почте - дурной тон. Единственное, где это простительно, - в разделе "Ищу исполнителя".

Так он и ищет, только разделы попутал. Видимо преподаватель дал свободное задание.
Если бы это было для себя, взял бы человек три дуины и сделал все приборы в одном корпусе на основе
уже существующих проектов...
спинным мозгом чувствую, что курсовой, а может даже больше )))

kvadro8
Offline
Зарегистрирован: 17.02.2017

Дурной тон,замечать ошибки других, не видя своих. Зачем мне частотомер, если у меня есть осцил, а по I2C МОЖНО ЗАВЯЗАТЬ КУЧУ УСТРОЙСТВ ПРИ ПОМОЩИ БИБЛИОТЕК и оптимизации работы скетчей. Уж вам бы надо знать такие вещи, господа крутые ардуинщики. Я не просил готовое решение, я интересовался возможностью создания данного проекта по моей задумке. Мне 43 года и я большее время из них заримаюсь ремонтом РЭА. Ардуино IDE для меня новая возможность облегчить свой труд, ну и конечно как развивающая  мозг платформа. Так что по поводу курсовой, это не про меня.

Мне нужен компактный прибор для работы в "поле", а сидя за столом в мастерской, у меня есть чем померять и посмотреть.

А по поводу трёх ардуин мини я думал, можно собрать и меньше, на своей плате и по своей схеме.

При таком отношении к новичкам на форуме, скорее всего так и сделаю, чем выпрашивать и унижаться, читая выше написанное о себе.

Так что, ищите ошибки и чувствуйте спинным мозгом или чем пониже.

vitmish
Offline
Зарегистрирован: 06.02.2017

Как создатель данной темы - я вынужден читать все новые комментарии по данной теме.

Поэтому не сочту нескромностью ответить на все вышенаписанные сообщения.

Задач у каждого много, хобби у каждого свое. В любом случае, кроме постановки задачи желательно видеть пути его решения и обсудить, на каком этапе нелегкого пути удалось споткнуться.

В противном случае, экономия своего времени для решения своих проблем за счет других - это вопрос денег, которые вы заработаете за это время и готовы поделиться с другими, которые решат вашу проблему.

Вроде бы все просто. Мне 48 и я благодарен за ту помощь, которую мне оказали на этом форуме. Хотя возраст тут не при чем.

Клапауций 823
Клапауций 823 аватар
Offline
Зарегистрирован: 13.01.2017

vitmish пишет:

Мне 48 и я благодарен за ту помощь, которую мне оказали на этом форуме. Хотя возраст тут не при чем.

ок. тебе 48 и ты блондинка.

vitmish
Offline
Зарегистрирован: 06.02.2017

Спасибо, что поделился своими влажными фантазиями

Клапауций 823
Клапауций 823 аватар
Offline
Зарегистрирован: 13.01.2017

vitmish пишет:

Спасибо, что поделился своими влажными фантазиями

покажи сиськи.

vitmish
Offline
Зарегистрирован: 06.02.2017

ссылку на ресурс с недорогими влажными салфетками для протирки монитора.... Нуна?

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

kvadro8 пишет:

 Зачем мне частотомер, если у меня есть осцил, а по I2C МОЖНО ЗАВЯЗАТЬ КУЧУ УСТРОЙСТВ ПРИ ПОМОЩИ БИБЛИОТЕК и оптимизации работы скетчей.

если вы не понимаете зачем частотомер и вам его заменяет осциллограф я пас...
А про IIC вам выше объяснили, даже для LCD дисплея эта шина уже тормоз
Делайте три нормальных раздельных прибора в одном корпусе и выложите в раздел проекты,
будут проблемы, вам помогут
PS мы тут многие начинающие

kvadro8
Offline
Зарегистрирован: 17.02.2017

Вот я и обратился за помошью чтобы мне указали этот путь. Повторюсь ещё раз я не искал готовых решений, я задал вопрос можно или нет, а меня обозвали студентом и ,,,,,,, ну дальше вы читали.

Так что извините. Для меня это не хобби, а способ облегчить свой труд. Мобильные приборы заводского изготовления мне не по карману, тот же осцил за 15-20 т.р. я не каждый месяц половину от этой суммы зарабатываю. У нас в провинции немного другие понятия о ценностях. А по поводу возраста, я написал, что бы некоторые господа поняли, что общаются не с пацаном который сутками сидит а сети на таких вот форумах и лажает новых форумчан, а с взрослым и адекватным мужиком из провинции.

 

vitmish
Offline
Зарегистрирован: 06.02.2017

Длинный путь начинается с первого шага.

В данном случае - начать писать свой скетч, пытаться решить свою проблему своими руками (головой)

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

Я вот сейчас сижу, готовлю уроки. Делаю примеры по Ардуино, перебираю все из набора. Мечтаю, как в Матрице - подключился, вкачал в мозг - и ты уже профи. Тяжело идет... За плечами только Фортран 30-летней давности

kvadro8
Offline
Зарегистрирован: 17.02.2017

У вас хотя бы это. В те года и компов то не было.,я сам впервые сел за комп когда стал работать на чпу станке. G-code вводили вручную и программы писали вручную,расчёты на миллиметровке с линейкой и циркулем в руках, так что шагов у меня много только не применимы они на сегодня. А я наоборот не хочу как в матрице, хочу именно сам до всего дойти но нет нужных знаний.

Вто и приходиться заходить на форумы, где тебя считают полным чайником.

 

nik182
Онлайн
Зарегистрирован: 04.05.2015

Осцилограх переносной до мегогерца оцифровки за 1400 руб по почте на али по тегу DSO138. Или http://arduino.ru/forum/proekty/mini-ostsillograf-arduino-na-lcd-5110

ESR и генератор http://arduino.ru/forum/proekty/transistor-tester-arduino

 

kvadro8
Offline
Зарегистрирован: 17.02.2017

Спасибо nik182. я на али провожу больше времени чем с женой, я в курсе сто там и по чём, кстати dso138 можно за 900р

взять там же, и нано, про и уно по адекватным ценам в пределах 200р. Вопрос не в этом меня интересует возможность, сделать универсальный переносной прибор. Я знаю что можно прикрутить в один корпус три прибора (можно хоть 10 ) с использованием одного дисплея. но это немножко не то. как вариант можно но ,,,,,,,,но не то.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

kvadro8 пишет:

Спасибо nik182. я на али провожу больше времени чем с женой, я в курсе сто там и по чём, кстати dso138 можно за 900р

взять там же, и нано, про и уно по адекватным ценам в пределах 200р. Вопрос не в этом меня интересует возможность, сделать универсальный переносной прибор. Я знаю что можно прикрутить в один корпус три прибора (можно хоть 10 ) с использованием одного дисплея. но это немножко не то. как вариант можно но ,,,,,,,,но не то.

Три можно, но не на ардуине, мозгов и скорострельности не хватит, ну может разве что DUE попробовать...

1. Осциллограф - внешний скорострельный АЦП
2. Генератор - на основе DDS

По шине не скажу, но это не I2С точно, даже в самом скоростном режиме 400Кб это мало

И выйдет это совсем не дёшево, а ведь идея совмещения три в одном ради этого затевалась
 

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

2Kvadro8:

Вы, надеюсь, не спонтанно задали вопрос на форуме, а читали его перед этим, хотя бы 2-3 дня?

В разделе "проекты" есть и генератор и транзистор тестер (ТТ) и осцилограф (даже два).

Генератор - ясен пень - нужен отдельный, в паре с осцилографом, но это, как раз, совсем не проблемма - он на ilc8038 делается отдельно. Китайцы продают такой набор для пайки. Там, правда, нужно немного головой поработать, чтобы диапазон расширить.

 

ТТ и осцил - оба на Нанке, то есть, при должных навыках программирования, вместе влезут в Мегу. И еще место останется для управления ilc8038.

---------------------

Вывод  - сдалать возможно, но очень не просто. Вам, если я верно оценил квалификацию и обучаемость, не будет под силу (вероятнее всего) никогда.

Я, и другие, кому это под силу - не станем делать. Осцил - DSO138 стоит, как Вам уже заметили, 1000р. Если не нравится, то есть два проекта на форуме, оба - проверенные.

Изобретение и построение велосипедов - деятельность почтенная, но КАК ХОББИ. Не для работы.

Как хобби - тут люди решают те задачи, которые вызывают ИНТЕРЕС - это самое главное.

Кто-то автоматизирует аквариум, теплицу, самогонный аппарат.

Кто-то делает 105-тую сигналку на дачу или 139-ый автозапуск на старый ТАЗ. Табло и фигурки на светодиодах, роботов и пр. Делают то, что им интресно.

Если Вы присоединитесь к нам, то, со временем, (вероятнее всего) найдете единомышленников. Но не ранее того, как сами, набивая шишки в темноте об учебник С, даташит на контроллер и "Хоровица и Хилла", пройдете существенную часть пути своего проекта.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

По генератору, так вам ВЧ или НЧ нужен, на ilc8038 только до 300кгц, а вот на ad9850 можно сделать от 1Гц до 40Mhz
И осциллограф - какая полоса нужна, мне так мегагерц до 150 )))

kvadro8
Offline
Зарегистрирован: 17.02.2017

Вот вы все говорите, не получится мозгов не хватит, но ведь на  uno  и due свет клином не сошёлся. Есть контроллеры , скажем XMega и подобные, почему бы не попробывать, есть же проекты?Вместо того чтобы разгонять до красна 328 на 27МГц и говорить потом что DSO138 хуже ослика на меге328, дали бы совет какой контроллер потянет мою идею и всё вопрос закрыт!!!

kvadro8
Offline
Зарегистрирован: 17.02.2017

Вот это другой разговор.Вполне приемлемый проект, странно как я его пропустил. Вот ещё бы ослика к нему прикрутить. Мне бы за глаза хватило.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

kvadro8 пишет:

Вот вы все говорите, не получится мозгов не хватит, но ведь на  uno  и due свет клином не сошёлся. Есть контроллеры , скажем XMega и подобные, почему бы не попробывать, есть же проекты?Вместо того чтобы разгонять до красна 328 на 27МГц и говорить потом что DSO138 хуже ослика на меге328, дали бы совет какой контроллер потянет мою идею и всё вопрос закрыт!!!

Сердцем проекта думаю надо делать какой-то из ORANGE PI, оставив ардуинки для общения с периферией, если ног на оном не хватит

kvadro8
Offline
Зарегистрирован: 17.02.2017

Ну про апельсины я пока как то не думал, но как вариант можно. Как то не доверяю я таким девайсам, уж слишком много в них натыкано, с ним разбираться надо будет месяца 3-4. Но опять же с мегой не сравнить.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

kvadro8 пишет:

Ну про апельсины я пока как то не думал, но как вариант можно. Как то не доверяю я таким девайсам, уж слишком много в них натыкано, с ним разбираться надо будет месяца 3-4. Но опять же с мегой не сравнить.

Да Вы батенька оптимист ...я о 3-4 месяца

kvadro8
Offline
Зарегистрирован: 17.02.2017

Я в своё время лазерный станок с чпу освоил за неделю, написание G code за две ( рабочие программы для производства ). Силовую и аппаратную часть за месяц ( ремонт и обслуживание ). Ну уж как нибудь с апельсинкой за три месяца то разберусь. А так -да, по поводу оптимизма.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Оптимист - мы живём в лучшем из миров
Пессимист - похоже так и есть )))

kvadro8
Offline
Зарегистрирован: 17.02.2017

Я действительно считаю что мы живём в лучшем из миров. А вы?

vitmish
Offline
Зарегистрирован: 06.02.2017

Те, кто успел сравнить, не могут оставить отзывы. Disconnected.

Так что считать можно как угодно - как комфортнее.