이 튜토리얼 은 PIC16F877A에서 타이머 를 배우고 사용하는 데 도움이되는 PIC 튜토리얼 시리즈 의 다섯 번째 튜토리얼입니다. 이전 튜토리얼에서 PIC 및 MPLABX IDE 소개로 시작한 다음 PIC를 사용하여 LED를 깜박이는 첫 번째 PIC 프로그램을 작성한 다음 PIC Microcontroller의 지연 기능을 사용하여 LED 깜박임 시퀀스를 만들었습니다. 이제 이전 튜토리얼 하드웨어에서 사용한 것과 동일한 LED 깜박임 시퀀스 를 사용하고이를 통해 PIC MCU에서 타이머를 사용하는 방법을 알아 봅니다. 이 튜토리얼을 위해 LED 보드에 버튼을 하나 더 추가했습니다. 자세한 내용은 자습서를 참조하십시오.
타이머 는 임베디드 프로그래머에게 중요한 도구 중 하나입니다. 우리가 디자인하는 모든 응용 프로그램에는 지정된 시간 간격 후에 무언가를 켜거나 끄는 것과 같은 타이밍 응용 프로그램이 포함됩니다. 좋아,하지만 이미 같은 일을하는 지연 매크로 (__delay_ms ())가 있는데 왜 타이머가 필요한가 !!
Delay ()가 있는데 왜 Timer인가?
지연 매크로를 "덤프"지연이라고합니다. 때문에 지연을 실행하는 동안 함수 MCU는 지연을 만들어 덤프를 앉아있다. 이 프로세스 동안 MCU는 ADC 값을 수신하거나 레지스터에서 아무것도 읽을 수 없습니다. 따라서 시간 지연이 정확하거나 길 필요가없는 LED 깜박임과 같은 응용 프로그램을 제외하고 지연 기능을 사용하는 것은 권장되지 않습니다.
지연 매크로도 가지고 다음과 같은 짧은 오심을,
- 지연 값은 지연 매크로에 대해 상수 여야합니다. 프로그램 실행 중에는 변경할 수 없습니다. 따라서 프로그래머 정의로 남아 있습니다.
- 타이머를 사용하는 것과 비교할 때 지연이 정확하지 않습니다.
- 더 큰 지연 값은 매크로를 사용하여 만들 수 없습니다. 예를 들어 30 분 지연은 지연 매크로로 만들 수 없습니다. 사용할 수있는 최대 지연은 사용 된 수정 발진기를 기반으로합니다.
PIC 마이크로 컨트롤러 타이머:
물리적으로 타이머는 값이 계속해서 255로 증가하는 레지스터이며, 다시 시작됩니다: 0, 1, 2, 3, 4… 255…. 0, 1, 2, 3……기타.
PIC16F877A PIC MCU는 세 가지 타이머 모듈이 있습니다. Timer0, Timer1 및 Timer2의 이름입니다. Timer 0 및 Timer 2는 8 비트 타이머이고 Timer 1은 16 비트 타이머입니다. 이 튜토리얼에서는 애플리케이션에 Timer 0을 사용합니다. Timer 0을 이해하면 Timer 1과 Timer 2에서도 쉽게 작업 할 수 있습니다.
Timer0 모듈 타이머 / 카운터에는 다음과 같은 기능이 있습니다.
- 8 비트 타이머 / 카운터
- 읽기 및 쓰기 가능
- 8 비트 소프트웨어 프로그래밍 가능 프리스케일러
- 내부 또는 외부 클록 선택
- FFh에서 00h로 오버플로시 인터럽트
- 외부 클록을위한 에지 선택
타이머 사용을 시작하려면 8 비트 / 16 비트 타이머, 프리스케일러, 타이머 인터럽트 및 Focs와 같은 멋진 용어 를 이해해야합니다. 이제 각각이 실제로 무엇을 의미하는지 살펴 보겠습니다. 앞서 말했듯이 PIC MCU에는 8 비트 타이머와 16 비트 타이머가 모두 있으며, 이들 간의 주요 차이점은 16 비트 타이머가 8 비트 타이머보다 훨씬 더 나은 해상도를 갖는다는 것입니다.
프리스케일러 는 타이머 상태를 증가시키는 로직에 도달하기 전에 발진기 클럭을 분할하는 마이크로 컨트롤러 부분의 이름입니다. 프리스케일러 ID의 범위는 1 ~ 256이고 프리스케일러의 값은 OPTION 레지스터 (풀업 저항에 사용한 것과 동일)를 사용하여 설정할 수 있습니다. 예를 들어 프리스케일러의 값이 64이면 64 번째 펄스 마다 타이머가 1 씩 증가합니다.
타이머가 증가하고 최대 값 인 255에 도달하면 인터럽트를 트리거하고 다시 0으로 초기화됩니다. 이 인터럽트를 Timer Interrupt라고합니다. 이 인터럽트는 MCU에이 특정 시간이 랩핑되었음을 알립니다.
FOSC은 발진기의 주파수를 의미, 그것은 사용되는 크리스탈의 주파수이다. Timer 레지스터에 걸리는 시간은 Prescaler의 값과 Fosc의 값에 따라 다릅니다.
프로그래밍 및 작업 설명:
이 튜토리얼에서는 2 개의 버튼을 2 개의 입력으로, 8 개의 LED를 8 개의 출력으로 설정합니다. 첫 번째 버튼은 시간 지연 (누를 때마다 500ms)을 설정하는 데 사용되며 두 번째 버튼은 타이머 시퀀스 깜박임을 시작하는 데 사용됩니다. 예를 들어 첫 번째 버튼을 세 번 누르면 (500 * 3 = 1500ms) 지연 시간이 1.5 초로 설정되고 버튼 2를 누르면 각 LED가 미리 정의 된 시간 지연으로 켜지고 꺼집니다. 이 튜토리얼의 끝에 있는 데모 비디오 를 확인하십시오.
이제 이러한 기본 사항을 염두에두고 코드 섹션 끝에있는 프로그램을 살펴 보겠습니다.
프로그램을 못 받으 셔도 괜찮지 만, 받으 셨다면 !! 자신에게 쿠키를주고 프로그램을 덤프하여 출력을 즐기십시오. 다른 사람들에게는 프로그램을 의미있는 부분으로 나누고 각 블록에서 무슨 일이 일어나고 있는지 설명하겠습니다.
항상 코드의 처음 몇 줄은 구성 설정 및 헤더 파일이므로 이전 자습서에서 이미 수행 했으므로 설명하지 않겠습니다.
다음으로 모든 줄을 건너 뛰고 바로 void main 함수로 이동합니다. 그 안에 Timer0에 대한 PORT 구성이 있습니다.
void main () {/ ***** 타이머 포트 구성 ****** / OPTION_REG = 0b00000101; // 외부 주파수와 64를 프리 스칼라로 사용하는 Timer0 // PULL UP도 활성화합니다. TMR0 = 100; // 0.0019968s의 시간 값을로드합니다. delayValue는 0-256 사이 일 수 있습니다. TMR0IE = 1; // PIE1 레지스터에서 타이머 인터럽트 비트 활성화 GIE = 1; // 글로벌 인터럽트 활성화 PEIE = 1; // 주변 장치 인터럽트 활성화 / *********** ______ *********** /
이를 이해하려면 PIC 데이터 시트의 OPTION 레지스터를 확인해야합니다.
이전 튜토리얼에서 논의했듯이 비트 7 은 PORTB에 대해 약한 풀업 저항을 활성화하는 데 사용됩니다. 위의 그림을 보면 비트 3 이 0이되어 설정중인 다음 프리스케일러를 WatchDogTimer (WDT)가 아닌 Timer로 사용해야 함을 MCU에 지시합니다. 타이머 모드는 비트 5 T0CS를 지우면 선택됩니다.
(OPTION_REG <5>)
이제 bits2-0 을 사용하여 타이머의 프리스케일러 값을 설정합니다. 위의 표와 같이 프리스케일러 값을 64로 설정하려면 비트를 101로 설정해야합니다.
다음으로 Timer0과 관련된 레지스터를 살펴 보겠습니다.
타이머는 일단 설정되면 증가하기 시작하고 256의 값에 도달 한 후 오버플로됩니다.이 시점에서 타이머 인터럽트를 활성화하려면 레지스터 TMR0IE 를 높게 설정해야합니다. Timer 0 자체가 주변기기 이므로 PEIE = 1 을 만들어 주변기기 인터럽트를 활성화해야합니다. 마지막으로 모든 작업 중에 MCU가 인터럽트에 대해 알림을받을 수 있도록 글로벌 인터럽트를 활성화해야합니다. 이것은 GIE = 1 로 만들어서 수행됩니다 .
지연 = ((256-REG_val) * (Prescal * 4)) / Fosc
위의 공식은 Delay 값을 계산하는 데 사용됩니다.
어디
REG_val = 100;
프리 스케일 = 64
Fosc = 20000000
이것은 계산에 따르면, 지연 = 0.0019968s
다음 라인 세트는 I / O 포트를 설정하는 것입니다.
/ ***** I / O를위한 포트 구성 ****** / TRISB0 = 1; // PORTB 핀 0이 버튼 1의 입력으로 사용됨을 MCU에 지시합니다. TRISB1 = 1; // PORTB 핀 1이 버튼 1의 입력으로 사용됨을 MCU에 지시합니다. TRISD = 0x00; // 포트 D의 모든 핀이 출력되도록 MCU에 지시합니다. PORTD = 0x00; // 모든 핀을 0으로 초기화 / *********** ______ *********** /
이는 동일한 하드웨어를 사용하고 있으므로 이전 튜토리얼과 동일합니다. 다른 버튼을 입력으로 추가 한 것을 제외하고는. 이것은 TRISB1 = 1 라인에 의해 수행됩니다 .
다음으로, 무한 while 루프 내부 에는 두 개의 코드 블록이 있습니다. 하나는 사용자로부터 타이머 입력을받는 데 사용되고 다른 하나는 LED를 통해 지연 시퀀스를 실행하는 데 사용됩니다. 각 줄에 대한 주석을 사용하여 설명했습니다.
while (1) {개수 = 0; // 메인 루프에서 타이머를 실행하지 않음 // ******* 사용자로부터 번호 지연 가져 오기 **** ////// if (RB0 == 0 && flag == 0) // 주어진 입력 {get_scnds + = 1; // get_scnds = get_scnds + http: // 증가 변수 flag = 1; } if (RB0 == 1) // 연속 증가를 방지하려면 flag = 0; / *********** ______ *********** /
get_scnds 라는 변수 는 사용자가 버튼 1을 누를 때마다 증가합니다. 플래그 (소프트웨어 정의) 변수는 사용자가 버튼에서 손가락을 뺄 때까지 증가 프로세스를 유지하는 데 사용됩니다.
// ******* 지연된 시퀀스 실행 **** ////// while (RB1 == 0) {PORTD = 0b00000001 <
버튼 2를 누르면 다음 블록이 작동합니다. 사용자가 이미 버튼 1을 사용하여 필요한 시간 지연을 정의했기 때문에 get_scnds 변수에 저장되었습니다 . hscnd 라는 변수를 사용합니다.이 변수는 ISR (Interrupt service routine)에 의해 제어됩니다.
인터럽트 서비스 루틴은 타이머 0 오버 플로우 때마다 호출 될 것이다 인터럽트이다. 버튼을 누를 때마다 시간 지연을 0.5 초 (0.5 초) 씩 증가 시키고 매 0.5 초마다 변수 hscnd 를 증가시켜야하는 것처럼 다음 블록에서 ISR에 의해 제어되는 방식을 살펴 보겠습니다. 0.0019968 초 (~ 2ms)마다 오버 플로우하도록 타이머를 프로그래밍 했으므로 250 * 2ms = 0.5 초이므로 1/2 초 카운트 변수는 250이어야합니다. 따라서 count가 250 (250 * 2ms = 0.5 초)이되면 0.5 초라 는 의미이므로 hscnd 를 1 씩 증가 시키고 count를 0으로 초기화합니다.
void interrupt timer_isr () {if (TMR0IF == 1) // 타이머 오버플로로 인해 타이머 플래그가 트리거되었습니다. {TMR0 = 100; // 타이머 값로드 TMR0IF = 0; // 타이머 인터럽트 플래그를 지 웁니다. ++; } if (count == 250) {hscnd + = 1; // hscnd는 0.5 초마다 증가합니다. count = 0; }}
따라서이 값을 사용하여 hscnd 와 비교 하고 사용자 정의 시간에 따라 LED를 이동합니다. 또한 지난 튜토리얼과 매우 유사합니다.
그것이 우리의 프로그램을 이해하고 작동하는 것입니다.
회로도 및 Proteus 시뮬레이션:
평소처럼 먼저 Proteus를 사용하여 출력을 확인 하겠습니다. 여기에 Proteus의 회로도 파일을 연결했습니다.
이전 LED 보드에 버튼을 추가하면 하드웨어를 사용할 준비가되었습니다. 다음과 같이 보일 것입니다.
연결이 완료되면 코드를 업로드하고 출력을 확인하십시오. 문제가 있으면 댓글 섹션을 사용하십시오. 또한 전체 프로세스를 이해 하려면 아래 비디오를 확인하십시오.