Для чего нужен пин
Как пользоваться Pinterest и зачем он нужен
«Пинтерест» (Pinterest) – это поисковая и визуальная платформа, в которой собраны изображения с различных ресурсов. В данной статье вы узнаете, как работает Пинтерест, как им пользоваться, и, какие инструменты предлагает этот сервис для продвижения бизнеса.
Как работает «Пинтерест» (Pinterest)?
Люди используют Пинтерест, чтобы сохранять идеи, изображения, интересные продукты, делиться информацией с друзьями или создавать закладки страниц для последующего чтения. Пинтерест отличается от социальных сетей, где пользователи делятся информацией и фото из личной жизни. Facebook и Instagram представляют идеальную версию вашей жизни. Отличие Пинтерест в том, что он предлагает неиссякаемый источник вдохновения, чтобы приблизиться к этому идеалу. Вот для чего нужен Пинтерест.
Что такое «Пин» (Pin)?
Давайте для начала разберемся с терминологией. «Пин» – это визуальная презентация продукта или идеи, которую кто-то сохранил для дальнейшего использования на своей «доске». Каждый пин включает в себя 3 составляющих элемента:
Когда кто-то кликает на пин, открывается полное изображение и описание. Повторное нажатие приведет на сайт источника, как правило, это пост в блоге или страница с каким-нибудь товаром. Аккаунт может содержать до 200000 пинов. Другие пользователи могут сохранять пины на своей «доске».
Что такое «Доска» (Pinterest Board)?
«Доска» представляет собой коллекцию личных пинов. Она находится во владении у одного пользователя, но также может быть добавлена другими. В одном аккаунте может содержаться до 300 досок. Хотя и сложно представить, как один пользователь может справиться с таким количеством.
Профиль в Пинтерест содержит следующую информацию:
Как работает Pinterest, когда я подписываюсь на других пользователей?
Изображения со страниц, на которые вы подписаны, начнут появляться в личной ленте. Пинтерест также произведет подборку материала, который, по мнению автоматического алгоритма, мог бы вам понравиться.
Как использовать Пинтерест для бизнеса?
Хотите, чтобы интернет-пользователи нашли ваш блог, прочитали его, оставили комментарий, поделились с друзьями? Конечно же хотите! В таком случае вам просто необходимы инструменты «Пинтереста» в его продвижении.
Вы, конечно же, скажите, что ваш блог не про ведение домашнего хозяйства, готовку, моду или фитнес. Но это совсем неважно!
Пинтерест – хорошая платформа для привлечения трафика на сайт. Столь высокий уровень популярности делает Пинтерест универсальным сервисом для продвижения сайтов любой тематики. Каждый месяц Пинтерест привлекает 200 миллионов активных пользователей. Благодаря такому уровню активности его можно рассматривать как отдельную поисковую систему. Поэтому, отвечая на вопрос о том, для чего нужен Pinterest, многие скажут, что для поиска фотографий и вдохновения.
Прежде, чем создавать свой пин, убедитесь, что изображение соответствует требованиям платформы:
Для того чтобы успешно использовать функции Пинтерест, вы должны четко понимать, как работает эта платформа, и, как другие используют ее.
Пинтерест – это не социальная сеть! Посетители сайта используют его для поиска вдохновения. Попробуйте самостоятельно опробовать предложенные функции в качестве обыкновенного пользователя.
Пинтерест хорош по нескольким причинам
Больше трафика. Наиболее мощная функция, которую готов предложить Пинтерест – это увеличение потенциального трафика. Почти все изображения, представленные на платформе, предлагают перейти по ссылке на оригинальный ресурс. Всего пару кликов мыши перенесут пользователя из океана красочных картинок на страницу вашего блога или интернет-магазина.
Отображение в результатах Google. Хотя внушительные цифры в социальных сетях могут здорово помочь вашему бизнесу, это далеко не конечная цель. Количество отображений в поисковых системах по-прежнему играет важную роль в продвижении дела.
В одной подробной статье для SEO-специалистов приводится пример строительной компании из Флориды. Несколько месяцев назад рекламный менеджер этой компании создал аккаунт в Пинтересте и разместил некоторое количество фото (в общей сложности не более 150 изображений). После этого аккаунт не проявлял особой активности, новые фотографии не загружались. Автор статьи произвел своеобразный эксперимент, введя название района во Флориде и слово «строительная компания» (constriction company) в поисковую строку Google. К его удивлению, аккаунт вышеупомянутой компании гордо разместился на второй строчке в перечне результатов. Этот пример наглядно подтверждает, насколько сильно может помочь Пинтерест в привлечении публики. Вот как работает Пинтерест, помогая получать клиентов для бизнеса.
Увеличение жизни контента. Создание авторского контента (постов, видео и подкастов) занимает уйму времени и сил. Порой бывает досадно, когда такой труд получает внимание лишь на короткий срок, а потом бесследно исчезает. Пинтерест поможет увеличить продолжительность жизни вашего контента.
Пины будут жить долго и счастливо, прикрепленные к специальным тегам, а также разместившись на «досках» других пользователей. Не дайте своему труду кануть в лету забвения!
Продажи. Как уже упоминалось ранее, Пинтерест создавался, чтобы объединять людей со схожими интересами. Люди очень часто бывают заинтересованы в покупках, не так ли? Соедините Пинтерес с онлайн-шопингом и вы получите идеальный тандем.
Упрощение доступа к товарам и услугам. Пинтерест продолжает увеличивать свою популярность не только на территории Северной Америки, но и по всему миру. Несмотря на то, что по своему формату платформа не является социальной сетью, она позволяет завязывать отношения между покупателями и продавцами, бизнес-партнерами и друзьями по интересам. Таким образом, вы можете расширить доступ к предлагаемой продукции.
Поначалу не понятно, как пользоваться Pinterest, и где инструкция к нему. Может даже показаться, что подобный формат, коим обладает описанная платформа, трудно применить на просторах русскоязычного сегмента. Разноплановый фотохостинг с урезанными функциями социальной сети. На первый взгляд выглядит пугающе, но это далеко не так.
Как вы уже могли убедиться, Пинтерест достаточно легок в использовании. Первое время придется потратить некоторые усилия на создание новых пинов, но потом вы «втянитесь» в процесс, и вся работа приобретет творческий элемент. Еще одно преимущество, а вовсе не недостаток, кроется в том, что Пинтерест еще не успел набрать должную популярность в России и странах СНГ.
У вас есть уникальная возможность раннего старта. Создавайте уникальный контент и занимайте те ниши, которые еще пустуют. А если вы простой пользователь, то можете не беспокоиться о гонке за трафиком и просто наслаждайтесь тысячами визуальных подборок для вдохновения (или создавайте свою)!
Теперь, когда вы ознакомились с основным функционалом Пинтереста, вы можете сами решить, насколько удобен этот сервис для личного пользования или чего-то большего.
Цифровые входы/выходы
Нумерация пинов
Пины пронумерованы на плате как “цифровые” D* пины и аналоговые A* пины. К цифровым пинам мы будем обращаться просто по их номеру, т.е. D3 это просто 3. С аналоговыми пинами чуть сложнее:
Режимы работы пинов
Если со входом/выходом всё понятно, то с подтяжкой давайте разберёмся. В режиме входа пин микроконтроллера не подключен никуда и ловит из воздуха всякие наводки, получая практически случайное значение. Для задания пину “состояния по умолчанию” используют подтяжку резистором к земле или питанию. Вот режим INPUT_PULLUP включает встроенную в микроконтроллер подтяжку пина к питанию. Подробнее об этом, со схемами и примерами я рассказывал в начале вот этого видео урока.
Вывод цифрового сигнала
Цифровой пин в режиме выхода ( OUTPUT ) может генерировать цифровой сигнал, т.е. выдавать напряжение. Так как понятие “цифровой” обычно связано с двумя состояниями, 0 и 1, цифровой пин может выдать 0 или 1, точнее: сигнал низкого или высокого уровня. Сигнал низкого уровня это 0 Вольт, грубо говоря в этом состоянии пин подключается к GND микроконтроллера. Сигнал высокого уровня подключает пин к VCC микроконтроллера, то есть к питанию. Если вы вспомните урок по питанию платы, то поймёте, что сигнал высокого уровня на цифровом пине будет варьироваться в зависимости от того, как питается плата Arduino. При питании от источника 5V на пине будет 5V, при питании от USB с потерей на защитном диоде мы получим около 4.7 Вольт на цифровом пине в режиме выхода с высоким сигналом. Самый главный момент касательно цифровых пинов: микроконтроллер – это логическое устройство, которое создано для управления другими устройствами при помощи логических (цифровых) сигналов. Под словом логическое я подразумеваю не силовое, то есть питать что-то от микроконтроллера нельзя, за редким исключением. На картинке с распиновкой выше вы можете найти надпись “Absolute MAX per pin 40mA, recommended 20mA“. Это означает, что максимум можно снять с пина 40 миллиампер, а рекомендуется не больше 20 миллиампер. Поверьте, для микроконтроллера это очень много. В других микроконтроллерах ограничение по току на пин может составлять 5-10 мА. Также есть общее ограничение на ток с цифровых пинов – 200 мА: “Absolute MAX 200mA for entire package“. Эту информацию можно найти в любом официальном источнике информации об Arduino и микроконтроллере в целом, в том числе в даташите на микроконтроллер. Что произойдёт, если снять с пина больше, чем он может отдать? Всё очень просто – он сломается. Что будет, если снять с нескольких пинов больше, чем может отдать микроконтроллер в целом? Правильно – сгорит микроконтроллер. Поэтому ничего мощнее светодиода и маленькой пищалки к микроконтроллеру подключать нельзя. Никаких моторчиков, лампочек, нагревателей, мощных радио-модулей и прочего питать от цифровых пинов нельзя. Цифровые пины служат для подачи команд другим устройствам, например реле/транзисторам для коммутации нагрузок. Но об этом мы поговорим отдельно. Сейчас вернёмся к вопросу подачи цифрового сигнала: для этого у нас есть функция digitalWrite(pin, value) :
Пример, в котором пины инициализируются как выходы, и на них подаётся сигнал:
Перейдём к чтению цифрового сигнала в режиме INPUT
Чтение цифрового сигнала
Цифровой пин может “измерять” напряжение, но сообщить он может только о его отсутствии (сигнал низкого уровня, LOW ) или наличии (сигнал высокого уровня, HIGH ), причём отсутствием напряжения считается промежуток от 0 до
2.1V. Соответственно от
2.1V до VCC (до 5V) микроконтроллер считает за наличие сигнала высокого уровня. Таким образом микроконтроллер спокойно может работать с логическими устройствами, которые шлют ему высокий сигнал с напряжением 3.3V, он такой сигнал примет как HIGH.
Данный код будет выводить в порт сигнал на пине D5. Если подключить его проводом к VCC – получим 1, если к GND – получим 0.
Как включить или выключить пин-код на телефоне
Защита смартфона для многих является приоритетом. Это неудивительно, учитывая, что мы храним в нем всю свою жизнь. Контакты, банковские карты, пароли, приватную переписку, документы по работе и многое-многое другое. Все это надо как-то защитить. Для этого производители придумывают большое количество степеней защиты. Пароль, графический ключ, сканирование лица, отпечаток пальцев, сканирование сетчатки… Все это хорошо, но царь всех паролей — это простой пин-код. Его надо ставить на все, что только можно, включая SIM-карту. Давайте-ка объясню, зачем. А заодно расскажу, как его включить и как выключить, если вам это будет надо.
Блокировка любого смартфона — это не пустой звук.
Для чего нужен пин-код телефона?
Ответ немного банален. Пин-код телефона нужен для того, чтобы сохранить его в безопасности и чтобы никто не получил доступ к содержимому вашего гаджета.
Также он нужен для того, чтобы вы могли активировать систему разблокировки по лицу или отпечатку пальцев. Прежде, чем их настроить, надо будет задать пин-код (или другой вид пароля). Эту нужно на тот случай, если биометрический метод разблокировки не сработает. Например, вы порежете палец.
Пин-код, как запасное средство разблокировки, спасает сейчас во время пандемии коронавируса. Выходя их дома в маске, не хочется каждый раз снимать ее для того, чтобы разблокировать смартфон. А зимой или во время занятий спортом может быть неудобно пользоваться сканером отпечатков. У меня комбо бывает летом, когда я еду на мотоцикле и останавливаюсь прочитать СМС. Перчатки с кевларовой нитью работают с сенсорным экраном, но закрывают отпечатки. А шлем закрывает лицо.
Как включить пин-код на смартфоне
Если при активации смартфона не задали пин-код или средство связи вам уже досталось активированным, вы можете задать нужный пин-код.
Для этого надо перейти в настройки, найти раздел ”Безопасность”, далее ”Блокировка экрана”. Если пароли у вас были отключены, вы сможете выбрать любой способ из предложенных. Если способ блокировки был включен, то вас попросят ввести пин-код, после чего можно будет выбрать пункт ”Нет” в выборе способа блокировки и снять защиту. Останется только подтвердить, что вы осознаете опасность.
Иногда названия пунктов могут отличаться, в зависимости от производителя. Например, в смартфонах Huawei и Honor настройка пароля вынесена в основное меню. Надо будет выбрать пункт ”Биометрические данные и пароли”, далее ”Пароль экрана блокировки”. Там вы можете его включить и задать нужные цифры. Если хотите включить биометрическую разблокировку, заходите в соответствующий пункт и активируете ее. Надо будет только задать пин-код перед активацией биометрических средств блокировки.
Чтобы отключить защиту, надо будет зайти в тот пункт настройки, который вам нужен, и отключить все, что надо. Перед отключением вас попросят ввести пин-код.
Если вам надо настроить не пин-код, а новый смартфон, вот хорошая инструкция.
Зачем нужен пин-код сим-карты?
Представьте себе такую ситуацию… Вы шли по улице, зашли куда-то и не заметили, как у вас украли смартфон. Например, в кинотеатре, театре или еще лучше, в аэропорту. То есть тогда, когда вы долго не сможете что-то сделать для блокировки симки.
С одной стороны, можно не бояться. Смартфон заблокирован. Его, конечно, жалко, но воспользоваться привязанными к нему картами никто не сможет — все, какие только можно, пароли включены. Но есть одна лазейка.
Вор просто достанет симку из вашего телефона, вставит ее в другое устройство и наберет свой номер. Так он узнает, какой номер телефона у вас. После этого он пойдет по сайтам банков в попытках восстановить ”забытый” пароль от личного кабинета. Долго искать не придется, так как проверить Сбербанк, ВТБ, Альфа-Банк, Тинькофф и Райффайзен Банк будет достаточно. Если время позволяет, можно проверить еще несколько вариантов.
После этого будет делом техники вывести все деньги, используя для подтверждения ваши же СМСки. Схема очень проста и изящна. Вы в это время будете смотреть кино или лететь на отдых, даже не зная, что что-то не так.
Для того, чтобы исключить такие ситуации, надо просто поставить пин-код на симку. Я уже уже рассказывал об этом подробно, но вкратце повторюсь. Даже банальных 9876 уже может быть достаточно для того, чтобы вор не угадал цифры с трех раз перед блокировкой карточки.
Если вы не включили пин-код на симку, первым делом звоните оператору или идите в салон связи и блокируйте ее. Практика показывает, что пользователи относятся к этому слишком расслабленно. А еще нельзя покупать симки в переходе.
Как включить пин-код на симке
Для того, чтобы защитить симку пин-кодом (лучше поздно, чем никогда), надо перейти в настройки смартфона, выбрать пункт ”Безопасность”, далее ”Дополнительные настройки”, потом ”Шифрование и учетные данные”. Теперь можно выбрать симку и настроить для нее пин-код.
Лично я давно пользуюсь всеми блокировками и вам советую. Они как ремень безопасности делаются не для того, чтобы были, а для вашей безопасности. Защиту симки тоже, хоть мы и считаем это пережитком прошлого. Но сейчас это стало как никогда актуально. Помните об этом.
Новости, статьи и анонсы публикаций
Свободное общение и обсуждение материалов
Маркетинг смартфонов может быть непростым делом, поскольку различные бренды стремятся привлечь как можно больше внимания со стороны потенциальных покупателей их продукции. И часто мы видим, что производители мобильных устройств делают это самыми странными и нечестными способами. Они осознанно идут на те шаги, которые мало кто посчитает правильными. Иногда это всплывает, и начинается каждый раз разного размера скандал. Часто это сваливается на ошибки или неправильную интерпретацию, но есть и совсем вопиющие случаи обмана, за которые сложно оправдаться и можно только попросить прощения. Именно о таких случаях мы и поговорим в этом статье.
Прошедшая неделя принесла нам ясность относительно нового процессора Qualcomm, который в следующем году будет устанавливаться едва ли не во все флагманские устройства на Android. Мы узнали, когда появится этот чипсет и его примерные характеристики. Так же мы узнали, что баг Google Pixel 6, связанный с плохим считыванием отпечатков пальцев, на самом деле является заранее запрограммированной функцией. Google даже объяснила, почему она так сделала. Были за прошедшие 7 дней и другие новости, которые могут в будущем повлиять на мир электроники. Один «MacBook» от Xiaomi чего стоит! Мы собрали все это в одном месте и готовы рассказать то, что надо знать о прошедшей неделе.
Вот сколько времени пользуюсь мобильниками, никогда не задавался зачем нужны эти pin и puk — коды?
Вот совсем недавно узнал что это и теперь хочу поделиться с теми кто также как и я, не знал что это такое:
PIN-коды (персональный идентификационный код):
PIN-код защищает SIM-карту от несанкционированного использования. Он запрашивается после установки SIM карты и при первом включении устройства. Он состоит из 4–8 цифр и обычно поставляется вместе с SIM-картой. Однако рекомендуется сменить исходный PIN-код и установить новый. Инструкции по установке PIN-кода приведены в руководстве по эксплуатации или на веб-сайте Nokia.
Код UPIN обычно предоставляется вместе с USIM-картой. USIM-карта — это расширенная версия SIM-карты, которая поддерживается мобильными телефонами UMTS.
Код PIN2 состоит из 4–8 цифр и поставляется с некоторыми SIM-картами. Он необходим для доступа к определенным услугам.
Если любой из перечисленных PIN-кодов был указан неправильно несколько раз подряд, потребуются соответствующие коды разблокировки PUK. Дополнительные сведения о PUK-кодах приведены далее.
PUK-коды (персональный деблокировочный ключ):
PUK-код, состоящий из 8 цифр, требуется для изменения заблокированного PIN-кода.
UPUK-код требуется для изменения заблокированного UPIN-кода.
PUK2-код требуется для изменения заблокированного PIN2-кода.
PUK-коды также предоставляются оператором сети.
Буду очень рад если кому то эта информация будет полезна:-)
К вопросу о пинах
Дню знаний посвящается.
Данный пост посвящен тому, с чем сталкиваются все пользователи Ардуино (далее по тексту А, имейте в виду что под этой буквой будет прятаться как сам кристалл, так и среда разработки программ), а именно с работой с портами ввода/вывода.
Вы спросите, а что, собственно, тут рассматривать? Функции работы с портами прописаны ясно, есть большое количество примеров, поэтому использование портов не представляет никакой сложности. Начальная программа мигания светодиодом использует эти функции и прекрасно работает, о чем речь?
Все это верно, но лишь до того момента, когда вам потребуется подключать к А что-нибудь пошустрее светодиода (у меня нет претензий к этим замечательным приборам, но обычно в силу специфики использования особого быстродействия от них не требуется), и тут то Вам понадобится эффективная работа с пинами (будем так для краткости именовать порты ввода/вывода), и тогда на форумах возникают вопросы «почему у меня так медленно работает программа», на которые молодые гуру мгновенно отвечают «работай напрямую с регистрами и будет тебе счастье» и показывают, как именно, по их мнению, следует это делать.
Несмотря на то, что в их ответе есть толика истины, тем не менее такой ответ далеко не полон, в чем то не совсем верен (посмотрите, как именно они рекомендуют работать с регистрами), не вполне оптимален, и не слишком понятен. Заполнить пространство между стандартными скетчами и подобным ответом и предназначен настоящий пост.
Поскольку я вижу перед собой читателя с различным уровнем подготовки, то постараюсь ориентироваться на различный диапазон знаний в области МК (микроконтроллеров), поэтому, если Вам что то покажется хорошо известным (а будет немало таких мест) смело пропускайте этот фрагмент, а вот если что то будет не вполне понятно, то комментарии и существуют для того, чтобы там задавать вопросы, я их читаю и, по мере своих сил, пытаюсь ответить.
Для начала, немного теории. Пины, как следует из их определения, предназначены для взаимодействия созданной Вами программы с внешним миром (при этом внутренним миром считается только сам МК). Для того, чтобы использовать пины, Вы должны знать об их существовании и, поскольку их более одного, уметь эти пины указывать (это называется именованием или адресацией). Поэтому каждый доступный Вам пин (а бывают и недоступные, но они нам неинтересны с практической точки зрения) должен иметь уникальный параметр, его характеризующий. В А приняты в качестве такого параметра номера пинов и, хотя это не единственный возможный способ, он по-своему неплох. Далее все, что Вам нужно знать, это о наличии связи пина, имеющего конкретный номер, с конкретным выводом МК и, соответственно, контакте на гребенке, через которую подключаются к Вашей плате (конечно, это плата А, но, раз Вы ее купили, она Ваша) различные внешние устройства, и соответственно, о влиянии конкретного пина на конкретное внешнее устройство.
Например, если Вы хотите, чтобы расположенный на плате А светодиод засветился, то Вы должны на пин 13 подать уровень «Low», а для продвижения данных через микросхему сдвигового регистра сформировать на пине 6 переход из низкого уровня в высокий и так далее. Причем для первого случая — управления светодиодом дальнейшие рассуждения не имеют особого смысла, поскольку приемником информации является человеческий глаз, а его возможности по части быстродействия не превышают десятков Герц, то для управления сдвиговым регистром время изменения уровня на ножке весьма существенно, так как для вывода информации на внешнее устройство (например, семи-сегментный индикатор) Вам потребуется множество изменений и их совокупное время может оказаться неприемлемым для конкретного случая (будет блокировать работу остальных частей программы, критичных по периоду опроса, типа обработки энкодера, что нарушит их работу). Ну а если Вы управляете пином виртуального SPI, то получившееся быстродействие SD карточки Вас весьма неприятно удивит, так что задача ускорения работы с пинами вполне практическая.
Для управления пинами в А существуют предопределенные функции, главной из которых является DigitalWrite, которой Вы должны сообщить номер пина для модификации и значение на нем после выполнения функции. Однако, если у Вас после написания команды DigitalWrite(13,Low) проблемы закончились (при условии, что Вы не забыли где то раньше команду настройки режима пина), то у исполняющей системы они только начинаются. Дело в том, что существуют архитектуры МК, в которых каждый пин действительно имеет уникальный адрес, чем обеспечивается легкое отображения Вашей команды на систему команд МК, чем и занимается исполняющая система (связка компилятора и системной библиотеки), но фирма Atmel в те времена, когда создавалась А, своих поклонников подобными изысками не баловала (это не совсем верно, но в первом приближении так). В микроконтроллерах семейства Мега, на которые платформа А исторически базировалась, принята несколько иная схема работы с пинами. Здесь работа с внешним миром осуществляется не через уникальные пины, а через порты ввода/вывода, которые представляют собой совокупность пинов (в данном случае не более 8) и, соответственно, каждый пин имеет в физическом представлении 2 параметра — имя порта (представляется буквой от А до Е в разных представителях семейства МК) и номером бита внутри порта (цифра от 0 до 7). Так, например, пин 13 может иметь физический адрес РB.5 в одном МК, и РC.0 в другом.
Поэтому первая задача исполняющей система — преобразовать номер пина в физическое представление для последующей работы с ними. Решать эту задачу можно различными способами и, на мой взгляд, в А это сделано не лучшим способом, но, к счастью, система является открытой, и мы можем внести необходимые изменения и исправления в нее.
Прежде всего, заметим, что в исполняющую систему входят две компоненты — компилятор (на самом деле под этим собирательным именем прячутся отнюдь не одна функция, а, как минимум, препроцессор, собственно компилятор, ассемблер, компоновщик и библиотекарь, а также исполняющая подсистема, представленная библиотечными модулями (скетчами). Так вот, задача преобразования должна быть решена либо на этапе компиляции, либо на этапе исполнения, либо каким то образом распределена между этими этапами. И предпочтительнее сделать как можно больше работы на первом этапе, поскольку затраты времени на нем пренебрежимы по сравнению со временем собственно написания кода, а вот любые затраты (памяти и времени) на этапе исполнения требуют расходования ограниченных (по сравнению с платформой разработки) ресурсов МК. К сожалению, данное предложение не всегда реализуемо, но в условиях, когда известен конкретный состав системы исполнения и наличествуют все исходные файлы, может быть весьма полезно. Но это я слегка забежал вперед, чуть приостановимся и посмотрим реализацию функции работы с пином в А. Вот исходный код функции
Сразу же отмечу, что данный код взят отсюда, как и последующие исходные коды, но он не похож на фэйковый, да и в других источниках мне попадался именно такой код, так что будем считать его действительно кодом для А.
Прежде, чем мы двинемся по тексту, для начала выскажу неудовольствие сигнатурой функции, и это неудовольствие вполне обоснованно. Оба параметра совершенно очевидно не являются целыми числами и принимают ограниченный набор значений, так что они должны быть определены, как экземпляры перечислимых типов, что позволит нам проконтролировать правильность передаваемых в них фактических параметров, по крайней мере в отношении константных выражений, что и сделано в моей реализации. Ну а теперь можно перейти и к рассмотрению кода.
Что мы тут видим — прежде всего преобразование номера пина в физический адрес, осуществленное путем извлечения информации из таблицы констант. Рассмотрим эту операцию более подробно, для чего пойдем по исходному тексту, смотрим код и видим операцию получения битовой маски:
И обнаруживаем, что это макрос-расширение, который передает номер пина другой функции и добавляет имя таблицы, где хранятся номера битов. Далее выясняем, что:
Это тоже макрос-обертка, передающий свои аргументы следующей функции, сразу же выясняется, что:
Это… да, верно, макрос-обертка, Вы начинаете улавливать принцип, передающий свои аргументы в функцию:
Которая является (кто бы мог подумать) макросом-оберткой для функции, которая является… а вот тут не угадали, должно же было все закончиться рано или поздно, настоящим макросом-подстановкой ассемлерной вставки. Мне не слишком понятно наличие четырех оберток, но, поскольку мы договорились (вернее я это утверждал, а Вы не спорили, или спорили, но я этого не заметил), что время компилятора не стоит ничего, то не будем акцентировать внимание на данном аспекте, а просто удивимся вслух, зафиксируем свое удивление на бумаге и пойдем дальше смотреть код.
Рассмотрим текст функции извлечения данных из таблицы более внимательно, тут есть ряд интересных моментов. Поскольку нам дана ассемблерная вставка, то следует учитывать особенности реализации архитектуры МК, для нас важно, что он 8-разрядный и аккумуляторный.
Обратим внимание на первые две строчки, где фактический параметр извлекается не из текста подстановки макроса, а из промежуточной переменной __addr16, и поставим вопрос — почему сделано именно так, это же лишние пересылки. Придуманный мною ответ — может быть, это действительно было необходимо, если мы желаем в качестве номера пина применять статически невычислимые выражения, то есть строку символов, значение которой невозможно определить на этапе компиляции с точностью до одной пересылки. Тогда при раскрытии макроса будут сгенерированы команды, вычисляющие данное выражение «на лету», результат передан в промежуточную переменную, а дальше использован по назначению. То есть в данном случае мы имеем учет особенностей препроцессора, а не архитектуры МК, за которые приходится платить быстродействием. Вы уже догадались, что я не в восторге от подобной практики, когда за возможность применять статически неопределенные выражения должны платить все вызовы функции, в том числе и с константными параметрами, которых будет подавляющее большинство.
(Позднее примечание. Просмотр реального кода показал, что эта строчка не порождает дополнительного кода в рассматриваемом компиляторе, ее удаление и прямая передача ассемблеру аргумента макроса не изменяет код ни насколько, так что видимо это наследие проклятого прошлого, так и оставим, раз на максимальную скорость не влияет, а текст удалять не хочется, идея то была неплохая).
Необходимое пояснение — хотя я и рассуждаю о недостатках реализации А функции, тем не менее должен признаться что самой платы А у меня нет, то есть конечно есть, но это так называемая А совместимая плата Intel Edisson, которая хоть и может программироваться из А среды, тем не менее никоим образом на является заменой платы собственно А. Следующий грех, в коем я должен признаться — я не пользуюсь А средой разработки, на что есть множество причин…
Далее (вернее, чуть ранее) мы видим извлечение дополнительной информации из вспомогательной таблицы, которая сообщает нам, не является ли данный пин выходным портом таймера. Я не очень понимаю, как именно этот факт может повлиять на нежелание исполняющей системы работать с таким пином без отключения таймера (мне кажется, что в данном случае она на себя много берет), но то, что такая проверка требует дополнительного времени, для меня несомненно. Возможно, это наследие проклятого прошлого, истинный смысл подобного решения недоступен для непосвященных в сокровенные тайны А. Что мы можем сделать для ускорения работы? Ну можно совместить данную проверку с получением индекса порта, введя специальное значение, тем более, что такая подобная проверка индекса порта на допустимость осуществляется несколькими строками позже. Далее, мы можем определить условную компиляцию, предоставив пользователю возможность определить, а готов ли он платить временем исполнения (если бы речь шла о времени компиляции, я был бы только рад) за дополнительную проверку. Ну и как вишенка на торте, само условие проверки с использованием двойного отрицания мне лично представляется несколько вычурным, простое условие if (timer == IS_ON_TIMER) ничем не уступает оригинальному условию, но понятнее при прочтении. Обратим еще внимание на то, что получаем это значение в одном месте, а используем (причем один раз) намного позже, что тоже не есть красиво, что неизбежно для языка С, но у нас то С++, и можно сделать правильнее, хоть и не быстрее.
Еще один интересный момент, связанный с проверкой на таймер. Тут присутствует несомненная ошибка, если Вы посмотрите на порождаемый код в функции выключения шима (посмотрите этот код самостоятельно) turnOffPWM(), то увидите возможность нарушения работы других модулей. Конечно, она будет проявляться крайне редко, может быть, вообще никогда не проявится (но не забывайте о законах Мерфи), но она есть и должна быть безусловно исправлена, ведь иначе ЭТО могут увидеть дети, и решить, «а я и не знал, что ТАК можно».
Далее следует проверка индекса порта на допустимость, поскольку далеко не все пины могут иметь физическое представление в конкретном МК. И опять тут не все сделано хорошо. Во первых, нарушается правило, что каждая функция должна иметь одну точку выхода, ну тут достаточно слегка подправить текст. Правда, возрастет цикломатическая сложность программы, но тут приходится выбирать, какое из взаимоисключающих правил поддерживать. Во вторых, мы опять должны платить за паранойю разработчиков временем исполнения, причем нас не спрашивают, нужна ли нам такая забота. Есть два варианта увеличения быстродействия этого фрагмента — первый это условная компиляция, а вот второй похитрее — указание в элементах таблицы, соответствующих отсутствующим пинам, адреса порта и номера бита, изменение которого нейтрально по отношению к внешним выводам (и внутренним регистрам МК, что даже более важно). Проще всего указать нулевую битовую маску для реального порта, но возможны варианты. Да, в этом случае мы проделаем бесполезную работу в случае неправильного номера пина (отсутствующего в данном МК), но не потратим время при правильном номере.
Вот в чем с разработчиками А нельзя не согласиться, так с необходимостью не допустить модификацию внутренних битов регистров МК при задании неверного номера пина, чем указанный фрагмент кода и занимается, но тогда почему, черт подери, такой проверки нет в самом начале функции, ведь если мы попросим изменить состояние пина 137, то получим совершенно непредсказуемое поведение программы, и это разработчиков А абсолютно не волнует — налицо забавное сочетание паранойи и пофигизма, я думал, последнее свойственно только нам, славянам. Мы можем вставить такую проверку в текст функции, но намного лучше делать, как я советовал в самом начале — создать пользовательский тип и компилятор сделает нужные проверки сам и на фазу исполнения ничего не останется. Опять таки, Вы легко можете данную проверку обойти и выстрелить, куда только захотите, но Вам придется ясно и четко компилятор о своем намерении предупредить и потом не жалуйтесь.
Смотрим дальше и замечаем, что номер бита извлекается в одну стадию, а адрес порта — в две стадии, сначала по номеру пина получаем индекс порта — число от 0 до количества портов, а затем на основании индекса извлекаем собственно адрес порта. Зачем так сделано, ведь это очевидно дольше, чем сразу получить нужный нам адрес — можно придумать два объяснения. Во-первых, такая методика дает бОльшую гибкость — честно говоря, притянутое за уши объяснение. Вторая возможная причина — экономия размера ПЗУ, которая составит в байтах количество пинов минус размер дополнительного кода, то есть байтов 6-8, что мне представляется явно недостаточной компенсацией за существенное уменьшение быстродействия. Более того, тот же результат может быть достигнут и при помощи указания в первой таблице не индекса, а смещения с последующим превращением его в адрес менее затратным путем сложения с базой или даже комбинирования, как продемонстрировано в моей реализации. Да, этот способ не столь переносим, как оригинальный, но насколько я помню, директивы условной компиляции никто не отменял. Вообще то, у меня складывается впечатление, что многие компоненты библиотек А делались на скорую руку из уже существующих универсальных (кто такой универсал — человек, который умеет делать множество дел одинаково плохо) заготовок, а дальше действовали по принципу «Эта штука работает? — Да. — Не трогай ее.» К сожалению, намного более быстрый способ обращения к портам через команды in и out в данном случае неприемлем, поскольку указать номер порта в качестве аргумента команды в общем случае невозможно.
Продолжим рассмотрение кода. Мы получили адрес порта и маску бита и можем приступить к собственно выполнению операции, то есть тут мы видим именно то, что нам рекомендуют юные гуру от А. Еще раз, как я уже неоднократно делал в своих постах, умоляю Вас так не делать. То есть другого пути изменить содержание бита в порте нет (а вот я Вас и обманул, есть, но об этом чуть позже), но совершенно необязательно оформлять этот путь в виде прямой операции. Обязательно оберните обращение к регистрам в макрос или инлайновую функцию, это Вам может сэкономить немало времени при отладке. Конечно, если Вы принадлежите к числу счастливчиков, которые никогда в своей жизни не забывали символ
перед маской, то обертка Вам не нужна (но тогда зачем Вы вообще это читаете, мой пост не для полубогов от программирования), но вреда она не принесет точно, а вот для нормальных людей, которым свойственно ошибаться, она весьма полезна. Причем авторы А о такой необходимости знают, посмотрите реализацию выключения ШИМ, там как раз стоит макрос на сброс бита, но в этом конкретном месте они такой возможностью высокомерно пренебрегают.
И еще обратим внимание на то, что собственно работа с регистром, а именно чтение-модификация-запись обрамлены дополнительными строками, назначение которых непонятно для неофитов. Мы то с Вами понимаем, что это защита от совместного использования ресурса, выполненная в классическом стиле критической секции, где бит разрешения прерывания используется в качестве семафора, но она с неизбежностью требует времени для исполнения, даже если она в данной конкретной программе (надеюсь, никто не обиделся, что я так назвал скетч) не нужна. Привлекая на помощь условную компиляцию, мы можем еще немного улучшить скорость работы функции. Рекомендую обратить внимание на то, что все вновь вводимые условия компиляции изначально поставлены таким образом, чтобы работа функции в режиме по умолчанию нисколько не изменилась, дабы сохранить преемственность, вдруг в каком то скетче учитывалось, что время работы функции именно такое, и это важное обстоятельство не должно изменяться.
Кстати, одно интересное наблюдение. При отсутствии защиты от совместного использования регистра может быть потеряна работа по изменению состояния битов порта, произведенная той частью программы, которая прервала работу другой части, и никогда не наоборот. Видимо, таким образом реализует себя мировая справедливость, выраженная в народной мудрости «кто мешает, того бьют».
И еще один маленький камешек в огород А — из текста функции нетрудно видеть, что описание работы функции не вполне верно — если значение второго параметра равно LOW, то бит будет сброшен, в противном случае (а не если параметр будет равен HIGH, как в описании) бит будет установлен. Если этот параметр принимает только указанные значения, то данное уточнение не имеет смысла, но в оригинальной функции его значения ничем не ограничены, кроме доброй воли программиста.
Для того, чтобы Вам были понятны следующие вычисления, под спойлером лежит получившийся при компиляции код с комментариями:
Теперь можно подвести итоги. Вызов+преамбула+постамбула — 4+9+10 = 23, защита ресурса — 3, защита таймера — 7+3 = 10, защита пина — 2 получение номера бита — 7, получение адреса порта — 7+14 = 21, модификация значения — 10/8, что дает нам время исполнения функции 76/74 такта, или при тактовой частоте МК 16 МГц составит 4.75/4.625 мксек — результат вполне ожидаемый для того, кто видел исходный код и знаком с архитектурой AVR. В разных источниках я видел разные цифры времени исполнения функции digitalWrite, но они были только больше полученных в данном случае.
Интересное наблюдение — время установки и сброса бита различаются, что не есть слишком хорошо. Данный недостаток легко исправить, заменив условие на обратное, тогда мы получаем 9/9 — выравнивание приводит к увеличению одного из времен, но зато они выравниваются — мелочь, а приятно.
Тот же одинаковый результат получается при использовании команды пропуска, причем мы получаем 8/8, но почему то (понятно почему, ведь изменяется логика работы функции, а это недопустимо) компилятор отказывается ее использовать и не хочет сделать такой код, как хотелось бы, а именно из следующего кода
получить следующую минимально возможную программу
Неожиданно пришло в голову следующее соображение — стандартная реализация временного отключения прерывания, рекомендованная фирмой Atmel в многочисленных примерах, небезопасна. Она уязвима в точке от чтения текущего значения регистра состояния и до запрета прерываний, так что результаты работы функции, прервавшей программу в этой точке, по изменению бита разрешения прерывания будут потеряны в момент восстановления регистра состояния сохраненным значением. Конечно, переход 0-1 просто невозможен, но переход 1-0 вполне себе представим. Как то мне не по себе стало от такого открытия, либо я чего то недопонимаю, либо одно из двух. Единственное, что могло бы спасти в подобной ситуации — внутренний запрет на прерывания на 1 такт после чтения регистра состояния, но в документации я такого примечания не нашел. Если кто в курсе — прошу в комменты.
Ну а теперь посмотрим, к чему мы пришли в результате реализации вышеперечисленных изменений при оптимизации на скорость. Вот исходный код:
Вызов+преамбула+постамбула — 4+1+4 = 9, защита ресурса — 0, защита таймера — 0, защита пина — 0, получение номера бита — 7, получение адреса порта — 7+2 = 9, модификация значения — 8/8, что дает нам время исполнения функции 9+7+9+8/8 = 33/33 такта, или при тактовой частоте МК 16 МГц составит 2.062/2.062 мксек, совсем неплохо, ускорение в 2 раза, но можно и лучше, для чего есть два пути.
Первый из них заключается в смене парадигмы использования пина, где в существующем подходе при каждом использовании функции заново происходят все вычисления. Альтернативой данному подходу будет разбиение работы с пином на две части — отдельно преобразование номера пина в физические параметры со всеми необходимыми проверками и отдельно использование полученных результатов для собственно модификации содержимого бита, соответствующего физическому адресу. Очевидно, что само по себе такое разбиение при однократном вызове функции не может привести к увеличению быстродействия, но мы крайне редко изменяем значение пина один раз в программе, а вот в противном случае выигрыш может быть значителен. Недостатком такого метода является необходимость выделения памяти для хранения промежуточных результатов, но за все в этом мире надо платить, ДарЗаНеБы. Получаем следующий код, иллюстрирующий данную возможность:
И мы видим, что наши усилия увенчались успехом — время модификации пина составляет всего лишь 13+3+9+8/8 = 33 такта при включенной защите от прерываний и 30 тактов при выключенной (остальные режимы не влияют на данную функцию, поскольку остались в фазе преобразования, а Вы догадались не ставить ее перед каждым вызовом фазы исполнения), при этом время вычисления адреса увеличилось незначительно, чего и следовало ожидать. Но почему прирост не слишком большой, всего лишь 10%, ведь мы убрали из фазы выполнения работу с таблицами? Все дело в извлечении параметров функции из памяти при таком подходе, обратите внимание на то, как возросла длительность преамбулы и длительность выборки (9) и поглотила значительную часть выигрыша от операции.
Для улучшения ситуации используем другой способ передачи параметров, а именно DigitalPut2(Pin13.Port,Pin13.Mask,LOW); и получаем куда больший выигрыш 15+8/8 = 24 такта с отключенной защитой (27 с защитой), что почти на 30% лучше быстрого варианта в 30 тактов и в 3 раза быстрее оригинального варианта:
Неплохо. но мы то рассчитывали на большее. Конечно, даже маленькая рыбка лучше большого таракана, но мы то хотим поймать большую рыбку, можно ли сделать это в нашем пруду?
Дело в том, что когда я заявлял о невозможности другого способа изменения состояния бита в регистре, я намекнул, что он таки есть. И этот путь связан с использованием специальных команд работы с битами, а именно команд с мнемониками CBI и SBI. Почему мы оставили эту возможность напоследок — потому что это зависимое решение и оно плохо реализуемое (вообще никак не реализуемое) в рамках языка С, но то же самое можно сказать и про чтение данных из таблиц, привлечение ассемблера неизбежно.
К сожалению, обе эти команды не принимают никаких параметров, что не позволяет указать номер пина для модификации и вид модификации, а эта информация есть часть самой команды и мы имеем чисто теоретически 32 различных команды для 32 различных портов. Учтем возможность наличия у каждого порта 8 бит и получим 256 различных команд. Поскольку вид модификации пина, а именно установка либо сброс бита, тоже есть часть команды, всего получается 512 различных команд.
Немаленькое такое количество, в архитектуре 51 всех команд было не более 256, а тут такая роскошь, но 16-разрядная система команд может себе это позволить. Конечно, далеко не все из этих 512 команд будут производить осмысленные действия на конкретном МК, но некоторые будут и мы должны иметь возможность максимально быстро одну конкретную команду из этого набора выполнить.
У читателя сразу возникнет вопрос — а зачем нам такие проблемы с привлечением ассемблера и прочих сложностей, и я сразу же на него отвечаю — эти команды атомарны (не-прерываемы) что позволяет нам существенно сэкономить на времени исполнения, не отключая защиту от совместного использования ресурса, поскольку для атомарных операция она излишня. Итак, мы можем реализовать обращение к конкретной нужной нам команде классическим способом, создав таблицу команд и получив доступ к ней при вычислении индекса в таблице «на лету», как показано в следующем фрагменте кода:
Вызов+преамбула+постамбула — 4+0+4 = 8, защита ресурса — 0 (но она есть), учет значения — 3, получение точки входа — 6, получение адреса функции — 3+3+2 = 8, выполнение операции 3+2+4 = 9, что дает нам время исполнения функции 8+3+6+8+9 = 34/34 такта. Пока не очень ясно, зачем мы вообще все это затеяли, но вот как раз наступил момент, когда мы можем (и должны) слегка улучшить код, порожденный компилятором, и заменить вызов функции p() на asm («ijmp \n\t») (ну не совсем так, но смысл передает), что позволяет нам сэкономить 4 такта на постамбуле за счет совмещения операций, итого 30 тактов с защитой.
При этом нам потребуется 3*П (максимальное количество пинов) слов памяти программ по 2 байта каждый — 1 слово для собственно кода команды, 1 слово для кода возврата после выполнения каждой команды и 1 слово для хранения адреса команды в таблице адресации. Сразу же отметим, что эти вычисления дают верхнюю границу, поскольку для несуществующих пинов точка входа в пустую функцию одна и мы должны выделить 2*П1 (количество реально используемых пинов + 1)+П слов памяти программ, тем не менее требуемое количество памяти неплохо бы уменьшить.
Пробуем применить принцип разделения фаз вместе с модификацией таблиц и получаем:
Вызов+преамбула+постамбула — 7+0+4 = 11, защита ресурса — 0 (но она есть), учет значения — 3, получение точки входа — 0, получение адреса функции — 0, выполнение операции 2+3+2+4 = 11(7), что дает нам время исполнения функции 11+3+11(7) = 25(21) тактов, что лучше, чем для варианта с портами на целых 6 тактов. Заметим, что для ослабления требований к памяти, мы расположили таблицу команд несколько иным образом, тогда нам потребуется ровно 2*П слов в памяти программ. Вам решать, какая реализация предпочтительнее, быстродействие их близко.
Если мы аккуратно перепишем на ассемблере вызов функции и саму функцию работы с пином (оставляю это упражнение на долю пытливого читателя), то получим 11+3+(3+2)5=19 тактов, и это, похоже, предел совершенства.
Что мы получили в результате такой резкой смены парадигмы — существенное увеличение быстродействия в варианте с защитой от совместного использования ресурса, но не слишком значительный прирост в сравнении с вариантом, когда для порта защита отключена. На первый взгляд, несколько странный результат, ведь если раньше основная работа производилась четырьмя командами, то теперь только одной и мы должны были бы получить кратный прирост скорости. Дело в том, что накладные расходы на выполнение собственно модификации состояния пина не изменились и мы по прежнему должны потратить 2 такта на вызов функции и 4 на выход из нее (а еще определенное количество тактов на передачу фактических параметров, но будем считать, что нам повезло и эта часть оптимизирована компилятором до полного отсутствия), раньше было 4+4=8 тактов на обработку, теперь получается 1+4=5 тактов и прирост производительности даже не в 2 раза, а если учесть еще и время на подготовку — пересылку параметров в регистры, то и того меньше. А заплатить за такое не слишком значительное увеличение быстродействия нам пришлось вполне конкретной памятью программ и данных для хранения адреса функции.
Недоумение читателя вполне понятно, но, во первых, это все равно увеличение быстродействия, и если нам очень нужна скорость, то мы можем себе позволить пожертвовать памятью (не бывает оптимизации без целевой функции с конкретными весами параметров), а во вторых такой подход с одной командой для выполнения работы позволяет нам в определенных случаях достичь максимально возможного быстродействия, то есть одной команды на операцию модификации пина.
Что это за случаи и почему они не всегда присутствуют, хотя и довольно таки часто? Речь идет о ситуации, когда выполнены два условия: первое — нам доступны исходные коды программных модулей, для которых необходима быстрая работа с пинами, и второе — номера пинов должны быть константными, то есть известны на этапе компиляции (именно константными, а не статически определенными, это важно). Тогда мы можем создать макро-подстановку для работы с пинами следующего вида:
Еще раз обращу Ваше внимание, что, например, для реализации интерфейса типа I2C или SPI данный способ представляется весьма привлекательным, обеспечивая действительно необходимое быстродействие, а вот реализация сканирования клавиатуры будет не слишком удобна, потребуется оператор выбора для включения конкретного пина, а максимально возможное быстродействие здесь не особо нужно, но решать Вам, как мы и договорились, я только даю Вам веревку, а способ нацеливания ее в нужное место остается в Вашей компетенции.
Другой идеальный вариант в том же самом случае выглядел бы как макроподстановка, генерящая код команды из своих константных аргументов, что нибудь вроде:
Но мне почему то построить подобную конструкцию не удалось, если кто знает, как это сделать, прошу в комментарии.
Если бы у нас был нормальный макро-язык в препроцессоре, то можно было бы написать обобщенную подстановку, которая генерировала бы оптимальный вариант для каждого случая, не заставляя программиста задумываться о том, какую конструкцию вызвать и какую парадигму использовать, но это из области беспочвенных мечтаний, поскольку стандартный препроцессор С таких возможностей не предоставляет (по крайней мере мне не предоставляет, если Вы с ним в более дружеских отношениях, поделитесь секретами).
Вот такое получилось эссе на тему быстрой работы с портами в система А, может быть, кто то станет лучше понимать происходящее в МК, для кого нибудь станет отправной точкой для своих собственных экспериментов с платформой. Кстати, у меня давно лежит недописанный пост на тему собственно платформы А как таковой (конечно, это не рассказ о том, как установить и настроить среду разработки и помигать светодиодом, я обычно парю с других эмпиреях), не нахожу в себе сил закончить и опубликовать, когда начинал, думал, что тема будет интересна широкому кругу читателей, а потом засомневался и решил сделать более практически применимый пост, который Вы и прочитали до конца, я надеюсь. Замотивируйте меня в опросе на его завершение и публикацию, ведь обратная связь — важная часть любого рода деятельности, в особенности публичной, каковой и является написание постов.