2014-11-29 11 views
3

В основном я преподаю в C. Программирую встроенные микроконтроллеры. (например, dsPIC33fj128gp804) Обычно я использую глобальную переменную и все, что я когда-либо читал, денонсирует с использованием глобальных переменных, таких как чума. Я работал над использованием меньше, но есть сценарий, который я не знаю, как не использовать глобальные переменные.глобальные переменные с прерываниями?

Микроконтроллер оснащен прерываниями. Прерывание - это событие, вызванное извне в аппаратном обеспечении. Когда прерывания запускаются, выполнение основного кода прекращается, текущие рабочие переменные сохраняются, выполняется предварительно назначенная функция, а затем основной код выбирает резервную копию там, где она была остановлена. Поскольку прерывание является автономной функцией, которая может запускаться в любой момент, ничто не может быть передано в или из функции.

Например, когда оборудование UART получает байт данных, эти данные необходимо переместить из аппаратного буфера до того, как они перейдут на запись.

void __attribute__((interrupt, no_auto_psv)) _U2RXInterrupt(void) 
{ 
GlobalVariable = U2RXREG; // Move data to global variable 
IFS4bits.U2RXIF = 0; // Clear the UART2 Receive Interrupt Flag 
} 

Есть ли способ сделать это без глобальных переменных или это исключение?

+0

Для разных потоков и ISR (процедуры обслуживания прерываний) вам действительно нужно использовать глобальные данные. Но иногда вам необходимо обеспечить взаимное исключение при доступе к этим данным. –

+0

Глобалы не являются чумой, многие люди говорят, что на самом деле не знают, почему или почему не кто-то сказал им об этом. Пойдите с тем, что вы знаете и медленно меняетесь, основываясь на опыте не на спекуляции ... –

+0

Если вы берете совет @ dwelch «медленно меняться», вы можете обнаружить, что вы «медленно» уменьшаете количество ошибок! Хотя мы, вероятно, очень много согласны, я не уверен, что соглашусь с этим. Правда, многие слепо следуют мантре «без глобалов», не потрудившись понять, почему или, что еще более важно, подходящие альтернативы. Понимание того, почему и каким образом является ключом к тому, чтобы не было соблазн предположить, что у вас есть специальный случай, когда он является либо ОК, либо необходим. Однако о язвах: [Оспа на глобалах] (http://www.embedded.com/electronics-blogs/break-points/4025723/A-pox-on-globals). – Clifford

ответ

2

Вы должны различать глобальную переменную с внешней связью и статическую переменную области файла. Вы можете решить свою проблему с помощью последней.

static volatile int shared_variable ; 

int getShared(){ return shared_variable ; } 

static void isr_handler() 
{ 
    shared_variable++ ; 
} 

Таким образом, в приведенном выше примере, единственный доступ к общей переменной внешней по отношению к единице перевода осуществляется с помощью функции getShared() доступа. Этот метод, конечно, зависит от использования отдельной компиляции, но это не плохо для многих причин.

Для других методов для избежания глобал и объяснений о том, почему вы должны это сделать, см Джека Ganssle-х A Pox on Globals

Другой вещью, чтобы рассмотреть, и причину, почему Глобал особенно проблематичные в данном случае является то, что общим переменным либо атомарным для доступа в критическом разделе. Например, на 16-разрядном dsPIC 32-разрядные обращения не являются атомарными, и в этом случае в функции доступа может быть помещена необходимая защита, тогда как если бы она была глобальной, каждый доступ должен быть индивидуально защищен:

Для пример:

static volatile uint32_t shared_variable ; 

int getShared() 
{ 
    uint32_t ret ; 

    _disable_interrupts() ; 
    ret = shared_variable ; 
    _enable_interrupts() ; 

    return ret ; 
} 
1

Использовать статические глобальные скобки как можно больше, чтобы переменная находилась только в области видимости в этом конкретном исходном файле. Используйте статические переменные, объявленные в функциях, которые используют их для еще большей изоляции.

Используйте volatile для всех переменных, используемых как в процедурах прерывания, так и в цикле основного кода.

Обратите внимание, что будучи изменчивым, НЕ означает, что вы «безопасно» используете эту переменную между ISR и основным кодом. Это НЕ гарантируется как доступ к Atomic, к которому обращается переменная с помощью одной команды CPU. Например, 16-разрядная переменная на 8-битном микросхеме будет принимать несколько инструкций считывания для чтения значения. Если прерывание срабатывает между вами, у вас будут испорченные 16-битные данные, потому что была прочитана только половина переменной. Первый 8-бит перед ISR и другой 8-й бит после возврата ISR. Это плохие данные, которые могут вызвать огромные проблемы, если указатели задействованы, а не просто передавать значение данных ADC, например. Это может привести к stackoverflow.

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

С небольшими встроенными системами, использующими статические глобальные переменные, на мой взгляд, отличный способ идти до тех пор, пока вы держите его до минимума и прямолинейно! Используйте структуры, чтобы еще больше разрушить глобалы.

Глобалы являются только «злыми», когда у вас слишком много, и они обращаются к ним взад и вперед по многим файлам. Он просто становится очень грязным, и вы можете легко создать другую переменную, которая имеет то же имя, что и другой существующий глобальный. Нехорошо.

+0

Я не вижу причины, чтобы избежать глобалов в простой встроенной программе C, и особенно не в interrupthandlers, если у вас нет очень веских причин (например, Clifford хорошо иллюстрирует) –

Смежные вопросы