Форум » Для начинающих. » Проблема ЧМЗ » Ответить

Проблема ЧМЗ

Алексей: У начинающих часто возникают вопросы, связанные с работой с портами контроллера. Проявляется это в непредвиденном изменении состояния одного или нескольких выводов контроллера. Очень часто данная проблема связана с непониманием работы процесса чтение\модификация\запись в приложении к работе с портами... Приведу пример, поясняющий это... В частности товарищ Galrad задал вопрос КЕА и пока не получил ответа В общем то этот пример и есть ответ на его вопрос... В качестве отладчика используется протеус, ссылка на проект в конце поста... Схема проста Увеличить ;**************************************************************************** ; Пример для понимания работы ЧМЗ и связанных с этим фокусов... ;**************************************************************************** [pre2] __config 1F01H #include <p16F627A.inc> errorlevel -302 ;============================================================================ ; Определение названия и положения регистров общего назначения. ;============================================================================ cblock 20h ; начальный адрес области данных endc ;============================================================================ ; START ;============================================================================ org 0x000 ; Вектор сброса ;============================================================================ ; Подготовительные операции ;============================================================================ START bcf STATUS, RP0 bcf STATUS, RP1 clrf PORTA clrf PORTB clrf T1CON clrf T2CON clrf CCP1CON clrf RCSTA movlw 07h movwf CMCON bcf INTCON,GIE bsf STATUS, RP0 clrf TXSTA clrf TRISA clrf TRISB movlw b'00001111' movwf OPTION_REG bcf STATUS, RP0 [/pre2] ;============================================================================ ; С этого момента пошагово выполняем программу, внимательно и с интересом ; наблюдаем за тем, что происходит в симуляторе... Получим результат не тот, ; что ожидаем! И такое происходит не только в протеусе!, но и реальном ; железе!!! ;============================================================================ [pre2]main clrf PORTB ; сброшу порт в нули чтобы bsf STATUS,RP0 ; быть уверенным что в выходных clrf TRISB ; защелках записаны 0 bcf STATUS,RP0 ; BsF PORTB,3 ; Понадобится позже... bsf STATUS,RP0 ; Теперь переключу часть выводов movlw b'01001001' ; на вход movwf TRISB ; bcf STATUS,RP0 ; bsf STATUS,RP0 ; Опять переключу порт на выход clrf TRISB ; убедиться что все пока нормально bcf STATUS,RP0 ; В ВЫХОДНЫХ ЗАЩЕЛКАХ ЧИСЛО .8!!! ; Пока проблем не наблюдается :) bsf STATUS,RP0 ; Опять переключу часть выводов movlw b'01001001' ; на вход. За счет резисторов movwf TRISB ; на этих выводах сформируется bcf STATUS,RP0 ; логический 0 или 1... ;============================================================================ ; А ТЕПЕРЬ, ВНИМАНИЕ, ФОКУС!!! Помните?, в защелках записано число .8!!! ;============================================================================ BsF PORTB,1 ; модифицирую порт бит ориентированной ; командой... По логике должен ; измениться только один 1 бит! И в ; результате должно бы получиться .10 bsf STATUS,RP0 ; Опять переключаю порт на выход clrf TRISB ; И ЧТО Я ВИЖУ В ПОРТУ? Совершенно bcf STATUS,RP0 ; не то, что ожидал... А ожидал .10 ; Даже скинулся 3 бит!!! а он был ; установлен мной ранее!!!!!!!!!! И ; я его не трогал!!! ;============================================================================ ; Что мы теперь видим в регистре PORTB? По идее должны бы видеть число ; .10... Была ведь записана .8 и в дополнение я поднял 1 бит... Что в ; в общем случае дает .10... На самом деле видим совершенно другую ; картину, .67, почему??? Причем 3 бит был поднят! а сейчас нет! ; Все дело в способе работы с регистрами в контроллере. Дело в том, ; что даже бит ориентированные команды не работают с одним единственным ; битом регистра. Сначала производится чтение из регистра, затем модификация ; всего байта, независимо от того, какая команда применяется, и только затем ; запись в регистр всех 8 бит с одним модифицированным. Вроде бы ничего ; такого, и проблем никогда с этим не возникает... Но вот такое творится ; только при работе с регистрами PORTx... И тут дело в том, что чтение ; производится исключительно с "выводов" контроллера, а вот запись производится ; в выходные защелки регистра. Т.е. получается что вместо одного регистра ; PORTx фактически имеем целых два! Один из них это выходные защелки порта, ; которые отключаются от физических выводов при работе на ВХОД. Но тем не ; менее чтение происходит "непосредственно" с выводов порта... Таким образом ; имеем, ЕСЛИ ПОРТ ХОТЯ БЫ ЧАСТИЧНО РАБОТАЕТ НА ВХОД, ЛЮБАЯ! КОМАНДА, ; ИЗМЕНЯЮЩАЯ ЗНАЧЕНИЕ РЕГИСТРА PORTX, БУДЕТ РАБОТАТЬ ТАК: ; 1. Чтение всего порта "непосредственно" с выводов контроллера ; 2. Затем его модификация. Причем не важно как мы работаем с портом! даже ; бит ориентированными командами BSF и BCF... ; 3. Ну и запись... Но запись производится не непосредственно на выводы ; порта :), а естественно в выходные защелки. ; Т.е. получается довольно тернистый путь, читаем с одного места, а пишем в ; другое... Что и может вызвать большие затруднения у начинающих программистов. ; Добавлю еще, что такая ситуация наблюдается до 16 серии включительно... За ; исключением новых контроллеров PIC16F(LF)xxxx. В них и более старших ; семействах уже введен дополнительный регистр LATx. Он и есть те самые ; выходные защелки. Чтение же порта происходит из регитра PORTx... В принципе, ; в ситуациях не связанных с ЧМЗ, без разницы к какому регистру обращаться. ; Т.о. разработчики устранили проблему ЧМЗ, но чтобы понимать и в старшем ; семействе откуда надо читать и куда писАть о проблеме ЧМЗ знать надо... ;============================================================================ goto main end[/pre2] Здесь лежит проект в протеусе, созданный специально для данного примера... Использовать в Обмене и статьях КЕА запрещено

