0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

PIC18F27Q43 Timer2

Last updated at Posted at 2024-05-23

ADコンバータのトリガーとしても使えるTimer2の初期設定と、フリーランモード(通常のタイマー)の設定。

IMG_4722.JPG

通常の周期カウントタイマーの設定の仕方。
データシートを読むと、いろいろな機能が重複して搭載されていて、周期タイマー(freeRunMode)の設定に戸惑うかもしれません。
今回は、単純な周期タイマーを作りたいので、必要最低限の知識を、データシートから抜粋していきます。

Timer2,4,6
・8ビットタイマー
・プリスケーラ(1:1 to 1:128)
・ポストスケーラ(1:1 to 1:16)
・Interrupt on T2TMR match with T2PR
T2PRレジスタとT2TMRレジスタのコンペアマッチで割込み発生。

Timer2、Timer4、Timer6は、すべて同じ機構。
Timer1、Timer3、Timer5は、16ビットタイマー。
Tiemr0だけ、別枠の機構。

1.Time2,4,6 ブロック図 

Timer2ブロックダイアグラム.png

PSYNCビット:Fosc/4つまり命令サイクルと、プリスケーラ出力を同期させるビット。

CSYNCビット:Time2関連のレジスタは、すべてFosc/4の命令クロックに同期して値を変えます。入力されるクロックが、同期していないと、予期せぬ動きと、グリッチノイズが発生する、可能性があります。CSYNCを使うと、TimerのONビットのセットと入力クロックを同期させることができます。

※データシートを読んでいて、分かりにくい部分です。
Timer2をonしたときの、突入状態で、システムと入力クロックの同期がとれていないと、予期せぬ動作を引き起こしますよ、という風に理解しています。

2.Time2 オペレーションモード

Timer2の動作モード
operationMode.png

softwareGateMode.png

softwareGateModeDaiagram.png

software Gate modeが従来のピックマイコンのTimerと、同様の動作をします。
Modeビットは、0b00000になります。

3.Timer2 初期化、割り込みコード

Timer2のインターバル時間は、5msに設定しています。プリスケーラは、1:16。ポストスケーラも1:16に設定。
割込み回数を100回数え、main関数内で、LEDを500ms間隔で点滅させています。

Q_Peripheral.h
#ifndef Q_PERIPHERAL27Q43_H
#define	Q_PERIPHERAL27Q43_H

#ifdef	__cplusplus
extern "C" {
#endif

#include <xc.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
    
#define Low 0
#define High 1
   
#define _XTAL_FREQ 32000000
#define BAUDRATE 115200
#define SET_SPBRG_DATA  (((unsigned int)((_XTAL_FREQ/4)/BAUDRATE))-1)
#define SET_SPBRG_DATA1 (((unsigned int)((_XTAL_FREQ/16)/BAUDRATE))-1)   
//USART---------------------------------------
#define RXUSART_BUFFER_SIZE 20
typedef struct
{
    uint8_t buf[RXUSART_BUFFER_SIZE];
    uint8_t length;
    uint8_t completed;
}_rxUsart;
extern _rxUsart rxUsart;
extern void usartInit(void);
extern void putch(uint8_t);
extern uint8_t getch(void);
//Timer--------------------------------------
typedef struct
{
    uint16_t cnt;
    bool fg;
}_tm;
extern _tm tm0,tm2;
extern void timer0Init(void);    
extern void timer2Init(void);
//IOC------------------------------------------
extern void iocInit(void);
typedef struct
{
    bool fg;
}_ioc;
extern _ioc ioc;  


#ifdef	__cplusplus
}
#endif

#endif	/* Q_PERIPHERAL27Q43_H */
Q_Peripheral.c

#include <pic18f27q43.h>
#include "Q_peripheral27Q43.h"

//*****************************************************//
//Timer0初期化
//*****************************************************//
_rxUsart rxUsart;
void usartInit(void)
{
    //1.ボーレート設定115200
    U1BRG=SET_SPBRG_DATA1;
    //2.モード 非同期
    U1CON0bits.MODE=0b0000; //Asynchronous 8-bit USART mode
    //4.Serial port enabled
    U1CON1bits.ON=1;
    //5.Transmit is enabled.
    U1CON0bits.TXEN=1;
    U1CON0bits.RXEN=1;
    //6.PPS
    PPSLOCK = 0x55; 
    PPSLOCK = 0xAA;
    PPSLOCKbits.PPSLOCKED = 0;//Unlock.
    U1RXPPS=0b010111;//RC7:rx
    RC6PPS=0x20;//RC6:tx
    TRISC|=0x80;
    PPSLOCK = 0x55; 
    PPSLOCK = 0xAA;
    PPSLOCKbits.PPSLOCKED = 1;//lock.
    //7.interrupt
    PIR4bits.U1RXIF=0;
    PIE4bits.U1RXIE=1; 
}

