마이크로콘트롤러 설계 – 4 Timer 실습 2 – T1, T3
Timer 실습 - Timer - Timer 관련 레지스터 - Timer를 이용한 입출력
ATmega128
LED sink / switch pullup 회로 470 PD2 5V 10K 104 (0.1uF) PC0 +5V PC1 PC7 …..
LCD 회로 V0 VSS +5V VDD PC0 PC1 PC2 PC4 PC5 PC6 PC7 RS R/W E DB4 DB5 DB6 LEDA LEDK #3 #2 #1 LCD 밝기 조절
LCD 함수 #include <delay.h> // LCD 초기화 함수 void LCD_init(void) { #define LINE2 0xC0 // 2nd Line Move #define HOME 0x02 // Cursor Home #define RSHIFT 0x1C // Display Right Shift #define LSHIFT 0x18 // Display Left Shift #define DISPON 0x0c // Display On #define DISPOFF 0x08 // Display Off void LCD_init(void); void LCD_String(char flash str[]); void Busy(void); void Command(unsigned char); void Data(unsigned char); // LCD 초기화 함수 void LCD_init(void) { DDRC = 0xFF; // 포트 C 출력 설정 PORTC &= 0xFB; //E = 0; // 충분한 지연시간을 통한 안정화 과정 delay_ms(15); Command(0x20); // D5=1 delay_ms(5); delay_us(100); // 초기화 과정 Command(0x28); // function set Command(0x06); // entry mode set Command(0x01); // all clear Command(0x0c); // display on }
// 인스트럭션 쓰기 함수 void Command(unsigned char byte) { Busy(); // 인스트럭션 상위 바이트 PORTC = (byte & 0xF0); // 데이터 PORTC &= 0xFE; // RS = 0; PORTC &= 0xFD; // RW = 0; delay_us(1); PORTC |= 0x04; // E = 1; PORTC &= 0xFB; // E = 0; // 인스트럭션 하위 바이트 PORTC = ((byte<<4) & 0xF0); // 데이터 } //데이터 쓰기 함수 void Data(unsigned char byte) { Busy(); // 데이터 상위 바이트 PORTC = (byte & 0xF0); // 데이터 PORTC |= 0x01; //RS = 1; PORTC &= 0xFD; //RW = 0; delay_us(1); PORTC |= 0x04; //E = 1; PORTC &= 0xFB; //E = 0; // 데이터 하위 바이트 PORTC = ((byte<<4) & 0xF0); // 데이터 } // Busy Flag Check -> 일반적인 BF를 체크하는 것이 아니라 // 일정한 시간 지연을 이용한다. void Busy(void) delay_ms(2); // 문자열 출력 함수 void LCD_String(char flash str[]) { char flash *pStr=0; pStr = str; while(*pStr) Data(*pStr++); }
Timer/counter1 & 3 관련 IO 레지스터 TCNT1(Timer/Counter1 Register) / TCNT3(Timer/Counter1 Register) OCR 1A, 1B, 1C, OCR3A, 3B, 3C TIFR (T/C Interrupt Flag Register) / ETIFR (Extended TIFR)
TIMSK (T/C Interrupt Mask Register) bit 4 – OCIE1A : timer/counter1 Output Compare A Interrupt Enable bit 3 – OCIE1B : timer/counter1 Output Compare B Interrupt Enable bit 2 – TOIE1 : Timer/counter1 Overflow Interrupt Enable ETIMSK (Extended TIMSK) bit 4 – OCIE3A : timer/counter3 Output Compare A Interrupt Enable bit 3 – OCIE3B : timer/counter3 Output Compare B Interrupt Enable bit 2 – TOIE3 : Timer/counter3 Overflow Interrupt Enable bit 1 – OCIE3C : timer/counter3 Output Compare B Interrupt Enable bit 0 – OCIE0C : timer/counter1 Output Compare C Interrupt Enable
TCCR1A (Timer/Counter1 Control Register A) bit 1, 0 – WGM11, WGM10(Waveform Generation Mode) TCCR1B (Timer/Counter1 Control Register B) bit 4, 3 – WGM13, WGM12(Waveform Generation Mode) 0000 : normal (n3, n2, n1, n0 순) 0100 : CTC – TOP : OCR1A bit 2:0 – CS02:00 (Clock Selection) 000 : 타이머 차단 001 : 1분주 010 : 8분주 011 : 64분주 100 : 256분주 101 : 1024분주 110 : 카운터, 하강 에지에서 동작 111 : 카운터 동작, 상승 에지에서 동작
실습 1 // 타이머/카운터1을 이용한 LED 제어 실험 (normal mode 0.5초 간격) // 오버플로우 인터럽트를 이용하여 0.5초마다 모든 LED를 ON/OFF (토클 출력)시키는 프로그램 // 256분주한 클럭 사용 // 0.5초 계산 // : 오버플로우 인터럽트 주기 : 1/16us * 256분주 * 31250 = 500ms // : 31250 = 65536 (MAX) – 34286 (TCNT1) unsigned char led = 0xFF; void main(void) { DDRF = 0xFF; // 포트 F 출력으로 설정 PORTF = led; // 포트 F에 초기값 출력 TIMSK = 0b00000100; // TOIE1 = 1; TCCR1A = 0b00000000; // 일반모드 (WGM11, WGM10) TCCR1B = 0b00000100; // 일반모드 (WGM13, WGM12), 프리스케일 = 256 TCNT1 = 34286; // 타이머/카운터1 레지스터 초기값 SREG = 0b10000000; // 전역 인터럽트 인에이블 비트 I 셋. while(1); // 무한 루프 } // 타이머/카운터1 오버플로우 서비스 루틴 interrupt [TIM1_OVF] void timer_int1(void) { TCNT1 = 34286; led = led ^ 0xFF; PORTF = led; }
실습 2 // 타이머/카운터1을 이용한 LED 제어 실험 (CTC 0.5초 간격) // 오버플로우 인터럽트를 이용하여 0.5초마다 모든 LED를 ON/OFF (토클 출력)시키는 프로그램 // 256 분주한 클럭 사용 // 0.5초 계산 // : 오버플로우 인터럽트 주기 : 1/16us * 256분주 * 31250 = 500ms unsigned char led = 0xFF; void main(void) { DDRF = 0xFF; // 포트 F 출력으로 설정 PORTF = led; // 포트 F에 초기값 출력 TIMSK = 0b00010000; // OCIE1A = 1; TCCR1A = 0b00000000; // CTC모드 (WGM11, WGM10 = 00) TCCR1B = 0b00001100; // CTC모드 (WGM13, WGM12 = 01), 프리스케일 = 256 TCNT1 = 0; // 타이머/카운터1 레지스터 초기값 OCR1A = 31250; // TOP값 설정 SREG = 0b10000000; // 전역 인터럽트 인에이블 비트 I 셋. while(1); // 무한 루프 } // 타이머/카운터1 오버플로우 서비스 루틴 interrupt [TIM1_COMPA] void timer_comp1a(void) { led = led ^ 0xFF; PORTF = led; }
실습 3 // 타이머/카운터3을 이용한 LED 제어 실험 (normal mode 0.5초 간격) // 오버플로우 인터럽트를 이용하여 0.5초마다 모든 LED를 ON/OFF (토클 출력)시키는 프로그램 // 256분주한 클럭 사용 // 0.5초 계산 // : 오버플로우 인터럽트 주기 : 1/16us * 256분주 * 31250 = 500ms // : 31250 = 65536 (MAX) – 34286 (TCNT1) unsigned char led = 0xFE; void main(void) { DDRF = 0xFF; // 포트 F 출력으로 설정 PORTF = led; // 포트 F에 초기값 출력 ETIMSK = 0b00000100; // TOIE3 = 1; TCCR3A = 0b00000000; // 일반모드 (WGM11, WGM10) TCCR3B = 0b00000100; // 일반모드 (WGM13, WGM12), 프리스케일 = 256 TCNT3H = 0x85; // 타이머/카운터1 레지스터 초기값, 34286=0x85EE TCNT3L=0xEE; SREG = 0b10000000; // 전역 인터럽트 인에이블 비트 I 셋. while(1); // 무한 루프 } // 타이머/카운터3 오버플로우 서비스 루틴 interrupt [TIM3_OVF] void timer_int1(void) { TCNT3H = 0x85; TCNT3L=0xEE; led = (led<<1) | 0b00000001; // 왼쪽 쉬프트 if(led == 0xFF) led = 0xFE; PORTF = led; }
실습 4 // 외부 인터럽트0 서비스 루틴 interrupt [EXT_INT0] void external_int0(void) { if(loc == 0) sec++; if(loc == 1) min++; if(sec > 59) sec -= 60; if(min > 59) min -= 60; time_display(); } // 외부 인터럽트1 서비스 루틴 interrupt [EXT_INT1] void external_int1(void) loc = (loc + 1) % 2; // 타이머1을 이용한 디지털시계 제작 - 분과 초를 LCD에 출력 // : 오버플로우 인터럽트 주기 : 1/16us * 256분주 * 62500 = 1000ms // : 62500 = 65536 (MAX) – 3036 (TCNT1) void time_display(void) int loc=0, min=0, sec=0; void main(void) { DDRD = 0b00000000; // PD0, PD1 입력 설정 (SW1, SW2) EIMSK = 0b00000011; // 외부 인터럽트0, 1 인에이블 EICRA = 0b00001010; // 외부 인터럽트0, 1 하강 에지 TIMSK = 0b00000100; // TOIE1 = 1; TCCR1A = 0b00000000; // 일반모드 (WGM11, WGM10) TCCR1B = 0b00000100; // 일반모드 (WGM13, WGM12), 프리스케일 = 256 TCNT1 = 3036; SREG = 0b10000000; // 전역 인터럽트 인에이블 비트 셋 LCD_init(); time_display(); while(1); // while(1) : 무한 루프 }
// 타이머/카운터1 오버플로우 서비스 루틴 interrupt [TIM1_OVF] void timer_int1(void) { TCNT1 = 3036; sec++; if(sec >= 60) { sec = 0; min++; if(min >= 60) min = 0; } time_display(); // 시간 출력 부함수 void time_display(void) { int temp1, temp0; Command(HOME); LCD_String(“Time : ”); temp1 = min / 10; // 분의 10자리 추출 temp0 = min % 10; // 분의 1자리 추출 Data(0x30 + temp1); Data(0x30 + temp0); LCD_String(“: ”); temp1 = sec / 10; // 초의 10자리 추출 temp0 = sec % 10; // 초의 1자리 추출 }
실습 5 // 타이머1을 이용하여 0.5초마다 앞자리 LCD 1 증가 // 타이머3를 이용하여 1초마다 뒷자리 LCD 1 감소 void num_display(void); int num1=0, num2=0, cnt1=0, cnt2=0; void main(void) { TIMSK = 0b00000100; // TOIE1 = 1 ETIMSK = 0b00000100; // TOIE3 = 1 TCCR1A = 0b00000000; // 일반모드 TCCR1B = 0b00000100; // 일반모드, 프리스케일 = 256 TCNT1 = 34286; TCCR3A = 0b00000000; // 일반모드 TCCR3B = 0b00000100; // 일반모드, 프리스케일 = 256 TCNT3H = 0x0B; TCNT3L=0xDC; SREG = 0b10000000; // 전역 인터럽트 인에이블 비트 셋 LCD_init(); while(1); // while(1) : 무한 루프 } // 타이머/카운터1 오버플로우 서비스 루틴 interrupt [TIM1_OVF] void timer_int1(void) { TCNT1 = 34286; num1++; if(num1 >= 10) num1 = 0; num_display(); cnt1 = 0; } // 타이머/카운터3 오버플로우 서비스 루틴 interrupt [TIM3_OVF] void timer_int3(void) TCNT3H = 0x0B; TCNT3L=0xDC; num2--; if(num2 <= 0) num2 = 9; cnt2 = 0;
// 값 출력 부함수 void num_display(void) { Command(HOME); LCD_String(“Number : ”); Data(0x30 + num1); LCD_String(“ - ”) Data(0x30 + num2); }
실습 6 // 외부 인터럽트0 서비스 루틴 interrupt [EXT_INT0] void external_int0(void) { num++; num_display(); } // 외부 인터럽트1 서비스 루틴 interrupt [EXT_INT1] void external_int1(void) TIMSK = 0b00000100; // TOIE1 = 1; TCCR1A = 0b00000000; // 일반모드 TCCR1B = 0b00000100; // 일반모드, 프리스케일 = 256 TCNT1 = 3036; // 타이머/카운터1 오버플로우 서비스 루틴 // 1/16us x 1024 x 256 = 16.384ms interrupt [TIM1_OVF] void timer_int1(void) if(num>0) num--; else { led = led ^ 0xFF; PORTF = led; 실습 6 // SW1을 누르면 초 증가, LCD에는 현재 초 표시 // SW2를 누르면 SW1을 통하여 설정된 초 뒤에 LED 점멸 void num_display(void); int num=0, cnt=0; int led=0xFF; void main(void) { DDRF = 0xFF; // 포트 F 출력으로 설정 PORTF = led; // 포트 F에 초기값 출력 DDRD = 0b00000000; // PD0 입력 설정 (SW1) EIMSK = 0b00000011; // 외부 인터럽트0 인에이블 EICRA = 0b00001010; // 외부 인터럽트0 하강 에지 SREG = 0b10000000; // 전역 인터럽트 인에이블 비트 셋 LCD_init(); num_display(); while(1); // while(1) : 무한 루프 }
// 값 출력 부함수 void num_display(void) { Command(HOME); LCD_String(“Number : ”); Data(0x30 + num); }