Ответов - 68, стр: 1 2 All

Photographer: Эдесь полный проект к этой статье. read modify write.rar

galrad: Спасибо. А можно продолжить тему с разъяснениями, как лучше избегать или устранять возникшие проблемы, связанные с ЧМЗ?

medved: Если же Вы внимательно прочитали первый пост данной темы, то должно стать понятно, что для избежания/устранения проблемы связанной с ЧМЗ перед переключением PORTx на выход следует записать в защелку требуемое значение. Еще раз обращаю внимание, что данная проблема возникает тогда, когда по ходу исполнения программы PORTx имеет переключения вход/выход. Первоначальная настройка контроллера не в счет.


Photographer: Наверно можно выделить дополнительные регистры параллельно портам (в PIC18 есть аппаратно ?). А не корректные команды заменить на корректные макросы, с теми же названиями и префиксом, работающие через дополнительные регистры, .

SanSanich: Лично я не совсем понял пояснения в предыдущих постах. Лучше пример в коде, как надо правильно сделать. Как происходит ошибка увидел, а вот как правильно сделать, в примере ?

Sergey Roslik: Так пример выше, в мплабе крутите его и наблюдаете состояние регистров, куда уже наглядней.

tester: Дополню Алексея: проблема из-за RMW (ЧМЗ) может возникнуть и без переключения направления портов. [pre2] clrf TRISB clrf PORTB ... bsf PORTB, 0 bsf PORTB, 1 [/pre2] При высокой тактовой частоте и сильной нагрузке на порте (или сравнительно большой ее емкостной составляющей) получится так, что RB0 останется в "0". Дело в том, что большинство инструкций по модификации регистров работают по принципу RMW. Когда устанавливается RB0, сначала читается текущее состояние порта (0x00), потом модифицируется нулевой бит (0x01) и затем производится запись обратно. Чем больше нагрузка на RB0, тем медленнее будет переходный процесс по установке лог "1" на выходе. Если сразу же за этой инструкцией вызвать еще одну RMW-инструкцию, то на стадии чтения порта напряжение на выходе RB0 может еще не успеть установиться выше порогового значения, и таким образом порт опять будет прочитан как 0x00. Далее модифицируется бит RB1 (0x02) и делается запись в порт. В результате мы получим совсем не то, что хотели, т.е. 0x02 вместо 0x03. Выходов - два: 1. Простой (по рекомендации микрочипа) - разделять RMW-инструкции над портами ввод/вывода хотя бы одним NOP'ом. 2. Правильный - работать через буферный регистр.