void putch(uint8_t _txData)
{
    if(U1ERRIRbits.TXMTIF==High)//シフトレジスタ空?
    {
        do{
            U1TXB=_txData;
            while(U1ERRIRbits.TXMTIF==Low);
        }while(U1FIFObits.TXBF);//TXバッファ空になるまで送信。
    }else{
        //error operation
    }
}

uint8_t getch(void)
{
    while(PIR4bits.U1RXIF==Low);//受信完了
    return U1RXB;
}

//*****************************************************//
//Timer0初期化
//*****************************************************//
_tm tm0;
void timer0Init(void)
{
//Timer0初期化--------------------------------------------------
    T0CON1bits.CS=0b010;//クロックソースFosc/4
    T0CON1bits.CKPS=0b0011;//プリスケ1:8
    T0CON0bits.MD16=1;//16bitsタイマー
    T0CON0bits.OUTPS=0b0000;//ポストスケーラ1:1
    TMR0H=0xD8;//10ms Fosc=32Mhz
    TMR0L=0xF0;//10ms 
    T0CON0bits.EN=1;
    PIE3bits.TMR0IE=1;
    PIR3bits.TMR0IF=0;
}

//*****************************************************//
 Timer2
//*****************************************************//
_tm tm2;
void timer2Init(void)
{
    TMR2=0x00;
    T2CONbits.OUTPS=0b1111;//postScaler 1:16
    T2CONbits.T2CKPS=0b100;//prescle1:16
    T2HLTbits.MODE=0b00000;//softwareGateMode(従来のTimer)
    T2HLTbits.PSYNC=1;//synchoronized to Fosc/4
    T2CLKCONbits.CS=0b00001;//Fosc/4
    //PR2=0x1F;//Fosc=32Mhz 1ms
    PR2=0x9C;//Fosc=32Mhz 5ms
    tm2.cnt=0;
    tm2.fg=false;        
    PIR3bits.TMR2IF=0;
    PIE3bits.TMR2IE=1;
    T2CONbits.TMR2ON=1;
}


//*****************************************************//
//ioc初期化
//*****************************************************//
_ioc ioc;
void iocInit(void)
{
    IOCCNbits.IOCCN0=1;//RC0
    TRISC|=0x01;//RC0
    PIE0bits.IOCIE=1;
    PIR0bits.IOCIF=0;
}


Q_interrupt.h
#ifndef Q_INTERRUPT_H
#define	Q_INTERRUPT_H

#ifdef	__cplusplus
extern "C" {
#endif

#include <xc.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include "Q_peripheral27Q43.h"
  
extern void __interrupt(irq(IRQ_U1RX)) USART1RX_ISR(void);    
extern void __interrupt(irq(IRQ_TMR0)) Timer0_ISR(void); 
extern extern void __interrupt(irq(IRQ_TMR2)) Timer2_ISR(void); 
extern void __interrupt(irq(IRQ_IOC)) IOC_ISR(void);

#ifdef	__cplusplus
}
#endif

#endif	/* Q_INTERRUPT_H */
Q_interrupt.c
#include "Q_interrupt27Q43.h"

//****************割り込み関数***********************//
// USART1割込み
//**************************************************//
void __interrupt(irq(IRQ_U1RX)) USART1RX_ISR(void)
{
    uint8_t ch;
    PIR4bits.U1RXIF=0;
    ch=getch();
    rxUsart.buf[rxUsart.length++]=ch;
    if(rxUsart.length>RXUSART_BUFFER_SIZE)
    {
        rxUsart.length=0;
    }
    if(ch==0x0a)
    {
        rxUsart.buf[rxUsart.length-2]=0x00;
        PIE4bits.U1RXIE=0;
        rxUsart.completed=1;
    }
}

//****************割り込み関数***********************//
// Timer0割込み
//**************************************************//
void __interrupt(irq(IRQ_TMR0)) Timer0_ISR(void)
{
    PIR3bits.TMR0IF=0;
    tm0.cnt++;
    if(tm0.cnt==50)
    {
        tm0.cnt=0;
        tm0.fg=true;
        T0CON0bits.EN=0;
        PIE3bits.TMR0IE=0;
    }
    
    TMR0L=0xF0;//10ms
}
//****************割り込み関数***********************//
// Timer2割込み
//**************************************************//
void __interrupt(irq(IRQ_TMR2)) Timer2_ISR(void)
{
    PIR3bits.TMR2IF=0;
    tm2.cnt++;
    if(tm2.cnt==100)
    {
        tm2.cnt=0;
        tm2.fg=true;//mainで処理。
        PIR3bits.TMR2IF=0;
        PIE3bits.TMR2IE=0;
    }
}

