Вопрос по времени выполнения
- Войдите на сайт для отправки комментариев
Хало all. Я раздумываю над писаниной Cyberlib-совместимых форков некоторых библиотек, например под nRF24L01, nRF905, LCD и т. п. - пока что это всё на этапе выбрасывания digitalWrite()/Read() и заменой на прямой вывод в порт. Возник вопрос, а насколько чётко внешняя периферия будет понимать это, и не окажется ли вывод слишком быстрым.
Вот что мы имеем. В справочном листке на mega написано: 20 млн итераций на 20 МГц, что даёт предполагать, что теоретически, на 16 МГц будет 16 млн. Многие инструкции, во всяком случае вывод в ноги точно, выполняются за один такт процессора, итого мигаем светодиодом в двух командах - получаем тау 65 наносекунд (62.5 если быть точным, но какая разница). Как говорится, такое и не всякий светодиод успеет (у инфракрасных фронты по 100 нс).
Собственно, решение простое - всего лишь подождать. У того же сдвигового регистра - весьма плохо понимаемая мной цифра "1.67 ns" (прям таки до сотых), в графе typ. В графе max уже цифра, исчисляющаяся сотнями. Это я так понимаю, когда в цехе литографии кот нассал и техпроцесс был грубо нарушен, когда питается от китайских солевых батареек, при нашествии инопланетян и так далее. В любом случае, двух тактов процессора вроде бы достаточно чтобы микруха поняла "о, мне на вход воздействуют, надо бы отреагировать".
Собсно, сколько именно ждать, у меня есть два варианта, и ряд некоторых новичковых вопросов по этому.
Вариант раз: наносекундные интервалы. Суть вопроса: я не умею писать ассемблерные вставки, не приемлю специальных значков типа тильд и двоеточий в тексте скетча, всё должно быть предельно понятно - обычный С работяги с завода, как то нечто.метод(); двоеточия в кейсе, в фигурных скобках то чего много; никаких \n\t и т. п., у меня сразу просыпается какой-то протест, я такие вещи считаю бинарной информацией и испытываю позывы удалить, как необязательные текстовые строки. Я так же знаю что одна инструкция выполняется в большинстве случаев один такт, так чего бы не выполнять много раз вывод, или считать переменную, или ещё что-то, вместо NOP и всяких вставок.
Правильно ли я понимаю:
for(i=0;i<8;i++); // 8 тактов, 0.5 мкс PORTx|,&,!=xx; // один такт то же самое; // второй такт, 125 нс всего
Вариант два: микросекундные интервалы. Минусы: пока не знаю; плюсы - можно пожертвовать памятью и сделать очередь (разновидность класса Dispatcher из Unreal Engine). Типа так:
passed=micros()-timestamp; if(passed>=interval0 && passed<interval1) action_pre(); if(passed>=interval1 && passed<interval2) action1(); if(passed>=interval2 && passed<interval3) action2(); if(passed>=interval3 && passed<interval4) action3(); if(passed>=interval4) action_post(); //... timestamp=micros();
У этого только 2 вопроса.
1. Отличаются ли принципиально функции _delay_us() (если таковая существует), delay_us(), delayMicroseconds()? Эксперименты с bitbang широтно-импульсным модулированием светодиода ничего не дают. Мигает чё-то. В руке поболтаешь - видны точки мерцания ("стоячая волна"). На глаз их - десятки, короче частоты порядка сотен герц.
Из этого проистекает второй вопрос, который также навеян некоторыми слухами из интернетов. Утверждается, что ядро Wiring, она же "системное окружение Ардуины", то бишь состояние её таймеров такое чтобы работало millis(), не способно считать микросекунды точнее четырёх. То есть бесполезно давать задержки меньше 4, не стоит ожидать из micros() значения, не кратные 4м. Так ли это? Ибо звучит бредом. Дабы попасть в 38 кГц приёмник, мной когда-то писалось delayMicroseconds(27). С одной стороны - оно слишком близко к 28, которое кратно 4. С другой стороны, вариант изменить значение мной никогда не пробовался. С третьей стороны, если бы это не работало, в сети бы появились недовольные комментарии народа, у которых не получилось обмануть 40, 42 кГц приёмники, или сколько там чтобы было такое тау, которое не кратно 4 мкс. Бред короче.
Предпочитаю первый способ. Просто много раз поделать одно и то же, или помотать цикл, чтобы скажем экран понял что ему дают (как я знаю - он КМОП, и следовательно медленный).
Исключительно из любопытства вопрос: назовите пожалуйста реальное применение вашего вопроса - зачем учитывать наносекунды или микросекунды и пытаться их уменьшить при выводе в периферию, учитываю что почти всегда МК работает быстрее чем периферия? Я тут недавно пытался спросить аналогично - так меня тухлыми помидорами закидали, но реально так ничего и не сказали почему например символ на дисплее будет выводиться вместо 12.3 мс - > 12.7 мс - кому это помешает?
Voodoo Doll, тяжкий путь выбираете для такого уровня познаний.
//Возник вопрос, а насколько чётко внешняя периферия будет понимать это, и не окажется ли вывод слишком быстрым.
Как правило успевает все, ардуиновские (читай 328-го) частоты для современной переферии ерунда, тем более для регистров.
//весьма плохо понимаемая мной цифра "1.67 ns" (прям таки до сотых), в графе typ. В графе max уже цифра, исчисляющаяся сотнями.
ссылку в студию, чето тут не так.
//_delay_us() (если таковая существует), delay_us(), delayMicroseconds()
Вобщем - формирование временных интервалов в разных масштабах времени сильно по разному, и циклы из нопов и таймер и счет прерываний таймера встречается. Подробней - в исходниках либ.
//То есть бесполезно давать задержки меньше 4, не стоит ожидать из micros() значения, не кратные 4м. Так ли это?
Да. Дискретность 4мксек, какая получится при вызове -плавает значение.
//Правильно ли я понимаю:
1
for
(i=0;i<8;i++);
// 8 тактов, 0.5 мкс
2
PORTx|,&,!=xx;
// один такт
3
то же самое;
// второй такт, 125 нс всего
Нет. Все зависит от типов величин, их константности, оптимизации и пр.
//если бы это не работало, в сети бы появились недовольные комментарии народа, у которых не получилось обмануть 40, 42 кГц
Вопрос в допусках, погрешностях и пр. подробностях. 39.5КГц приемник на 40КГц признает, чередование периодов соответствующих 39КГц и 41КГц - тоже. Излишняя точность недостаток ума вобщем.
Voodoo Doll, аргумент типа "покупать маину с максимальной скоростью 200 км/ч абсолютно бессмысленно - никогда не будешь успевать затормозить там, гда нужно" лично я считаю неубедительными. Ездить нужно с той скоростью, которую допускает дорожнаяч обстановка, а не асегда с максимальной.
Во-первых, никто не заставляет Вас переключать пин обратно следующей же командой через 62 нс. Можно и парочку NOP'ов подождать.
Во-вторых, сдвиговый регистр, например, легко работает на 50 МГц, тогда как с Ардуины получить более 8 никак не получится. И сдвиговый регистр здесь - скорее правило, чем исключение.
Помню мне как-то пришлось подгадывать временные интервал под протолкол: на 4 мкс (скорость обмена 250 кбод) должно было приходиться 4 digitalWrite, при том, что стандартная digitalWrite выполняется около 6 мкс. Естественно, пришлось использовать аналоги побыстрее и обеспечивать нужные интервал NOP'ами, т.к. delayMicroseconds(1) давала слишком большую задержку.
Кстати, если micros() действительно считает с дискретностью 4-8 мкс, то delayMicroseconds() почти честно отрабатывает с точностью до микросекунды (только конкретно delayMicroseconds(1) выполняется чуть дольше 1 мкс).
В другом проекте нужно было формировать звук с частотой дискретизации более 48 кГц. ПОнятно, что в прерывании длиной 21 мкс особенно с несколькими digitelWrite особенно не разгуляешься.
Ну а так - все зависит от задачи: в одном случае лучше применить одно, а в другом - совершенно другое.
Я тут недавно пытался спросить аналогично - так меня тухлыми помидорами закидали, но реально так ничего и не сказали почему например символ на дисплее будет выводиться вместо 12.3 мс - > 12.7 мс - кому это помешает?
Насколько я помню, Вам пытались объяснить, что 12 мс на 1 символ - это слишком много. И если Вы правильно перепишете свою функцию вывода символа, чтобы она выполнялась не 12, а 0.2 мс, то разница в 0.4 мс будет вполне себе ощутима.
А делать какие-либо выводы, основыываясь на явно невменяемом коде - совершенно некорректно.
Я тут недавно пытался спросить аналогично - так меня тухлыми помидорами закидали, но реально так ничего и не сказали почему например символ на дисплее будет выводиться вместо 12.3 мс - > 12.7 мс - кому это помешает?
Насколько я помню, Вам пытались объяснить, что 12 мс на 1 символ - это слишком много. И если Вы правильно перепишете свою функцию вывода символа, чтобы она выполнялась не 12, а 0.2 мс, то разница в 0.4 мс будет вполне себе ощутима.
А делать какие-либо выводы, основыываясь на явно невменяемом коде - совершенно некорректно.
Не правильно вы помните, впрочем не важно, надоело объяснять