ADコンバータのトリガーとしても使えるTimer2の初期設定と、フリーランモード(通常のタイマー)の設定。
通常の周期カウントタイマーの設定の仕方。
データシートを読むと、いろいろな機能が重複して搭載されていて、周期タイマー(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 ブロック図
PSYNCビット:Fosc/4つまり命令サイクルと、プリスケーラ出力を同期させるビット。
CSYNCビット:Time2関連のレジスタは、すべてFosc/4の命令クロックに同期して値を変えます。入力されるクロックが、同期していないと、予期せぬ動きと、グリッチノイズが発生する、可能性があります。CSYNCを使うと、TimerのONビットのセットと入力クロックを同期させることができます。
※データシートを読んでいて、分かりにくい部分です。
Timer2をonしたときの、突入状態で、システムと入力クロックの同期がとれていないと、予期せぬ動作を引き起こしますよ、という風に理解しています。
2.Time2 オペレーションモード
3.Timer2 初期化、割り込みコード
Timer2のインターバル時間は、5msに設定しています。プリスケーラは、1:16。ポストスケーラも1:16に設定。
割込み回数を100回数え、main関数内で、LEDを500ms間隔で点滅させています。
#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 */
#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;
}
#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 */
#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);
}
// 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;
}