SanSanich: Вот так будет правильно? [pre2] bcf STATUS,RP1 bsf STATUS,RP0 movlw b'11110000' ; 0-3 выход, 4-7 вход movwf TRISB clrf OPTION_REG ; резисторы отключены (бит 7 RBPU тоже в 0) bcf STATUS,RP0 movlw b'11111111' ; можно так? Получим на 0-3 "1", на вход не влияет? movwf PORTB movf PORTB,w ; читаем порт movwf TEMP bsf TEMP,0 ; устанавливаем в 0 бите 1 bсf TEMP,7 ; и в 7 бите 0 bcf STATUS,RP1 bsf STATUS,RP0 movf TEMP,w ; перенапрАвливаем порт 7 на выход, 0 порт на вход movwf TRISB bcf STATUS,RP0 movf TEMP,w ; устанавливаем в порт movwf PORTB ; '0xxx111x' x это 3 состояние, на вход [/pre2]

Алексей: tester пишет: проблема из-за RMW (ЧМЗ) может возникнуть и без переключения направления портов. Не знал SanSanich пишет: Вот так будет правильно? Александр, чет я тебя не пойму... Если работать через буфер, то сначала уж запомни состояние выходов(Т.е. защелок порта), потом переключи порт на вход, сделай что тебе нужно и перед переключением снова на выход перепиши буфер в защелки. и только после этого переключай снова на выход... Ну еще по обстоятельствам смотри, может быть у тебя еще получится так, что состояние порта за это время могло вполне законно измениться... SanSanich пишет: movlw b'11111111' ; можно так? Получим на 0-3 "1", на вход не влияет? movwf PORTB Это я вообще не понимаю для чего? Если ты про примечание testerа, то имеется ввиду что ты должен завести какой либо буферный регистр и все операции по модификации порта ты сначала должен сделать с ним, и только потом одним махом скопировать этот регистр в защелки.Т.е. ты просто исключаешь несколько обращений подряд к PORTx, из за чего могут возникнуть проблемы... При единичном обращении такого не будет...

SanSanich: Вот я и прошу на примере показать, лучше на моём. Если не трудно. До меня так лучше доходит! Защёлки это регистр PORTB? Алексей пишет: то сначала уж запомни состояние выходов(Т.е. защелок порта) [pre2] movf PORTB,w ; читаем порт movwf TEMP [/pre2] Алексей пишет: потом переключи порт на вход, сделай что тебе нужно [pre2] bcf STATUS,RP1 bsf STATUS,RP0 movlw b'01110001' ; перенапрАвливаем порт 7 на выход, 0 порт на вход movwf TRISB ; получаем 0-вход, 1-3-выход, 4-6-вход, 7-выход bcf STATUS,RP0 bsf PORTB,7 nop bcf PORTB, 1 [/pre2] Алексей пишет: и перед переключением снова на выход перепиши буфер в защелки. и только после этого переключай снова на выход... А вот тут я не понял. Покажите тупому на примере!!!

Алексей: SanSanich пишет: Защёлки это регистр PORTB? Нет, это выводы контроллера... Защелки это регистр нечто вроде виртуального... Когда выводы работает на выход эти оба регистра сединены вместе... Когда же выводы переключаешь на вход, они размыкаются и становятся совершенно разными физически... Но чтение идет именно с выводов, а запись происходит в защелку порта, которая отключена от выводов... Теперь, если на входах сигнал не соответствует внутренней защелке, то чтение с выводов и запись защелки изменит состояние защелки и при переключении на выход лог. сигналы поменяются... Для лучшего понимания посмотри устройство портов, сразу будет понятнее... Позже выложу еще на чипмк...

