Неправильное поведение контроллера с переменной в глобальной области видимости

SAlex_S
Offline
Зарегистрирован: 13.11.2016

Добрый день.

Сразу говорю, что код выкладывать не буду. Если только кусками.

Суть проблемы: Я задаю переменную в глобальной области видимости. Потом инкрементирую её в функции вызванной по внешнему прерыванию. Она становиться равной 3 (условно). Потом я сравниваю её во втором внешнем прерывании и она становиться равной -1. Происходит это конкретно в момент вызова второго внешнего прерывания. (До момента обращения к переменной). После выхода из второго прерывания переменная по прежнему равна -1 и ей снова можно инкрементировать, но от -1. Вот такой странный ресет переменной.

Условия.

Среда: Arduino IDE 1.6.11

Плата: MEGA 2560

P.S. Бился над задачей около двух недель. В самом начале переменная ещё просто обнулялась. Но я уже менял во всем скетче типы переменных. И много чего делал. 

Выход я конечно придумал. Для работы со значением во втором прерывании я делаю дополнительную переменную в которой передаю значение. Но считаю это решение костылём.

Моё мнение. Компилятор не правильно задаёт область видимости переменной и во втором прерывании не позволяет прочесть значение переменной, а инрементирует его заново. И потом возвращает его переменной как истинное.

Конечно, может это особенность архитектуры AVR, не позволять двум прерываниям работать с одной переменной.

Я прошу совета ГУГУ С++

 

Клапауций 234
Offline
Зарегистрирован: 24.10.2016

SAlex_S пишет:

Сразу говорю, что код выкладывать не буду. Если только кусками.

сразу говорю - иди впень... кусками

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

SAlex_S пишет:

Моё мнение. Компилятор не правильно задаёт область видимости переменной и во втором прерывании не позволяет прочесть значение переменной, а инрементирует его заново. И потом возвращает его переменной как истинное.

Ну у вас 2 пути:

1 идиотское - поменять копилятор в среде.

2 реальное - поменять свое мнение. И пользоваться тем компилятором который есть и всех устраивает.

bwn
Offline
Зарегистрирован: 25.08.2014

volatile ?

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

SAlex_S пишет:

Сразу говорю, что код выкладывать не буду. 

И не надо.

SAlex_S пишет:

Моё мнение. Компилятор не правильно 

Мнение о "неправильности компилятора" высказывают (высказывали и будут высказывать) горе-программисты во все времена. В 1982 перед входом в комнату дежурной смены ВЦКП СУ в Томске даже висела вывеска: "Да, у нас фортран не работает, и что?"

SAlex_S пишет:

может это особенность архитектуры AVR, не позволять двум прерываниям работать с одной переменной.

Это особенность Вашей секретной программы. Разбирайтесь.

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

Все переменные, которые пользуются И изменяются в прерываниях обязаны объявляться как volatile. Врочем, вам уже про это намекнули..

nik182
Offline
Зарегистрирован: 04.05.2015

А в основной программе ещё скобками запрета прерываний окружена.

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

Сначала предположил что это инкрементируется байт, но обнаружив -1, уже думаю что там int, а стало быть, да - надо окружать запретом прерываний - @see "атомарное чтение".

SAlex_S
Offline
Зарегистрирован: 13.11.2016

Arhat109-2 пишет:

Сначала предположил что это инкрементируется байт, но обнаружив -1, уже думаю что там int, а стало быть, да - надо окружать запретом прерываний - @see "атомарное чтение".

Переменная глобальная, т.е. volatile. Тип long. 

С "атомарным чтением" ни разу не сталкивался но суть понял. Похоже это и есть причина по которой программа работает не правильно. (Хотя можно и на комилятор сослаться, что он не понял, что переменная должна обрабатываться атомарно.)

Arhat109-2 Я с лету не нашел материал для обучения по этой теме. Можешь дать ссылку для изучения этого вопроса?

nik182
Offline
Зарегистрирован: 04.05.2015

Volatile значит не глобальная, а вольная, независимая, изменяющая значение без контроля программы. Например любой входной регистр. Если обращении к такой переменной не атомарно ( = несколько байт ) то прерывание может поменять часть переменной и после прерывания результат будет иметь неопределённое значение. Поэтому в основной программе перед обращением к такой переменной надо запретить прерывания, после обращения снова разрешить.
Глобальной может быть любая переменная. Всё зависит от места и вида объявления.
Компилятор предупреждает о возможном изменении переменной, но не считает это ошибкой. От вас это предупреждение спрятали, что бы не заморачивать начинающих.

SAlex_S
Offline
Зарегистрирован: 13.11.2016

Arhat109-2, nik182 Большое спасибо

Я перешел на однобайтовые переменные в критичных местах и применил Volatile. Заработало. Так же применил экранирование прерываний.

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

SAlex_S пишет:

Я перешел на однобайтовые переменные в критичных местах и применил Volatile. Заработало. Так же применил экранирование прерываний.

УРА! Автор все же решил не менять компилятор в среде Ардуино, а так же не начал переписывать синтаксис языка Си.

Угроза обновления прошла мимо. Аплодисменты TC от благодарных пользователей Ардуино.

Клапауций 234
Offline
Зарегистрирован: 24.10.2016

qwone пишет:

Автор все же решил не менять компилятор в среде Ардуино, а так же не начал переписывать синтаксис языка Си.

я запретил.