작업 :
1.LCD에 타이머 초시계
2.응용해서 스위치로 제어
개요:
1.타이머에 자동증가값을 넣어 초당 시간 출력
2.외부인터럽트로 각각 버튼을 눌렀을때 stop, 1분증가 , 리셋등의 명령
lcd.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | #ifndef __LCD_H__ #define __LCD_H__ #include "main.h" #define RS 4 #define RW 5 #define EN 6 #define BUS PORTA #define CTL PORTC // 케릭터lcd명령어 pdf 파일참고 #define LCD_CLR 0x01 //화면지우기 #define LCD_HOME 0x02 // 03가능// 홈 #define LCD_ENT 0x06 //S:0Shift OFF, I/D:1 Increase Mode // 엔트리모드셋 2진수 0110 #define LCD_DSP 0x0F //D:1 Display On C:1 Cursor on B:1 Blink On 1 // 2진수 1111 #define LCD_CUR 0x14 //S/C:0 Shift Cursor OFF R/L:1 // 2진수 0001 0100 #define LCD_FUNC 0x38 //DL:1 Data length 8bit N:1 2Line F:0 Font 5X8 // 2진수 0011 1000 void LCD_Init(void); void LCD_Inst(unsigned char ucInst); void LCD_Data(unsigned char ucData); void LCD_Str(char const *cString); #endif //__LCD_H_ | cs |
6~8번 : 각각 pin 번호 부여 LCD 모듈 컨트롤하기위한 RS,RW,E
10번 : PORTA를 BUS로 지정
11번 : PORTC를 제어로 지정
14번 : C영역 0000 0001 clear displayer 명령 실행
15번 : C영역 0000 0010 Return Home 명령 실행
16번 : C영역 0000 0110 Entry Mode 1 커서방향은 오른쪽으로 이동 SHIFT가 0이므로 쉬프트 X
17번 : C영역 0000 1111 디스플레이 제어 - Display ON ,화면 ON,커서 ON,커서 깜박임 ON
18번 : C영역 0001 0100 Cursor or Display Shift 명령 실행 - 오른쪽으로 커서 이동
19번 : C영역 0011 1000 Function Set 명령어 실행 ,Bus Size 8Bit, 2Line,5*10 font dots
21~24번 : 각각의 함수원형
lcd.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 | #include "lcd.h" void LCD_Init(void) { DDRC = ( 1 << RS )|( 1 << RW )|( 1 << EN ); //rs,rw,en 열기 DDRA = 0xFF; CTL = ( 0 << RS )|( 0 << RW )|( 0 << EN ); //Low 상태CTL == PORTC BUS = 0x00; LCD_Inst(LCD_FUNC); LCD_Inst(LCD_DSP); LCD_Inst(LCD_ENT); LCD_Inst(LCD_CUR); LCD_Inst(LCD_CLR); LCD_Inst(LCD_HOME); return; } void LCD_Inst(unsigned char ucInst) { //unsigned char int ucInst = 0x41; // ucInst volatile unsigned int uiCnt; //A 구간 CTL = CTL & (~ (1 << RS)); // CTL == PORTC CTL = CTL & (~ (1 << RW)); CTL = CTL & (~ (1 << EN)); BUS = ucInst; for(uiCnt = 0 ; uiCnt < 30000; uiCnt++); //B 구간 for(uiCnt = 0 ; uiCnt < 30000; uiCnt++); //c 구간 CTL = CTL | (1 << EN); // high 값을 가지므로 for(uiCnt = 0 ; uiCnt < 30000; uiCnt++); //D 구간 CTL = CTL & (~ (1 << EN)); for(uiCnt = 0 ; uiCnt < 30000; uiCnt++); //E 구간 for(uiCnt = 0 ; uiCnt < 30000; uiCnt++); return; } void LCD_Data(unsigned char ucData) { volatile unsigned int uiCnt; //A 구간 CTL = CTL | (1 << RS); CTL = CTL & (~ (1 << RW)); CTL = CTL & (~ (1 << EN)); BUS = ucData; for(uiCnt = 0 ; uiCnt < 30000; uiCnt++); // BUS를 통해 DATA와 Instruction 구간적 시간벌이 //B 구간 for(uiCnt = 0 ; uiCnt < 30000; uiCnt++); //c 구간 CTL = CTL | (1 << EN); // high 값을 가지므로 for(uiCnt = 0 ; uiCnt < 30000; uiCnt++); //D 구간 CTL = CTL & (~ (1 << EN)); for(uiCnt = 0 ; uiCnt < 30000; uiCnt++); //E 구간 for(uiCnt = 0 ; uiCnt < 30000; uiCnt++); return; } void LCD_Str(char const *cString) { while(0 != *cString) { LCD_Data(*cString); ++cString; } return; } | cs
lc |
3번 : lcd_Init 함수 - LCD 초기화
5번 : PortC의 4,5,6핀에 각각 RS, RW, E 출력 설정
6번 : PortA 모두 출력
7번 : 제어 모두 Low로 설정
8번 : Bus도 0로 초기화
9~14번 : 각각의 기능들을 초기화
19번 : LCD_Inst 함수
24번~26번 : A구간 비트&연산에 의해 RS,RW,E는 모두 0
27번 : 문자를 버스에 넣음
28번 : 딜레이
35번 : B구간은 A가 유지되므로 딜레이만 시킴
40번 : C구간에서 E는 High 값을 가짐 LCD Enable
47번 : D구간에서 E는 Low 값을 가짐 LCD disable
56번 : E 구간 현상유지 딜레이만 함
61번 : LCD_Data 함수
65번 : A구간 RS 에 high값을 줘서 DATA전달 RW,E는 0
68번 : Bus에 문자넣음
72번 : B구간 현상유지하며 딜레이
75번 : C구간에서 E는 High 값을 가짐 LCD Enable
79번 : D구간에서 E는 Low 값을 가짐 LCD disable
83번 : E구간 현상유지 딜레이만 함
88번 : LCD_Str 함수
cString에 값이 있는지 판단후 있으면 cString문자열을 LCD_Data함수에 문자열을 하나씩 담아서 보냄
tczero.h
| #ifndef __TCZERO_H__ #include "main.h" #define __TCZERO__ #define __STOP__ 0 #define __START__ 1 extern volatile unsigned int uiSec; void __vector_1(void); void __vector_2(void); void __vector_3(void); void __vector_21(void) ; void TCZero_Init(void);
#endif //__TCZERO_H_ | cs |
7번 : uiSec을 main.c에서도 사용가능하게 초기화
09~13번 : 각각 벡터 함수원형
tczero.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 | #include "tczero.h" static volatile unsigned int uiMsec; //static외부에서 접근 불가 volatile unsigned int uiSec; volatile unsigned int uiSState; void TCZero_Init(void) { //TCCR0A = (0 << COM0A1)|(0 << COM0A0)|(0<< COM0B1) |(0 << COM0B0) |(0 << WGM01)|(0 << WGM00); // 현재는X 출력파형 X TCCR0B = (0 << FOC0A) |(0 << FOC0B)|(0 << WGM02) |(0 << CS02) |(0 << CS01)|(0 << CS00); //분주 비64 // CS02 ,CS01 ,CS00 0,1,1 OCR0A = 250; TIMSK0 = (0 << OCIE0B)|(1 << OCIE0A)|(0 << TOIE0); // A만 사용 EICRA = (3 << ISC2)|(3 << ISC1)|(3 << ISC0); EIMSK = (1 << INT2)|(1 << INT1)|(1 << INT0); uiSState = __STOP__; return; } void __vector_21(void) //0.001 초 마다 호출 { ++uiMsec; if(uiMsec >= 1000) // 1초 시간 세는것 메인에서 안해도됨 { uiMsec = 0; ++uiSec; } } void TCZero_MSDelay(unsigned int uiDtime) { if( uiDtime > 1000) // 인자검사 { uiDtime = 1000; } uiMsec = 0; while(uiMsec < uiDtime); } void __vector_1(void) // 인터럽트 포트 D 1로 제어 { //토글 스위치 volatile unsigned int uiCnt; if(uiSState == __STOP__) { TCCR0B = (0 << FOC0A) |(0 << FOC0B)|(0 << WGM02) |(0 << CS02) |(1 << CS01)|(1 << CS00); uiSState = __START__; } else { TCCR0B = (0 << FOC0A) |(0 << FOC0B)|(0 << WGM02) |(0 << CS02) |(0 << CS01)|(0 << CS00); uiSState = __STOP__; } for(uiCnt = 0; 30000>uiCnt ; ++uiCnt); return; } void __vector_2(void) // 리셋버튼 { volatile unsigned int uiCnt; TCCR0B = (0 << FOC0A) |(0 << FOC0B)|(0 << WGM02) |(0 << CS02) |(0 << CS01)|(0 << CS00); uiSec = 0; uiSState = __STOP__; for(uiCnt = 0; 30000>uiCnt ; ++uiCnt); return; } void __vector_3(void) // 1분 증 { volatile unsigned int uiCnt; uiSec=uiSec+60; for(uiCnt = 0; 30000>uiCnt ; ++uiCnt); return; } | cs |
3번 : uiMsec 외부에서는 접근 못하게 static 선언
7번 : 타이머 초기화함수
주파수 | 분주비 | 클럭당 소요시간 | 기준시간 | 카운터 |
16000000 | 1 | 0.00000006250000000000 | 0.001 | 16000.000 |
| 8 | 0.00000050000000000000 | 0.001 | 2000.000 |
| 64 | 0.00000400000000000000 | 0.001 | 250.000 |
| 256 | 0.00001600000000000000 | 0.001 | 62.500 |
| 1024 | 0.00006400000000000000 | 0.001 | 15.625 |
분주비 64에 의해서 TCCR0B,OCR0A 설정
TIMSK 타이머/카운터 0~2 에서 발생하는 인터럽트를 개별적으로 허용하는 기능을 수행하는 레지스터 OCIE0A만 사용
22번 : vector21 함수 0.001초마다 호출
32번 : MSDelay 함수...느려지는문제로 인해 메인에서 사용안함
42번 : 토글 스위치 제어 정지및 시작하는 함수 , (PortD 1번를 사용하며 인터럽트발생시 회로에서 호출됨)
45번 : uiState가 Stop 상태일때 시작 , uiState가 Start 상태일때 Stop
55번 : 딜레이
59번 : 리셋 함수 (PortD 2번를 사용하며 인터럽트발생시 회로에서 호출됨)
TCCR0B 를 초기화 시키고 uiSec을 0, uiSState를 stop으로 만들어 시간을 0초로 다시 설정
70번 : 1분 증가 함수 uiSec에 60을 더해 1분 증가 시킴 (PortD 3번를 사용하며 인터럽트발생시 회로에서 호출됨)
main.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 | #ifndef __MAIN_H__ #define __MAIN_H__ #define PINA (*((volatile unsigned char *)0x20)) #define DDRA (*((volatile unsigned char *)0x21)) #define PORTA (*((volatile unsigned char *)0x22)) #define PINC (*((volatile unsigned char *)0x26)) #define DDRC (*((volatile unsigned char *)0x27)) #define PORTC (*((volatile unsigned char *)0x28)) #define EICRA (*((volatile unsigned char *)0x69)) #define EICRB (*((volatile unsigned char *)0x6A)) #define EIMSK (*((volatile unsigned char *)0x3D)) #define SREG (*((volatile unsigned char *)0x5F)) #define TCNT0 (*((volatile unsigned char *)0x46)) #define TCCR0A (*((volatile unsigned char *)0x44)) #define TCCR0B (*((volatile unsigned char *)0x45)) #define TIMSK0 (*((volatile unsigned char *)0x6E)) #define TIFR0 (*((volatile unsigned char *)0x35)) #define OCR0A (*((volatile unsigned char *)0x47)) #define OCR0B (*((volatile unsigned char *)0x48)) // ACSR (*((volatile unsigned char *)0x50)) //Timer #define COM0A1 7 #define COM0A0 6 #define COM0B1 5 #define COM0B0 4 #define WGM01 1 #define WGM00 0 #define FOC0A 7 #define FOC0B 6 #define WGM02 3 #define CS02 2 #define CS01 1 #define CS00 0 #define OCIE0B 2 #define OCIE0A 1 #define TOIE0 0 //LCD #define INT7 7 #define INT6 6 #define INT5 5 #define INT4 4 #define INT3 3 #define INT2 2 #define INT1 1 #define INT0 0 #define ISC7 6 #define ISC6 4 #define ISC5 2 #define ISC4 0 #define ISC3 6 #define ISC2 4 #define ISC1 2 #define ISC0 0 #define sei() __asm__ __volatile__ ("sei" ::) #define sleep() __asm__ __volatile__ ( "sleep" "\n\t" :: ) void __vector_1 (void) __attribute__((signal, used, externally_visible)); void __vector_2 (void) __attribute__((signal, used, externally_visible)); void __vector_3 (void) __attribute__((signal, used, externally_visible)); void __vector_21 (void) __attribute__((signal, used, externally_visible)); //timer #endif //__MAIN_H_ | cs |
4~24번 : 각각 주소설정
26~61번 : 각각 초기값설정
63~64번 : sei및 sleep 정의
66~68번 : 인터럽트 벡터(interrupt vector) 인터럽트가 발생했을 때, 그 인터럽트를 처리할 수 있는 서비스 루틴들의 주소를 가지고 있는 공간
vector1, vector2, vector3, vector21 사용
main.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | #include "main.h" #include "lcd.h" #include "tczero.h" int main(void) { unsigned int uiTime; char caTime[] = "00:00:00"; LCD_Init(); // TCZero_Init(); sei(); uiTime = uiSec = 0;//37543; //% 60; while(1) { caTime[7]='0'+uiSec%60%10; caTime[6]='0'+uiSec%60/10; caTime[4]='0'+uiSec/60%60%10; caTime[3]='0'+uiSec/60%60/10; caTime[1]='0'+uiSec/60/60%10; caTime[0]='0'+uiSec/60/60/10; LCD_Inst(LCD_HOME); LCD_Str(caTime); while(uiTime == uiSec); // 증가하지 않으면 멈춤 uiTime = uiSec; //시간이 지나면 값이 입력됨 } return 0; } | cs |
9번 : caTime 배열 초기화
10~11번 : LCD와 타이머 초기화
13번 : uiTime과 uiSec을 0으로 초기화
18~23번 : 각각 시,분,초를 비트단위로 자르고 2자리숫자를 한자리로 맞춰서 배열에 넣음
24번 : lcd home 호출
25번 : 문자열을 lcd에 출력
26번 : 시간이 튀는 문제를 방지하기위해 uiTime에 시간을 일단저장후 uiSec과 비교해서 시간값이 증가하면 uiTime에 입력
연결 :
출력:
Stop/Start 토글 스위치
1분 증가 스위치
리셋 스위치