AVR & ATmega

CodeVisionAVR ANSI C Language 요점 정리(2)

EP 기술연구소 2010. 4. 19. 14:34

}

void main(void){

int i;

i = alfa(); /* return = 1 */

i = alfa(); /* return = 2 */

}

 

extern 선언 : 다른 파일에 선언된 변수는 extern 선언을 해야한다.

extern int xyz;

전역 변수는 SRAM Global Variables 영역에 저장되고, 지역 변수는 SRAM Data Stack 영역에 dynamic하게 할당된다.

 

l        외부 SRAM의 특정 번지에 전역 변수를 지정하는 방법

@ 연산자 사용하여 전역 변수를 특정 SRAM 위치에 배치할 수 있다.

int  a  @0x80                    /* 정수 변수 a는 외부 SRAM 0x80에 할당 */

struct x {

             int a;

             char c;

             } alfa @0x90          /* 0x90 번지에 구조체 alfa 할당 */

 

l        비트(bit) 변수

비트 변수는 레지스터 R2에서 R15까지 사용 가능: 최대 112 비트.

:

bit alfa=1;             /* bit0 of R2 */

bit beta;               /* bit1 of R2 */

void main(void){

if(alfa) beta != beta;

}

비트 변수 크기 지정은 Project|Configure|C Compiler|Compilation|Bit Variable Size에서 지정할 수 있다.

가능한 작게 지정하는 것이 좋음 (전역 변수에서 많이 사용 가능)

 

l        I/O 레지스터의 비트 단위 액세스

I/O 레지스터를 비트 단위로 액세스 할 수 있다.

 

:

DDRA.0 = 1;          /* Port A의 비트 0을 출력 포트로 함 */

DDRA.1 = 0;          /* Port A의 비트 1을 입력 포트로 함 */

PORTA.0 = 1;        /* Port A의 비트 0 1 출력 */

If(PINA.1){            /* Port A의 비트 1를 판별하여 처리 */

 

/* 코드 추가 */

 

}

프로그램의 판독을 좋게 하려면 #define을 사용하여 의미 부여 사용.

 

#define alarm_input PINA.2

void main(void){

if(alarm_input)

}

 

l        EEPROM 액세스

 

AVR 내부의 EEPROM 사용은 전역 변수 앞에 eeprom 키워드를 사용하여 가능하다.

 

:

eeprom int alfa=1;               /* Chip 프로그램 시에 EEPEOM 1값 저장 */

eeprom char beta;

eeprom long array1[5];

eeprom char string[]=Hello;   /* Chip 프로그램 시에 EEPEOM에 문자열 저장 */

 

void main(void){

int i;

int eeprom *ptr_to_eeprom;   / EEPROM 포인터 */

alfa = 0x55;                        /* EEPROM 0x55 값 직접 쓰기 */

ptr_to_eeprom=&alfa;

ptr_to_eeprom=0x55;            / 포인터 사용하여 간접적으로 쓰기 */

i=alfa;                                /* EEPROM에서 직접적으로 값 읽기 */

i=*ptr_to_eeprom;   /* EEPROM에서 간접적으로 값 읽기 */

}

EEPROM의 포인터는 항상 16비트를 사용함.

 

l        인터럽트 사용 하기

interrupt 키워드를 사용.

: 여기서 벡터 번호는 AT90S8515에 대한 것 임.

interrupt [2] void external int0(void){               /* 외부 인터럽트 */

 

/* 여기에 처리 코드를 넣는다 */

}

interrupt [8] void timer0 overflow(void){           /* 타이머0 Overflow 인터럽트 */

 

/* 여기에 처리 코드를 넣는다 */

}

인터럽트 벡터 번호는 1부터 시작.

인터럽트 처리 시작 부분에서 자동적으로 레지스터를 스택에 저장하고 인터럽트 종료 시 다시 스택에서 레지스터로 회복해 놓는다.

자동적으로 저장하는 레지스터는 R0, R1, R22 ~ R31, SREG이다.

만일 레지스터를 대피하는 인터럽트 처리 시간을 조금이라도 단축하고자 하는 경우 #pragma savereg 지시자를  사용한다.

:

#pragma savereg- /* 레지스터 저장 기능 OFF */

interrupt [1] void my_irq(void){

 

/* 사용하는 레지스터 만 저장 예: R30, R31, SREG 만 사용하는 경우 */

#asm

             push r30

             push r31

             in r30, SREG

             push      r30

#endasm

/* 여기에 C 코드를 놓음 */

/* 레지스터 SREG, R31, R30 회복 */

#asm

             pop        r30

             out         SREG,r30

             pop        r31

             pop        r30

#endasm

}

#pragma savereg+ /* 레지스터 저장 기능 on */

 

l        어셈블리 언어 첨가

#asm #endasm 사용

:

void delay(unsigned char i){

while(i--){

             #asm

                           nop

                           nop

             #endasm

             };

}

다음과 같이 한 줄로 표현 할 수도 있다.

#asm(sei)          /* 인터럽트 인에이블 */

어셈블리 루틴에서 R0, R1, R22 ~ R31은 자유롭게 사용할 수 있다. 단 인터럽트 루틴 안에서 사용 시에는 스택에 저장 및 회복을 해야 한다.

 

l        딜레이(delay) 함수 사용

CodeVisionAVR에서는 일정 시간 동안 지연하는 2개의 딜레이 함수를 제공한다.

void        delay_us(unsigned int n);                 /* micro(u) sec 단위 지연 함수 */

void        delay_ms(unsigned int n);   /* milli(m) sec 단위 지연 함수 */

:

delay_us(100);      /* 100 usec 지연 */

delay_ms(123);      /* 123 msec 지연 */

딜레이 함수를 사용하기 전에 delay.h 헤더 파일을 포함해야 되고, 정확한 시간을 위해서는 Project|Configure|C Compiler 메뉴의 AVR chip 클럭 주파수가 정확히 설정되어야 한다.

지연 동안 인터럽트가 처리될 수 있고 인터럽트가 처리되면 지연 시간이 늘어 날 수 있다.좀더 정확한 시간을 원하면 지연 시간동안 인터럽트를 금지할 필요가 있다.

:

#asm (cli)          /* 인터럽트 디스어블 */

delay_us(100);      /* 100 usec 지연 */

#asm(sei)          /* 인터럽트 인에이블 */

 

l        표준 함수 및 응용 함수 사용

CodeVionAVR C 컴파일러에서는 거의 모든 ANSI 표준 함수를 제공하고 있으며, 기타 LCD, 온도 센서, 시계 소자 등 여러 가지 라이브러리 함수를 제공하고 있는데 이에 대한 자세한 내용은 CodeVisionAVR User Manual을 참조 바람.