Notice: Memcache::get(): Server localhost (tcp 11211) failed with: Connection refused (111) in /home/a146/www/we.easyelectronics.ru/engine/lib/external/DklabCache/Zend/Cache/Backend/Memcached.php on line 134
Ещё про чарлиплексинг / AVR / Сообщество EasyElectronics.ru

Ещё про чарлиплексинг

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

Схема:
Изображение - savepic.su — сервис хранения изображений


Светодиоды можно подключать как по схеме с общим анодом, так и общим катодом. Для выбора режима работы используется #define COMMON_ANODE если у вас светодиоды с общим катодом, то уберите эту строчку из avrcrpx.h. Также там можно указать другие порты.

Почти весь код находится в функции crpx12SM(), для нормальной работы она должна вызываться не реже 100раз в секунду.

crpxSetLeds(uint16_t val) — устанавливает состояния светодиодов, номер светодиода соответствует номеру бита в передаваемом параметре.

Пример:

crpxSetLeds(0);// выключает все
crpxSetLeds(0xffff);// включает все
crpxSetLeds(0b0000000011000000);// включает 7 и 8
// и т. д.


В прикрепленном архиве исходники и тестовая прошивка для attiny13.
Ну и на гитхабе.
Файлы в топике: avrcrpx.zip

Комментарии (10)

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

С ходу не понравилось следующее:

— Что делает функция crpxSetLeds()? Нет, понятно, «устанавливает состояния светодиодов». Но нафига она нужна, если переменная crpxLedsA — глобальная? Это же не stm32, надо экономить :) Так что установку состояния можно было бы просто выполнять, присвоив переменной crpxLedsA нужное значение — напрямую, а не через функцию

— Что делает переменная crpxSt? Нигде не инициализируется, нигде не используется, да еще жрет оперативку (ну потому что глобальная). Ах да, точно — используется в switch. Только никто не дает гарантии, что начальное значение crpxSt=0. А если там мусор?

Как в том анекдоте: Буратино дали три яблока. Два он съел. Сколько яблок осталось у Буратино? Думаете одно? Ничего подобного. Никто не знает сколько у него уже было яблок до этого. Мораль — всегда обнуляйте переменные!

Да и в принципе можно сделать crpxSt локальной — целый байт в оперативке сэкономим :)
+1
— Что делает переменная crpxSt? Нигде не инициализируется, нигде не используется, да еще жрет оперативку (ну потому что глобальная). Ах да, точно — используется в switch. Только никто не дает гарантии, что начальное значение crpxSt=0. А если там мусор?
Да, моя ошибка. В принципе ничего страшного не должно случится, avr-gcc всегда вставляет код инициализирующий глобальные переменные, это можно увидеть в дизасм. файле.

— Что делает функция crpxSetLeds()? Нет, понятно, «устанавливает состояния светодиодов». Но нафига она нужна, если переменная crpxLedsA — глобальная? Это же не stm32, надо экономить :) Так что установку состояния можно было бы просто выполнять, присвоив переменной crpxLedsA нужное значение — напрямую, а не через функцию
Изначально функция по другому работала, после правки решил оставить для наглядности, хотя лучше наверное было сделать макросом или вообще убрать
0
 Но нафига она нужна, если переменная crpxLedsA — глобальная?

Здесь момент спорный. С точки зрения API модуля лучше иметь зависимость от функции чем от переменной, т. к. в любой момент мы можем поменять реализации функции и это не отразится на вызывающем коде.

 Только никто не дает гарантии, что начальное значение crpxSt=0.

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

Да и в принципе можно сделать crpxSt локальной

Дык в текущей реализации нельзя, эта переменная должна сохранять свое значение между вызовами crpx12SM (на можно ее объявать как statics внутри этой функции)
+1
Здесь момент спорный. С точки зрения API модуля лучше иметь зависимость от функции чем от переменной, т. к. в любой момент мы можем поменять реализации функции и это не отразится на вызывающем коде.
+1. Алсо, эту функцию следовало сделать инлайновой, тогда она бы еще и не давала никакого оверхеда вообще.
+1
 функцию следовало сделать инлайновой


Да, тогда не будет накладных расходов. Но у такого подхода тоже есть небольшой минус — нам придется разрешить доступ извне модуля к crpxLedsA (в принципе это не критично, но хотелось бы ее спрятать, т. к. кто-то может попытаться писать туда напрямую, минуя обертку)
0
функцию следовало сделать инлайновой
хорошая идея… кстати, вроде gcc имеет свойство при оптимизации все простые функции превращать в инлайновые автоматом.
0
В данном случае эта «простая» функция crpxSetLeds реализована в другом модуле и если ее не вынести как инлайновою в хедер, компилятор не сможет ее заинлайнить.

На этапе компиляции компилятор может заинлайнить функцию (в зависимости от опций оптимизации и т. д.) если реализация функции находится в том же модуле. При раздельной компиляции каждый модуль собирается отдельно и заинлайнить функцию компилятор не может т. к. банально «не видит» ее реализацию.

Есть Link Time Optimization (LTO), когда уже линкер может вытянуть скомпилированный код из одного объектного файла и подставить в другой вместо вызова функции. Но, хотя в принципе, GCC поддерживает LTO, в версии для AVR он так не умеет (по крайней мере не умел, исправьте меня если я ошибаюсь)
0
ее не вынести как инлайновою в хедер, компилятор не сможет ее заинлайнить.
Ну может оно и к лучшему :)
0
Можно еще заюзать multi-unit translation или как там его neiver называл. Как я понял, если gcc скормить за раз несколько сырков — он сможет проводить кроссмодульные оптимизации.
0
переменная должна сохранять свое значение между вызовами
да, точно, ступил.
0
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.