Алексей: Вот как пример из даташита структуры вывода RB0 Увеличить Тут очень четко видно откуда производится чтение и куда запись... регистр PORTx это считай есть физическая ножка контроллера, и есть защелка данных, которая может отключаться от вывода... Соответственно отсюда и все проблемы с ЧМЗ, ведь читаем напрямую с вывода, но запись уже происходит в защелку данных...

SanSanich: Алексей пишет: Но чтение идет именно с выводов Какими командами читать? С какого регистра? Можно на примере, если не трудно.

Алексей: Давай чуть позже, мне сейчас бежать надо? на работу. Насчет чтения... Читает контроллер сам, неважно чем ты обращаешься, даже если выводишь в защелку чего то, он сначала прочитает, модифицирует и запишет... А чтобы тебе считать с порта, то у тебя нет выбора, только регистр PORTx и все...

SanSanich: Ок, по возможности, мне на примере надо

medved: SanSanich пишет: Какими командами читать? Читать стандартными командами. Фишка не в том как читать, а в том откуда читать и куда записывать. Читаешь с ножки МК, а пишешь в защелку. Уровни на ножке и защелке могут отличаться. Вот это и нужно учитывать

Алексей: medved пишет: Уровни на ножке и защелке могут отличаться. Вот это и нужно учитывать Лучше и не скажешь

Photographer: Похоже понять то что не понятно, ещё сложнее SanSanich пишет: А вот тут я не понял. [pre2]; movf PORTB,w ; читаем порт, теперь в TEMP у тебя вместо PORTB ; movwf TEMP ; Но здесь это пока не надо bcf STATUS,RP1 bsf STATUS,RP0 movlw b'01110001' ; перенапрАвливаем порт 7 на выход, 0 порт на вход movwf TRISB ; получаем 0-вход, 1-3-выход, 4-6-вход, 7-выход bcf STATUS,RP0 ; bsf PORTB,7 ; У тебя же TEMP вместо PORTB ; nop ; Вот и работай с ним ; bcf PORTB, 1 ; а не с портом. movf PORTB,w ; читаем порт непосредственно перед изменением movwf TEMP ; теперь в TEMP у тебя вместо PORTB bsf TEMP,7 ; Делаем изменения nop ; Здесь nop нужен нет? пусть будет. bsf TEMP,1 movf TEMP,w ; Вносим изменения в PORTB movwf PORTB ; [/pre2] Вроде так.

tester: Photographer пишет: Вроде так. Не совсем. Смысл буферного регистра в том, чтобы не перетирать его значение прочитанным состоянием портов. Т.е. "movf PORTB, w/movwf TEMP" - лишнее. Фрагмент должен выглядеть так: [pre2] movlw PORTB_INIT movwf Temp ; Инициализируем единожды movwf PORTB bsf status, rp0 movlw TRISB_INIT movwf TRISB bcf status, rp0 ... bsf Temp, 7 ; Все RMW операции - только над буферным регистром bsf Temp, 1 movf Temp, w movwf PORTB ; Запись в порт только присваиванием ... [/pre]

Photographer: tester пишет: Т.е. "movf PORTB, w/movwf TEMP" - лишнее На самом деле. По скольку мы имеем дело только в выходами, то и значения на них изначально будут/должны быть одинаковыми, в смысле предустановленными, а не считанными. Спасибо. Я здесь набросал готовый проект с глюками. Хотел что нибудь законченное сделать, но потом передумал. Не знай как в реале, но Протеус показывает страшный глюк. Смысл устройства и программы понять легко. Надо выключить все сегменты индикатора, а потом кнопками по одному сегменту включить. Пример не лучший, но что есть. Будут лучше - выкладывайте. Предлагаю всем желающим, на одном этом примере потренироваться и исправить ошибку. Не просто добиться правильной работы, а именно исправить с учётом эффекта ЧМЗ. Архив этого проекта здесь.

