再度PIC18F4550でタイマーを使う
2023/04/23


新しいコンパイラーでLEDの点滅が出来たので、LEDの点滅をタイマーで動作させてみる。

ヘッダーのプログラムは、以前作ったものをそのまま使っても大丈夫だった。
※詳しいの説明は以前の「PIC18F4550を使ってタイマーを動かす」を参照



//#include < xc.h > // include processor files - each processor file is guarded.  

void Open_Timer1(void);
void Start_Timer1(void);

// 水晶振動子 20MHz
// configでPLLDIV = 5   20/5-> 4MHz入力を行いPLLで96MHz発振
// CPUDIV = OSC1_PLL2    96MHzを半分にし、48MHzでCPUを駆動する
//
// タイマーはFosc/4で動き、T1CONのプリスケーラーで1/8にしているので
// 48000000/(4*8)->1500000
// 16ビットのカウンター1につき1/1500000->0.66666μ秒
unsigned char Timer1_time_L;    // 必要な時間 20ms とすると
unsigned char Timer1_time_H;    // 0.02/(1/1500000)->30000
                                // 65536-30000->35536->8AD0
int t_count;


タイマーを動作させる関数は、以下のようなものになる。

Open_Timer1で初期設定を行い、Start_Timer1でタイマーの実行開始を行う。
これも以前作ったプログラムをほぼそのままの状態で使用して大丈夫だったが、どうもロープライオリティの割り込みがうまく動かない。
色々試して、ハイプライオリティの割り込みは動いたのである。
ただ、どうもロープライオリティの割り込みがうまく動いてくれないので、引き続き実験を続行中なのである。



//#include < stdio.h >
//#include < stdlib.h >
#include "xc.h"
#include "Timer01.h"

void Open_Timer1(void) {
        
    T1CONbits.RD16 = 1;         // 16bit
    T1CONbits.T1RUN = 1;        //
    T1CONbits.T1CKPS1 = 1;      // プリスケーラー1/8
    T1CONbits.T1CKPS0 = 1;      //
    T1CONbits.T1OSCEN = 0;      //
    T1CONbits.T1SYNC = 1;       // 
    T1CONbits.TMR1CS = 0;       // internal clock

    TMR1L = Timer1_time_L;                  
    TMR1H = Timer1_time_H;                  
    
    INTCONbits.GIE = 1;   // Enables all high priority interruptsts
    INTCONbits.PEIE = 1;  // Enables all low priority peripheral interrupts
    
    PIR1bits.TMR1IF = 0;        // TMR1 register did not overflow
    PIE1bits.TMR1IE = 1;        // Enables the TMR1 overflow interrupt
    IPR1bits.TMR1IP = 1;        // High priority
//    IPR1bits.TMR1IP = 0;        // Low priority  ※これがイマイチうまく動かない。
    
    RCONbits.IPEN = 1;          // Enable priority levels on interrupts

}

void Start_Timer1(void) {
 
  T1CONbits.TMR1ON = 1;       // timer start

}


次がタイマーで起動される割り込みルーチン。
このプログラムが20ミリ秒毎に起動される。

今回は、タイマーで起動される都度、RD2のLEDを反転させる。

今回は、ここでだいぶ手間取った。
前回は「void interrupt isr(void)」というコードを書いてうまく動いたのだが、今回はどうもうまく動かない。
調べると、「void __interrupt() SYS_InterruptHigh(void)」と書くとハイプライオリティの割り込みは動くのである。
「void __interrupt() SYS_InterruptLow(void)」と書いても動くのだが、タイマーの設定でロープライオリティにする「IPR1bits.TMR1IP = 0」とうまく動かない。
どうもイマイチ謎があって気分が悪いのである。



//#include < stdio.h >
//#include < stdlib.h >
#include "xc.h"
#include "Timer01.h"

//
//  割り込み関数
//
//void interrupt isr(void)            // 割り込み関数
void __interrupt() SYS_InterruptHigh(void)            // 割り込み関数
//void __interrupt() SYS_InterruptLow(void) 
{

    if (RD2 == 0) {
        RD2 = 1;
    } else {
        RD2 = 0;
    }
    
    if( PIR1bits.TMR1IF )
	{            // タイマ1割り込み?
        PIR1bits.TMR1IF = 0;        // TMR1 register did not overflow
        TMR1L = Timer1_time_L;                 
        TMR1H = Timer1_time_H;                 
    } else {
        RD3 = 1;
    }
}


最後にメインのプログラム。

メインのプログラムは、タイマーのオープンとスタートを行った後は、RD0とRD1のLEDを5ms毎に高速で点滅させているだけである。
タイマー割り込みで、メインの動作と関係なくRD2が20ms毎に反転を繰り返す。



/*
 * File:   TIMERTEST01.c
 * Author: 
 *
 * Created on 2023/04/14, 11:43
 */
//#include < stdio.h >
//#include < stdlib.h >
#include "xc.h"
#include "Timer01.h"

#define _XTAL_FREQ 48000000    // 使用するPIC等により動作周波数値を設定する
                               // 水晶は20MHz でPLLで48MHz動作

// コンフィギュレーション pic18f4550  c18
#pragma config PLLDIV = 5, CPUDIV = OSC1_PLL2, USBDIV = 2
#pragma config FOSC = HSPLL_HS, FCMEN = OFF, IESO = OFF
#pragma config PWRT = ON, BOR = OFF, BORV = 0
#pragma config VREGEN = ON, WDT = OFF, WDTPS = 1
#pragma config CCP2MX = OFF, PBADEN = OFF, LPT1OSC = OFF
#pragma config MCLRE = OFF, STVREN = OFF, LVP = OFF
#pragma config ICPRT = OFF, XINST = OFF, DEBUG = OFF
#pragma config CP0 = OFF, CP1 = OFF, CP2 = OFF, CP3 = OFF
#pragma config CPB = OFF, CPD = OFF
#pragma config WRT0 = OFF, WRT1 = OFF, WRT2 = OFF, WRT3 = OFF
#pragma config WRTC = OFF, WRTB = OFF, WRTD = OFF
#pragma config EBTR0 = OFF, EBTR1 = OFF, EBTR2 = OFF, EBTR3 = OFF, EBTRB = OFF

/*
 * 
 */
int main(int argc, char** argv) {
    
    TRISD = 0b00000000;			// PORTD = 0-7 output
    PORTD = 0b00000000;			// PORTD = 0
            
    Timer1_time_H = 0x8A;       // タイマー用 20ms
    Timer1_time_L = 0xD0;       // タイマー用
//    Timer1_time_H = 0x00;       // タイマー用 0.4369ms
//    Timer1_time_L = 0x00;       // タイマー用
    Open_Timer1();
    
    t_count = 0;
    Start_Timer1();
    
    while(1){

        RD0 = 1;
        RD1 = 0;
//        for(i=0;i<5000;i++);   // 5msのディレイ
        __delay_ms(5) ;        // 5msのディレイ
        RD0 = 0;
        RD1 = 1;
//        for(i=0;i<5000;i++);   // 5msのディレイ
        __delay_ms(5) ;        // 5msのディレイ

    }

    return (EXIT_SUCCESS);
}


test_pgm004
これが動作中のRD0とRD2で、時間軸は5msである。



HOME