MCU: PIC18F45K20
IDE: MPLAB X IDE v6.00
Compiler: XC8 v2.36
데이터시트를 참조하여 인터럽트를 사용하여 타이머를 구동해 보도록 해 보겠습니다.
File > New Project를 클릭하여 프로젝트를 생성합니다.
Standalone Project 선택 후 Next >
알맞는 Device를 선택하고 Next >
Compiler 선택하고 Next >
Project Name, Location 설정하고 Finish
프로젝트 생성 완료
main.c 파일을 생성합니다.
기본 설정 코드는 아래 링크에서 사용했던 것을 사용합니다.
[PIC][MPLABX][XC8] GPIO :: 취미 블로그 (tistory.com)
1. Timer0 레지스터
아래는 타이머0의 블럭 다이어그램입니다.
타이머 0 인터럽트 플래그인 TMR0IF는
8Bit Mode에서는 TMR0가 255 -> 0 으로 되었을 때
16Bit Mode에서는 TMR0가 65535 - > 0 으로 되었을 때
1로 설정됩니다.
TMR0ON: Timer0 Enable / Stop 설정
T08BIT: Timer0 8 bit / 16 bit 설정
T0CS : 클럭 소스 설정
T0SE: Timer0 Source Edge 설정 (T0CS = 1일때 유효)
PSA: 분주비 Enable / Disable 설정
T0PS: 분주비 설정
여기서 저는 클럭 소스를 Fosc/4로 설정하고, 16Bit Timer에 1:8의 분주비를 사용하겠습니다.
T0CON = 0b00000010;
2. Timer0 시간계산
Time = 4 / Fosc * Prescaler * Counter
저는
16Bit Timer에
Fosc = 64000000
Prescaler = 8
Counter = 2000
으로 설정하면
4 / 64000000 * 8 * 2000 = 0.001 = 1ms가 됩니다.
즉 Timer0가 2000을 세면 1ms마다 인터럽트가 걸리도록 세팅합니다.
PIC18F45K20의 타이머는 기본적으로 0, 1, 2, ... 처럼 숫자를 올리는 UP Timer 입니다.
16Bit 모드에서 2000을 세면 인터럽트가 걸리기 위해서는 65535 - 2000 값으로 설정해 주어야 합니다.
65535 - 2000 = 63535 = 0xF82F
이 값을 TMR0H와 TMR0L 에 값을 써줍니다.
void Initialize_Timer0(void)
{
T0CON = 0b00000010;
TMR0H = 0xF8;
TMR0L = 0x2F;
}
3. 인터럽트 설정
다음은 PIC18F45K20의 인터럽트 로직입니다.
위 TMR0 인터럽트가 걸리기 위한 조건은 다음과 같습니다.
TMR0IF == 1 && TMR0IE == 1 && TMR0IP == 1
&&
GIEH / GIE == 1
PIC 18F45K20 은 인터럽트 벡터가 0x0008h, 0x0018h 두개가 있습니다.
높은 우선순위로 설정된 인터럽트 (xxIP == 1)는 0x0008h 인터럽트 벡터 번지에서 발생되고
낮은 우선순위로 설정된 인터럽트 (xxIP == 0)는 0x0018h 인터럽트 벡터 번지에서 발생됩니다.
저는 TMR0 인터럽트를 사용하기 위해서 다음과 같이 설정합니다.
void Initialize_Interrupt(void)
{
INTCON = 0b10100000;
INTCON2 = 0b00000100;
}
이제 인터럽트 벡터 함수를 만들어 주어야 합니다.
MPLAB_XC8_C_Compiler_User_Guide_for_PIC.pdf 파일을 보면 인터럽트에 대한 내용이 있습니다.
위를 바탕으로 다음과 같이 함수를 만들어 줍니다.
volatile uint32_t tick = 0;
void TMR0_ISR(void)
{
tick++;
}
void __interrupt(high_priority) InterruptManager (void)
{
if(INTCONbits.TMR0IE == 1 && INTCONbits.TMR0IF == 1)
{
TMR0H = 0xF8;
TMR0L = 0x2F;
INTCONbits.TMR0IF = 0;
TMR0_ISR();
}
}
타이머0 인터럽트가 발생하면 TMR0H, TMR0L 값을 63535로 다시 설정하고 tick 변수 값을 1 증가시키도록 하였습니다.
또 TMR0IF 비트 설명을 보면
TMR0 register has overflowed (must be cleared by software)
라고 software로 clear 시켜주어야 한다고 되어 있기 때문에
INTCONbits.TMR0IF = 0;
코드도 넣어주었습니다.
이제 Timer0와 인터럽트 설정이 끝났습니다.
이제 초기화 함수를 부르는 코드와 1초마다 PORTD를 토글 시키는 코드를 작성합니다.
// PIC18F45K20 Configuration Bit Settings
// 'C' source line config statements
// CONFIG1H
#pragma config FOSC = INTIO67 // Oscillator Selection bits (HS oscillator, PLL enabled (Clock Frequency = 4 x FOSC1))
#pragma config FCMEN = OFF // Fail-Safe Clock Monitor Enable bit (Fail-Safe Clock Monitor disabled)
#pragma config IESO = OFF // Internal/External Oscillator Switchover bit (Oscillator Switchover mode disabled)
// CONFIG2L
#pragma config PWRT = OFF // Power-up Timer Enable bit (PWRT disabled)
#pragma config BOREN = SBORDIS // Brown-out Reset Enable bits (Brown-out Reset enabled in hardware only (SBOREN is disabled))
#pragma config BORV = 18 // Brown Out Reset Voltage bits (VBOR set to 1.8 V nominal)
// CONFIG2H
#pragma config WDTEN = OFF // Watchdog Timer Enable bit (WDT is controlled by SWDTEN bit of the WDTCON register)
#pragma config WDTPS = 32768 // Watchdog Timer Postscale Select bits (1:32768)
// CONFIG3H
#pragma config CCP2MX = PORTC // CCP2 MUX bit (CCP2 input/output is multiplexed with RC1)
#pragma config PBADEN = ON // PORTB A/D Enable bit (PORTB<4:0> pins are configured as analog input channels on Reset)
#pragma config LPT1OSC = OFF // Low-Power Timer1 Oscillator Enable bit (Timer1 configured for higher power operation)
#pragma config HFOFST = ON // HFINTOSC Fast Start-up (HFINTOSC starts clocking the CPU without waiting for the oscillator to stablize.)
#pragma config MCLRE = ON // MCLR Pin Enable bit (MCLR pin enabled; RE3 input pin disabled)
// CONFIG4L
#pragma config STVREN = ON // Stack Full/Underflow Reset Enable bit (Stack full/underflow will cause Reset)
#pragma config LVP = ON // Single-Supply ICSP Enable bit (Single-Supply ICSP enabled)
#pragma config XINST = OFF // Extended Instruction Set Enable bit (Instruction set extension and Indexed Addressing mode disabled (Legacy mode))
// CONFIG5L
#pragma config CP0 = OFF // Code Protection Block 0 (Block 0 (000800-001FFFh) not code-protected)
#pragma config CP1 = OFF // Code Protection Block 1 (Block 1 (002000-003FFFh) not code-protected)
#pragma config CP2 = OFF // Code Protection Block 2 (Block 2 (004000-005FFFh) not code-protected)
#pragma config CP3 = OFF // Code Protection Block 3 (Block 3 (006000-007FFFh) not code-protected)
// CONFIG5H
#pragma config CPB = OFF // Boot Block Code Protection bit (Boot block (000000-0007FFh) not code-protected)
#pragma config CPD = OFF // Data EEPROM Code Protection bit (Data EEPROM not code-protected)
// CONFIG6L
#pragma config WRT0 = OFF // Write Protection Block 0 (Block 0 (000800-001FFFh) not write-protected)
#pragma config WRT1 = OFF // Write Protection Block 1 (Block 1 (002000-003FFFh) not write-protected)
#pragma config WRT2 = OFF // Write Protection Block 2 (Block 2 (004000-005FFFh) not write-protected)
#pragma config WRT3 = OFF // Write Protection Block 3 (Block 3 (006000-007FFFh) not write-protected)
// CONFIG6H
#pragma config WRTC = OFF // Configuration Register Write Protection bit (Configuration registers (300000-3000FFh) not write-protected)
#pragma config WRTB = OFF // Boot Block Write Protection bit (Boot Block (000000-0007FFh) not write-protected)
#pragma config WRTD = OFF // Data EEPROM Write Protection bit (Data EEPROM not write-protected)
// CONFIG7L
#pragma config EBTR0 = OFF // Table Read Protection Block 0 (Block 0 (000800-001FFFh) not protected from table reads executed in other blocks)
#pragma config EBTR1 = OFF // Table Read Protection Block 1 (Block 1 (002000-003FFFh) not protected from table reads executed in other blocks)
#pragma config EBTR2 = OFF // Table Read Protection Block 2 (Block 2 (004000-005FFFh) not protected from table reads executed in other blocks)
#pragma config EBTR3 = OFF // Table Read Protection Block 3 (Block 3 (006000-007FFFh) not protected from table reads executed in other blocks)
// CONFIG7H
#pragma config EBTRB = OFF // Boot Block Table Read Protection bit (Boot Block (000000-0007FFh) not protected from table reads executed in other blocks)
// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.
#include <xc.h>
#define _XTAL_FREQ (64000000UL)
volatile uint32_t tick = 0;
void Initialize_SystemClock(void)
{
OSCCONbits.IRCF = 0b111;
OSCCONbits.SCS = 0b00;
OSCTUNEbits.PLLEN = 1;
}
void Initialize_Port(void)
{
TRISD = 0x00;
}
void Initialize_Timer0(void)
{
T0CON = 0b00000010;
TMR0H = 0xF8;
TMR0L = 0x2F;
}
void Run_Timer0(void)
{
T0CONbits.TMR0ON = 1;
}
void Stop_Timer0(void)
{
T0CONbits.TMR0ON = 0;
}
void Initialize_Interrupt(void)
{
INTCON = 0b10100000;
INTCON2 = 0b00000100;
}
void TMR0_ISR(void)
{
tick++;
}
void __interrupt(high_priority) InterruptManager (void)
{
if(INTCONbits.TMR0IE == 1 && INTCONbits.TMR0IF == 1)
{
TMR0H = 0xF8;
TMR0L = 0x2F;
INTCONbits.TMR0IF = 0;
TMR0_ISR();
}
}
void main(void)
{
uint32_t time = 0;
Initialize_SystemClock();
Initialize_Port();
Initialize_Timer0();
Initialize_Interrupt();
Run_Timer0();
while (1) {
if (tick - time > 1000) {
time = tick;
PORTD ^= 0xFF;
}
}
return;
}
'MCU > PIC' 카테고리의 다른 글
Microchip Programmer & Debugger (0) | 2022.06.15 |
---|---|
[PIC][MPLABX][XC8][MCC]TIMER0 + 인터럽트 (0) | 2022.06.15 |
[PIC][MPLABX][XC8] GPIO (0) | 2022.06.14 |
[PIC][MPLABX][XC8] 개발환경 구축 (0) | 2022.06.11 |
[PIC][XC8][MPLAB X][MCC] GPIO (0) | 2022.06.11 |
[XC8] 컴파일 Warning 메세지 띄우지 않기 (0) | 2022.03.28 |