pavelm-ks Опубликовано 21 ноября, 2017 Поделиться Опубликовано 21 ноября, 2017 (изменено) Всем привет! Никто не сталкивался с тем, чтобы протеус не корректно обрабатывал операцию сравнения 16 битной перерменной? Ситуация такая: - Накодил в CVAVR - в коде есть место где ожидется пока обнулится переменная расчета времени (в прерывании таймера она уменьшается от рассчитанного значения до 0 ) while (timer>0) //ожидаем таймер { }; // Timer 0 overflow interrupt service routine interrupt [TIM0_OVF] void timer0_ovf_isr(void) { // Place your code here if (timer>0)timer--;//декриминируем таймер при условии что он больше 1 чтобы "не перевалить за 0". } Переменную таймера компиллер загнал в два регистра R13,R12. Так вот эта зараза протеус при симуляции, периодически (бывает через цикл, бывает через 2,5,10, как ему вздумается) вываливается из while как только R13=0x00 и ему пофиг, что R12=0xFF при этом. А бывает нормально - ожидает пока оба регистра обнулятся... Это все же глюк протеуса или что-то с кодом или компиллером? Кто-то сталкивался с подобным? Спасибо! Вот, написал и осинило. Глюк решился путем разбивки оператора while на две части while (timer>255) //ожидаем таймер { }; while (timer>0) //ожидаем таймер { }; Но так и не понятно что именно было причиной .Может как-то прерывние таймера неудачно вызывалось в какой-то "не подходящий" момент проверки while. Изменено 21 ноября, 2017 пользователем pavelm-ks 0 Ссылка на комментарий Поделиться на другие сайты Поделиться
snn_krs Опубликовано 21 ноября, 2017 Поделиться Опубликовано 21 ноября, 2017 Если переменная изменяется в прерывании, надо объявлять volatile. volatile uint16_t timer; 0 Ссылка на комментарий Поделиться на другие сайты Поделиться
20% скидка на весь каталог электронных компонентов в ТМ Электроникс!Акция "Лето ближе - цены ниже", успей сделать выгодные покупки!Плюс весь апрель действует скидка 10% по промокоду APREL24 + 15% кэшбэк и бесплатная доставка!Перейти на страницу акции Реклама: ООО ТМ ЭЛЕКТРОНИКС, ИНН: 7806548420, info@tmelectronics.ru, +7(812)4094849
IMXO Опубликовано 21 ноября, 2017 Поделиться Опубликовано 21 ноября, 2017 49 минут назад, pavelm-ks сказал: Глюк Proteus или баг кода? незнание языка, изучайте: http://pic24.ru/doku.php/osa/articles/volatile_for_chainiks 0 Ссылка на комментарий Поделиться на другие сайты Поделиться
Выбираем схему BMS для заряда литий-железофосфатных (LiFePO4) аккумуляторовОбязательным условием долгой и стабильной работы Li-FePO4-аккумуляторов, в том числе и производства EVE Energy, является применение специализированных BMS-микросхем. Литий-железофосфатные АКБ отличаются такими характеристиками, как высокая многократность циклов заряда-разряда, безопасность, возможность быстрой зарядки, устойчивость к буферному режиму работы и приемлемая стоимость. Но для этих АКБ очень важен контроль процесса заряда и разряда для избегания воздействия внешнего зарядного напряжения после достижения 100% заряда. Инженеры КОМПЭЛ подготовили список таких решений от разных производителей. Подробнее>>Реклама: АО КОМПЭЛ, ИНН: 7713005406, ОГРН: 1027700032161
ARV Опубликовано 21 ноября, 2017 Поделиться Опубликовано 21 ноября, 2017 По-моему, тут проблема вовсе не в volatile - CVAVR плевать хотел на volatile, для него все глобальные переменные одинаковы. Проблема тут, по-моему, с атомарным доступом... переменная-то int, и меняется в прерывании... 1 Если забанить всех, кто набрался смелости думать независимо, здорово будет на форуме - как на кладбище: тишина, птички поют... Ссылка на комментарий Поделиться на другие сайты Поделиться
Yurkin2015 Опубликовано 21 ноября, 2017 Поделиться Опубликовано 21 ноября, 2017 (изменено) 7 часов назад, pavelm-ks сказал: прерывние таймера неудачно вызывалось Восьмибитный процессор делает операцию сравнения двухбайтной переменной (timer>0) в два этапа. Сначала он из памяти в регистр загружает младший байт timer и проверяет его на ноль. Если не равен, то просто выход из сравнения. Если младший равен нулю, то процессор загружает старший байт timer и сравнивает его с нулём. Если и старший равен, то считается, что и всё двухбайтовое число timer равно нулю. Так как в цикле while больше ничего не делается, а только с чумовой скоростью загружаются и проверяются одни и те же байты, то очень легко попасть прерыванием между проверкой младшего и старшего байтов. Вот, и выходит, что при timer = 0x0100 сначала загрузили младший байт, проверили и получили ==0. Но тут случилось прерывание и в результате timer = 0x00FF. Но мы-то уже младший проверили. Поэтому после прерывания загружаем старший байт, проверяем его и снова получаем == 0! В полной уверенности объявляем, что оба байта равны 0 и выходим из while(). Для борьбы с такими ситуациями надо проверку timer > 0 делать в самом прерываниии и изменять какой-нибудь флаг, если == 0. Например, так: byte not_null; // Timer 0 overflow interrupt service routine interrupt [TIM0_OVF] void timer0_ovf_isr(void) { if (timer>0)timer--;//декриминируем таймер при условии что он больше 0, чтобы "не перевалить за 0". else not_null = 0; } main() { .... timer = 0x123; not_null = 1; while(not_null){};//ожидаем таймер ... } Изменено 21 ноября, 2017 пользователем Yurkin2015 3 Ссылка на комментарий Поделиться на другие сайты Поделиться
pavelm-ks Опубликовано 22 ноября, 2017 Автор Поделиться Опубликовано 22 ноября, 2017 12 hours ago, Yurkin2015 said: Вот, и выходит, что при timer = 0x0100 сначала загрузили младший байт, проверили и получили ==0. Но тут случилось прерывание и в результате timer = 0x00FF. Но мы-то уже младший проверили. Поэтому после прерывания загружаем старший байт, проверяем его и снова получаем == 0! В полной уверенности объявляем, что оба байта равны 0 и выходим из while(). Спасибо за разъяснения, я примерно так и думал , но по полочкам разложить не мог (как собака все понимаю, а сказать не могу :)). А voletile переменная была объявлена , так что это тут точно ни при чем. 0 Ссылка на комментарий Поделиться на другие сайты Поделиться
Рекомендуемые сообщения
Присоединяйтесь к обсуждению
Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.
Примечание: Ваш пост будет проверен модератором, прежде чем станет видимым.