//****************割り込み関数***********************//
// IOC割込み
// ※印は、割り込み関数実行中の変化を取りこぼさないためのコード。
//**************************************************//
void __interrupt(irq(IRQ_IOC)) IOC_ISR(void)
{
    uint8_t val,mask;
    
    PIR0bits.IOCIF=0;
    val=IOCCF;  //※IOCフラグレジスタ読み出し
    mask=0xFF;  //※ゼロクリアマスク
    mask=mask^val;//現状を記録
    printf("IOCCF:%02X mask:%02X\n", IOCCF, mask);
    if(IOCCNbits.IOCCN0==1 && val==0x01)
    {
        ioc.fg=true; //main関数で実処理開始
        PIE0bits.IOCIE=0;//一時割り込み停止
    }
    //zero clear--------------    
    IOCCF&=mask;   //※状態変化の取りこぼしをしない。
    printf("IOCCF:%02X\n",IOCCF);
}


main.c
// PIC18F27Q43 Configuration Bit Settings

// 'C' source line config statements

// CONFIG1
#pragma config FEXTOSC = OFF    // External Oscillator Selection (Oscillator not enabled)
#pragma config RSTOSC = HFINTOSC_64MHZ// Reset Oscillator Selection (HFINTOSC with HFFRQ = 64 MHz and CDIV = 1:1)

// CONFIG2
#pragma config CLKOUTEN = OFF   // Clock out Enable bit (CLKOUT function is disabled)
#pragma config PR1WAY = OFF     // PRLOCKED One-Way Set Enable bit (PRLOCKED bit can be set and cleared repeatedly)
#pragma config CSWEN = ON       // Clock Switch Enable bit (Writing to NOSC and NDIV is allowed)
#pragma config FCMEN = OFF      // Fail-Safe Clock Monitor Enable bit (Fail-Safe Clock Monitor disabled)

// CONFIG3
#pragma config MCLRE = EXTMCLR  // MCLR Enable bit (If LVP = 0, MCLR pin is MCLR; If LVP = 1, RE3 pin function is MCLR )
#pragma config PWRTS = PWRT_OFF // Power-up timer selection bits (PWRT is disabled)
#pragma config MVECEN = ON      // Multi-vector enable bit (Multi-vector enabled, Vector table used for interrupts)
#pragma config IVT1WAY = ON     // IVTLOCK bit One-way set enable bit (IVTLOCKED bit can be cleared and set only once)
#pragma config LPBOREN = OFF    // Low Power BOR Enable bit (Low-Power BOR disabled)
#pragma config BOREN = SBORDIS  // Brown-out Reset Enable bits (Brown-out Reset enabled , SBOREN bit is ignored)

// CONFIG4
#pragma config BORV = VBOR_1P9  // Brown-out Reset Voltage Selection bits (Brown-out Reset Voltage (VBOR) set to 1.9V)
#pragma config ZCD = OFF        // ZCD Disable bit (ZCD module is disabled. ZCD can be enabled by setting the ZCDSEN bit of ZCDCON)
#pragma config PPS1WAY = OFF     // PPSLOCK bit One-Way Set Enable bit (PPSLOCKED bit can be cleared and set only once; PPS registers remain locked after one clear/set cycle)
#pragma config STVREN = ON      // Stack Full/Underflow Reset Enable bit (Stack full/underflow will cause Reset)
#pragma config LVP = ON         // Low Voltage Programming Enable bit (Low voltage programming enabled. MCLR/VPP pin function is MCLR. MCLRE configuration bit is ignored)
#pragma config XINST = OFF      // Extended Instruction Set Enable bit (Extended Instruction Set and Indexed Addressing Mode disabled)

// CONFIG5
#pragma config WDTCPS = WDTCPS_31// WDT Period selection bits (Divider ratio 1:65536; software control of WDTPS)
#pragma config WDTE = OFF       // WDT operating mode (WDT Disabled; SWDTEN is ignored)

// CONFIG6
#pragma config WDTCWS = WDTCWS_7// WDT Window Select bits (window always open (100%); software control; keyed access not required)
#pragma config WDTCCS = SC      // WDT input clock selector (Software Control)

// CONFIG7
#pragma config BBSIZE = BBSIZE_512// Boot Block Size selection bits (Boot Block size is 512 words)
#pragma config BBEN = OFF       // Boot Block enable bit (Boot block disabled)
#pragma config SAFEN = OFF      // Storage Area Flash enable bit (SAF disabled)
#pragma config DEBUG = OFF      // Background Debugger (Background Debugger disabled)

