Задержка (delay) и buzzer
- Войдите на сайт для отправки комментариев
Ср, 03/04/2013 - 10:01
К моей Arduino Mega, к 7 порту подключен buzzer (пищалка). Включаю я его таким образом:
analogWrite(7, 252); // Almost any value can be used except 0 and 255 delay(210); // wait for a delayms ms analogWrite(7, 0); // 0 turns it off
Как видно в этой конструкции есть delay который на несколько микро секунд останавливает работу всего Arduino. Как-то можно избавится от этой остановки?
http://arduino.ru/tutorials/BlinkWithoutDelay
День добрый.
у меня похожий вопрос:
каки способом поставить обратный отсчёт в микросекундах? либо каки способом написать самому такую функцию?
Вот часть моего кода где надо заменить delay на сountdown.
Заранее благодарен
Aleksej
каки способом поставить обратный отсчёт в микросекундах? либо каки способом написать самому такую функцию?
Чтобы ответить на этот вопрос, необходимо понять, чем этот ваш countdown должен отличаться от банального delay.
Ведь это явно не общепринятый обратный отсчет времени - в микросекундном то диапазоне!
>каки способом поставить обратный отсчёт в микросекундах? либо каки способом написать самому такую функцию?
Таким же как и в миллисекундах, только использовать, для получения времени не millis(), а micros()
Только учтите, что велкиой точности - вы уже не добъетесь.
Интересный вопрос, а у меня есть еще один вариант ответа.
Что такое обратный отсчет? Это фиксированный от какого то момента времени отсчет в обратную сторону.
Как можно это реализовать? Например так:
1. Зафиксировать начало отсчета (сохранить текущий micros())
2. В нужное время считать снова micros() и вычесть из зафиксированного значения (см.п.1) двойную разницу между считанным micros() и зафиксированным значением.
Мозг в куче? Если да, то вот формула:
Конечно нужно помнить, что micros переполняется и переходит снова в ноль, но это совсем другая история.
Благодарю за подсказки и ответы,
в этом случае идёт речь о блоке управления ДВС.
В первой стадии программирую корректировку зажигания и угол опережения зажигания вот таблица расчета угла: http://oi49.tinypic.com/107mm53.jpg
Способ обработки:
1. Измеряю интервал между импульсами ВМТ.
2. Выбираем из таблицы нужный угол в виде задержки.
3. Корректирую угол (вакум в коллекторе + температура + итд.)
4. Ставим таймер на время X из таблицы + корректировка.
5. Ну а потом транзистор катушка и поджигаю смесь.
Что требуется запрограммировать.
1. Array со значениями из из таблицы (имеется).
2. Функцию выдачи импульсов (имеется).
3. Задержку (не решил как)
4. Offset для корректировки зажигания (в работе).
4. Таймер для расчёта интервала (имеется).
Если я правильно понял, во время задержки - вам не нужно "заниматся еще чем-то" (мерять датчики и т.п.). То есть скетч можно остановить банальным delay(). Только вам нужно в микросекундах. Значит используем
Arduino - DelayMicroseconds
Но... тут все очень сильно зависит от того сколько именно микросекунд вам нужно. Если там речь идет про единицы микросекуд и десятки - будет очень сложно. И наверное без оцилографа все это - не настроить.
На малых значениях - delayMicroseconds - может врать. Ну и нужно помнить, что в зависимости от платы, вся работа с микросекундами крато 4-рем ил 8-ми (то есть выставить задержку точно в 5-микросекунд - уже не получится никак).
Так же, скорее всего от digitalWrite отказыватся. На таких интервалах - она недопустимо медленная. Нужно Прямое управления выходами через регистры микроконтроллера Atmega
ну и возможно, прийдется, для повышения точности перейти на использование таймеров аппаратных. В легком случае - погуглить библиотеки таймеров готовые, в тяжолых - брать даташит, статьи и разбиратся со всеми этими "регистрами таймеров/пред-делителями и проч". Тут может оказать помощь книжечка Arduino Cookbook автора Michael Margolis (нагугливатся на торрентах) - там вот как раз такие задачи и описаны. Вернее даны "рецепты-примеры" готовые (без особых теорий).
День добрый,
наконец-то заработало, вот код:
теперь буду разбираться с выходами.
Погодите. Ваше решение правомочно, но.... в нем есть маленький подвох. Особенно при использовании микросекунд.
Смотрите. У вас time1 и time2 - unsigned long . Максимальное числе в него влазит 4,294,967,295 . То есть через 4294967295 микросекунд, наступит переполнение и начнется отсчет от нуля.
Прикинем. Это 4294967 миллисекунд, 4295 секунды, 71 минута, или 1 час 11 минут.
То ест где-то через час непрерывной работы, ваша логика time_1 = time_1 + 300000; даст сбой . В time1 в результате сложения, образуется цифра меньше чем текущие время и условие time_1 <= micros() срабоатет сразу, а не через 300 милисекунд, как вы ожидали.
К счастью, лечение тут простое. В time1 - нужно просто запоминать время. Не ничего не добавляя. А вот само условие переписать как
Такой вариант - не подвержен проблеме переполнения.
Кстати, как только вы в этой же манере перепишите и условие time2, вы увидите что вам вообщем-то и не нужно "две переменных", а достаточно одной time и двух условий
if(micros()-time>=300000...
if(micros()-time>=300100...
И еще.
Не знаю специально или нет, но вы понимаете что у вас "отсчет времени" начнется только когда digitalRead(sensor) c HIGHT упадет в LOW? То есть не когда на сенсор прийдет импульс запустится таймер, а когда "волна спадет"? То есть к вашему таймеру, в неявном виде еще добавляется сама длина импульса.
Что-бы "ловить фронт сигнала", а не спад,есть два подхода. Один из них - использовать attachInterrupt()
Второй - запоминать в конце loop текущией значение сенсора, и запускать таймер по условию
Я бы - использовал attachInterrupt. На таких малых интервалах, думаю через него точней будет.
Спасибо за подсказки. Функция attachInterrupt() заработала не сразу, программа делала что хотела подавала хаотично сигнал на выход т.к. attachInterrupt() прерывает Loop() функцию помогли две команды:
вот по этой ссылке можно узнать больше: http://www.arduino.cc/en/Reference/AttachInterrupt
теперь работает нормально, вот код:
Это хорошо что вы нашли про запрет прерываний, но... что-то уже больно радикально. Похоже на избавление от занозы путем ампутации ноги. Возможно и нет другого решения, но "запрещать и не пущать" - лучше в последнюю очередь. Не будем уподоблятся политикам. При запрещенных прерываниях - у вас не идут часы (millis(), micsros()), Serial - теряет данные, импульсы - будут пропускатся.
Вообщем лучше, все-таки выяснить
а. Какому именно кусочку кода мешают прерывания и постаратся только его оборачивать в запрет. Только "самое критичное". Держать "в запрете прерываний" 90% процентов процессорного времени - это, мягко говоря - стремно.
б. Понять "а почему же они вообще у вас происходят"? Откуда берутся сработки прерываний? Я же, так понимаю, сами импульсы идут реже чем 300 милисекунд? Следовательно, по идее они должны происходить только когда "loop крутится и ждет", а значит ничему они не помешают.
Есть подозрение что "мусорные сработки" провоцирует само включение индуктора. Есть возможность это отсделить, не происходит "нежданное" прерывание именно в момент дергания?
А еще вы забыли про volatile (перечитайте attachInterrupt(), раздел "замечания по использованию").
И еще "напрямую" вы немного не аккуратно сбрасываете/выставляете биты. Возможно в вашем случае и не мешает это, но... лучше не привыкать. Вот смотрите в строке 12, направление порта вы выставили "аккуратно", поменяли только тот бит который вам нужно, остальные оставили "как есть". А вот в строках 23,24 - ставите нужный вам бит и насильно обнуляете все остальные. Не глядя.
Кстати не обязательно "работать только напрямую" или "только чере digitalWrite" - вполне можно миксовать эти два подхода. Например использовать pinMode что-бы не хмурить мозг (все равно в этот момент скорость не важна), а уж сами ноги - дергать через PORTD. Не скажу что "миксовать нужно" (в единообразии - тоже есть плюсы), просто вот "есть такая лазейка для лени" :)
А еще вы забыли про volatile (перечитайте attachInterrupt(), раздел "замечания по использованию").
Не получается применить attachInterrupt(), я переписал программу работает на первый взгляд корректно и исправил управление входами также добавил второй канал т.к двигатель имеет два цилиндра. Вот код:
Вопрос, можноли использовать регистры входов как условие? Например: if (PORTD == 00100000)
>Вопрос, можноли использовать регистры входов как условие
Можно.
> if (PORTD == 00100000)
Будет глючить. Так вы проверяете состояние сразу всех битов. А так как остальные у вас выставлены в режим входа, то могут ловить помехи из эфира. И условие может сработать, а может и нет. if(PORTD & B010) - проверяем только второй бит.
И у установкой/стяния битоввы на хомутали. Ну как минимум потому что опять устанавливаете PORTD не глядя какое у него текущие состояние. Посмотрите на свою же строку 8-мь. Вы там в регистре устанавливаете два бита. Все верно, почему же когда аналогичная задача - установить биты в строке 22 - у вас вдруг вылез Xor каких-то двух чисел?
Вообщем ставит бит так:
Можно использовать сокращенный синтаксис, раз мы PORD и справа и слева используем.
А что-бы глазами не высчитвать количество нулей и было сразу видно что это имено седьмой бит - можно сдвиговую операцию применить
Теперь снимаем бит (xor у нас выйдет на сцену когда мы захотим "переключать биты", а не "выключить не смотря на текущие состояние).
PORTD=PORT & B01111111 // сбрасываем седьмой бит, все остальные оставляя как есть
Что-бы глазами не инвертировать число, можем заставить комп сделать это
PORTD=PORT & ~ B10000000
И так же как делали это с установка
PORTD&=~B10000000
Или
PORTD&=~(1<<7)
И проверять в условии, установлен или нет - тоже можем так же
if(PORTD & (1<<7)) - проверим только седьмой бит
P.S. А в какой момент у вас происходит "мусорное срабатывание прерывания" - вы так и не сказали. То ли биты не те выставляли (с хором это было возможно), то ли вообще в схеме ошибка и ловили мусор из эфира, то ли дребезг у вас там.
Кстати у вас видно много повторений micros()-time_1
А еще, что-бы было легче читать код и переносить, если потрубется, исполнительные на другие пины, можно это все эти включения, выключения вынести в дефайны. Написать ввеху скетча
И включать выключать в коде так:
P.S. А в какой момент у вас происходит "мусорное срабатывание прерывания" - вы так и не сказали. То ли биты не те выставляли (с хором это было возможно), то ли вообще в схеме ошибка и ловили мусор из эфира, то ли дребезг у вас там.
С хором это было не связанно, т.к. я пробовал с командами digital.Read / Wtite. Толком честно говоря тоже не разбирался.
Теперь пытаюсь задать время цикла и задержку. Имеется таблица с расчитаными значениями задержки после поступления импульса на сенсор.
http://oi45.tinypic.com/oge8lx.jpg
Угол опережения на графике рассчитывается с помощью трёх квадратных уравнений. для оборотов 0-2000, 2000-3000, 3000-7000. Справится ли контролер если я буду каждый раз при поступление импульса рассчитывать угол в виде задержки ? или рассчитать заранее отрезки времени с интервалом в 200 оборотов и задать с помощью if(30000 >= time && time >= 35000) почти 40 условий? или можно ли задать условие в функции switch case в таком виде case 30000 >= time && time >= 35000:?
> Толком честно говоря тоже не разбирался
Вместо запрета прерываний, можно еще в самом обработчике "давить лишние сработки". В самом time_set() то же делать if(micros()-time_1) меньше какая-то значения - не запускать таймер и не обновлять time_1 . Вообщем если с прошлого импульса прошло слишком мало времени - игнорировать этот.
Или - еще вариант. При сработке импульса. Делать detachInterrupt (прекращать слушать прерывание) и снова делать attachInterrupt только когда после того как погазили второй индуктор.
> Справится ли контролер если я буду каждый раз при поступление импульса рассчитывать угол в виде задержки
Конечно справится. Но это естественно займет время. Можете поэксперементировать и засечь сколько занимает вычисление квадратного, но.... на микросекундах большая вероятсность что уже будет ощутимо.
>или рассчитать заранее отрезки времени с интервалом
Да, я бы делал именно так.
>и задать с помощью if(30000 >= time && time >= 35000) почти 40 условий? или можно ли задать условие в функции switch case
Да вообщем-то "как вам удобней". Что if, что switch - это синтаксический сахар. В бинарные коды оно, скорее всего, одинаково скомпилируется. Так что выбор между ними - дело эстетики.
Но моя эстетика - говорит что раз это "табличные данные", то и в коде их лучше всего делать в виде таблицы. То есть - массива. И потом по этому массиву пробегатся for-ом. находить нужную строку.
Что-бы не засорять скетч, я бы эту таблицу вынес в отдельный файл .h файл. И подключал его к основному скетчу через #include. Тогда эти цифры - не будут мозолить глаза. А если нужно - можно иметь несколько таблиц (несколько файлов) и подключать нужную из них просто меняя одну строчку. Может быть полезно при эксперементах/настройках.
P.S. Кстати, если будет время - интерестно было-бы подробней узнать что же именно вы делалет (подозреваю что что-то для мото-техники). Какого именно потребительского эффекта надеетесь добится (мощность, приемистость, экономия топлива?). Может и себе захочется что-то подобное сделать :)
P.S.S. А с битовыми операциями - разберитесь все-таки. Их нужно знать. Не только для прямой рабты с портами. Сделайте отдельный скетч, и попробуйте поигратся с разными числами/операцями выводя результат через Serial.println(val,BIN) и глядя что получается.
День добрый,
спасибо за подсказки, буду разбираться.
Но моя эстетика - говорит что раз это "табличные данные", то и в коде их лучше всего делать в виде таблицы. То есть - массива. И потом по этому массиву пробегаться for-ом. находить нужную строку.
А это интересно, наверное попробую так посмотрим что получится.
P.S.S. А с битовыми операциями - разберитесь все-таки. Их нужно знать. Не только для прямой работы с портами. Сделайте отдельный скетч, и попробуйте поиграться с разными числами/операциями выводя результат через Serial.println(val,BIN) и глядя что получается.
а здесь я ссылался на вот эту ссылку http://arduino.cc/en/Reference/BitwiseAnd та как раз это объясняется, но похоже нужно ещё раз прочитать.
P.S. Кстати, если будет время - интересно было-бы подробней узнать что же именно вы делали (подозреваю что что-то для мототехники). Какого именно потребительского эффекта надеетесь добиться (мощность, приемистость, экономия топлива?). Может и себе захочется что-то подобное сделать :)
Стоит у меня в гараже мотоцикл 31 год уже ему. Когда я его покупал, т.к. у меня нет прав перегонял его мой знакомый а я ехал за ним. После этого наверно неделю проветривал машину от мотоциклетного дыма, он ведь двухтактный и работает на смеси масла и бензина. Тогда и возникла идея сделать мозги для двигателя. Которые управляют впрыском бензина и масла а также распределением зажигания и всего остального что радует водителя при воскресной прогулочной езде. Теперь собираю по кусочкам программу.Начал с зажигания т.к. особо переделывать двигатель не придется а потом уж все остальное. Есть страница где можно немного подсмотреть как это делается http://secu-3.org/ там даже код программы выложен.
Если уж нато пошло можно и тему переименовать. Если модераторы непротив например на "2 stroke engine ECU"
Но моя эстетика - говорит что раз это "табличные данные", то и в коде их лучше всего делать в виде таблицы. То есть - массива. И потом по этому массиву пробегатся for-ом. находить нужную строку.
Интересный код получактся:
Даже не вникая. Строка 11. Бесконечный цикл. Не путайте = и ==
что-то мудреное изобретаете.
по прерыванию с ноги инт обрабатывайте прерывание настраиваете, если надо таймер, запускаете таймер.
по прерыванию от таймера выполняете действие, останавливаете таймер.
и пишите лучше, обращаясь напрямую к регистрам.
Максим, ты шо? Три года прошло.))))