Позвольте спросить, обязательно ли ставить скобки? В примере, который Вы привели, нету скобок, окружающих end_led+amount (15 строка кода)!
А попробовать? 99% что не обязательно. Просто не хотел хмурить мозг и вглядыватся в порядок операций на конкретном месте. Если в мыслях они у меня должны вначале сложится, а потом все остальное - ну так я и их поставлю. Лишними не будут :)
Если я четко вижу что порядок операций тут однозначен - можно опустить (а можно не опускать). Вообщем тут они не от "синтаксиса языка", а "как в математике". Просто обозначить какие операции должны первыми идти. Или даже просто "выдилить визуально", что-бы глазами легче вспринималось.
P.S. Пример с синусойдой уже не актуален. См. дальше :)
Всё равно светодиоды в обратном порядке не переключаются!
byte brightness = 0; // уставливаем начально значение яркости
byte fadeAmount = 5; // шаг приращения/убывания яркости
byte ledAmount = 1; // шаг перехода между светодиодами
byte leds[]={3,5,6,9,10,11} ; // список пинов диодов, будет зажигать именно в этом порядке, добавил еще один диод на 13
byte index=0; // индекс в массиве leds текущего диода
#define TOTAL sizeof(leds)/sizeof(byte) // вычисляем сколько всего у нас светиков
void setup() {
for(byte i=0;i<TOTAL;i++)pinMode(leds[i],OUTPUT); // все на выход
}
void loop() {
analogWrite(leds[index], brightness);
// измением значение в переменной для яркости
brightness = brightness + fadeAmount;
// при достижение крайних значений для яркости
// меняем знак переменной шага приращения/убывания яркости
if (brightness == 0 || brightness == 255) {
fadeAmount = -fadeAmount ;
if(brightness==0){ // пора переходить к следующему диоду
analogWrite(leds[index], 0); // полностью гасим текущий
index++; // переходим к следующему
if(index==TOTAL || index==0) ledAmount = -ledAmount;
}
}
// делаем паузу для достижения плавного наращивания/убывания яркости
delay(5);
}
Подскажите пожалуйста, что здесь написано неправильно!
Подсказка: TOTAL - это количество элементов. А index - это индекс :) Причем в C нумерация массива идет С НУЛЯ! Поэтому какий индекс будет у последнего элемента?
Может и еще "что-то" есть, но уже не сегодня смотреть буду.
Подсказка: TOTAL - это количество элементов. А index - это индекс :) Причем в C нумерация массива идет С НУЛЯ! Поэтому какий индекс будет у последнего элемента?
Но в обратном порядке светодиоды переключаться почему-то всё равно не хотят!
byte brightness = 0; // уставливаем начально значение яркости
byte fadeAmount = 5; // шаг приращения/убывания яркости
byte ledAmount = 1; // шаг перехода между светодиодами
byte leds[]={3,5,6,9,10,11} ; // список пинов диодов, будет зажигать именно в этом порядке, добавил еще один диод на 13
byte index=0; // индекс в массиве leds текущего диода
#define TOTAL sizeof(leds)/sizeof(byte) // вычисляем сколько всего у нас светиков
void setup() {
for(byte i=0;i<TOTAL;i++)pinMode(leds[i],OUTPUT); // все на выход
}
void loop() {
analogWrite(leds[index], brightness);
// измением значение в переменной для яркости
brightness = brightness + fadeAmount;
// при достижение крайних значений для яркости
// меняем знак переменной шага приращения/убывания яркости
if (brightness == 0 || brightness == 255) {
fadeAmount = -fadeAmount ;
if(brightness==0){ // пора переходить к следующему диоду
analogWrite(leds[index], 0); // полностью гасим текущий
index++; // переходим к следующему
if(index==(TOTAL-1) || index==0) ledAmount = -ledAmount;
}
}
// делаем паузу для достижения плавного наращивания/убывания яркости
delay(5);
}
Но в обратном порядке светодиоды переключаться почему-то всё равно не хотят!
Ну значит есть ошибка. Есть расхождение между "ментальной моделью" и тем что написано в коде. И нужно научится ее находить (работа кодера-программера на 80-90% из этого и состоит. это основное "время-провождение" :) Поэтому и важна "читабельность" :) Не научившись искать-исправлять-разбиратся - программить вообще не возможно. Никакой гугл не поможет найти ошибку в собственной логике, а на "помощь извне" - тоже не всегда можно расчитывать
Правда есть хитрость: иногда нужно объяснить кому-то "вот смотри, у меня все правильно - работает это вот так......" *&#### Понял! Вот собака. Часто "объясни другому" почему-то работает магически. Хотя если самому себе тот же текст "проговаривать" - не помогает :(
Ладно, вернемся к нашим баранам.
Находить можно двумя способами. Либо "крутить в голове" (на листочке бумаги). Возмите свои переменные, присвойте им какие-то значение (мысленно), лучше "граничные", там где по вашему "должно что-то происходить".
И дальше идите по каждой строчке кода и выполняйте ее в голове. При index=1; В стороке n - не меняется, n+1 - не меняется, n+2 - о!, увеличился, стал index=2. Идем дальше, а тут у нас ledAmount поменял знак... идем дальше index стал.... ;%№%; а должен был .....
Если сложно представить и "не получается", ну значит возложим это на комп. Сделаем Serial.begin(...) в setup(), а возле analogWrite поставим
Serial.print("index=");Serial.print(index); Serial.print("; brightness=");Serial.print(brightness); // и так далее, любые переменные которые нас интересуют
Serial.println();
Увеличим delay(), что-бы данные бежали не так быстро, открываем Serial монитор и смотрим что у нас происходит. Ищем где "что-то пошло не так". Потом ищем в коде строчку, которая, по нашему мнению, должна была что-то сделать, но не сделала. Всматриваемся в нее. Если она "вроде все правильно", но там есть какие-то переменная - значит начинаем и за ней следить. Убеждаемся что к нужному моменту она имеет значение которое мы ожидаем. Если нет ... аналогично ищем "почему нет?". Где для нее "что-то пошло не так".
Еще один простой способ, воспользоваться отладчиком и пройти программу по шагам. Поскольку здесь прерываний нет, это будет проделать легко, воспользуйтесь этим замечательным инструментом: http://sourceforge.net/projects/dumpmon/files/
Рекомендую. Посмотрите примеры, там всё просто.
Еще один простой способ, воспользоваться отладчиком и пройти программу по шагам. Поскольку здесь прерываний нет, это будет проделать легко, воспользуйтесь этим замечательным инструментом: http://sourceforge.net/projects/dumpmon/files/ Рекомендую. Посмотрите примеры, там всё просто.
Не, думаю, все-таки для начала нужно разобратся как самому через Serial дебагать. Иногда, все-таки нужно и "выводить по условию" и "что-то подхачить" и т.п.
Вещь, конечно, полезная. Такие вещи однозначно должны идти "в копилку". Но не всегда приминима (когда памяти "ой-ой", подключать любую внешнюю либу, что-бы посмотреть одну переменную - ой не хочется).
Да и "все просто" - это для нас с вами. А новичку, даже не забыть dumpmonLoop(); вставить и то может быть проблемой (и понять что это за "магия"). Не забывайте про банальный перегруз информацией. Это как в машине: новичку трудно следить за дорогой, потому что еще приходится думать какой ногой педаль нажимать.
Да банально, даже забрать себе эту либу. Нынче далеко не все знают что такое .tar.gz (про склонировать git репозиторий я вообще молчу). Ну даже если случайно стоит архиватор... так ведь либу еще нужно уметь происталить (не велика премудрость, но ведь в первый раз тоже разобратся нужно). А она еще явно, под старое ide писалось. Не дай бог вылезет стандартное "WProgram.h не нахожу".
Так что, безусловно, спасибо за наводку. Взять ее на вооружение нужно, но после того как скетч "дожмется" без нее (благо там чих, в одной строчке поправить осталось :)
Либа свежая, я на леонардо тестил. Отчасти ты прав, но иногда при пошаговом выполнении много нового узнаешь. Думаю ТС разберется сам, юзать или нет.
Хотя лентяев тут хватает :)
Надеюсь никого не обидел
... ищем в коде строчку, которая, по нашему мнению, должна была что-то сделать, но не сделала. Всматриваемся в нее. Если она "вроде все правильно", но там есть какие-то переменная - значит начинаем и за ней следить. Убеждаемся что к нужному моменту она имеет значение которое мы ожидаем. Если нет ... аналогично ищем "почему нет?". Где для нее "что-то пошло не так".
Наконец-то нашел! Заменил строку
index++;
на
index = index+ledAmount;
Полностью исправленный вариант:
byte brightness = 0; // уставливаем начально значение яркости
byte fadeAmount = 5; // шаг приращения/убывания яркости
byte ledAmount = 1; // шаг перехода между светодиодами
byte leds[]={3,5,6,9,10,11} ; // список пинов диодов, будет зажигать именно в этом порядке, добавил еще один диод на 13
byte index=0; // индекс в массиве leds текущего диода
#define TOTAL sizeof(leds)/sizeof(byte) // вычисляем сколько всего у нас светиков
void setup() {
for(byte i=0;i<TOTAL;i++)pinMode(leds[i],OUTPUT); // все на выход
}
void loop() {
analogWrite(leds[index], brightness);
// измением значение в переменной для яркости
brightness = brightness + fadeAmount;
// при достижение крайних значений для яркости
// меняем знак переменной шага приращения/убывания яркости
if (brightness == 0 || brightness == 255) {
fadeAmount = -fadeAmount ;
if(brightness==0){ // пора переходить к следующему диоду
analogWrite(leds[index], 0); // полностью гасим текущий
index = index+ledAmount; // переходим к следующему
if(index==(TOTAL-1) || index==0) ledAmount = -ledAmount;
}
}
// делаем паузу для достижения плавного наращивания/убывания яркости
delay(5);
}
Первоначально в этом коде я умудрился сделать 2 ошибки!
1. Я не учел, что нумерация в массиве начинается с нуля! (строка 29)
2. Не задействовал переменную ledAmount в 28 строке!
Первую ошибку я исправил только после явной подсказки! Вторую долго и нудно искал, анализируя значения переменных, полученные через "Serial монитор"!
Чтобы упростить себе задачу я значительно увеличил значение шага переменной для изменения яркости
byte fadeAmount = 51;
и сократил количество светодиодов до трех
byte leds[]={9,10,11} ; // список пинов диодов
То, что я увидел стало неожиданностью! index всё увеличивался и увеличивался, попутно при этом туда-сюда менялась brightness (яркость). В общем, проанализировав это, я понял, что так в принципе и должно быть! Но то, что началось дальше (на значении index=20) вызвало у меня полное недоумение! Как переменная может принимать значания не кратные шагу её увеличения/уменьшения??? И почему после index=20 вдруг начинает идти index=94 ???
Первоначально в этом коде я умудрился сделать 2 ошибки!
Поверте это немного и обычно. И вы никогда не прекратите их делать. Навыки только позволят сократить время на а) как быстро обнаружить что "что-то так", б) локализовать проблему, в) исправить.
ivan_vasilevich пишет:
и сократил количество светодиодов до трех
....
на значении index=20
....
я увидел стало неожиданностью!
Я тоже. Просто интерестно, при длине массива в три штуки, для какого, по вашему, пина дуины выполнится anaglogWrite(leds[index],...) при index=20?
ivan_vasilevich пишет:
И почему после index=20 вдруг начинает идти index=94 ???
Можно гадать, но обратите внимание, на
ivan_vasilevich пишет:
index=20; brightness=145
index=94; brightness=196
Как вы думаете, это случано так совпало что index=94, в точности равен brightness предыдущего loop минус шаг (145-51)?
ivan_vasilevich пишет:
Кому интересно можете посмотреть:
Не интерестно. Какой смысл в логе незвестного скетча? Скетч который выдает этот лог - вы не превели. Запустить, проверить, пощупать его никто не может. Известно только что вы в нем что-то меняли (количество диодов, шаги, может еще что-то). Вообщем "экстрасенсы в отпуске"
P.S. А вообще вы молодец. Не опускаете руки, ищите, дожимаете, пытаетесь осознать если происходит что-то "непонятное, не логично" - именно так и надо :)
Это для развлечения, между разборками. В программе есть "загадка", программа работает по другому алгоритму, если добавить одну строку и перекомпилировать программу.
В начале программы есть некоторые параметры, которые позволяют менять характер работы светодиодов, я поставил 4, больше у меня нет ;) На трех тоже всё работает.
Да, я особо не заботился о некоторых вещах, на другие обращал очень пристальное внимание, потому где то кривости могут быть. Зато прикольно моргает. Спасибо ТС, если бы он так долго не разбирался, я бы и не написал этот новогодний опус.
/* Список пинов изменения яркости светодиодов с использованием PWM */
const word leds[] = { 9, 10, 11, 6 };
/*
* Определяем длительность задержки (в мс) между увеличением яркости на одном светодиоде
* Это позволяет изменить скорость изменения яркости светодиодов
*/
const word delay_bw_fade = 5;
/*
* Шаг изменения яркости
*/
int brightness_step = 5;
/*
* Остальная часть не требует настройки.
*/
/* Определяем количество пинов в массиве */
#define leds_cnt (sizeof(leds)/sizeof(int))
void setup()
{
/* Только для отладки инициализируем последовательный порт. Скорость может быть любой */
Serial.begin( 57600 );
/*
* Инициализируем все пины из массива на вывод.
*/
for( word i = 0; i < leds_cnt; ++i )
{
pinMode( leds[ i ], OUTPUT );
}
}
/*
* Простейщая функция, которая увеличивает яркость одного светодиода (номер пина передается как параметр p_led)
* от минимума до максимума, затем уменьшает его до минимума, после чего производится выход в вызывающую программу
*/
void fadeOneLed(int p_led)
{
/* Шаг изменения яркости */
int l_br_step = brightness_step;
/*
* Выполняем цикл плавного сначала увеличения, потому уменьшения яркости светодиода (пин p_led)
* Здесь нет проверки окончания цикла, потому, если удалить команду break из цикла, эта функция никогда не завершится.
*/
for(int l_br = 0;; l_br += l_br_step)
{
/* Проверяем, дошли ли мы до верхней границы, если да, то нужно уменьшать яркость */
if( l_br > 255 )
{
/* Просто меняем шаг на отрицательное значение */
l_br_step = -l_br_step;
/*
* Сразу считаем первое значения для уменьшения яркости
* Здесь мы точно знаем, что шаг отрицательный
*/
l_br = 255 + l_br_step;
}
/*
* Цикл не бесконечный, нужно когда то и закончить его. А закончить его нужно, когда при уменьшении яркости мы дойдем до
* отрицательного значения.
* l_br_step < 0 - это признак того, что яркость уменьшается
* l_br < 0 - то, что мы закончили цикл
*/
if( l_br < 0 && l_br_step < 0 )
{
/* Полностью гасим светодиод, поскольку l_br не всегда будет 0 при выходе */
analogWrite( p_led, 0 );
/* Прекращаем цикл */
break;
}
/*
* Выполняем главное, устанавливаем яркость светодиода
* Она будет изменяться так (для шага = 5):
* 0, 5, 10, ... 250, 255, 250, 245, ... 5, 0
* Главное здесь то, что l_br здесь будет всегда в пределах 0..255
*/
analogWrite( p_led, l_br );
/* Делаем задержку, чтобы увидеть изменения яркости, иначе всё будет происходить очень быстро */
delay(delay_bw_fade);
}
}
void loop()
{
#ifdef USE_SEQ_MODE
/*
* Цикл в прямом направлении. Здесь видно, что последний светодиод из массива не попадает в обработку,
* он попадет в обработку в следующем цикле.
*/
for( word l_led_index = 0; l_led_index < leds_cnt - 1; ++l_led_index )
{
fadeOneLed( leds[ l_led_index ] );
}
/*
* Цикл в обратном направлении. Здесь видно, что последний светодиод из массива будет первым, а первый светодиод
* в обработку не попадает, он попадает в обработку в цикле выше.
*/
for( word l_led_index = leds_cnt - 1; l_led_index > 0; --l_led_index )
{
fadeOneLed( leds[ l_led_index ] );
}
/*
* Циклы закончены, отметимся в порт и начнем сначала
*/
Serial.println( "One step" );
#else
static word l_last_index = leds_cnt + 1;
word l_led_index;
for(;;)
{
l_led_index = random() % leds_cnt;
if( l_led_index != l_last_index )
{
l_last_index = l_led_index;
break;
}
}
fadeOneLed( leds[ l_led_index ] );
brightness_step = 1 + ( random() % 15 );
#endif
}
Это для развлечения, между разборками. В программе есть "загадка", программа работает по другому алгоритму, если добавить одну строку и перекомпилировать программу.
К сожалению, нет диодов под руками, а по Serial разгадывать - не так захватывающе.
Меня сейчас другая "загадка" мучает. На MAC ноуте каком-то видел. В режиме sleep, а него индикатор не просто "мигает", а разгорается и гаснет. Причем не линейно. Эта не линейность и частота подобранна таким образом, что без всяких объяснений, у всех, первая ассоциация приходящая в голову от простого взгляда, даже без наводящих вопросов "дыхание во сне". Интуитивно понятно "ноут спит" :)
Вот реально кажется что он "дышит" этим светодиодом! Завораживает. Такой эффект обычным светиком!
Но воспроизвести - пока не получается. Пытался нагуглить где-нибудь у физиологов, параметры дыхания спящего человека - не вдача. Метод "научного тыка" - не прокатил. Хоть бери и ище в загашниках датчик дыхания и записывай себя :)
Update: вот как всегда. Поплакался что "не могу найти" и нашел http://thecustomgeek.com/2011/06/17/breathing-sleep-led/ Правда на видео эффект ощущается "слегка". На встроенном LED-де тоже "слегка", нужно будет с белым попробовать (ну и код, конечно, переписать в что-то более вменяемое).
Мне кажется что типа синусоиды, потому что при спокойном дыхании на крайних точках дыхание как бы приостанавливается, точнее замедляется. Щас попробую, шагом поиграться или просто тупо синус использовать, точнее косинус, во, забыл уже, надо погуглить
Мне кажется что типа синусоиды, потому что при спокойном дыхании на крайних точках дыхание как бы приостанавливается, точнее замедляется. Щас попробую, шагом поиграться или просто тупо синус использовать, точнее косинус, во, забыл уже, надо погуглить
Я в предыдущие сообщение добавил найденную реализацию.
Я посмотрел в гугле, дыхание - примерно пила (быстрый подъем, потом несколько более медленный спад). Короче - это уже скушная задача, просто подобрать параметры. ;) Я поподбирал, что то такое получается, в общем немного работы и можно подобрать для себя приятный ритм "дыхания" светодиодов. Мне такое скушно :)
Хотя вот вариант, на котором я закончил исследование, чего зря пропадать. Не совсем дыхание, но прикольней "дышат". Здесь реализована пила, у которой спад медленней чем нарастание примерно в два раза:
/* Список пинов изменения яркости светодиодов с использованием PWM */
const word leds[] = { 9, 10, 11, 6 };
/*
* Определяем длительность задержки (в мс) между увеличением яркости на одном светодиоде
* Это позволяет изменить скорость изменения яркости светодиодов
*/
const word delay_bw_fade = 15;
/*
* Шаг изменения яркости
*/
int brightness_step_up = 5;
int brightness_step_down = -(brightness_step_up / 2 + 1);
/*
* Остальная часть не требует настройки.
*/
/* Определяем количество пинов в массиве */
#define leds_cnt (sizeof(leds)/sizeof(int))
void setup()
{
/* Только для отладки инициализируем последовательный порт. Скорость может быть любой */
Serial.begin( 57600 );
/*
* Инициализируем все пины из массива на вывод.
*/
for( word i = 0; i < leds_cnt; ++i )
{
pinMode( leds[ i ], OUTPUT );
}
}
/*
* Простейщая функция, которая увеличивает яркость одного светодиода (номер пина передается как параметр p_led)
* от минимума до максимума, затем уменьшает его до минимума, после чего производится выход в вызывающую программу
*/
void fadeOneLed(int p_led)
{
/* Шаг изменения яркости */
int l_br_step = brightness_step_up;
/*
* Выполняем цикл плавного сначала увеличения, потому уменьшения яркости светодиода (пин p_led)
* Здесь нет проверки окончания цикла, потому, если удалить команду break из цикла, эта функция никогда не завершится.
*/
for(int l_br = 0;; l_br += l_br_step)
{
/* Проверяем, дошли ли мы до верхней границы, если да, то нужно уменьшать яркость */
if( l_br > 255 )
{
/* Просто меняем шаг на отрицательное значение */
l_br_step = brightness_step_down;
/*
* Сразу считаем первое значения для уменьшения яркости
* Здесь мы точно знаем, что шаг отрицательный
*/
l_br = 255 + l_br_step;
}
/*
* Цикл не бесконечный, нужно когда то и закончить его. А закончить его нужно, когда при уменьшении яркости мы дойдем до
* отрицательного значения.
* l_br_step < 0 - это признак того, что яркость уменьшается
* l_br < 0 - то, что мы закончили цикл
*/
if( l_br < 0 && l_br_step < 0 )
{
/* Полностью гасим светодиод, поскольку l_br не всегда будет 0 при выходе */
analogWrite( p_led, 0 );
/* Прекращаем цикл */
break;
}
/*
* Выполняем главное, устанавливаем яркость светодиода
* Она будет изменяться так (для шага = 5):
* 0, 5, 10, ... 250, 255, 250, 245, ... 5, 0
* Главное здесь то, что l_br здесь будет всегда в пределах 0..255
*/
analogWrite( p_led, l_br );
/* Делаем задержку, чтобы увидеть изменения яркости, иначе всё будет происходить очень быстро */
delay(delay_bw_fade);
}
}
void loop()
{
#ifdef USE_SEQ_MODE
/*
* Цикл в прямом направлении. Здесь видно, что последний светодиод из массива не попадает в обработку,
* он попадет в обработку в следующем цикле.
*/
for( word l_led_index = 0; l_led_index < leds_cnt - 1; ++l_led_index )
{
fadeOneLed( leds[ l_led_index ] );
}
/*
* Цикл в обратном направлении. Здесь видно, что последний светодиод из массива будет первым, а первый светодиод
* в обработку не попадает, он попадает в обработку в цикле выше.
*/
for( word l_led_index = leds_cnt - 1; l_led_index > 0; --l_led_index )
{
fadeOneLed( leds[ l_led_index ] );
}
/*
* Циклы закончены, отметимся в порт и начнем сначала
*/
Serial.println( "One step" );
#else
static word l_last_index = leds_cnt + 1;
word l_led_index;
for(;;)
{
l_led_index = random() % leds_cnt;
if( l_led_index != l_last_index )
{
l_last_index = l_led_index;
break;
}
}
fadeOneLed( leds[ l_led_index ] );
#ifdef USE_SIN
delay( 800 );
#else
brightness_step_up = 1 + ( random() % 15 );
brightness_step_down = -(brightness_step_up / 2 + 1);
#endif
#endif
}
Не интерестно. Какой смысл в логе незвестного скетча? Скетч который выдает этот лог - вы не превели. Запустить, проверить, пощупать его никто не может...
Я не использовал для анализа кода никаких скетчей, а просто, как Вы и советовали, прописал в void setup() Serial.begin (9600); и добавил в прогу кусочек кода, выводящий значения переменных через Serial порт.
Serial.print("index=");Serial.print(index); Serial.print("; brightness=");Serial.print(brightness); // и так далее, любые переменные которые нас интересуют
Serial.println();
А всякие регистры, стеки, дампы памяти пр. - для меня это "темный лес"? В ассемблере абсолютно не разбираюсь. Хотелось бы конечно освоить, но не знаю, осилю ли я его?
Решил начать писать программы для микроконтроллеров с Arduino - говорят, проще этой платформы нету ничего! Но, как видите, с простейшей программой "бегущего огонька" на светодиодах я разбираюсь уже второй или третий день! Наконец-то она заработала, как нужно!
P.S.: Большое спасибо всем, кто помог мне и указал на ошибки!
Забейте на ассемблер, для простых и учебных задач здесь вполне достаточно С/С++.
Обычно ассемблер нужен во времязависимых задачах, когда нужно быстро сработать и/или рассчитать задержки на выполнении программы. А если посмотреть реализацию, например analogWrite, то там столько кода, что мало не покажется, потому расчитать задержку - нереально. Но за всё нужно платить, либо просто, либо эффективно.
Тем более с ассемблером будут проблемы с переходом на другую Ардуино, в частности Uno и Leonardo настолько разные по пинам, что мало не покажется.
Я не использовал для анализа кода никаких скетчей,
Да ну? :) В терминологии ардуины "скетч" это есть программа которую вы заливаете в дуину. В обычных языках называют "исходник, исходный текст", а вот тут они зачем-то такой термин придумали. sketch- эскиз. Видимо что-бы подчеркнуть что "все очень просто" :) Так что любой пример выше, который "целостный" и можно залить в дуину - это скетч :)
ivan_vasilevich пишет:
а просто, как Вы и советовали, прописал в void setup() Serial.begin (9600); и добавил в прогу кусочек кода, выводящий значения переменных через Serial порт.
Serial.print("index=");Serial.print(index); Serial.print("; brightness=");Serial.print(brightness); // и так далее, любые переменные которые нас интересуют
Serial.println();
А всякие регистры, стеки, дампы памяти пр. - для меня это "темный лес"? В ассемблере абсолютно не разбираюсь. Хотелось бы конечно освоить, но не знаю, осилю ли я его?
Дык вас пока никто не призывал. В стеки, дампы и проч. Вот то что у вас получилось после того как "добавил как вы советовали", "поменял шаг", "уменьшил количество диодов" - вот это и нужно было дать сюда в качестве примера. То есть "сама программа" и "что выводит" в паре. Что-бы любой мог повторить ваши "непонятнки" и как index становится 98 и проч. А то вы лог дали, а "кто его делает" - нет. А явно же там где-то очепятались или еще что-то. Как иначе объяснить почему у вас яркость и индекс скачут, не видя кода который вы запускаете? Вы задали вопрос, но инфу для анализа-ответа дали только частично.
На да ладно. Если он не сохранился - значит эти чудеся останутся тайной. Конечный вариант заработал - и ладно.
На да ладно. Если он не сохранился - значит эти чудеся останутся тайной...
Нет .. скорее всего не не останутся! Глючный вариант (где index скачет с 20 на 94) я еще не удалил! Привожу в полном объеме! Все, кому не лень, могут загрузить его с свою плату, а затем, жмакнув на кнопочку "Монитор порта" посмотреть, что там твориться!
byte brightness = 0; // уставливаем начально значение яркости
byte fadeAmount = 51; // шаг приращения/убывания яркости
byte ledAmount = 1; // шаг перехода между светодиодами
byte leds[]={9,10,11} ; // список пинов диодов, будет зажигать именно в этом порядке, добавил еще один диод на 13
byte index=0; // индекс в массиве leds текущего диода
#define TOTAL sizeof(leds)/sizeof(byte) // вычисляем сколько всего у нас светиков
void setup() {
Serial.begin (9600);
for(byte i=0;i<TOTAL;i++)pinMode(leds[i],OUTPUT); // все на выход
}
void loop() {
analogWrite(leds[index], brightness);
Serial.print("index=");Serial.print(index); Serial.print("; brightness=");Serial.print(brightness); // и так далее, любые переменные которые нас интересуют
Serial.println();
// измением значение в переменной для яркости
brightness = brightness + fadeAmount;
// при достижение крайних значений для яркости
// меняем знак переменной шага приращения/убывания яркости
if (brightness == 0 || brightness == 255) {
fadeAmount = -fadeAmount ;
if(brightness==0){ // пора переходить к следующему диоду
analogWrite(leds[index], 0); // полностью гасим текущий
index++; // переходим к следующему
if(index==(TOTAL-1) || index==0) ledAmount = -ledAmount;
}
}
// делаем паузу для достижения плавного наращивания/убывания яркости
delay(50);
}
Может кто-нибудь и разберётся, в чём причина появления подобных глюков
Может кто-нибудь и разберётся, в чём причина появления подобных глюков
На самом деле и запускать не пришлось. Я, где-то в самом начале ветки, рекомендовал вам пойти в раздел програмирования (в шапке сайта) и ознакомится со всеми типами данных. Нет типов которые "лучше и хуже". Нельзя сказать "всегда используйте byte" или "всегда int". Нужно танцевать от того какие числа ожидаются в переменной (знаковость, диапазон, целые/вещественные) и т.п. И исходя из этого выбирать тип переменной. Минимально-достаточный.
Так же, повторюсь "но там есть какие-то переменная - значит начинаем и за ней следить". Раз те переменные что мы уже смотрим ведут себя не правильно, значит по аналогии стоит посмотреть еще и на те переменные от которых они зависят. И там бы вы сразу увидели чудеса еще круче :)
Вообщем перепроверте типы переменных. Так же, кроме вывода в Serial значений самих переменных, можно втыкитьва что-то типа Serial.println("Zahli v IF");. Что-бы убедится действительно заходим в какой-то IF когда собирались (или узнать о том, что почему-то не заходим. посмотреть какие значения переменных были, перед тем как условие не сработало и т.п.).
...кроме вывода в Serial значений самих переменных, можно втыкитьва что-то типа Serial.println("Zahli v IF");. Что-бы убедится действительно заходим в какой-то IF когда собирались (или узнать о том, что почему-то не заходим. посмотреть какие значения переменных были, перед тем как условие не сработало и т.п.).
Спасибо за очень толковый совет! Это действительно момогает в отладке - можно сделать нечто вроде простейшего log-файла без вспомогательных программ!
Я только-что добавил несколько строк в глючную прогу, но ранее появлявшийся глюк (с перескоком index=20 на index=94) исчез! Но теперь глюк начинает появляться после index=24)
В общем, у меня промелькнула мысля, что это в переменную больше не влазит! Потому, что она задана как byte! Но неужели каждый index съедает 10 байт, а не один, потому что значения яркости для index меняются 10 раз (от 0 до 255 с шагом 51 сначала туда, потом обратно)
Или я неправильно рассуждаю? Привожу код проги и лог-файл, выведенный через Serial
byte brightness = 0; // уставливаем начально значение яркости
byte fadeAmount = 51; // шаг приращения/убывания яркости
byte ledAmount = 1; // шаг перехода между светодиодами
byte leds[]={9,10,11} ; // список пинов диодов, будет зажигать именно в этом порядке, добавил еще один диод на 13
byte index=0; // индекс в массиве leds текущего диода
#define TOTAL sizeof(leds)/sizeof(byte) // вычисляем сколько всего у нас светиков
void setup() {
Serial.begin (9600);
for(byte i=0;i<TOTAL;i++)pinMode(leds[i],OUTPUT); // все на выход
}
void loop() {
analogWrite(leds[index], brightness);
Serial.print("index=");Serial.print(index); Serial.print("; brightness=");Serial.print(brightness); // и так далее, любые переменные которые нас интересуют
Serial.println();
// измением значение в переменной для яркости
brightness = brightness + fadeAmount;
// при достижение крайних значений для яркости
// меняем знак переменной шага приращения/убывания яркости
if (brightness == 0 || brightness == 255) {
Serial.print("Voshli_v_IF");Serial.println();
fadeAmount = -fadeAmount ;
if(brightness==0){ // пора переходить к следующему диоду
analogWrite(leds[index], 0); // полностью гасим текущий
Serial.println();Serial.print("Go_to_the_next_LED");Serial.println();
index++; // переходим к следующему
if(index==(TOTAL-1) || index==0) ledAmount = -ledAmount;
}
}
// делаем паузу для достижения плавного наращивания/убывания яркости
delay(500);
}
Я только-что добавил несколько строк в глючную прогу, но ранее появлявшийся глюк (с перескоком index=20 на index=94) исчез! Но теперь глюк начинает появляться после index=24)
Как выглядит этот "глюк после index=24"? На приведенной вами полубесконечной простыне начало 25-го цикла выглядит ровно так же, как и начало предыдущих двадцати четырех. Потом - как я понимаю - конец простыни. Никакого перескока углядеть не удается.
ivan_vasilevich пишет:
В общем, у меня промелькнула мысля, что это в переменную больше не влазит! Потому, что она задана как byte! Но неужели каждый index съедает 10 байт, а не один, потому что значения яркости для index меняются 10 раз (от 0 до 255 с шагом 51 сначала туда, потом обратно)
А с чего вы взяли, что index съедает 10 байт? А не 2? Или 38?
По поводу "больше не влазит".
В старом варианте скетча у вас начальное значение для brightness равнялось пяти, а шаг изменения составлял 51. Поэтому получалось:
1-е приращение: 5+51=56 все в порядке
2-е приращение: 56+51=107 все в порядке
3-е приращение: 107+51=158 все в порядке
4-е приращение: 158+51=209 все в порядке
5-е приращение: 209+51=262 все в порядке? Отнюдь. Byte позволяет хранить значения от 0 до 255. При попытке втюхать в байт число, превышающее 255, происходят два события:
1) в байт загружаются 8 младших битов. Для 262 (b100000110) это 6 (b00000110).
2) наличие единички в 8-м бите (ну и в более старших) приводит к генерации прерывания по переполнению. Обработку которого разработчики Ардуино скрыли от пользователей.
Как результат, на 5-м приращении у вас получалось 209+51=6. Глюк, как вы это называете.
В новом варианте скетча значения начальной яркости и шага ее приращения имеют одно из тех удачных соотношений, когда значение яркости на одном из шагов принимает значение тютелька в тютельку равное 255, т.е. условие на проверку максимума уже выполнилось, а переполнения еще не произошло. В обратную сторону тоже все нормально - яркость получает-таки значение 0.
А с index (который byte) срыва мозгов (от превышения разрядности) можно ожидать на 255-й итерации.
Обратите внимание на строки 2 и 28 последнего опубликованного варианта вашего скетча.
Во второй строке переменная определяется как byte, т.е. изменяющаяся в диапазоне от 0 до 255, а в 28-й ей изменяют знак. Нехорошо. Уж лучше char тогда взять. То же самое можно сказать и по поводу ledAmount. Да и для brightness тип int более уместен - негоже производить эксперрименты с приращением/сравнением величин в опасной близости от границ диапазона их изменения.
И, наконец, обратите пристальное внимание на строчку 6 (особенно на комментарий):
byteindex=0; // индекс в массиве leds текущего диода
и на то, что вы выводите с отладочной информацией:
index=5, index=25 и так далее...
В каком диапазоне у вас должен изменяться index? Не [0..2] случайно? Так какого ... он принимает значение 3 и так далее - до полного ступора программы? Не стоит ли здесь после строки
if(index==(TOTAL-1) || index==0) ledAmount = -ledAmount;
добавить
if(index==TOTAL) index = 0;
чтобы сразу же после выхода индекса за верхнуюю границу массива начать отсчет сначала?
Или я неправильно рассуждаю? Привожу код проги и лог-файл, выведенный через Serial
Правильно рассуждаете. Только чуть-чуть не продолжили свою мысль (и не сделали вывод из того что уже успели "нарассуждать"). Нужно было попытатся применить это рассуждение в коде.
"Не влезть" можно в две стороны. Как с торону слишком больших чисел, так и в сторону "слишком маленьких". Я ведь не зря жирным выделил слово "беззнаковость" и сказал "смотрите на переменные от которых зависят дурящие index,brightness)
Вообщем еще раз смотрите какие значения вы ожидаете в переменных и подбирайте им подходящие типы (step962 вообщем-то уже рассписал детально)
step962 пишет:
if(index==TOTAL) index = 0;
Это не спасет отца русском демократии :) "отрицательный" ledAmount может нам дать прыжок Index совсем не на 1-ницу. И мы проскочим эту проверку. Тут нужно скорее index>=TOTAL
Для топикстартера: обнуление index=0 в данном случае не "решение проблемы", а скорее "аварийная заплатка". Срабатывание этой строчки уже означает что где-то раньше логика нарушилась. Попытка минимизировать катастрофу от этого. По хорошему кроме index=0 нужно еще, обязательно(!), в этом случае выводить в Serial "Караул! Индекс вышел за границы массива". И возможно даже останавливать скетч полностью. В вашем случае это не "катастрофа", но обычно выход за границы означает полную непредсказуемость дальнейшего поведения. Могут входы, случайно, на выход повключатся (и повыгорать если там снаружи что-то подается). Да банально, к примеру, если вы рулите роботизированной сварочной головкой весом в 300 кг, двигающеся со скоростью 9 м/c, то лучше вывести ошибку и остановится полностью, чем начать дергатся непонятно куда и как :). Рядом с такой штукой стоять даже когда она не глючит - страшно, даже когда знаешь что у нее "длины руки" не хватит пол- метра что-бы тебя достать :)
Это не спасет отца русском демократии :) "отрицательный" ledAmount может нам дать прыжок Index совсем не на 1-ницу. И мы проскочим эту проверку. Тут нужно скорее index>=TOTAL
А это было бы следующим шагом избавления от мелочей, мешающих правильному прохождению программы: Избавление от проверок на равенство, которые нормально работают только при единичном инкременте/декременте, а при произвольном значении шага приращения проскакиваются просто на ура, что мы и видем (видели) на примере оперирования с brightness.
leshak пишет:
"отрицательный" ledAmount может нам дать прыжок Index совсем не на 1-ницу.
Нам может, топикстартеру - нет. Ведь у него index просто инкрементируется (index++), без использования ledAmount.
А это было бы следующим шагом избавления от мелочей, мешающих правильному прохождению программы:
Не, не... при "правильном прохождение" эта проверка вообще не нужна. Она никогда не выполнится. Сработает более раннее index==(TOTAL-1). Это же как раз "аварийный клапан". Поэтому либо "больше или равно" или "вообще убрать". От index==TOTAL - нет пользы при любых раскладах.
P.S. И, кстати, index++ - топик стартер уже нашел и пролечил (сообщение #60). Тут просто уже идет разбирательсво "почему-же он так прыгал". То есть "как не допустить переполнения" - уже выяснили. Сейчас просто осмысляем "а как же переполнение работает", почему index++ приводил именно к тамким результатам.
P.S. И, кстати, index++ - топик стартер уже нашел и пролечил (сообщение #60). Тут просто уже идет разбирательсво "почему-же он так прыгал". То есть "как не допустить переполнения" - уже выяснили. Сейчас просто осмысляем "а как же переполнение работает", почему index++ приводил именно к тамким результатам.
А я ваш козырный туз джокером покрою: сообщение #72. ;) Индекс у ТС благополучно пробегает значения от 0 до аж 25. И это при работе с массивом из трех элементов.
P.S. И, кстати, index++ - топик стартер уже нашел и пролечил (сообщение #60). Тут просто уже идет разбирательсво "почему-же он так прыгал". То есть "как не допустить переполнения" - уже выяснили. Сейчас просто осмысляем "а как же переполнение работает", почему index++ приводил именно к тамким результатам.
А я ваш козырный туз джокером покрою: сообщение #72. ;) Индекс у ТС благополучно пробегает значения от 0 до аж 25. И это при работе с массивом из трех элементов.
Не побъете :) Если внимательно прочитаете ветку, то увидите что #72 появился в ответ на просьбу дать СТАРЫЙ код, до фикса, лог которого был опубликован ранее без самого скетча и дальше пытаемся понять как он работает. К тому моменту index++ уже был обнаружен ТС самостоятельно :) И тут скорее идет рассуждение "почему он себя так ведет", чем "что исправить". index++ уже "известный баг". А вот с типами - пока еще в процессе борьбы .
2TC: обратите внимание, что, судя по логу. У вас диод "не гастися" до конца. Вы то перешли "к следующем" при brightness==0, но ведь текущему-то вы 0 - так и не скомандовали. На нем осталась ярокость 51.
Значит вам нужно либо еще дополнительно делать analogWrite при переходе, либо менять brightness уже после проверок (тогда к моменту проверки у вас brightness и состояния самого леда будут совпадать).
Я не даром давал свой пример для развлечения, вопросы с индексами я смотрел достаточно тщательно, думал, может кто посмотрит и увидит как можно делать проверки и т.п. у меня там шаги разные могут быть, недаром в начало скетча вынес изменяемую часть.
судя по логу. У вас диод "не гастися" до конца. Вы то перешли "к следующем" при brightness==0, но ведь текущему-то вы 0 - так и не скомандовали. На нем осталась ярокость 51.
Значит вам нужно либо еще дополнительно делать analogWrite при переходе, либо менять brightness уже после проверок (тогда к моменту проверки у вас brightness и состояния самого леда будут совпадать).
Ещё одна загадка! Предыдущий светодиод НЕ может не погаснуть полностью, поскольку в программе есть строка явно указывающая ему это сделать!
analogWrite(leds[index], 0); // полностью гасим текущий
Я думаю дело не в программе, а в том, что для правильного вывода log-файла нужно было добавить ещё одну строчку вывода в Serial port! Вот как выглядел код, "неправильно"( точнее не полностью) показывающий значения переменных.
byte brightness = 0; // уставливаем начально значение яркости
byte fadeAmount = 51; // шаг приращения/убывания яркости
byte ledAmount = 1; // шаг перехода между светодиодами
byte leds[]={9,10,11} ; // список пинов диодов, будет зажигать именно в этом порядке, добавил еще один диод на 13
byte index=0; // индекс в массиве leds текущего диода
#define TOTAL sizeof(leds)/sizeof(byte) // вычисляем сколько всего у нас светиков
void setup() {
Serial.begin (9600);
for(byte i=0;i<TOTAL;i++)pinMode(leds[i],OUTPUT); // все на выход
}
void loop() {
analogWrite(leds[index], brightness);
Serial.print("index=");Serial.print(index); Serial.print("; brightness=");Serial.print(brightness); // и так далее, любые переменные которые нас интересуют
Serial.println();
// измением значение в переменной для яркости
brightness = brightness + fadeAmount;
// при достижение крайних значений для яркости
// меняем знак переменной шага приращения/убывания яркости
if (brightness == 0 || brightness == 255) {
Serial.print("Voshli_v_IF");Serial.println();
fadeAmount = -fadeAmount ;
if(brightness==0){ // пора переходить к следующему диоду
analogWrite(leds[index], 0); // полностью гасим текущий
Serial.println();Serial.print("Go_to_the_next_LED");Serial.println();
index++; // переходим к следующему
if(index==(TOTAL-1) || index==0) ledAmount = -ledAmount;
}
}
// делаем паузу для достижения плавного наращивания/убывания яркости
delay(500);
}
А вот дополненный вариант:
byte brightness = 0; // уставливаем начально значение яркости
byte fadeAmount = 51; // шаг приращения/убывания яркости
byte ledAmount = 1; // шаг перехода между светодиодами
byte leds[]={9,10,11} ; // список пинов диодов, будет зажигать именно в этом порядке, добавил еще один диод на 13
byte index=0; // индекс в массиве leds текущего диода
#define TOTAL sizeof(leds)/sizeof(byte) // вычисляем сколько всего у нас светиков
void setup() {
Serial.begin (9600);
for(byte i=0;i<TOTAL;i++)pinMode(leds[i],OUTPUT); // все на выход
}
void loop() {
analogWrite(leds[index], brightness);
Serial.print("index=");Serial.print(index); Serial.print("; brightness=");Serial.print(brightness); // и так далее, любые переменные которые нас интересуют
Serial.println();
// измением значение в переменной для яркости
brightness = brightness + fadeAmount;
// при достижение крайних значений для яркости
// меняем знак переменной шага приращения/убывания яркости
if (brightness == 0 || brightness == 255) {
Serial.print("Voshli_v_IF");Serial.println();
fadeAmount = -fadeAmount ;
if(brightness==0){ // пора переходить к следующему диоду
analogWrite(leds[index], 0); // полностью гасим текущий
Serial.print("index=");Serial.print(index); Serial.print("; brightness=");Serial.print(brightness);
Serial.println();Serial.print("Go_to_the_next_LED");Serial.println();
index++; // переходим к следующему
if(index==(TOTAL-1) || index==0) ledAmount = -ledAmount;
}
}
// делаем паузу для достижения плавного наращивания/убывания яркости
delay(500);
}
В Serial он выводит такое (привожу небольшой фрагмент)
Ну проморгал я "// полностью гасим", хотя это и есть "вам нужно либо еще дополнительно делать analogWrite". Не заметил что это уже сделано.
Ну что делать с index++ - вы уже знаете сами. Причем "срочно", как только вы нашли выход за границы массива - дальше можно особо не смотреть. До того как это не пофиксано, с другими глюками можно и не разбиратся. Вероятность что 90% их обусловлена выходом - очень велика. Тут вы легко отделались только потому что читаете из массива, а не пишите в него. Если бы писали, то "чудес" было-бы в пять раз больше (и еще труднее для понимания). Так что "вначале его фиксаем", а потом заново смотрим какие глюки остались (может другие проявлятся начнут).
Ну осталось типы подправить (справитесь? Вроде тут уже и я и step962 "обнамекались" об этом :) И убедится что "все рабоает" не только визуально (глаз может и обманывать), но и по логу.
Цитата:
, но ранее появлявшийся глюк (с перескоком index=20 на index=94) исчез!
Подозреваю, что был какой-то промежуточный, не сохранившийся вариант где вы случайно подкручивали index с помощью fadeAmount. Уж больно подозрительно цифры совпали. В пробах мелькнуло что-то типа (index=brightness - fadeAmount).
Ну осталось типы подправить (справитесь? Вроде тут уже и я и step962 "обнамекались" об этом :) И убедится что "все рабоает" не только визуально (глаз может и обманывать), но и по логу.
Странно, но и без изменения типов прога работает нормально! Странный глюк возникает, когда количество светодиодов в массиве задавать не типом byte, а int !!! Прога ошибается в подсчете количества светодиодов в два раза! Подключено и задано 4-ре, она же думает, что их 8 (от0 до7)!
Вот код
int brightness = 0; // уставливаем начально значение яркости
int fadeAmount = 51; // шаг приращения/убывания яркости
int ledAmount = 1; // шаг перехода между светодиодами
int leds[]={6,9,10,11} ; // список пинов диодов, подключенных в PWM выходам
int index=0; // индекс в массиве leds текущего диода
#define TOTAL sizeof(leds)/sizeof(byte) // вычисляем сколько всего у нас светиков
void setup() {
Serial.begin (9600);
for(int i=0;i<TOTAL;i++)pinMode(leds[i],OUTPUT); // все на выход
}
void loop() {
analogWrite(leds[index], brightness);
Serial.print("index=");Serial.print(index); Serial.print("; brightness=");Serial.print(brightness); // и так далее, любые переменные которые нас интересуют
Serial.println();
// измением значение в переменной для яркости
brightness = brightness + fadeAmount;
// при достижение крайних значений для яркости
// меняем знак переменной шага приращения/убывания яркости
if (brightness == 0 || brightness == 255) {
fadeAmount = -fadeAmount ;
Serial.print("Voshli_v_IF");Serial.println();
if(brightness==0){ // пора переходить к следующему диоду
analogWrite(leds[index], 0); // полностью гасим текущий
Serial.print("index=");Serial.print(index); Serial.print("; brightness=");Serial.print(brightness);Serial.println();
index=index+ledAmount; // переходим к следующему
Serial.print("Go to the next LED");Serial.println();
if(index==(TOTAL-1) || index==0) ledAmount = -ledAmount;
}
}
// делаем паузу для достижения плавного наращивания/убывания яркости
delay(100);
}
и лог-файл
index=0; brightness=0
index=0; brightness=51
index=0; brightness=102
index=0; brightness=153
index=0; brightness=204
Voshli_v_IF
index=0; brightness=255
index=0; brightness=204
index=0; brightness=153
index=0; brightness=102
index=0; brightness=51
Voshli_v_IF
index=0; brightness=0
Go to the next LED
index=1; brightness=0
index=1; brightness=51
index=1; brightness=102
index=1; brightness=153
index=1; brightness=204
Voshli_v_IF
index=1; brightness=255
index=1; brightness=204
index=1; brightness=153
index=1; brightness=102
index=1; brightness=51
Voshli_v_IF
index=1; brightness=0
Go to the next LED
index=2; brightness=0
index=2; brightness=51
index=2; brightness=102
index=2; brightness=153
index=2; brightness=204
Voshli_v_IF
index=2; brightness=255
index=2; brightness=204
index=2; brightness=153
index=2; brightness=102
index=2; brightness=51
Voshli_v_IF
index=2; brightness=0
Go to the next LED
index=3; brightness=0
index=3; brightness=51
index=3; brightness=102
index=3; brightness=153
index=3; brightness=204
Voshli_v_IF
index=3; brightness=255
index=3; brightness=204
index=3; brightness=153
index=3; brightness=102
index=3; brightness=51
Voshli_v_IF
index=3; brightness=0
Go to the next LED
index=4; brightness=0
index=4; brightness=51
index=4; brightness=102
index=4; brightness=153
index=4; brightness=204
Voshli_v_IF
index=4; brightness=255
index=4; brightness=204
index=4; brightness=153
index=4; brightness=102
index=4; brightness=51
Voshli_v_IF
index=4; brightness=0
Go to the next LED
index=5; brightness=0
index=5; brightness=51
index=5; brightness=102
index=5; brightness=153
index=5; brightness=204
Voshli_v_IF
index=5; brightness=255
index=5; brightness=204
index=5; brightness=153
index=5; brightness=102
index=5; brightness=51
Voshli_v_IF
index=5; brightness=0
Go to the next LED
index=6; brightness=0
index=6; brightness=51
index=6; brightness=102
index=6; brightness=153
index=6; brightness=204
Voshli_v_IF
index=6; brightness=255
index=6; brightness=204
index=6; brightness=153
index=6; brightness=102
index=6; brightness=51
Voshli_v_IF
index=6; brightness=0
Go to the next LED
index=7; brightness=0
index=7; brightness=51
index=7; brightness=102
index=7; brightness=153
index=7; brightness=204
Voshli_v_IF
index=7; brightness=255
index=7; brightness=204
index=7; brightness=153
index=7; brightness=102
index=7; brightness=51
Voshli_v_IF
index=7; brightness=0
Go to the next LED
index=6; brightness=0
index=6; brightness=51
index=6; brightness=102
index=6; brightness=153
index=6; brightness=204
Voshli_v_IF
index=6; brightness=255
index=6; brightness=204
index=6; brightness=153
index=6; brightness=102
index=6; brightness=51
Voshli_v_IF
index=6; brightness=0
Go to the next LED
index=5; brightness=0
Подозреваю, что возможно, что-то не так в этой строке
#define TOTAL sizeof(leds)/sizeof(byte) // вычисляем сколько всего у нас светодиодов
Хотелось бы конечно лог файл нормальный сделать, чтобы всё было действительно логично
то есть при переходе по светодиодам "Вперед" выводилось бы "Go to the next LED", а "Назад" - "Back to the prev_LED"
Только, я вот не понимаю, как это можно реализовать! Подскажите пожалуйста!
...Значит вам нужно либо еще дополнительно делать analogWrite при переходе, либо менять brightness уже после проверок (тогда к моменту проверки у вас brightness и состояния самого леда будут совпадать).
Чесно говоря, не представляю, как это можно вообще выключить светодиод без дополнительного AnalogWrite с нулевым значением! Разве он не будет мигать дальше???
Ну осталось типы подправить (справитесь? Вроде тут уже и я и step962 "обнамекались" об этом :) И убедится что "все рабоает" не только визуально (глаз может и обманывать), но и по логу.
Странно, но и без изменения типов прога работает нормально! Странный глюк возникает, когда количество светодиодов в массиве задавать не типом byte, а int !!! Прога ошибается в подсчете количества светодиодов в два раза! Подключено и задано 4-ре, она же думает, что их 8 (от0 до7)!
Подозреваю, что возможно, что-то не так в этой строке
#define TOTAL sizeof(leds)/sizeof(byte) // вычисляем сколько всего у нас светодиодов
Наконец-то понял в чём ошибка при подсчете элементов массива! И почему разница ровно в 2 раза! int как раз и занимает в 2 раза больше памяти, чем byte, поэтому делить нужно правильно указывая тип!
Поменял эту строку на
#define TOTAL sizeof(leds)/sizeof(int) // вычисляем сколько всего у нас светодиодов
Программа заработала нормально!
лог файл
index=0; brightness=0
index=0; brightness=51
index=0; brightness=102
index=0; brightness=153
index=0; brightness=204
Voshli_v_IF
index=0; brightness=255
index=0; brightness=204
index=0; brightness=153
index=0; brightness=102
index=0; brightness=51
Voshli_v_IF
index=0; brightness=0
Go to the next LED
index=1; brightness=0
index=1; brightness=51
index=1; brightness=102
index=1; brightness=153
index=1; brightness=204
Voshli_v_IF
index=1; brightness=255
index=1; brightness=204
index=1; brightness=153
index=1; brightness=102
index=1; brightness=51
Voshli_v_IF
index=1; brightness=0
Go to the next LED
index=2; brightness=0
index=2; brightness=51
index=2; brightness=102
index=2; brightness=153
index=2; brightness=204
Voshli_v_IF
index=2; brightness=255
index=2; brightness=204
index=2; brightness=153
index=2; brightness=102
index=2; brightness=51
Voshli_v_IF
index=2; brightness=0
Go to the next LED
index=3; brightness=0
index=3; brightness=51
index=3; brightness=102
index=3; brightness=153
index=3; brightness=204
Voshli_v_IF
index=3; brightness=255
index=3; brightness=204
index=3; brightness=153
index=3; brightness=102
index=3; brightness=51
Voshli_v_IF
index=3; brightness=0
Go to the next LED
index=2; brightness=0
index=2; brightness=51
index=2; brightness=102
index=2; brightness=153
index=2; brightness=204
Voshli_v_IF
index=2; brightness=255
index=2; brightness=204
index=2; brightness=153
index=2; brightness=102
index=2; brightness=51
Voshli_v_IF
index=2; brightness=0
Go to the next LED
index=1; brightness=0
index=1; brightness=51
index=1; brightness=102
index=1; brightness=153
index=1; brightness=204
Voshli_v_IF
index=1; brightness=255
index=1; brightness=204
index=1; brightness=153
index=1; brightness=102
index=1; brightness=51
Voshli_v_IF
index=1; brightness=0
Go to the next LED
index=0; brightness=0
index=0; brightness=51
index=0; brightness=102
index=0; brightness=153
index=0; brightness=204
Voshli_v_IF
index=0; brightness=255
index=0; brightness=204
index=0; brightness=153
index=0; brightness=102
index=0; brightness=51
Voshli_v_IF
index=0; brightness=0
Go to the next LED
index=1; brightness=0
index=1; brightness=51
index=1; brightness=102
index=1; brightness=153
index=1; brightness=204
Voshli_v_IF
Хотелось бы конечно лог файл нормальный сделать, чтобы всё было действительно логично
то есть при переходе по светодиодам "Вперед" выводилось бы "Go to the next LED", а "Назад" - "Back to the prev_LED"
Только, я вот не понимаю, как это можно реализовать! Подскажите пожалуйста!
Подумал вот и решил добавить в прогу такой вот кусочек кода:
if (index <= (TOTAL-1) && index < (index + ledAmount)){Serial.print("Go to NEXT_LED >>>");Serial.println();}
else {Serial.print("<<< Go to PREV_LED");Serial.println();}
Теперь прога не только работает нормально, но и выдает логичный и понятный (по крайней мере я так думаю) лог файл!
Полный вариант проги:
int brightness = 0; // уставливаем начально значение яркости
int fadeAmount = 51; // шаг приращения/убывания яркости
int ledAmount = 1; // шаг перехода между светодиодами
int leds[]={6,9,10,11} ; // список пинов диодов, подключенных в PWM выходам
int index=0; // индекс в массиве leds текущего диода
#define TOTAL sizeof(leds)/sizeof(int) // вычисляем сколько всего у нас светиков
void setup() {
Serial.begin (9600);
for(int i=0;i<TOTAL;i++)pinMode(leds[i],OUTPUT); // все на выход
}
void loop() {
analogWrite(leds[index], brightness);
Serial.print("index=");Serial.print(index); Serial.print("; brightness=");Serial.print(brightness); // и так далее, любые переменные которые нас интересуют
Serial.println();
// измением значение в переменной для яркости
brightness = brightness + fadeAmount;
// при достижение крайних значений для яркости
// меняем знак переменной шага приращения/убывания яркости
if (brightness == 0 || brightness == 255) {
fadeAmount = -fadeAmount ;
Serial.print("Voshli_v_IF");Serial.println();
if(brightness==0){ // пора переходить к следующему диоду
analogWrite(leds[index], 0); // полностью гасим текущий
Serial.print("index=");Serial.print(index); Serial.print("; brightness=");Serial.print(brightness);Serial.println();
if (index <= (TOTAL-1) && index < (index + ledAmount)){Serial.print("Go to NEXT_LED >>>");Serial.println();}
else {Serial.print("<<< Go to PREV_LED");Serial.println();}
index=index+ledAmount; // переходим к следующему
if(index==(TOTAL-1) || index==0) ledAmount = -ledAmount;
}
}
// делаем паузу для достижения плавного наращивания/убывания яркости
delay(100);
}
P.S. А строки 34, 35 проги можно было как-то сократить??? Интересно знать мнение специалистов! Подскажите пожалуйста!
Ну, если не рассматривать идею удаления отладочного вывода (согласитесь, сокращение при этом будет - ого-го ;)), то вот это
index < (index + ledAmount)
сократив одинаковые члены в левой и правой частях, можно записать как
0 < (0 + ledAmount)
или - что привычнее - как
ledAmount>0
ну, а если учесть, что 38-я строка по определению ограничивает значения index диапазоном [0..TOTAL-1], то ... что? Правильно - выкидываем нафиг первую проверку. В итоге получаем:
if(ledAmount>0) бла-бла-бла
Что в приблизительном переводе на общечеловеческий язык означает: "если ledamount положительный. то перебираем светодиоды вверх по индексу, в противном случае - вниз". Почти дословно то, что вы генерируете своей отладкой. Как сокращать это выражение дальше - не представляю. Может быть общество поможет ;)
Наконец-то понял в чём ошибка при подсчете элементов массива! И почему разница ровно в 2 раза! int как раз и занимает в 2 раза больше памяти, чем byte, поэтому делить нужно правильно указывая тип!
С определением размера массива - верно. Но вот скажите, на кой кляп тут вообще массив int-тов? Вы где-то видели дуину с пинами больше 255? Или попадались дуины с отрицательными пинами?
А index зачем стал int-том? У вас может быть отрицательное количество диодов? Или ихм может быть "пару тысяч".
Почитайте типы. Не нужно их "подбирать" пока не заработает. Это же не магия где "нужное слово угадать нужно". Тут важно именно понимание. Почему для index взяли byte, а для ledAmount int (хотя экономней был бы char)
Я уже подсказывал, см. сообщения #62 и #66 содержат исходники с подробнейшими комментариями, где можно увидеть, щас..
в #62 сообщении строки с 45 по 83 - цикл изменеия яркости, там есть все проверки.
Более того в сообщении #66 шаг изменения яркости меняется в случайном порядке (строки 126-127), и всё та же функция изменения яркости нормально работает (см. строки 46 - 83).
Позвольте спросить, обязательно ли ставить скобки? В примере, который Вы привели, нету скобок, окружающих end_led+amount (15 строка кода)!
Позвольте спросить, обязательно ли ставить скобки? В примере, который Вы привели, нету скобок, окружающих end_led+amount (15 строка кода)!
А попробовать? 99% что не обязательно. Просто не хотел хмурить мозг и вглядыватся в порядок операций на конкретном месте. Если в мыслях они у меня должны вначале сложится, а потом все остальное - ну так я и их поставлю. Лишними не будут :)
Если я четко вижу что порядок операций тут однозначен - можно опустить (а можно не опускать). Вообщем тут они не от "синтаксиса языка", а "как в математике". Просто обозначить какие операции должны первыми идти. Или даже просто "выдилить визуально", что-бы глазами легче вспринималось.
P.S. Пример с синусойдой уже не актуален. См. дальше :)
Отличный код, компактнее наверное и не придумаешь..
Да и придумать что-то получше Вашей программы (с использованием массива для вызова из него номеров светодиодов) вряд ли кому-то удасться!
Но я так и недокумекал, как сделать так, чтобы огонек бежал назад (ячейки массива вызывались в обратном порядке! Пробовал писать и так:
и так:
Всё равно светодиоды в обратном порядке не переключаются!
Подскажите пожалуйста, что здесь написано неправильно!
Подсказка: TOTAL - это количество элементов. А index - это индекс :) Причем в C нумерация массива идет С НУЛЯ! Поэтому какий индекс будет у последнего элемента?
Может и еще "что-то" есть, но уже не сегодня смотреть буду.
Подсказка: TOTAL - это количество элементов. А index - это индекс :) Причем в C нумерация массива идет С НУЛЯ! Поэтому какий индекс будет у последнего элемента?
На единичку меньше, чем количество элементов!
Большое спасибо за подсказку!
Написал вот так:
Но в обратном порядке светодиоды переключаться почему-то всё равно не хотят!
Но в обратном порядке светодиоды переключаться почему-то всё равно не хотят!
Ну значит есть ошибка. Есть расхождение между "ментальной моделью" и тем что написано в коде. И нужно научится ее находить (работа кодера-программера на 80-90% из этого и состоит. это основное "время-провождение" :) Поэтому и важна "читабельность" :) Не научившись искать-исправлять-разбиратся - программить вообще не возможно. Никакой гугл не поможет найти ошибку в собственной логике, а на "помощь извне" - тоже не всегда можно расчитывать
Правда есть хитрость: иногда нужно объяснить кому-то "вот смотри, у меня все правильно - работает это вот так......" *&#### Понял! Вот собака. Часто "объясни другому" почему-то работает магически. Хотя если самому себе тот же текст "проговаривать" - не помогает :(
Ладно, вернемся к нашим баранам.
Находить можно двумя способами. Либо "крутить в голове" (на листочке бумаги). Возмите свои переменные, присвойте им какие-то значение (мысленно), лучше "граничные", там где по вашему "должно что-то происходить".
И дальше идите по каждой строчке кода и выполняйте ее в голове. При index=1; В стороке n - не меняется, n+1 - не меняется, n+2 - о!, увеличился, стал index=2. Идем дальше, а тут у нас ledAmount поменял знак... идем дальше index стал.... ;%№%; а должен был .....
Если сложно представить и "не получается", ну значит возложим это на комп. Сделаем Serial.begin(...) в setup(), а возле analogWrite поставим
Увеличим delay(), что-бы данные бежали не так быстро, открываем Serial монитор и смотрим что у нас происходит. Ищем где "что-то пошло не так". Потом ищем в коде строчку, которая, по нашему мнению, должна была что-то сделать, но не сделала. Всматриваемся в нее. Если она "вроде все правильно", но там есть какие-то переменная - значит начинаем и за ней следить. Убеждаемся что к нужному моменту она имеет значение которое мы ожидаем. Если нет ... аналогично ищем "почему нет?". Где для нее "что-то пошло не так".
Еще один простой способ, воспользоваться отладчиком и пройти программу по шагам. Поскольку здесь прерываний нет, это будет проделать легко, воспользуйтесь этим замечательным инструментом: http://sourceforge.net/projects/dumpmon/files/
Рекомендую. Посмотрите примеры, там всё просто.
Не, думаю, все-таки для начала нужно разобратся как самому через Serial дебагать. Иногда, все-таки нужно и "выводить по условию" и "что-то подхачить" и т.п.
Вещь, конечно, полезная. Такие вещи однозначно должны идти "в копилку". Но не всегда приминима (когда памяти "ой-ой", подключать любую внешнюю либу, что-бы посмотреть одну переменную - ой не хочется).
Да и "все просто" - это для нас с вами. А новичку, даже не забыть dumpmonLoop(); вставить и то может быть проблемой (и понять что это за "магия"). Не забывайте про банальный перегруз информацией. Это как в машине: новичку трудно следить за дорогой, потому что еще приходится думать какой ногой педаль нажимать.
Да банально, даже забрать себе эту либу. Нынче далеко не все знают что такое .tar.gz (про склонировать git репозиторий я вообще молчу). Ну даже если случайно стоит архиватор... так ведь либу еще нужно уметь происталить (не велика премудрость, но ведь в первый раз тоже разобратся нужно). А она еще явно, под старое ide писалось. Не дай бог вылезет стандартное "WProgram.h не нахожу".
Так что, безусловно, спасибо за наводку. Взять ее на вооружение нужно, но после того как скетч "дожмется" без нее (благо там чих, в одной строчке поправить осталось :)
Либа свежая, я на леонардо тестил. Отчасти ты прав, но иногда при пошаговом выполнении много нового узнаешь. Думаю ТС разберется сам, юзать или нет.
Хотя лентяев тут хватает :)
Надеюсь никого не обидел
... ищем в коде строчку, которая, по нашему мнению, должна была что-то сделать, но не сделала. Всматриваемся в нее. Если она "вроде все правильно", но там есть какие-то переменная - значит начинаем и за ней следить. Убеждаемся что к нужному моменту она имеет значение которое мы ожидаем. Если нет ... аналогично ищем "почему нет?". Где для нее "что-то пошло не так".
Наконец-то нашел! Заменил строку
на
Полностью исправленный вариант:
Первоначально в этом коде я умудрился сделать 2 ошибки!
1. Я не учел, что нумерация в массиве начинается с нуля! (строка 29)
2. Не задействовал переменную ledAmount в 28 строке!
Первую ошибку я исправил только после явной подсказки! Вторую долго и нудно искал, анализируя значения переменных, полученные через "Serial монитор"!
Чтобы упростить себе задачу я значительно увеличил значение шага переменной для изменения яркости
и сократил количество светодиодов до трех
То, что я увидел стало неожиданностью! index всё увеличивался и увеличивался, попутно при этом туда-сюда менялась brightness (яркость). В общем, проанализировав это, я понял, что так в принципе и должно быть! Но то, что началось дальше (на значении index=20) вызвало у меня полное недоумение! Как переменная может принимать значания не кратные шагу её увеличения/уменьшения??? И почему после index=20 вдруг начинает идти index=94 ???
Кому интересно можете посмотреть:
index = index+ledAmount;
Верно :) Облегчение?
Полностью исправленный вариант:
Ну так он работает или нет? :)
Первоначально в этом коде я умудрился сделать 2 ошибки!
Поверте это немного и обычно. И вы никогда не прекратите их делать. Навыки только позволят сократить время на а) как быстро обнаружить что "что-то так", б) локализовать проблему, в) исправить.
и сократил количество светодиодов до трех
на значении index=20
....
я увидел стало неожиданностью!
Я тоже. Просто интерестно, при длине массива в три штуки, для какого, по вашему, пина дуины выполнится anaglogWrite(leds[index],...) при index=20?
И почему после index=20 вдруг начинает идти index=94 ???
Можно гадать, но обратите внимание, на
Как вы думаете, это случано так совпало что index=94, в точности равен brightness предыдущего loop минус шаг (145-51)?
Кому интересно можете посмотреть:
Не интерестно. Какой смысл в логе незвестного скетча? Скетч который выдает этот лог - вы не превели. Запустить, проверить, пощупать его никто не может. Известно только что вы в нем что-то меняли (количество диодов, шаги, может еще что-то). Вообщем "экстрасенсы в отпуске"
P.S. А вообще вы молодец. Не опускаете руки, ищите, дожимаете, пытаетесь осознать если происходит что-то "непонятное, не логично" - именно так и надо :)
Это для развлечения, между разборками. В программе есть "загадка", программа работает по другому алгоритму, если добавить одну строку и перекомпилировать программу.
В начале программы есть некоторые параметры, которые позволяют менять характер работы светодиодов, я поставил 4, больше у меня нет ;) На трех тоже всё работает.
Да, я особо не заботился о некоторых вещах, на другие обращал очень пристальное внимание, потому где то кривости могут быть. Зато прикольно моргает. Спасибо ТС, если бы он так долго не разбирался, я бы и не написал этот новогодний опус.
Это для развлечения, между разборками. В программе есть "загадка", программа работает по другому алгоритму, если добавить одну строку и перекомпилировать программу.
К сожалению, нет диодов под руками, а по Serial разгадывать - не так захватывающе.
Меня сейчас другая "загадка" мучает. На MAC ноуте каком-то видел. В режиме sleep, а него индикатор не просто "мигает", а разгорается и гаснет. Причем не линейно. Эта не линейность и частота подобранна таким образом, что без всяких объяснений, у всех, первая ассоциация приходящая в голову от простого взгляда, даже без наводящих вопросов "дыхание во сне". Интуитивно понятно "ноут спит" :)
Вот реально кажется что он "дышит" этим светодиодом! Завораживает. Такой эффект обычным светиком!
Но воспроизвести - пока не получается. Пытался нагуглить где-нибудь у физиологов, параметры дыхания спящего человека - не вдача. Метод "научного тыка" - не прокатил. Хоть бери и ище в загашниках датчик дыхания и записывай себя :)
Update: вот как всегда. Поплакался что "не могу найти" и нашел http://thecustomgeek.com/2011/06/17/breathing-sleep-led/ Правда на видео эффект ощущается "слегка". На встроенном LED-де тоже "слегка", нужно будет с белым попробовать (ну и код, конечно, переписать в что-то более вменяемое).
Мне кажется что типа синусоиды, потому что при спокойном дыхании на крайних точках дыхание как бы приостанавливается, точнее замедляется. Щас попробую, шагом поиграться или просто тупо синус использовать, точнее косинус, во, забыл уже, надо погуглить
Я в предыдущие сообщение добавил найденную реализацию.
Я посмотрел в гугле, дыхание - примерно пила (быстрый подъем, потом несколько более медленный спад). Короче - это уже скушная задача, просто подобрать параметры. ;) Я поподбирал, что то такое получается, в общем немного работы и можно подобрать для себя приятный ритм "дыхания" светодиодов. Мне такое скушно :)
Хотя вот вариант, на котором я закончил исследование, чего зря пропадать. Не совсем дыхание, но прикольней "дышат". Здесь реализована пила, у которой спад медленней чем нарастание примерно в два раза:
Кому интересно можете посмотреть:
Не интерестно. Какой смысл в логе незвестного скетча? Скетч который выдает этот лог - вы не превели. Запустить, проверить, пощупать его никто не может...
Я не использовал для анализа кода никаких скетчей, а просто, как Вы и советовали, прописал в void setup() Serial.begin (9600); и добавил в прогу кусочек кода, выводящий значения переменных через Serial порт.
А всякие регистры, стеки, дампы памяти пр. - для меня это "темный лес"? В ассемблере абсолютно не разбираюсь. Хотелось бы конечно освоить, но не знаю, осилю ли я его?
Решил начать писать программы для микроконтроллеров с Arduino - говорят, проще этой платформы нету ничего! Но, как видите, с простейшей программой "бегущего огонька" на светодиодах я разбираюсь уже второй или третий день! Наконец-то она заработала, как нужно!
P.S.: Большое спасибо всем, кто помог мне и указал на ошибки!
Забейте на ассемблер, для простых и учебных задач здесь вполне достаточно С/С++.
Обычно ассемблер нужен во времязависимых задачах, когда нужно быстро сработать и/или рассчитать задержки на выполнении программы. А если посмотреть реализацию, например analogWrite, то там столько кода, что мало не покажется, потому расчитать задержку - нереально. Но за всё нужно платить, либо просто, либо эффективно.
Тем более с ассемблером будут проблемы с переходом на другую Ардуино, в частности Uno и Leonardo настолько разные по пинам, что мало не покажется.
Удачи!
Я не использовал для анализа кода никаких скетчей,
Да ну? :) В терминологии ардуины "скетч" это есть программа которую вы заливаете в дуину. В обычных языках называют "исходник, исходный текст", а вот тут они зачем-то такой термин придумали. sketch- эскиз. Видимо что-бы подчеркнуть что "все очень просто" :) Так что любой пример выше, который "целостный" и можно залить в дуину - это скетч :)
а просто, как Вы и советовали, прописал в void setup() Serial.begin (9600); и добавил в прогу кусочек кода, выводящий значения переменных через Serial порт.
А всякие регистры, стеки, дампы памяти пр. - для меня это "темный лес"? В ассемблере абсолютно не разбираюсь. Хотелось бы конечно освоить, но не знаю, осилю ли я его?
Дык вас пока никто не призывал. В стеки, дампы и проч. Вот то что у вас получилось после того как "добавил как вы советовали", "поменял шаг", "уменьшил количество диодов" - вот это и нужно было дать сюда в качестве примера. То есть "сама программа" и "что выводит" в паре. Что-бы любой мог повторить ваши "непонятнки" и как index становится 98 и проч. А то вы лог дали, а "кто его делает" - нет. А явно же там где-то очепятались или еще что-то. Как иначе объяснить почему у вас яркость и индекс скачут, не видя кода который вы запускаете? Вы задали вопрос, но инфу для анализа-ответа дали только частично.
На да ладно. Если он не сохранился - значит эти чудеся останутся тайной. Конечный вариант заработал - и ладно.
На да ладно. Если он не сохранился - значит эти чудеся останутся тайной...
Нет .. скорее всего не не останутся! Глючный вариант (где index скачет с 20 на 94) я еще не удалил! Привожу в полном объеме! Все, кому не лень, могут загрузить его с свою плату, а затем, жмакнув на кнопочку "Монитор порта" посмотреть, что там твориться!
Может кто-нибудь и разберётся, в чём причина появления подобных глюков
Может кто-нибудь и разберётся, в чём причина появления подобных глюков
На самом деле и запускать не пришлось. Я, где-то в самом начале ветки, рекомендовал вам пойти в раздел програмирования (в шапке сайта) и ознакомится со всеми типами данных. Нет типов которые "лучше и хуже". Нельзя сказать "всегда используйте byte" или "всегда int". Нужно танцевать от того какие числа ожидаются в переменной (знаковость, диапазон, целые/вещественные) и т.п. И исходя из этого выбирать тип переменной. Минимально-достаточный.
Так же, повторюсь "но там есть какие-то переменная - значит начинаем и за ней следить". Раз те переменные что мы уже смотрим ведут себя не правильно, значит по аналогии стоит посмотреть еще и на те переменные от которых они зависят. И там бы вы сразу увидели чудеса еще круче :)
Вообщем перепроверте типы переменных. Так же, кроме вывода в Serial значений самих переменных, можно втыкитьва что-то типа Serial.println("Zahli v IF");. Что-бы убедится действительно заходим в какой-то IF когда собирались (или узнать о том, что почему-то не заходим. посмотреть какие значения переменных были, перед тем как условие не сработало и т.п.).
Запускать, подробней смотреть - буду уже завтра.
...кроме вывода в Serial значений самих переменных, можно втыкитьва что-то типа Serial.println("Zahli v IF");. Что-бы убедится действительно заходим в какой-то IF когда собирались (или узнать о том, что почему-то не заходим. посмотреть какие значения переменных были, перед тем как условие не сработало и т.п.).
Спасибо за очень толковый совет! Это действительно момогает в отладке - можно сделать нечто вроде простейшего log-файла без вспомогательных программ!
Я только-что добавил несколько строк в глючную прогу, но ранее появлявшийся глюк (с перескоком index=20 на index=94) исчез! Но теперь глюк начинает появляться после index=24)
В общем, у меня промелькнула мысля, что это в переменную больше не влазит! Потому, что она задана как byte! Но неужели каждый index съедает 10 байт, а не один, потому что значения яркости для index меняются 10 раз (от 0 до 255 с шагом 51 сначала туда, потом обратно)
Или я неправильно рассуждаю? Привожу код проги и лог-файл, выведенный через Serial
log-файл для тех, кому интересно:
Я только-что добавил несколько строк в глючную прогу, но ранее появлявшийся глюк (с перескоком index=20 на index=94) исчез! Но теперь глюк начинает появляться после index=24)
Как выглядит этот "глюк после index=24"? На приведенной вами полубесконечной простыне начало 25-го цикла выглядит ровно так же, как и начало предыдущих двадцати четырех. Потом - как я понимаю - конец простыни. Никакого перескока углядеть не удается.
В общем, у меня промелькнула мысля, что это в переменную больше не влазит! Потому, что она задана как byte! Но неужели каждый index съедает 10 байт, а не один, потому что значения яркости для index меняются 10 раз (от 0 до 255 с шагом 51 сначала туда, потом обратно)
А с чего вы взяли, что index съедает 10 байт? А не 2? Или 38?
По поводу "больше не влазит".
В старом варианте скетча у вас начальное значение для brightness равнялось пяти, а шаг изменения составлял 51. Поэтому получалось:
1-е приращение: 5+51=56 все в порядке
2-е приращение: 56+51=107 все в порядке
3-е приращение: 107+51=158 все в порядке
4-е приращение: 158+51=209 все в порядке
5-е приращение: 209+51=262 все в порядке? Отнюдь. Byte позволяет хранить значения от 0 до 255. При попытке втюхать в байт число, превышающее 255, происходят два события:
1) в байт загружаются 8 младших битов. Для 262 (b100000110) это 6 (b00000110).
2) наличие единички в 8-м бите (ну и в более старших) приводит к генерации прерывания по переполнению. Обработку которого разработчики Ардуино скрыли от пользователей.
Как результат, на 5-м приращении у вас получалось 209+51=6. Глюк, как вы это называете.
В новом варианте скетча значения начальной яркости и шага ее приращения имеют одно из тех удачных соотношений, когда значение яркости на одном из шагов принимает значение тютелька в тютельку равное 255, т.е. условие на проверку максимума уже выполнилось, а переполнения еще не произошло. В обратную сторону тоже все нормально - яркость получает-таки значение 0.
А с index (который byte) срыва мозгов (от превышения разрядности) можно ожидать на 255-й итерации.
Обратите внимание на строки 2 и 28 последнего опубликованного варианта вашего скетча.
Во второй строке переменная определяется как byte, т.е. изменяющаяся в диапазоне от 0 до 255, а в 28-й ей изменяют знак. Нехорошо. Уж лучше char тогда взять. То же самое можно сказать и по поводу ledAmount. Да и для brightness тип int более уместен - негоже производить эксперрименты с приращением/сравнением величин в опасной близости от границ диапазона их изменения.
И, наконец, обратите пристальное внимание на строчку 6 (особенно на комментарий):
byte
index=0;
// индекс в массиве leds текущего диода
и на то, что вы выводите с отладочной информацией:
index=5, index=25 и так далее...
В каком диапазоне у вас должен изменяться index? Не [0..2] случайно? Так какого ... он принимает значение 3 и так далее - до полного ступора программы? Не стоит ли здесь после строки
if(index==(TOTAL-1) || index==0) ledAmount = -ledAmount;
добавить
if(index==TOTAL) index = 0;
чтобы сразу же после выхода индекса за верхнуюю границу массива начать отсчет сначала?
мысля, что это в переменную больше не влазит
....
Или я неправильно рассуждаю? Привожу код проги и лог-файл, выведенный через Serial
Правильно рассуждаете. Только чуть-чуть не продолжили свою мысль (и не сделали вывод из того что уже успели "нарассуждать"). Нужно было попытатся применить это рассуждение в коде.
"Не влезть" можно в две стороны. Как с торону слишком больших чисел, так и в сторону "слишком маленьких". Я ведь не зря жирным выделил слово "беззнаковость" и сказал "смотрите на переменные от которых зависят дурящие index,brightness)
Вообщем еще раз смотрите какие значения вы ожидаете в переменных и подбирайте им подходящие типы (step962 вообщем-то уже рассписал детально)
if(index==TOTAL) index = 0;
Это не спасет отца русском демократии :) "отрицательный" ledAmount может нам дать прыжок Index совсем не на 1-ницу. И мы проскочим эту проверку. Тут нужно скорее index>=TOTAL
Для топикстартера: обнуление index=0 в данном случае не "решение проблемы", а скорее "аварийная заплатка". Срабатывание этой строчки уже означает что где-то раньше логика нарушилась. Попытка минимизировать катастрофу от этого. По хорошему кроме index=0 нужно еще, обязательно(!), в этом случае выводить в Serial "Караул! Индекс вышел за границы массива". И возможно даже останавливать скетч полностью. В вашем случае это не "катастрофа", но обычно выход за границы означает полную непредсказуемость дальнейшего поведения. Могут входы, случайно, на выход повключатся (и повыгорать если там снаружи что-то подается). Да банально, к примеру, если вы рулите роботизированной сварочной головкой весом в 300 кг, двигающеся со скоростью 9 м/c, то лучше вывести ошибку и остановится полностью, чем начать дергатся непонятно куда и как :). Рядом с такой штукой стоять даже когда она не глючит - страшно, даже когда знаешь что у нее "длины руки" не хватит пол- метра что-бы тебя достать :)
if(index==TOTAL) index = 0;
Это не спасет отца русском демократии :) "отрицательный" ledAmount может нам дать прыжок Index совсем не на 1-ницу. И мы проскочим эту проверку. Тут нужно скорее index>=TOTAL
А это было бы следующим шагом избавления от мелочей, мешающих правильному прохождению программы: Избавление от проверок на равенство, которые нормально работают только при единичном инкременте/декременте, а при произвольном значении шага приращения проскакиваются просто на ура, что мы и видем (видели) на примере оперирования с brightness.
"отрицательный" ledAmount может нам дать прыжок Index совсем не на 1-ницу.
Нам может, топикстартеру - нет. Ведь у него index просто инкрементируется (index++), без использования ledAmount.
А это было бы следующим шагом избавления от мелочей, мешающих правильному прохождению программы:
Не, не... при "правильном прохождение" эта проверка вообще не нужна. Она никогда не выполнится. Сработает более раннее index==(TOTAL-1). Это же как раз "аварийный клапан". Поэтому либо "больше или равно" или "вообще убрать". От index==TOTAL - нет пользы при любых раскладах.
P.S. И, кстати, index++ - топик стартер уже нашел и пролечил (сообщение #60). Тут просто уже идет разбирательсво "почему-же он так прыгал". То есть "как не допустить переполнения" - уже выяснили. Сейчас просто осмысляем "а как же переполнение работает", почему index++ приводил именно к тамким результатам.
P.S. И, кстати, index++ - топик стартер уже нашел и пролечил (сообщение #60). Тут просто уже идет разбирательсво "почему-же он так прыгал". То есть "как не допустить переполнения" - уже выяснили. Сейчас просто осмысляем "а как же переполнение работает", почему index++ приводил именно к тамким результатам.
А я ваш козырный туз джокером покрою: сообщение #72. ;) Индекс у ТС благополучно пробегает значения от 0 до аж 25. И это при работе с массивом из трех элементов.
P.S. И, кстати, index++ - топик стартер уже нашел и пролечил (сообщение #60). Тут просто уже идет разбирательсво "почему-же он так прыгал". То есть "как не допустить переполнения" - уже выяснили. Сейчас просто осмысляем "а как же переполнение работает", почему index++ приводил именно к тамким результатам.
А я ваш козырный туз джокером покрою: сообщение #72. ;) Индекс у ТС благополучно пробегает значения от 0 до аж 25. И это при работе с массивом из трех элементов.
Не побъете :) Если внимательно прочитаете ветку, то увидите что #72 появился в ответ на просьбу дать СТАРЫЙ код, до фикса, лог которого был опубликован ранее без самого скетча и дальше пытаемся понять как он работает. К тому моменту index++ уже был обнаружен ТС самостоятельно :) И тут скорее идет рассуждение "почему он себя так ведет", чем "что исправить". index++ уже "известный баг". А вот с типами - пока еще в процессе борьбы .
2TC: обратите внимание, что, судя по логу. У вас диод "не гастися" до конца. Вы то перешли "к следующем" при brightness==0, но ведь текущему-то вы 0 - так и не скомандовали. На нем осталась ярокость 51.
Значит вам нужно либо еще дополнительно делать analogWrite при переходе, либо менять brightness уже после проверок (тогда к моменту проверки у вас brightness и состояния самого леда будут совпадать).
Я не даром давал свой пример для развлечения, вопросы с индексами я смотрел достаточно тщательно, думал, может кто посмотрит и увидит как можно делать проверки и т.п. у меня там шаги разные могут быть, недаром в начало скетча вынес изменяемую часть.
судя по логу. У вас диод "не гастися" до конца. Вы то перешли "к следующем" при brightness==0, но ведь текущему-то вы 0 - так и не скомандовали. На нем осталась ярокость 51.
Значит вам нужно либо еще дополнительно делать analogWrite при переходе, либо менять brightness уже после проверок (тогда к моменту проверки у вас brightness и состояния самого леда будут совпадать).
Ещё одна загадка! Предыдущий светодиод НЕ может не погаснуть полностью, поскольку в программе есть строка явно указывающая ему это сделать!
Я думаю дело не в программе, а в том, что для правильного вывода log-файла нужно было добавить ещё одну строчку вывода в Serial port! Вот как выглядел код, "неправильно"( точнее не полностью) показывающий значения переменных.
А вот дополненный вариант:
В Serial он выводит такое (привожу небольшой фрагмент)
Ну проморгал я "// полностью гасим", хотя это и есть "вам нужно либо еще дополнительно делать analogWrite". Не заметил что это уже сделано.
Ну что делать с index++ - вы уже знаете сами. Причем "срочно", как только вы нашли выход за границы массива - дальше можно особо не смотреть. До того как это не пофиксано, с другими глюками можно и не разбиратся. Вероятность что 90% их обусловлена выходом - очень велика. Тут вы легко отделались только потому что читаете из массива, а не пишите в него. Если бы писали, то "чудес" было-бы в пять раз больше (и еще труднее для понимания). Так что "вначале его фиксаем", а потом заново смотрим какие глюки остались (может другие проявлятся начнут).
Ну осталось типы подправить (справитесь? Вроде тут уже и я и step962 "обнамекались" об этом :) И убедится что "все рабоает" не только визуально (глаз может и обманывать), но и по логу.
, но ранее появлявшийся глюк (с перескоком index=20 на index=94) исчез!
Подозреваю, что был какой-то промежуточный, не сохранившийся вариант где вы случайно подкручивали index с помощью fadeAmount. Уж больно подозрительно цифры совпали. В пробах мелькнуло что-то типа (index= brightness - fadeAmount).
Ну осталось типы подправить (справитесь? Вроде тут уже и я и step962 "обнамекались" об этом :) И убедится что "все рабоает" не только визуально (глаз может и обманывать), но и по логу.
Странно, но и без изменения типов прога работает нормально! Странный глюк возникает, когда количество светодиодов в массиве задавать не типом byte, а int !!! Прога ошибается в подсчете количества светодиодов в два раза! Подключено и задано 4-ре, она же думает, что их 8 (от0 до7)!
Вот код
и лог-файл
Подозреваю, что возможно, что-то не так в этой строке
Хотелось бы конечно лог файл нормальный сделать, чтобы всё было действительно логично
то есть при переходе по светодиодам "Вперед" выводилось бы "Go to the next LED", а "Назад" - "Back to the prev_LED"
Только, я вот не понимаю, как это можно реализовать! Подскажите пожалуйста!
...Значит вам нужно либо еще дополнительно делать analogWrite при переходе, либо менять brightness уже после проверок (тогда к моменту проверки у вас brightness и состояния самого леда будут совпадать).
Чесно говоря, не представляю, как это можно вообще выключить светодиод без дополнительного AnalogWrite с нулевым значением! Разве он не будет мигать дальше???
Ну осталось типы подправить (справитесь? Вроде тут уже и я и step962 "обнамекались" об этом :) И убедится что "все рабоает" не только визуально (глаз может и обманывать), но и по логу.
Странно, но и без изменения типов прога работает нормально! Странный глюк возникает, когда количество светодиодов в массиве задавать не типом byte, а int !!! Прога ошибается в подсчете количества светодиодов в два раза! Подключено и задано 4-ре, она же думает, что их 8 (от0 до7)!
Подозреваю, что возможно, что-то не так в этой строке
Наконец-то понял в чём ошибка при подсчете элементов массива! И почему разница ровно в 2 раза! int как раз и занимает в 2 раза больше памяти, чем byte, поэтому делить нужно правильно указывая тип!
Поменял эту строку на
Программа заработала нормально!
лог файл
Хотелось бы конечно лог файл нормальный сделать, чтобы всё было действительно логично
то есть при переходе по светодиодам "Вперед" выводилось бы "Go to the next LED", а "Назад" - "Back to the prev_LED"
Только, я вот не понимаю, как это можно реализовать! Подскажите пожалуйста!
Подумал вот и решил добавить в прогу такой вот кусочек кода:
Теперь прога не только работает нормально, но и выдает логичный и понятный (по крайней мере я так думаю) лог файл!
Полный вариант проги:
Фрагмент лог-файла!
P.S. А строки 34, 35 проги можно было как-то сократить??? Интересно знать мнение специалистов! Подскажите пожалуйста!
P.S. А строки 34, 35 проги можно было как-то сократить??? Интересно знать мнение специалистов! Подскажите пожалуйста!
Ну, если не рассматривать идею удаления отладочного вывода (согласитесь, сокращение при этом будет - ого-го ;)), то вот это
index < (index + ledAmount)
сократив одинаковые члены в левой и правой частях, можно записать как
0 < (0 + ledAmount)
или - что привычнее - как
ledAmount>0
ну, а если учесть, что 38-я строка по определению ограничивает значения index диапазоном [0..TOTAL-1], то ... что? Правильно - выкидываем нафиг первую проверку. В итоге получаем:
if
(ledAmount>0) бла-бла-бла
Что в приблизительном переводе на общечеловеческий язык означает: "если ledamount положительный. то перебираем светодиоды вверх по индексу, в противном случае - вниз". Почти дословно то, что вы генерируете своей отладкой. Как сокращать это выражение дальше - не представляю. Может быть общество поможет ;)
Наконец-то понял в чём ошибка при подсчете элементов массива! И почему разница ровно в 2 раза! int как раз и занимает в 2 раза больше памяти, чем byte, поэтому делить нужно правильно указывая тип!
С определением размера массива - верно. Но вот скажите, на кой кляп тут вообще массив int-тов? Вы где-то видели дуину с пинами больше 255? Или попадались дуины с отрицательными пинами?
А index зачем стал int-том? У вас может быть отрицательное количество диодов? Или ихм может быть "пару тысяч".
Почитайте типы. Не нужно их "подбирать" пока не заработает. Это же не магия где "нужное слово угадать нужно". Тут важно именно понимание. Почему для index взяли byte, а для ledAmount int (хотя экономней был бы char)
Я уже подсказывал, см. сообщения #62 и #66 содержат исходники с подробнейшими комментариями, где можно увидеть, щас..
в #62 сообщении строки с 45 по 83 - цикл изменеия яркости, там есть все проверки.
Более того в сообщении #66 шаг изменения яркости меняется в случайном порядке (строки 126-127), и всё та же функция изменения яркости нормально работает (см. строки 46 - 83).
Ссылки на сообщения #62: http://arduino.ru/forum/programmirovanie/strannaya-i-ne-logichnaya-rabota-prosteishei-programmki-dlya-upravleniya-svet?page=1#comment-20001 и #66: http://arduino.ru/forum/programmirovanie/strannaya-i-ne-logichnaya-rabota-prosteishei-programmki-dlya-upravleniya-svet?page=1#comment-20009
Конечно учатся люди по разному, я в свое время учился по чужим исходникам, постигая их прелести и ошибки, зачем придумывать велосипед?
Удачи!