// CONFIG8
#pragma config WRTB = OFF       // Boot Block Write Protection bit (Boot Block not Write protected)
#pragma config WRTC = OFF       // Configuration Register Write Protection bit (Configuration registers not Write protected)
#pragma config WRTD = OFF       // Data EEPROM Write Protection bit (Data EEPROM not Write protected)
#pragma config WRTSAF = OFF     // SAF Write protection bit (SAF not Write Protected)
#pragma config WRTAPP = OFF     // Application Block write protection bit (Application Block not write protected)

// CONFIG10
#pragma config CP = OFF         // PFM and Data EEPROM Code Protection bit (PFM and Data EEPROM code protection disabled)

// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.

#include <xc.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include "Q_peripheral27Q43.h"
#include "Q_interrupt27Q43.h"
#include "Q_initialize.h"
#include "Q_I2C1.h"
#include "I2C_LCD.h"
#include "stringFormat.h"

void portInit(void);
void oscillatorInit(void);
void vicInit(void);

void main(void)
{
    uint8_t counter=0;
    //CPUハード初期化-----------------------
    portInit();
    oscillatorInit();
    vicInit();
    
    //周辺機能初期化--------------------------------
    timer0Init();
    timer2Init();
    iocInit();
    usartInit();
    printf("START Interrupt On Change\n");    
    I2C1_Init();    
    
    INTCON0bits.GIE=1;//Enable all masked interrupts
    
    while(1)
    {
        //Timer0 interrupt process-------
        if(tm0.fg)
        {
            tm0.fg=false;
            PORTBbits.RB0=~PORTBbits.RB0;
            T0CON0bits.EN=1;
            PIE3bits.TMR0IE=1;
        } 
        //Timer2 interrupt process-------
        if(tm2.fg)
        {
            tm2.fg=false;
            PORTBbits.RB2 = ~PORTBbits.RB2;
            PIR3bits.TMR2IF=0;
            PIE3bits.TMR2IE=1;
        }
        //Usart interrupt process--------
        if(rxUsart.completed)
        {
            rxUsart.completed=false;
            printf("echo:%s\n",rxUsart.buf);
            rxUsart.length=0;
            PIE4bits.U1RXIE=1;
        }
        
        //Interrupt On Change Interrupt process--------
        if(ioc.fg)
        {
            ioc.fg=false;
            printf("Switch ON:%d\n",counter);
            PORTBbits.RB1=~PORTBbits.RB1;
            counter++;
            PIE0bits.IOCIE=1;
        }
    }
    return;
}

void oscillatorInit(void)
{
    //オシレータ設定----------------
    OSCCON3bits.CSWHOLD=1;//Hold
    OSCCON1bits.NDIV=1;//64Mhz/2=32Mhz;
    while(!OSCCON3bits.NOSCR);
    while(!PIR0bits.CSWIF);//ready state
    PIR0bits.CSWIF=0;
    OSCCON3bits.CSWHOLD=0;
    while(!OSCCON3bits.ORDY);
}

void portInit(void)
{
    //ポート設定----------------------    
    PORTA=0x00;
    LATA=0x00;
    ANSELA=0x00;
    TRISA=0x00;
    
    PORTB=0x00;
    LATB=0x00;
    ANSELB=0x00;
    TRISB=0x00;
    
    PORTC=0x00;
    LATC=0x00;
    ANSELC=0x00;
    TRISC=0x00;
    
     //PPS---------------------
    PPSLOCK = 0x55;
    PPSLOCK = 0xAA;
    PPSLOCKbits.PPSLOCKED = 0;
    
    //I2C1-------------------------
    //RC4 for SDA
    RC4PPS=0x38;
    I2C1SDAPPS=0x14;
    //RC3 for SCL
    RC3PPS = 0x37;
    I2C1SCLPPS=0x13;
    
    PPSLOCK = 0x55;
    PPSLOCK = 0xAA;
    PPSLOCKbits.PPSLOCKED = 1;
    
    ODCONCbits.ODCC3=1;
    ODCONCbits.ODCC4=1;
    
    RC3I2Cbits.TH=1;
    RC4I2Cbits.TH=1;
    
}

void vicInit(void)
{
 //割り込みテーブルaddress設定----------------------------------
    INTCON0bits.GIE=0;//Enable all masked interrupts
    IVTLOCK=0x55;
    IVTLOCK=0xAA;
    IVTLOCKbits.IVTLOCKED=0;
    IVTBASE = 0x000008;
    IVTLOCK=0x55;
    IVTLOCK=0xAA;
    IVTLOCKbits.IVTLOCKED=1;
}
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?