Photographer: По проекту ко мне был вопрос - почему так запутанно расположены кнопки. Всё просто, они расположены в соответствии с расположением сегментов индикатора. Т.е. верхнему сегменту "а" соответствует верхняя кнопка... и так далее И ещё, объяснять мне как это должно работать не надо. Просто решите эту задачку. Если не понятно, спрашивайте здесь. Кто нибудь ответит. А потом сравним результаты, решения, подходы Анатолий Медведев medved подправил схему. Можно заменить ту что в проекте. Копия read modify write_1.DSN

igor: Photographer пишет: Смысл устройства и программы понять легко. Надо выключить все сегменты индикатора, а потом кнопками по одному сегменту включить. Photographer пишет: Не знай как в реале, но Протеус показывает страшный глюк. Photographer пишет: И ещё, объяснять мне как это должно работать не надо. Просто решите эту задачку. Если не понятно, спрашивайте здесь. Так в чём глюк то заключается? Что решать?

Photographer: Есть пример - глючная програмка. Включи в Протеусе - увидишь. Есть хорошая подсказка от tester-а. Если есть желание - можно потренироваться (всем на одном примере). Я ответ знаю и тоже подготовлю рабочий вариант. Потом можно будет сравнить. SanSanich пишет: Ок, по возможности, мне на примере надо Вроде всё объяснили, но не все поняли. Как не на одной задачке решать эту проблему. Задачка простая, проще некуда. Пример решения и объяснения есть. Её надо решать самому, тому кто не понял. Если я сейчас выложу ответ этой простой задачки, то опять кто то не поймёт. Я уже и так и эдак рассказал. Как ещё рассказывать, уже не представляю. Ясно же, научить нельзя, можно только научиться. Это прописная истина. Ладно, попробую ещё с другого конца подойти. Ты знаешь как ещё по другому объяснить SanSanich-у? А другим? Загляни в школьные учебники. Там после объяснения темы и примеров, даются задачки, без ответов. Вернее ответы есть в методичке учителя. Вот и это и есть такая задачка в конце темы. Если ещё кто нибудь спросит на хрена я выложил эту задачку - я застрелюсь.

igor: igor пишет: Так в чём глюк то заключается? Что решать? Photographer пишет: Есть пример - глючная програмка. Включи в Протеусе - увидишь. Я не хочу догадываться. Или говоришь - где глюк, или я говорю - на хрена ты её выложил?

Алексей: Альберт, почему у тебя выводы порта В не подтянуты в источнику питания У тебя на вывода неопределенный уровень. Что ты хочешь таким образом показать?

galrad: Photographer пишет: Копия read modify write_1.DSN У меня показывает, что страничка инфицирована вирем

medved: galrad пишет: У меня показывает, что страничка инфицирована вирем Попробуйте скачать отсюда

galrad: Спасибо! Здесь нормально!

galrad: Сделал подтяжки на плюс. Сейчас хорошо видно как работает программа с нестабильными скачками сегментов. http://zalil.ru/30831734

galrad: Действительно, проблема устраняется очень просто, если понять мехамизм его возникновения. Поначалу запутался, но когда разобрался, то "все стало на свои места". Думаю, что Альберт прав, подчеркнув на самостоятельном решении задачки, в принципе она очень простая, главное понять. Ну, что же, еще один шаг вперед

