- Embedder’s life
- Подтягивающие резисторы: номинал имеет значение
- Электроника для всех
- Блог о электронике
- AVR. Учебный Курс. Отладка программ. Часть 3
- 22 thoughts on “AVR. Учебный Курс. Отладка программ. Часть 3”
- Электроника для всех
- Блог о электронике
- AVR. Учебный курс. Устройство и работа портов ввода-вывода
- 191 thoughts on “AVR. Учебный курс. Устройство и работа портов ввода-вывода”
Embedder’s life
Подтягивающие резисторы: номинал имеет значение
В прошлый раз я писал про приключения с UART’ом, произошедшие, в общем, сугубо по моему недосмотру. Сегодня все будет интереснее.
В том девайсе, над которым я работаю, в числе прочего есть порт RS-485. Для реализации оного я выбрал микросхему MAX13433E. По прочтении даташита она производит впечатление простого и удобного прибора: из обвязки требуется всего два керамических конденсатора, все защиты встроены (по выводам RS-485 ESD-защита 30 kV), так что для не особо суровой линии можно обойтись без дополнительных супрессоров и прочего. Сказка, а не микросхема.
Получил детали, спаял, подключил, написал код для общения через RS-485, начал тестить и наткнулся на сюрприз — интерфейс работал через раз. Тыкание осциллографом и тесты с коммуникацией в обход показали, что проблема в микросхеме — до нее сигнал (в направлении приема) есть, после нее — нет.
Более пристальное изучение феномена показало, что переход из состояния «не работает» в состояние «работает» совершается, если ткнуть пальцем/щупом в вывод разрешения работы приемной части, и после этого счастье длится до выключения питания. Создавалось ощущение, что вывод болтается в воздухе. Тем не менее, этот вход был подтянут к земле (активный ноль) резистором в 12 килоом, и замеры показывали полную идиллию — резистор не оборван, земля — это земля и вообще все хорошо.
В общем, оказалось, что резистор озвученного номинала великоват. Казалось бы, там же CMOS-вход, в чем дело? Я подозреваю, все дело в цепях, которые обеспечивают то, что в даташите названо «hot-swap capability». Смысл в том, что после включения питания внутренние цепи подтяжки обеспечивают неактивные уровни на входах разрешения приема и включения передатчика. На странице 15 даташита уверяют, что после выхода в рабочий режим эти цепи становятся полностью прозрачными, и изначально я так понял, что отключаются они либо по таймауту, либо после стабилизации напряжения питания. Тем не менее, похоже, что на самом деле эти цепи отключаются в момент подачи первого «сильного» логического уровня на соответствующий вход разрешения. Приемник-то у меня должен быть включен всегда, и потому я просто подтянул его вход разрешения к земле. Видимо, номинал в 12 килоом оказался слишком велик для того, чтобы упомянутый блок внутри микросхемы почувствовал его наличие.
Я поменял номинал подтягивающего резистора на 2.4 килоома, и сейчас все работает. Конечно, насколько я прав покажут более серьезные тесты, но пока ощущение, что все дело было именно в этом, только крепнет.
UPD:
m08pvv пожаловался, что в статье нет картинок. Поправляю это. 😀
Электроника для всех
Блог о электронике
AVR. Учебный Курс. Отладка программ. Часть 3
Метод 3. USART (Работа с последовательными интерфейсами)
Пожалуй самым популярным отладочным интерфейсом является все же USART. Во-первых, он поддерживается аппаратно почти всеми микроконтроллерами. Во-вторых, он прост в использовании и требует всего один/два сигнальных провода, а в третьих, для связи с компом не надо городить никаких специфичных девайсов. В худшем случае UART-USB или UART-RS232 конвертер на FT232RL или MAX232.
Пользоваться им проще простого — в любой момент, когда нам это захочется, мы берем и отправляем нужный байт по этому интерфейсу. При этом достаточно заранее его настроить — стандартная инициализация UART:
; Usart INIT .equ XTAL = 8000000 .equ baudrate = 9600 .equ bauddivider = XTAL/(16*baudrate)-1 uart_init: LDI R16, low(bauddivider) OUT UBRRL,R16 LDI R16, high(bauddivider) OUT UBRRH,R16 LDI R16,0 OUT UCSRA, R16
; Прерывания запрещены, прием-передача разрешен. LDI R16, (1
Для отправки надо записать наше маркерное число в регистр UDR, пусть это будет код буквы «А».
LDI R16,’A’ OUT UDR,R16
Я даже проверку на занятость UDR не делаю. Для одиночного байта, если у нас отправки по UART нет и участок не зациклен, этого вполне достаточно — регистр будет свободен. Разумеется в реальной программе такого делать не следует, но для отладочной затычки вполне сойдет.
Можно нафаршировать весь код такими вот затычками, но с разными буквами и смотреть в терминалке в каком порядке программа выполняется по выдаваемому слову. Правда учитывайте тот момент, что если данные будут сыпаться в терминалку быстрей чем она ее может прожевать, то регистр UDR захлебнется и у нас будет полная лажа. В этом случае можно сделать затычку чуть сложней, с ожиданием освобождения UDR
LDI R16,’A’ SBIS UCSRA,UDRE ; Пропуск если нет флага готовности RJMP PC-1 ; ждем готовности — флага UDRE OUT UDR, R16 ; шлем байт
Можно в макрос это запихать:
.MACRO DEB_SEND PUSH R16 LDI R16,@0 SBIS UCSRA,UDRE RJMP PC-1 OUT UDR,R16 POP R16 .ENDM
Заодно R16 в стеке спрячем, так что макрос можно юзать где угодно, словно команду:
Но это затормозит выполнение программы, могут полететь тайминги. Так что если у вас есть какие то участки жестко зависимые от времени (скажем тайминги протокола 1-wire), то данная затычка даст сбой.
Выводить можно любую инфу. Например содержание нужных регистров, содержание переменных, ячеек памяти, состояния битов регистров периферии. Что хотим поглядеть — то и тащим. Надо только загрузить это в UDR. А поскольку там могут быть произвольные значения, то глядеть их лучше через терминалку способную показывать в хексах. Например, моя любимая Terminal v1.9b.
Также полезно выбрасывать в терминал маркеры прохождения кода. Чтобы оценить правильность переходов и логики работы.
Еще настоятельно рекомендую заиметь спец литеру отправляемую в терминал сразу же после инициализации USART, еще до перехода к основной программе. У меня это обычно буква «R». От «Reset». Это позволяет поймать момент перезагрузки контроллера.
Например, глючила у меня программа. Все работало нормально, но при попытке принять байт все начинало странно глючить. Все облазил, код весь до дыр проглядел. По коду все должно работать… Наконец воткнул в код OUTI UDR,’R’ еще до вхождения в main. Опаньки — а контроллер то сбрасывается!
А почему контроллер может сбрасываться? Сбой по питанию я исключил сразу — не было там ничего такого, что бы могло дергаться. RESET был подтянут через 10кОм и особо тоже не вихлялся. Что еще?
Срыв стека, если произошел переход за конец кода, тоже похож на сброс — программа уходит за конец памяти и возвращается к нулевому адресу. Прошарил в отладчике и этот момент — нет срыва. Но может срыв не сразу, а спустя несколько итераций? Поставил .ORG на предпоследний адрес флеша и прописал туда маркер — не вылазит, значит срыва стека нет.
Да и код был прост как мычание, нечему там глючить. Накидал отладочных маркеров по коду, засылающих байты в строго определенном порядке — в терминалке высветилась фраза «УБЕЙ СИБЯ АПСТОЛ» — значит прога работает четко по алгоритму.
Заглянул под панельку… Вот в чем засада — медная ворсинка от провода МГТФ попала между RXD и RST (На меге8 они совсем рядом) и при приходе байта в порт дрыганья на RXD сбрасывали контроллер. Соблюдайте чистоту на рабочем месте! Не допетри я тогда поставить на перезагрузку маркер, так я бы до утра ковырялся с кодом. А так я резко сузил круг возможных косяков и ушло не более десяти минут на отлов этого бага.
Управление кодом, добыча произвольных данных
Но не едиными маркерами сыт боец USART’овой отладки.
Мы же можем не только слать, но и принимать! А принятое обрабатывать! Так что нам мешает делать полноценные брейкпоинты?
PUSH R16 SBIS UCSRA,RXC RJMP PC-1 IN R16,UDR ; Читаем UDR, чтобы сбросить RXC флаг POP R16
Данный код является банальным бряком, т.е. программа на ней встанет как вкопанная до тех пор, пока мы не зашлем ей байт в терминалку. Удобно, особенно когда осциллографа нет под рукой, можно, например, спокойно мультиметром уровни замерить на выводах, а потом пустить прогу до следующего чекпоинта.
В сочетании с маркерами дает еще и информацию о том, где мы встали. Но можно же и большее заиметь!
Что нам мешает сделать небольшой обработчик команд? Скажем, если мы послали R — выдаст значение нужного регистра, если М — ячейки памяти, I — байта из IO, а G — пойдет дальше:
Пример макроса может быть таким:
.MACRO DEB_CMD PUSH R16 ; Сохраняем регистр и флаги в стек IN R16,SREG PUSH R16 SBIS UCSRA,RXC RJMP PC-1 IN R16,UDR ; Читаем UDR, чтобы сбросить RXC флаг ; Определяем что там пришло CPI R16,’R’ BREQ PC+0x07 ; BREQ REGISTER CPI R16,’M’ BREQ PC+0x07 ; BREQ MEMORY CPI R16,’I’ BREQ PC+0x09 ; BREQ IO CPI R16,’G’ BREQ PC+0x0A ; BREQ GONEXT OUT UDR,@0 ; REGISTER — отправляем в UDR значение регистра RJMP PC+0x0008 ; Проверка на пустоту UDR тут скорей всего не нужна. ; Т.к. пока впечатаешь ручкам в терминалку байт, наверняка ; все что хотело уйти уже уйдет и UDR опустошится. LDS R16,@1 ; MEMORY — шлем значение из памяти OUT UDR,R16 RJMP PC+0x0004 IN R16,@2 ; IO — шлем значение из порта ввода-вывода. OUT UDR,R16 POP R16 ; GONEXT — достаем все сохраненное из стека и идем дальше OUT SREG,R16 POP R16 .ENDM
Как видишь, макрос массово использует относительные переходы (иначе при вставке двух макросов метки будут дублироваться). Так что модифицировать его нужно очень осторожно. Высчитывая команды. Но есть спрособ проще — написать его вначале с обычными метками, скомпилить, запустить отладку, потом открыть дизассемблер (view->disassembler) и поглядеть там смещения.
Используется просто — вставляешь в код такую штуку:
И при попадании в это место МК остановится и будет ждать приказа. По команде G — пойдет дальше. По команде R — даст содержание регистра R15, по команде M — содержание ячейки ОЗУ с адресом 0х0000, а по команде I — значение из порта PORTD. Порты, регистры, ячейки памяти вписываешь те которые хочешь посмотреть. Если нужно что то одно, то пишешь в ненужные поля любые подходящие значения. Ну или делаешь узкоспециализированные макросы под память, регистр и порт ВВ.
Можно еще прерывания запретить, чтобы стопор был полный, но не забывай, что всякие таймеры продолжают тикать самостоятельно вне зависимость от того работает МК или зациклен в ожидании команды. А еще, если включен WATCHDOG, то он может и за задницу укусить. Поэтому в макрос можно и команду WDR добавить, в цикл ожидания байта.
Более того, никто не запрещает написать простейший (или сложный) командный обработчик с шахматами и поэтессами, позволяющий указывать непосредственно в передаваемой команде какой ресурс надо забрать. Или что и в какой регистр записать, куда перейти… В общем, этакий микро SoftICE (если кто еще помнит этот легендарный отладчик).
А если дружишь с какими-нибудь Дельфями, то можешь снаружи и отладчик написать, который через этот супервизор будет выковыривать все нужные данные по USART и раскладывать их красивыми рядами на панельках, дабы было любо-дорого глядеть. Например Николев в своем отладочном модуле так и сделал, правда он через SPI работал, но не суть важно.
Оставляю это на самостоятельное изучение 🙂
На Си все пишется примерно в том же ключе. Можешь функции забабахать под это дело. Можешь макросы, тут по желанию.
Спасибо. Вы потрясающие! Всего за месяц мы собрали нужную сумму в 500000 на хоккейную коробку для детского дома Аистенок. Из которых 125000+ было от вас, читателей EasyElectronics. Были даже переводы на 25000+ и просто поток платежей на 251 рубль. Это невероятно круто. Сейчас идет заключение договора и подготовка к строительству!
А я встрял на три года, как минимум, ежемесячной пахоты над статьями :)))))))))))) Спасибо вам за такой мощный пинок.
22 thoughts on “AVR. Учебный Курс. Отладка программ. Часть 3”
Блин! Как же я раньше-то не додумался отладчик сделать? Привык в VB, привык что там много_чего есть, теперь мучаюсь, а НАДО =) DI HALT, спасибо за идею, и за статью.
Кидайте заявки на программу внутрь этого комментария: что там должно быть, что хочется, чтобы было, как лучше это сделать. Будет время — напишу, выложу с исходниками.
Если таких контр. точек с пол сотни, то задолбаешься расшифровывать буквы в терменале. Если есть место на кристале и запас по времени между метками, то лучше отправлять короткое сообщение на прерваниях. Возможно наложение , но мир же не идеален.
====================== Отправляем текст ============================================== LDI R16,Low(m1*2) STS $60,R16 LDI R16,High(m1*2) STS $61,R16 RCALL sent_txt ====================== Идём в_JOB_ывать дальше ======================================= ======================= Экшин в прерывании =========================================== sent_txt: ; Передача завершена PUSH R16 IN R16,SREG PUSH R16 PUSH R30 PUSH R31 LDS ZL,$60 LDS ZH,$61 LPM R16, Z+ CPI R16,0 BREQ END_SENT_TXT OUT UDR,R16 STS $60,ZL STS $61,ZH END_SENT_TXT: POP R31 POP R30 POP R16 OUT SREG,R16 POP R16 RETI m1: .db «Заебали лунатики. «,00 m2: .db «Заебали лунатики. «,00 m3: .db «Заебали лунатики. «,00 m4: .db «Заебали лунатики. «,00 m5: .db «Заебали лунатики. «,00
Возможно стоит собрать себе небольшой набор полезных отладочных функций типа: вывод стека на терминал, условный бряк, минимальный аналог printf, hex/dec/bin2char* и т.п. При отсутствии jtag и невозможности подключить светодиод, может помочь.
Я последнее время собрал себе http://www.mikrocontroller.net/topic/92704 вот такое устройство на ЖКИ 320х240. Подключаю его вместо терминала прямо к железке.. Есть у меня библиотечка которая умеет послать туда текст или число… Есть вариант который умеет посылать текст или число на определённые координаты на мониторчику. Думал о том чтобы приделать кнопки для обратной связи — но как то руки не дошли 🙂 Часто возникает проблема с синхронизацией скорости когда мега работает на внутриннем генераторе. Приходится доля начала находить подходящую константу для скорости. http://wowa.cz/alex/100_5294.JPG и http://wowa.cz/alex/100_5293.JPG — это фото первого прототипа. щас это уже в коробочке 🙂
а как работает LDI R16, (1
Ясно что меняет задает биты, но не ясно как работает, последовательность написания RXEN-UDRIE важна? В описании регистра UCSRB другая. И как меняются биты этой командой тоже не ясно. Или это макрос для компилятора?
Электроника для всех
Блог о электронике
AVR. Учебный курс. Устройство и работа портов ввода-вывода
С внешним миром микроконтроллер общается через порты ввода вывода. Схема порта ввода вывода указана в даташите:
Но новичку там разобраться довольно сложно. Поэтому я ее несколько упростил :
Итак, что же представляет собой один вывод микроконтроллера. Вначале на входе стоит небольшая защита из диодов, она призвана защитить ввод микроконтроллера от превышения напряжения. Если напряжение будет выше питания, то верхний диод откроется и это напряжение будет стравлено на шину питания, где с ним будет уже бороться источник питания и его фильтры. Если на ввод попадет отрицательное (ниже нулевого уровня) напряжение, то оно будет нейтрализовано через нижний диод и погасится на землю. Впрочем, диоды там хилые и защита эта помогает только от микроскопических импульсов от помех. Если же ты по ошибке вкачаешь в ножку микроконтроллера вольт 6-7 при 5 вольтах питания, то никакой диод его не спасет.
Конденсатор, нарисованный пунктиром, это паразитная емкость вывода. Хоть она и крошечная, но присутствует. Обычно ее не учитывают, но она есть. Не забивай голову, просто знай это, как нибудь я тебе даже покажу как её можно применить 😉
Дальше идут ключи управления. Это я их нарисовал рубильниками, на самом деле там стоят полевые транзисторы, но особой сути это не меняет. А рубильники наглядней.
Каждый рубильник подчинен логическому условию которое я подписал на рисунке. Когда условие выполняется — ключ замыкается. PIN, PORT, DDR это регистры конфигурации порта.
Есть в каждом контроллере AVR (в PIC есть тоже подобные регистры, только звать их по другому).
Например, смотри в даташите на цоколевку микросхемы:
Видишь у каждой почти ножки есть обозначение Pxx. Например, PB4 где буква «B» означает имя порта, а цифра — номер бита в порту. За порт «B» отвечают три восьмиразрядных регистра PORTB, PINB, DDRB, а каждый бит в этом регистре отвечает за соответствующую ножку порта. За порт «А» таким же образом отвечают PORTA, DDRA, PINA.
PINх
Это регистр чтения. Из него можно только читать. В регистре PINx содержится информация о реальном текущем логическом уровне на выводах порта. Вне зависимости от настроек порта. Так что если хотим узнать что у нас на входе — читаем соответствующий бит регистра PINx Причем существует две границы: граница гарантированного нуля и граница гарантированной единицы — пороги за которыми мы можем однозначно четко определить текущий логический уровень. Для пятивольтового питания это 1.4 и 1.8 вольт соответственно. То есть при снижении напряжения от максимума до минимума бит в регистре PIN переключится с 1 на 0 только при снижении напруги ниже 1.4 вольт, а вот когда напруга нарастает от минимума до максимума переключение бита с 0 на 1 будет только по достижении напряжения в 1.8 вольта. То есть возникает гистерезис переключения с 0 на 1, что исключает хаотичные переключения под действием помех и наводок, а также исключает ошибочное считывание логического уровня между порогами переключения.
При снижении напряжения питания разумеется эти пороги также снижаются, график зависимости порогов переключения от питающего напряжения можно найти в даташите.
DDRx
Это регистр направления порта. Порт в конкретный момент времени может быть либо входом либо выходом (но для состояния битов PIN это значения не имеет. Читать из PIN реальное значение можно всегда).
- DDRxy=0 — вывод работает как ВХОД.
- DDRxy=1 вывод работает на ВЫХОД.
PORTx
Режим управления состоянием вывода. Когда мы настраиваем вывод на вход, то от PORT зависит тип входа (Hi-Z или PullUp, об этом чуть ниже).
Когда ножка настроена на выход, то значение соответствующего бита в регистре PORTx определяет состояние вывода. Если PORTxy=1 то на выводе лог1, если PORTxy=0 то на выводе лог0.
Когда ножка настроена на вход, то если PORTxy=0, то вывод в режиме Hi-Z. Если PORTxy=1 то вывод в режиме PullUp с подтяжкой резистором в 100к до питания.
Есть еще бит PUD (PullUp Disable) в регистре SFIOR он запрещает включение подтяжки сразу для всех портов. По дефолту он равен 0. Честно говоря, я даже не знаю нафиг он нужен — ни разу не доводилось его применять и даже не представляю себе ситуацию когда бы мне надо было запретить использование подтяжки сразу для всех портов. Ну да ладно, инженерам Atmel видней, просто знай что такой бит есть. Мало ли, вдруг будешь чужую прошивку ковырять и увидишь что у тебя подтяжка не работает, а вроде как должна. Тогда слазаешь и проверишь этот бит, вдруг автор прошивки заранее где то его сбросил.
Общая картина работы порта показана на рисунке:
Теперь кратко о режимах:
- Режим выхода
Ну тут, думаю, все понятно — если нам надо выдать в порт 1 мы включаем порт на выход (DDRxy=1) и записываем в PORTxy единицу — при этом замыкается верхний ключ и на выводе появляется напряжение близкое к питанию. А если надо ноль, то в PORTxy записываем 0 и открывается уже нижний вентиль, что дает на выводе около нуля вольт. - Вход Hi-Z — режим высокоимпендансного входа.
Этот режим включен по умолчанию. Все вентили разомкнуты, а сопротивление порта очень велико. В принципе, по сравнению с другими режимами, можно его считать бесконечностью. То есть электрически вывод как бы вообще никуда не подключен и ни на что не влияет. Но! При этом он постоянно считывает свое состояние в регистр PIN и мы всегда можем узнать что у нас на входе — единица или ноль. Этот режим хорош для прослушивания какой либо шины данных, т.к. он не оказывает на шину никакого влияния. А что будет если вход висит в воздухе? А в этом случае напряжение будет на нем скакать в зависимости от внешних наводок, электромагнитных помех и вообще от фазы луны и погоды на Марсе (идеальный способ нарубить случайных чисел!). Очень часто на порту в этом случае нестабильный синус 50Гц — наводка от сети 220В, а в регистре PIN будет меняться 0 и 1 с частотой около 50Гц - Вход PullUp — вход с подтяжкой.
При DDRxy=0 и PORTxy=1 замыкается ключ подтяжки и к линии подключается резистор в 100кОм, что моментально приводит неподключенную никуда линию в состояние лог1. Цель подтяжки очевидна — недопустить хаотичного изменения состояния на входе под действием наводок. Но если на входе появится логический ноль (замыкание линии на землю кнопкой или другим микроконтроллером/микросхемой), то слабый 100кОмный резистор не сможет удерживать напряжение на линии на уровне лог1 и на входе будет нуль.
Также почти каждая ножка имеет дополнительные функции. На распиновке они подписаны в скобках. Это могут быть выводы приемопередатчиков, разные последовательные интерфейсы, аналоговые входы, выходы ШИМ генераторов. Да чего там только нет. По умолчанию все эти функции отключены, а вывод управляется исключительно парой DDR и PORT, но если включить какую-либо дополнительную функцию, то тут уже управление может полностью или частично перейти под контроль периферийного устройства и тогда хоть запишись в DDR/PORT — ничего не изменится. До тех пор пока не выключишь периферию занимающую эти выводы.
Например, приемник USART. Стоит только выставить бит разрешения приема RXEN как вывод RxD, как бы он ни был настроен до этого, переходит в режим входа.
Совет:
С целью снижения энергопотребления и повышения надежности рекомендуется все неиспользованные пины включить в режим PullUp тогда их не будет дергать туда сюда помехой, а если на порт свалится грубая сила (например, монтажник отвертку уронит и коротнет на землю) то линия не выгорит.
Как запомнить режимы, чтобы не лазать каждый раз в справочник:
Чем зазубривать или писать напоминалки, лучше понять логику разработчиков, проектировавших эти настройки, и тогда все запомнится само.
- Самый безопасный для МК и схемы, ни на что не влияющий режим это Hi-Z.
- Очевидно что этот режим и должен быть по дефолту.
- Значения большинства портов I/O при включении питания/сбросе = 0х00, PORT и DDR не исключение.
- Соответственно когда DDR=0 и PORT=0 это High-Z — самый безопасный режим, оптимальный при старте.
- Hi-Z это вход, значит при DDR=0 нога настроена на вход. Запомнили.
- Однако, если DDR=0 — вход, то что будет если PORT переключить в 1?
- Очевидно, что будет другой режим входа. Какой? Pullup, другого не дано! Логично? Логично. Запомнили.
- Раз дефолтный режим был входом и одновременно в регистрах нуль, то для того, чтобы настроить вывод на выход надо в DDR записать 1.
- Ну, а состояние выхода уже соответствует регистру PORT — высокий это 1, низкий это 0.
- Читаем же из регистра PIN.
Есть еще один способ, мнемонический:
1 похожа на стрелку. Стрелка выходящая из МК — выход. Значит DDR=1 это выход! 0 похож на гнездо, дырку — вход! Резистор подтяжки дает в висящем порту единичку, значит PORT в режиме Pullup должен быть в единичке!
Для детей в картинках и комиксах 🙂
Для большей ясности с режимами приведу образный пример:
Уровень напряжения на выводе словно планка, которая может двигаться вертикально вверх или вниз. В режиме Hi-Z мы можем на эту планку только смотреть, а двигать или как то на нее воздействовать мы не можем. Поэтому любая помеха может ее дрыгать как угодно, но зато если мы ее куда прицепим, то ее уровень будет зависеть только от другой цепи и ей мы не помешаем.
В режиме PullUp эту планку мы пружиной подтянули кверху. Слабые помехи не смогут больше ее дрыгать как угодно. С другой стороны шине она может помешать, но не факт что заблокирует ее работу. От шины зависит и ее силы. А еще мы можем отслеживать тупую внешнюю силу, вроде кнопки, которая может взять и придавить ее к земле. Тогда мы узнаем что кнопка нажата.
В режиме OUT у нас планка прибита гвоздями к земле или прижата домкратом к питанию. Внешняя сила может ее пересилить только сломав домкрат или сломается сама. Тупая внешняя сила просто разрушает наш домкрат или вырывает гвозди из пола с мясом. В любом случае — девайс в помойку.
Спасибо. Вы потрясающие! Всего за месяц мы собрали нужную сумму в 500000 на хоккейную коробку для детского дома Аистенок. Из которых 125000+ было от вас, читателей EasyElectronics. Были даже переводы на 25000+ и просто поток платежей на 251 рубль. Это невероятно круто. Сейчас идет заключение договора и подготовка к строительству!
А я встрял на три года, как минимум, ежемесячной пахоты над статьями :)))))))))))) Спасибо вам за такой мощный пинок.
191 thoughts on “AVR. Учебный курс. Устройство и работа портов ввода-вывода”
я понимаю что с каждым годом молодежь все деградирует. но чтоб да таких пояснений в виде картинок :)) юморно, может в универах это за программу обучения возьмут 🙂