인터럽트(Interrupt)와 전자 룰렛
학습목표 - Interrupt를 활용하여 LED전자 룰렛을 만들 수 있다
인터럽트를 활용하여 좌우의 끝으로 이동하는 LED 전구를 멈추게 하는 코딩을 해보자.
/*** 코딩 절차 ***/
I. 문장으로 표현
II. 큰 덩어리로 코딩할 부분 나누기
III. 덩어리로 나눈 부분 세부화
IV. 코딩
V. 실행
VI. 디버깅
I. 문장으로 표현
LED전구 8개에 불이 하나씩만 번갈아 가면서 켜지게 하고 한쪽 끝으로 이동하고 나면 다시 반대 방향으로 이동하게 하는 코드를 짜보자.
인터럽트(Interrupt)를 활용하여 버튼(pull-up상태)이 눌러져 있을 때 전구의 이동이 멈추게 만들어보자.
인터럽트는 INT4를 활용하고 인터럽트 벡터 no.는 AVR교재 p/137을 참조한다.
외부 인터럽트는 레지스터 설정은 low level일 때 발생한다.
II. 큰 덩어리로 코딩할 부분 나누기
1. LED 이동 코딩
2. 스위치를 넣으면 인터럽트가 작동하여 이동이 멈추는 코딩
III. 덩어리로 나눈 부분 세부화
1. LED 이동 코딩
- 8개의 LED전구에 좌에서 우로 전구의 불이 이동하게 한다.
- 우측 끝으로 이동했을 때, 좌측으로 이동하게 한다.
- 좌측 끝으로 이동했을 때, 우측으로 이동하게 한다.
2. 스위치를 넣으면 인터럽트가 작동하여 이동이 멈추는 코딩
- INT4를 활용하도록 포트를 설정해 준다. 교재 p/137를 참고하자.
- 외부 인터럽트 컨트롤 레지스터의 이름이 무엇인지 확인한다.
- 외부 인터럽트 컨트롤 레지스터의 설정 값을 확인하고, low level일 때 인터럽트 가동하게 설정해준다.
우선 회로도를 그려주자.
/*** 설정 ***/
PORT: C는 출력, E는 interrupt 입력
스위치는 pull-up
LED 전구는 common anode type으로 연결하여 low 값이 입력 되었을 때 LED on
![](https://t1.daumcdn.net/cfile/tistory/213CA037552F4AD022)
LED가 좌우로 움직이는 코딩을 마친 후 인터럽트 설정을 해주자.
![](https://t1.daumcdn.net/cfile/tistory/21512A34552F4AE321)
EICRA는 0x02, low level로 설정해주자.
INT4을 사용하기 때문에 아래와 설정을 해주어야 한다.
EICRB = 0x02; //low level 동작 설정
EIMSK = 0x10; //외부 인터럽트 허용 레지스터 - 인터럽트 4번 외부 인터럽트 허용
소스는 아래와 같다.
/*** main.c ***/
#include <atm2560.h> //#include <avr/interrupt.h> #include "SMART.h"
int main(void) { /*** LED 입력 값을 넣어줄 변수 만들기 ***/
unsigned char ucLED=0xFE;
/*** Delay를 위한 변수 입력 ***/
volatile unsigned int uiCnt;
/*** 사용할 PORT 설정 ***/ DDRC = 0xFF; //PORT C 모두 사용 DDRE = 0xEF; //PORT E의 5번째 핀 사용
/*** 인터럽트 설정 ***/
SREG &= 0x7F; //interrupt disable, 설정 중 오동작을 막기 위해 EICRB = 0x02; //low level 동작 설정 EIMSK = 0x10; //외부 인터럽트 허용 레지스터 - 인터럽트 4번 외부 인터럽트 허용 SREG |= 0x80; //0B 1000 0000 핀만 1을 넣어주고 나머지는 그대로
while(1) { /*** LED불 좌에서 우 이동 코드 ***/ PORTC= ucLED; Delay(); ucLED = ucLED << 1; ucLED |= 0x01;
/*** LED불 우 끝으로 갔을 때 좌로 이동 코드 ***/ while(ucLED==0xFF) { ucLED = 0x7F; PORTC = ucLED; Delay(); while(1) { ucLED=ucLED >> 1; ucLED |= 0x80; PORTC = ucLED; Delay(); if(ucLED==0xFE) break; } } } return 0; }
void __vector_5(void) { /*** PINE가 0x00일때 잡아 놓아라 ***/ while(1) { while(PINE==0x00);
break; } }
|
/*** SMART.h ***/
#ifndef __SMART_H__ #define __SMART_H__
/**** General Purpose Register A - L ****/
#define PORTA (*((volatile unsigned char*)0x22)) #define DDRA (*((volatile unsigned char*)0x21)) #define PINA (*((volatile unsigned char*)0x20))
#define PORTB (*((volatile unsigned char*)0x25)) #define DDRB (*((volatile unsigned char*)0x24)) #define PINB (*((volatile unsigned char*)0x23))
#define PORTC (*((volatile unsigned char*)0x28)) #define DDRC (*((volatile unsigned char*)0x27)) #define PINC (*((volatile unsigned char*)0x26))
#define PORTD (*((volatile unsigned char*)0x2B)) #define DDRD (*((volatile unsigned char*)0x2A)) #define PIND (*((volatile unsigned char*)0x29))
#define PORTE (*((volatile unsigned char*)0x2E)) #define DDRE (*((volatile unsigned char*)0x2D)) #define PINE (*((volatile unsigned char*)0x2C))
#define PORTF (*((volatile unsigned char*)0x31)) #define DDRF (*((volatile unsigned char*)0x30)) #define PINF (*((volatile unsigned char*)0x2F))
#define PORTG (*((volatile unsigned char*)0x34)) #define DDRG (*((volatile unsigned char*)0x33)) #define PING (*((volatile unsigned char*)0x32))
#define PORTH (*((volatile unsigned char*)0x102)) #define DDRH (*((volatile unsigned char*)0x101)) #define PINH (*((volatile unsigned char*)0x100))
#define PORTJ (*((volatile unsigned char*)0x105)) #define DDRJ (*((volatile unsigned char*)0x104)) #define PINJ (*((volatile unsigned char*)0x103))
#define PORTK (*((volatile unsigned char*)0x108)) #define DDRK (*((volatile unsigned char*)0x107)) #define PINK (*((volatile unsigned char*)0x106))
#define PORTL (*((volatile unsigned char*)0x10B)) #define DDRL (*((volatile unsigned char*)0x10A)) #define PINL (*((volatile unsigned char*)0x109))
/* 인터럽트 사용을 위한 레지스터 */
#define EICRA (*((volatile unsigned char*)0x69)) #define EICRB (*((volatile unsigned char*)0x6A)) #define EIMSK (*((volatile unsigned char*)0x3D)) #define EIFR (*((volatile unsigned char*)0x3C)) #define SREG (*((volatile unsigned char*)0x5F))
/* CPU 동작시간을 맞춰주기 위한 Dealy문과 값 지정 */
#define Delay(x) for(uiCnt=0; uiCnt<(dNum1); ++uiCnt)
#define dNum1 50000 #define dNum2 300000 #define dNum3 10000000
/* 함수 원형 선언 */ void __vector_5(void)__attribute__((signal,used,externally_visible));
#endif //__SMART_H__ |
-----------------------------------------------------------------------------------------------------
포인터를 활용한 1/2차원 배열의 값과 주소
학습목표
1차원 배열의 값과 주소에 대해 이해하고 여러 가지 형태를 사용하여 출력할 수 있다.
2차원 배열의 값과 주소에 대해 이해하고 여러 가지 형태를 사용하여 출력할 수 있다.
지난 시간에 이어 2차원 배열에 대하여 수업을 해 보아요. \=_=/ \=_=/
시간이 남아 퓨전...(드래곤볼 참조)
퓨... \=_=/ \=_=/
전... o-(=_=)o- -o(=_=)-o
합... /=_=/ \=_=\
![](https://t1.daumcdn.net/cfile/tistory/215BBE36552F73D932)
배열에서 배열의 이름자체는 배열의 주소 값을 나타낸다.
ex) A[5]; printf("%p", A); -> A의 주소 출력
![](https://t1.daumcdn.net/cfile/tistory/2718B636552F73DA13)
int A[5]라는 배열이 있다고 하면,
![](https://t1.daumcdn.net/cfile/tistory/212C8E36552F73DC07)
![](https://t1.daumcdn.net/cfile/tistory/226BEE36552F73DD2A)
A는 주소 값으로써 상수이고 p는 주소 변수이다.
p가 변수임을 확인해 보자.
![](https://t1.daumcdn.net/cfile/tistory/236F1236552F73DF29)
![](https://t1.daumcdn.net/cfile/tistory/26511E36552F73E030)
p는 대입연산자(=)를 활용하여 그 값을 바꿀 수 있는 주소 변수임을 알 수 있다.
하지만 배열 A 또는 B는 주소 값을 나타내는 주소 상수로써 값을 변화 시킬 수 없다.
![](https://t1.daumcdn.net/cfile/tistory/230F2736552F73E119)
변수와 상수의 차이라는 점을 제외하고는 배열의 이름과 주소 변수(포인터)는 똑같이 사용할 수 있다.
/*** 네트워크 삼천포 ***/
![](https://t1.daumcdn.net/cfile/tistory/237D3339552F73E238)
![](https://t1.daumcdn.net/cfile/tistory/251EBB39552F73E326)
![](https://t1.daumcdn.net/cfile/tistory/257A2F39552F73E536)
![](https://t1.daumcdn.net/cfile/tistory/2437B839552F73E71A)
natservice가 있을 때 이것을 삭제해야 컴퓨터가 정상적으로 가동한다.
삭제하는 방법 http://todaki.tistory.com/2646
각설! 네트워크 삼천포 break;
--------------------------------------------------------------------------
배열의 타입은 int[X]이다. // X는 선언 시 입력한 상수.
const를 어떻게 쓰느냐에 따라 고정되는 값이 다르다.
포인터 변수 int * p에서,
const를 * 앞에 붙이면 *가 가리키는 값을 수정할 수 없고,
const를 변수명 바로 앞에 붙이면 가리키는 주소 값을 바꿀 수 없게 된다.
![](https://t1.daumcdn.net/cfile/tistory/22176A39552F73E92A)
![](https://t1.daumcdn.net/cfile/tistory/2433A139552F73EA1C)
2차원 배열로 넘어가서,
우선 for문을 사용하여 값과 주소를 출력해보자!
![](https://t1.daumcdn.net/cfile/tistory/22605539552F73EC03)
![](https://t1.daumcdn.net/cfile/tistory/23058E34552F73EE30)
차원수만큼의 대괄호([])가 있으면 그것은 값을 뜻한다.
차원수만큼의 포인터(*)가 있으면 그것은 값을 뜻한다.
대괄호의 역할을 포인터가 할 수 있다. 또한 포인터의 역할을 대괄호가 할 수 있다.
정리하면 대괄호의 수 + 포인터의 수 = 차원수 가 되면 값을 뜻한다.
대괄호의 수와 포인터의 수가 차원수보다 작게 되면 그것은 주소를 뜻한다.
코드와 결과 값!
/*** 2dimArry.c ***/
#include <stdio.h>
int main(void) { /*** 사용자의 가독성을 생각한 배열 코딩 ***/
int A[2][3]= { {1,2,3}, {4,5,6} }; int iCnt1; //행의 출력을 위한 카운터 int iCnt2; //열의 출력을 위한 카운터
for(iCnt1=0; iCnt1<2; ++iCnt1) { for(iCnt2=0; iCnt2<3; ++iCnt2) { printf("[%d]", A[iCnt1][iCnt2]); } putchar('\n'); }
putchar('\n'); for(iCnt1=0; iCnt1<2; ++iCnt1) { for(iCnt2=0; iCnt2<3; ++iCnt2) { printf("[%08X]", &A[iCnt1][iCnt2]); } putchar('\n'); } putchar('\n');
printf("A[0][0]의 값은 [%d]입니다.\n", A[0][0]); printf("*(A[0]+0)의 값은 [%d]입니다.\n", *(A[0]+0)); printf("*((*A+0)+0)의 값은 [%d]입니다.\n", *((*A+0)+0)); printf("*(A[0])의 값은 [%d]입니다.\n", *(A[0])); printf("**A의 값은 [%d]입니다.\n\n", **A);
printf("A[1][2]의 값은 [%d]입니다.\n", A[1][2]); printf("*(A[1]+2)의 값은 [%d]입니다.\n", *(A[1]+2)); printf("*((*A+2)+3)의 값은 [%d]입니다.\n\n", *((*A+2)+3));
printf("A[0][0]의 주소는 [%08X]입니다.\n", &A[0][0]); printf("(A[0]+0)의 주소는 [%08X]입니다.\n", (A[0]+0)); printf("((A+0)+0)의 주소는 [%08X]입니다.\n", ((A+0)+0));
return 0;
} |
![](https://t1.daumcdn.net/cfile/tistory/2743D834552F73F00C)