Photographer: Я уезжал из города. сейчас отвечу как смогу. Алексей пишет: Альберт, почему у тебя выводы порта В не подтянуты в источнику питания У тебя на вывода неопределенный уровень. Что ты хочешь таким образом показать? Я просто сделал проект с глючной индикацией. К сожалению глюков в нём оказалось больше чем надо Ну вопервых я забыл сделать управление катодом индикатора. Это надо для совместной работы с кнопками. Подтяжку к питанию не надо, выхода МК и так подтянуты к плюсу. Я поставил вместо светодиода транзистор на катод и всё встало на свои места. в смысле схемотехники. Да, кстати, medved сделал ещё один вариант в протеусе с шинами... давайте так, если кто хочет, то может доработать его, поставит транзистор на катод индикатора и включит в свой проект. Так будет интересней вот он И это... вчера брал флешку у жены... так что извините. И где она эти вирусы находит, там же у тёщи интернета даже нет... разве что на работе. Проверьте пожалуйста. Я то просканировал комп и файл онлайн проверил. Но эта зараза неистребима. Модифицируются вечно. ЧМЗ полный короче Итак на счёт проекта... сделать можно как угодно... Если даже я знаю 10 способов, то имею ввиду, что есть ешё десяток способов которые я не знаю. Проект схематически получился не удачный. Заставить включаться сегменты при нажатии кнопок просто. Т.е. кнопкой на выводе делаешь 0, и на том же выводе появляется единица для сегмента индикатора. Это я сделал в своём варианте. Сейчас хочу посмотреть что будет если не использовать временный регистр для порта. Надеюсь, что будут наглядныые нерабочие варианты. Проект может не работать сдуру или наспех. А вот заставить не работать когда всё логично и правильно, оказывается не просто. Может кто то другой проект предложит? Хотелось сделать наглядный пример, как должно быть, но не работает и вариант как надо на самом деле. Тот что работает выложить? или потом сразу оба варианта?.... ладно, вот он. У меня показывает Известных вирусов: 5212594 Дата последнего обновления: 10-04-2011 Размер файла (Kb): 45 Тел вирусов: 0 Файлов: 15 Предупреждений: 0 Архивов: 1 Подозрительных: 0

Photographer: Самое прикольное, что в "оптимизированном" варианте хватает одной команды чтобы считать со входа все кнопки, инвертировать результат, записать на выход и переключится с кнопок на индикатор [pre2]main bsf STATUS,RP0 ; Включим порт movlw b'01111111' ; на вход movwf TRISB ; bcf STATUS,RP0 ; bcf PORTB,7 ; Выключим индикатор. comf PORTB,F ; Читаем, модифицируем, записываем в порт и включаем транзистор :-) bsf STATUS,RP0 ; Теперь переключим входа clrf TRISB ; на выход bcf STATUS,RP0 ; call Pause_10 ; Можно отдохнуть ; или заняться другими делами. goto main[/pre2] Но это сгодится только для этого случая и это плохо.

Photographer: А вот и пример ошибки, для этого случая. Перед тем как инвертировать командой comf, мы командой bcf выключаем индикатор. А попробуйте после comf, обратно включить индикатор подобным образом командой bsf. Тут же данные на защёлках инвертируются обратно [pre2]main bsf STATUS,RP0 ; Включим порт movlw b'01111111' ; на вход movwf TRISB ; bcf STATUS,RP0 ; bcf PORTB,7 ; Выключим индикатор. comf PORTB,F ; Читаем, инвертируем, записываем в порт bsf PORTB,7 ; Включим индикатор. и в защёлках данные инвертировались обратно :-) bsf STATUS,RP0 ; Теперь переключим входа clrf TRISB ; на выход bcf STATUS,RP0 ; call Pause_10 ; Можно отдохнуть ; или заняться другими делами. goto main[/pre2] Я тут подумал, всё таки не стоит использовать использовать для записи в порт регистр с названием Temp. Для каждого порта нужен свой регистр примерно с такими названиями как PORTA_OUT PORTB_OUT PORTC_OUT

MAZ: Уважаемые коллеги. Прошу внимательно прочитать "нижележащее" , как следует это запомнить и руководствоваться этим правилом в дальнейшем. Если нужно, в несколько "бит-приёмов", следующих друг за другом, изменить состояния 2-х или более каналов порта, работающих "на выход" (как в первой проге Павла), то в этом случае целесообразно отказаться от применения бит-ориентированных команд типа bcf/bsf, а сделать это с помощью байт-ориентированных команд. По-первости, я тоже "вляпывался в эту бяку" (её коварство в том, что в симуляторе норма, а "в железе" конфуз). И не один раз, а много. И соответствующая "шизофрения" тоже была. Короче, прислушайтесь к "вышележащему", доброму совету и соответствующих проблем не будет. Вот так,просто и доходчиво. Можно сказать, своими словами, с красивыми отступлениями мастер объяснил ЧМЗ. Это не всякому дано.

