Digitalwrite arduino чем заменить

Mastering Arduino

Collection of reference, tutorial, cheatsheet, tips and tricks for Arduino and related shields / modules. You can also get code snippets and alternative library for programming Arduino, highly optimized for better performance and smaller code size. Also feature some schematic for your Arduino projects. You can also build your own Arduino DIY from scratch, or hacking / tweaking Arduino boards according to your needs.

Monday, October 21, 2013

Fastest digitalRead / digitalWrite Alternative

Arduino’s standard digitalRead/digitalWrite is well known for two reasons: it’s simplicity / ease to use, and. it’s extraordinary slow speed.

Fastest alternative is by using direct port manipulation. For example, alternative to digitalWrite( 13, HIGH ) is PORTB |= (1 . Compiler will translated that code into 2-cycle instruction using sbi opCode. In 16 MHz, it will be executed in about 130 nano-seconds.

However it’s not equivalent of digitalWrite. Beside of setting corresponding pin with specified value, digitalWrite also check and turn PWM output off for corresponding pin with PWM capability. If you’ve previously use PWM on corresponding pin (i.e., by invoking analogWrite function), this method won’t work.

Anyway, this condition is rarely encountered. Usually once a pin assigned as PWM-driven pin, it will never reverted back to «normal» (non-PWM-driven) pin. So rather than wasting execution time on invoking unnecessary code, we should take a little bit control and explicitly turn PWM off only if it’s really necessary.

To keep it simple and easy to use, we’ll use following macros (note that this code only works with ATmega8/168/328-based board such Arduino Uno. Other MCU might have different pin numbering!):

Thus, you can save valuable code space and get dramatically faster execution by changing:

  • pinMode( pin, INPUT ); with pinAsInput( pin );
  • pinMode( pin, OUTPUT ); with pinAsOutput( pin );
  • pinMode( pin, INPUT_PULLUP); with pinAsInputPullUp( pin );
  • digitalWrite( pin, LOW ); with digitalLow( pin );
  • digitalWrite( pin, HIGH ); with digitalHigh( pin );
  • digitalRead( pin ) with digitalState( pin )

Additionally, rather than typing if( digitalState( pin ) == HIGH ) you can type if( isHigh( pin ) ) for clearer code clarity. Also use isLow( pin ) rather than digitalState( pin ) == LOW .

Now let’s try it in action. Load the Blink.pde example sketch and try to compile. You’ll get 1,084 bytes of compiled code. Now insert our new macros in the beginning of the file, and replace the code according to
changing guide above.

Your source code will be like this (comments removed, newly inserted macros are not shown):

After compiling, we’ll get size reduction to 956 bytes. Not much fat-loss, eh? Actually you can get much smaller code, by changing the way you define associated led symbol.

First, it’s defined as int (with range from -32,768 to 32,767) which taken 2 bytes. A pin number in Arduino Uno is from 0 to 19, so it’s a waste to declared it as int (2 bytes). If you really need to put it in variable, you should defined it with byte ( uint8_t ) type.

Second, and most importantly, since the LED won’t changed it’s pin attachment on middle of execution, you should define it as constant with const keyword. This way, compiler will evaluate associated macro condition in compile time (instead of making actual run-time code to evaluate variable arguments).

Take hard notice on this issue. Under any circumstances, use variable only if you need to change it’s value (variable ⇒ able to vary) throughout execution. Otherwise, always use const (constant ⇒ always the same, never changed). You’ll save a lot of code space and execution time by follow this simple rule.

So, try changing the int led = 13; statement with const byte led = 13 (or simply #define led 13 ) and recompile you code. Now your slim program only takes 674 bytes, more than 30% size reduction!

How fast is digitalHigh / digitalLow versus digitalWrite in common 16 MHz clockrate? For digitalWrite it depends on whether specified pin has PWM capabilities or not (from about 3.6 µs to 4.8 µs). For digitalHigh / digitalLow , it is exactly 130 ns (2 cycles), so it’s between 27-37 times faster ).


Помогите пожалуйста избавиться от digitalRead и digitalWrite

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

Помогите пожалуйста избавиться от digitalRead ( ) и digitalWrite ( ) не могу понять, запутался очень.

Контроллер Arduino pro mini 328p

Я смог только понять вот это и то не могу поять верно или нет

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

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

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

А почему там 5 а не 6 ?
8-9-10-11-12-13, почему 5 ?

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

Потому что пин PB5 (пятый пин порта B). Читайте дальше, там есть про распиновку.

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

Спасибо большое, я начинаю монимать кажется.

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

Вот в этой статье даже картинка есть — соответсвие пинов чипа пинам ардуины.

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

Парни проверьте плиз запутался в самой прорамме как заменить шифтаут или аналог реад

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

shiftОut нельзя заменить одной командой. В файле c:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino\wiring_shift.c определяется эта команда. По образу и подобию можно написать свою c заменой digitalWrite работающую быстрее и занимающую меньше места.

analogRead заменять не имеет смысла. Она и так написана нормально.

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

OdinTakoi , зачем Вам 2 набора latchPin/dataPin/clockPin?

По-хорошему это надо делать на аппаратном SPI, если нужна скорость.

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

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

Про shiftОut поня, не осилю.
Про аналогреад понял смысла нет.
2 набора потому что 4 сдвиговых регистра управляющиеся в корне по разному, 2 шт от датчика движения и 2 от света по времени.

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

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

— цепочка входных сдвиговых регистров,

— цепочка выходных сдвиговых регистров,

— цифровой сигнальный процессор.

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

Афигеть ты мозг)))))))))))
я так не смогу(((((

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

А где.. ключевая фраза- я тобой горжусь :)

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

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


Оптимизация кода Ардуино и ускорение работы.

В этом примере, я покажу как можно сократить использование памяти и ускорить работу программы в 5 раз. Думаете это невозможно или трудно? Как оказалось совсем не трудно. Надо всего лишь придерживаться нескольких правил и ваш код будет работать в 5 раз быстрее, а памяти Ардуино вам хватит на любую проект.

Эта строка показывает объем флеш-памяти в Arduino, занятым скетчем, и процент от предела в 30 Кбайт, так как 2 Кбайт уже занято загрузчиком. Внимательно смотрите за этими данными, при превышении 70 процентов возможны сбои в работе программы.
и 9 байт динамической памяти ОЗУ или RAM.

ОЗУ в Arduino используется для хранения переменных и других данных, имеющих отношение к выполняющейся в данный момент программе. ОЗУ — энергозависимая память и после отключения питания память очищается.

Теперь добавим Serial.begin что бы иметь возможность выводить информацию в монитор порта. Значения сразу изменились. Программа пока ничего не делает, но уже потребляет
1438 байта или 4% памяти FLASH и 184 байта или 8% динамической памяти. Получается, что эта функция занимает 1000 байт в памяти Ардуино и 175 байт динамической памяти. Пустячок, но не приятно.

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

Узнаем и сохраним в переменную TIME1 текущее время начала выполнения кода.
Создадим цикл на 1000 итераций. Если проще, то светодиод мигнёт 1000 раз, но вы этого не заметите, так как это произойдёт очень быстро. Затем мы сохраним время после выполнения кода и подсчитаем разницу времени.
То же самое сделаем с другим примером, но там мы не будем обращаться к digitalwrite а будем работать напрямую с регистрами контроллера. Как я сказал дальше я всё объясню. Так же сохраним время до и после, и подсчитаем разницу.

Ну и в конце узнаем во сколько раз второй код выполняется быстрее первого.
Откроем монитор порта и посмотрим. Так как весь код я разместил в setup, то он сработает всего 1 раз.
Видите, на выполнение 1 примера контроллеру понадобилось 7544 микросекунды, а второй пример занял всего 1324. Итого получилось что обращаясь непосредственно к портам контроллера мы получаем ускорение работы в 5 раз. Правда не плохо?
Это значит, что 1 выполнение команды digitalwrite занимает примерно 7,5 микросекунды, а обращение к порту и запись непосредственно в регистр 1,3 микросекунды.

Памяти стало еще немного меньше.
1716 байта или 5% памяти FLASH и 194 байта или 9% динамической памяти. Мы истратили ещё 220 байт памяти и 20 байт динамической памяти.
Теперь выведем на экран значения. Так как цикл loop крутится бесконечно, то и время работы будет постоянно увеличиваться. Вычислив среднее значение мы получим 200 – 208 микросекунд. Так что среднее работы почти пустого скетча 200 микросекунд. Много это или мало решайте сами. Кстати так вы узнаете оптимист вы или пессимист. Кто не понял, это отсылка на стакан, какой он полупустой или наполовину полный.

Подведём итог.
Пустой скетч занимает 444 байта FLASH памяти и 9 байт динамической памяти ОЗУ. Слегка заполненный занимает уже 1716 байта или 5% памяти FLASH и 194 байта или 9% динамической памяти.
Мы истратили 4% FLASH памяти, и 9% памяти ОЗУ.

Это было про ускорение работы, а теперь снова вернёмся к оптимизации кода.

Теперь загрузим обычный пример блинк и посмотрим сколько он занимает. Мигать будем светодиодом который находится на плате Ардуино и который подключен к 13 выводу Ардуино УНО и Ардуино НАНО.
Вы сами видите сколько памяти задействовано при работе этого скетча. А можно ли как-то уменьшить это значение. Оказывается да, и несколькими способами. Самым агрессивным, но немного трудный способ я сейчас покажу.
А потом перейдём к более простому, и если останется время, то я более подробно остановлюсь на сложном способе.
Во первых полностью уйдём от setup и loop. Заменим их одной main.
Сначала посмотрим на распиновку платы Ардуино НАНО, у УНО будет аналогично.
Возьмём порт B. Именно там и находится наш светодиод.

  • Нулевой бит этого порта соответствует выходу d8
  • Первый порту d9
  • Второй порту d10
  • Третий порту d11
  • Четвёртый порту d12
  • Пятый порту d13

А так как светодиод находится на тринадцатом выводе получается нам нужен пятый бит, так как отсчёт ведётся от нуля.
Отсчитываем пятый бит справа на лево и ставим единичку для включения светодиода и нолик для выключения. Delay здесь немного отличается от привычного нам, но 1000 миллисекунд, по прежнему равно 1 секунде. Загружаем скетч и смотрим результат. Светодиоды мигают так же как и в прежнем скетче, раз в секунду, но посмотрите на то сколько занято памяти.
Мы получили экономию памяти больше чем в 5 раз. Думаю, что это не плохой результат. Но сомневаюсь, что многие будут использовать этот метод, поэтому будем использовать более простой и привычный нам Ардуинщикам способ.
Для этого примера я собрал небольшую схему состоящую из 8 светодиодов и LED индикатора. Конечно можно было бы работать и с 1 светодиодом, но тогда будет очень маленький разрыв в значениях и это будет не так заметно.
Скетч я специально не оптимизировал, что бы показать как не надо делать. И наверняка многие из так делают, и им будет интересно посмотреть почему так делать не правильно.
В начале идёт блок комментариев и я советую вам всегда вначале писать что это за программа, когда вы её сделали и что она делает. Потому что через некоторое время вы полностью забудете что это и это будет вам подсказкой.

Дальше идёт подключение LCD индикатора. Затем я создал именованные переменные соответствующие цветам светодиодов. Всегда старайтесь называть переменные так что бы было понятно для чего он были созданы, и номера выходов Ардуино к которым они были подключены.
Затем я сделал несколько пауз для мигания светодиодами. Все они имеют разный интервал. Сначала они мигают часто, но с каждым новым светодиодом мигание становится реже.
Подключил Serial.begin и сделал несколько настроек индикатора. Так как для работы светодиодов выводы Ардуино должны быть установлены как выходы, то я так и сделал. Выходы надо указывать обязательно в отличие от входов. Так что если вы подключаете какой-нибудь датчик и он передаёт данные на вход Ардуино, то указывать INPUT не обязательно, хотя и не запрещено.
Ну и в цикле loop мы по очереди включаем светодиоды делаем паузу, выводим сообщение на индикатор и пишем в монитор порта, что включили светодиод. Затем делаем паузу чтобы видеть что светодиод зажёгся, и гасим его, опять же пишем в монитор что светодиод погас. Снова делаем паузу и переходим к следующему светодиоду. В конце включаем все светодиоды и выключаем их. И вот такой простенький пример занимает аж 27% памяти Ардуино и целых 67% памяти ОЗУ.
Теперь будем оптимизировать код.

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

Поехали дальше.
Разберёмся с переменными которые мы создаём в которых мы сохраняем номера выводов микроконтроллера. Например, я использовал 8 светодиодов и подключил их к выходам с 5 по 12 микроконтроллера и использовал для этого переменные с типом int. Это можно делать, но это не правильно, так как каждая такая переменная отбирает по 2 байта памяти.
И вообще переменные надо использовать только для тех значений которые изменяются в процессе работы, поэтому они и называются переменными. Нам же здесь надо использовать константы или директивs препроцессора, типа define. Давайте проверим тот и другой способ.
Сначала изменим значение на константы и загрузим скетч. Как видите значения не изменились. Теперь попробуем поменять на define. Объём памяти остался неизменным. Как же так. А всё дело в том, что умный компилятор может распознать какие переменные в процессе работы кода не изменяются и оптимизировать их. Но лучше на это не надеяться, а сразу указать один из этих двух способов. По желанию. Я в примере оставлю define. Так как он был последним.

Теперь подробнее разберёмся с паузами.
Так как мы заранее знаем какие они должны быть, то мы можем подобрать для них тип переменной. Для экономии памяти старайтесь выбирать наименьший из возможных типов. Так как это напрямую влияет на размер памяти. Вот самые распространённые типы. Так как у меня максимальное значение 1500, то я выбираю тип int. Так как он поддерживает значение от -32768 до 32767. Если у вас значение до 65535, то вы можете указать тип переменной unsigned int то есть беззнаковое и у вас всё равно будет занято 2 байта в памяти, а вот если у вас 65536, то тогда придётся указать тип переменной long А ЭТО УЖЕ 4 БАЙТА ПЯМЯТИ. Ну надеюсь понятно рассказал.
Теперь давайте попробуем эти переменные заменить на константы и посмотрим сможем ли мы сэкономить немного памяти. У нас получилось сэкономить 2 байта. Если честно, то странно, я думал, что получится сэкономить побольше. Проверим, может мы что делаем не так?

И если компилятор действительно такой умный и не используемые в коде переменные делает константами, то попробуем изменить их значение в коде и посмотреть что будет. Будем изменять паузу на единичку. Мы получили ошибку, так как все паузы сейчас объявлены как константы и в коде их нельзя изменить. Сделаем их снова переменными типа int.
Прошиваем код и видим, что у нас уменьшился объём флэш памяти и увеличился объём динамической памяти на 2 байта. Как раз столько занимает переменная типа инт. Значит всё работает и компилятор действительно умный, и не используемые в коде переменные преобразует в константы. Теперь изменим все паузы и посмотрим на сколько вырастет объём памяти.
Объём действительно подрос. И динамическая память теперь весит на 20 байт больше – это как раз 10 переменных пауза по 2 байта. Но наша задача уменьшить код а не увеличить. Поэтому возвращаем все на место и паузы, уже больше по привычке чем по необходимости ставим в define.

Пойдём дальше. Основная наша задача освободить как можно больше динамической памяти. Флэш можно забивать почти под завязку. А вот динамическая память нам очень нужна, а её всего 2 килобайта. Поэтому все строки что мы выводим в монитор порта мы перебросим во флэш, тем самым освободим от них ОЗУ.
Для этого перед каждой строчкой ставим макрос F() он размещает строку во флеш память, тем самым освобождая динамическую память. Флэш 32 килобайта а динамическая всего 2 кило, есть разница?

Прошиваем ардуино и смотрим результат. И вот эта не сложная операция освободила нам больше 30% динамической памяти, уменьшив размер в байтах в 2 раза. Задействовав всего 6% флэш памяти.

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

Теперь как и обещал рассмотрим сравнение двух примеров обычный и с доступом к регистрам портов. Это конечно тема для отдельного видео, поэтому здесь я расскажу очень коротко.
Из основного примера урока выкинем всё лишнее. Лишним оказались все переменные – это паузы и номера выводов микроконтроллера. Все эти значения будем сразу писать в код. Это конечно не правильно, позволит нам существенно сократить объём памяти. У нас получился вот такой короткий код, на 64 строчки.
А здесь этот же код, но с обращением к регистрам. Светодиоды мы подключили к выводам с 5 по 12 Ардуино. Смотрите насколько короче запись обращения к регистрам чем обычная запись с pinmode().
А так мы мигаем светодиодами. Эти строчки замена digitalWrite. Код сократился уже до 47 строчек.

Здесь, на примере установки цифрового пина Ардуино d7 я показал два способа установки регистров в HIGH и LOW, какой использовать выбирайте сами.
D7 находится на порту D, в седьмом регистре если считать с 0. Чтобы включить светодиод, надо установить его в единицу, а выключить в ноль.
Но как и у любого способа здесь тоже есть положительные и отрицательные сторона, свои за и против.
Это результат двух скомпилированных примеров. Какой из них с доступом к регистром думаю говорить не надо.

Со своей задачей мы справились. Мне хотелось рассказать побольше, но и так видео получилось большим, целых 17 минут, при среднем просмотре моих уроков в 3 минуты. Редко кто доходит и до половины. Если будут желающие то я сниму продолжение, есть ещё очень много способов уменьшить размер кода и увеличить скорость. Это только вершина айсберга. Спасибо тем кто досмотрел до конца.