2014-11-29 2 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과 주 코드간에이 변수를 "안전하게"공유하고 있음을 의미하지 않습니다. 단일 CPU 명령으로 변수에 액세스하는 경우 원자 액세스가 보장되는 것은 아닙니다. 예를 들어, 8 비트 마이크로의 16 비트 변수는 값을 읽기 위해 여러 읽기 명령어를 사용합니다. 그 사이에 인터럽트가 발생하면 변수의 절반 만 읽혀지기 때문에 16 비트 데이터가 손상됩니다. ISR 이전의 첫 번째 8 비트와 ISR이 반환 된 후 나머지 8 비트. 이것은 예를 들어 ADC 데이터 값을 전달하는 것보다 포인터가 관련되어 있으면 큰 문제를 일으킬 수있는 잘못된 데이터입니다. 이로 인해 스택 오버 플로우가 발생할 수 있습니다.

간단한 액세스는 인터럽트를 빠르게 비활성화하고, 값을 읽고, 일련 화 된 액세스를 보장하기 위해 값을 재사용해야합니다.

정적 전역을 사용하는 소형 임베디드 시스템은 제 의견으로는 최소한의 비용으로 계속 유지하는 것이 좋습니다. 구조를 사용하여 전역을 더 적게 분해합니다.

지구본은 너무 많아서 많은 파일에서 앞뒤로 액세스 할 때 "악마"입니다. 그냥 지저분 해지고 다른 기존 글로벌과 같은 이름을 가진 다른 변수를 쉽게 만들 수 있습니다. 안좋다.

+0

일반적인 C 임베디드 프로그램에서 전역 변수를 피할 이유는 보이지 않습니다. 아주 좋은 이유가 없다면 (특히 Clifford가 잘 보여 주듯이) –

관련 문제