Dmitry Dubrovenko: MAZ пишет: Если нужно, в несколько "бит-приёмов", следующих друг за другом, изменить состояния 2-х или более каналов порта, работающих "на выход" (как в первой проге Павла), то в этом случае целесообразно отказаться от применения бит-ориентированных команд типа bcf/bsf, а сделать это с помощью байт-ориентированных команд.Погодите-ка. Насколько понимаю, имеем два варианта "ошибки ЧМЗ" (назовём её так). 1. Ошибка возникает из-за неправильной череды настроек порта на вход-выход (то, что описАл Алексей в начале). 2. Ошибка возникает из-за воздействия внешней нагрузки, которая не даёт мнгновенно измениться выходу защёлки. Получается, что в/у рекомендация распространяется только на второй случай. Если состояние портов будет изменяться мнгновенно, то почему бы не использовать подряд бит-ориентированные команды? На практике же, мнгновенного (или по крайней мере, укладывающегося в МЦ) изменения достичь, наверно, нереально. Однако не припоминаю, что бы у меня два изменения портов следовали друг за другом. Обязательно сперва были какие-то команды, определяющие условие (т.е. "задержка"). Я не прав?

MAZ: Дмитрий прости, но это не мои рекомендации. Алексей, кажется хорошо объяснил, что , читаем с одного места, а пишем в другое. Dmitry Dubrovenko пишет: Однако не припоминаю, что бы у меня два изменения портов следовали друг за другом. Обязательно сперва были какие-то команды, определяющие условие (т.е. "задержка"). Я не прав? Мне кажется ты не правильно ставишь вопрос. Изменение на выводе порта настроенного на вых. можно делать и последовательно, ну nop между ними вставить. Алексей пишет: Но вот такое творится ; только при работе с регистрами PORTx... И тут дело в том, что чтение ; производится исключительно с "выводов" контроллера, а вот запись производится ; в выходные защелки регистра. Т.е. получается что вместо одного регистра ; PORTx фактически имеем целых два! Один из них это выходные защелки порта, ; которые отключаются от физических выводов при работе на ВХОД. Но тем не ; менее чтение происходит "непосредственно" с выводов порта... Таким образом ; имеем, ЕСЛИ ПОРТ ХОТЯ БЫ ЧАСТИЧНО РАБОТАЕТ НА ВХОД, ЛЮБАЯ! КОМАНДА, ; ИЗМЕНЯЮЩАЯ ЗНАЧЕНИЕ РЕГИСТРА PORTX, БУДЕТ РАБОТАТЬ ТАК: ; 1. Чтение всего порта "непосредственно" с выводов контроллера ; 2. Затем его модификация. Причем не важно как мы работаем с портом! даже ; бит ориентированными командами BSF и BCF... ; 3. Ну и запись... Но запись производится не непосредственно на выводы ; порта :), а естественно в выходные защелки.

Dmitry Dubrovenko: MAZ пишет: Изменение на выводе порта настроенного на вых. можно делать и последовательно, ну nop между ними вставить.Так и я про то же. Только дополнил, что из личного опыта, перед изменением состояния выхода, у меня сперва следует ряд команд, где выясняется, необходимо ли это изменение. Поэтому, между двумя изменениями порта "автоматически" получается "ноп". Это всё про второй "случай". Честно говоря, раньше я о нём как-то не задумывался. Про первый же (про который Алексей говорил), я давно знаю, и для себя взял за правило менять направление порта бит-ориентированными командами (по мере возможности, разумеется).

SanSanich: Dmitry Dubrovenko пишет: для себя взял за правило менять направление порта бит-ориентированными командами (по мере возможности, разумеется). Бит или байт-ориентированными?

medved: На известном форуме "мастер" предпринял попытку объяснить проблему ЧМЗ: "Частотная составляющая", и особенно в случаях работы на максимальной Fosc, конечно же важна. Её признак - избавление от "бяки" после осуществления "врезки" NOPов, но у меня были такие случаи, что "врезки" даже десятков NOPов не помогали. Значит, это функциональный "глюк". Стало интересно и решил разобраться. Вот что получилось. Исполнение команды bcf/bsf происходит следующим, специфическим образом. После осуществления декодирования команды (Q1), происходит копирование, во внутренний буфер состояний выводов порта (Q2). Во внутреннем буфере устанавливается то состояние выбранного бита, которое задано командой bcf/bsf (Q3). Далее, содержимое внутреннего буфера копируется (Q4) в регистр порта. Обратите внимание на то, что происходит чтение (Q2) состояний выводов порта. Если все каналы порта настроены "на выход", то и проблем нет, так как выходы всех защёлок электрически подключены к соответствующим выводам порта. Проблем нет также и в случае наличия одного канала порта, работающего на вход. А вот если часть из них (от 2-х и более) настроена на работу "на вход" (высокоимпендансное состояние, выходы соответствующих защёлок электрически от них отключены), то могут быть проблемы, и весьма существенные. Например, состояние выводов порта (допустим, С), ранее настроенного на работу "на выход", такое: 111х хххх, где х - то, что нужно оставить без изменения. Архинужно сменить 111х хххх на 000х хххх. Допустим, что перед применением команды bcf/bsf, по каким-то уважительным причинам, левые 3 канала порта С настроены "на вход" (например, ПИКу нужно опросить флаг занятости ЖК-модуля и/или свершить другие подвиги, требующие такой настройки). То есть, входы этих ПИК-каналов переведены в высокоимпендансное состояние (Rвх - много мегоом). Если к ним подключены входы управления неким внешним устройством также имеющие высокое Rвх., то более чем вероятно, что на выводах RC7,6,5 установятся единичные логические уровни. Посмотрим, что получится. 1. bcf PortC,7 Во внутренний буфер запишется 111х хххх. В регистр PortС запишется 011х хххх. Если на этом и закончить (то есть, нужно сбросить только один-разьединственный бит №7), то всё в норме, но по условию задачи, этого мало. "Потоково" сбрасываем дальше. 2. bcf PortC,6 Во внутренний буфер запишется 111х хххх. Выполнение: 101х хххх. В регистр PortB запишется 101х хххх. 3. bcf PortC,6 Во внутренний буфер запишется 111х хххх. Выполнение: 110х хххх. В регистр PortС запишется 110х хххх. Вывод: было нужно 000х хххх, а получилось 110х хххх, что чревато нехорошими последствиями. Предположим, что 3 старших канала порта С управляют режимами работы ЖК-модуля, и архинужно сделать так, чтобы после осуществления перевода этих каналов на работу "на выход", в соответствующих защёлках было установлено состояние 000х хххх, а в наличии имеется 110х хххх. Вопрос: что это такое? Ответ: функциональный сбой в работе ЖК-модуля, который в упор не запланирован конструктором. Это что-то типа "глюка". В этом случае, никакие разделительные NOPы не помогут. Хоть сто штук (условно). Эту беду, с помощью дополнительных команд, победить можно, но зачем, ведь эту "страсть" можно заменить всего-лишь тремя байт-ориентированными командами, после чего описанного выше безобразия просто не будет. Ещё раз дружески советую: в случаях возникновения подобного рода конфузов, нужно просто перейти с бит-ориентированных команд, на байт-ориентированные, и все дела ("дёшево и сердито"). Проверено жизнью, и не один раз (эквивалент "штампа ОТК"). Что по этому тексту думают профессионалы и начинающие?

medved: В регистр PortС запишется 011х хххх. Если на этом и закончить (то есть, нужно сбросить только один-разьединственный бит №7), то всё в норме, но по условию задачи, этого мало. "Потоково" сбрасываем дальше. 2. bcf PortC,6 Во внутренний буфер запишется 111х хххх. Для меня лично (по данному тексту) осталось загадкой почему во внутренний буфер запишется 111х хххх, ведь в регистр уже записано 011х хххх. И если после первого BCF все будет в норме, то во время второго BCF в регистре почему-то вылазит "бяка". Прямо полтергейст какой-то.



полная версия страницы