PICのdelay関数について

PICには指定した時間だけ、停止させるdelay_xx()関数が用意されている。sleep()wait()のPIC版である。XC8コンパイラとXC16コンパイラで使い方がちょっと違うので、メモしておく。

XC8コンパイラ

_XTAL_FREQで動作しているクロック周波数を指定する必要がある。実際のクロック周波数と_XTAL_FREQの値が合ってないと、指定した時間よりも短くまたは長くdelayしてしまうので注意。

PIC16F1455を使ったMCCのクロック設定画面。USBデバイスとして機能させるために内部クロックで48MHzになるように設定している。

pic_delay02

MCCプラグインでGenerateすると、device_config.hに自動的にMCCで定義したクロック周波数の値で定義されているはずである。

#ifndef DEVICE_CONFIG_H
#define	DEVICE_CONFIG_H

#define _XTAL_FREQ 48000000

#endif	/* DEVICE_CONFIG_H */

delay関数は、秒、ミリ秒、マイクロ秒単位で指定できる関数がある。xc8コンパイラのヘッダpic.h内に定義がある。8bitマイクロコントローラの場合、クロック周波数が4カウントで1サイクルなので、クロック周波数を4で除算して、ミリ秒ならさらに1/1000、マイクロなら1/1000000した値を_delay()に指定している。

// NOTE: To use the macros below, YOU must have previously defined _XTAL_FREQ
#define __delay_us(x) _delay((unsigned long)((x)*(_XTAL_FREQ/4000000.0)))
#define __delay_ms(x) _delay((unsigned long)((x)*(_XTAL_FREQ/4000.0)))

以下のようにコールできる。

void main(void)
{
    SYSTEM_Initialize();
    while(1){
        __delay(1); // 1sec delay
        __delay_us(200); // 100ms delay
        __delay_ms(300); // 300us delay
    }

XC16コンパイラ

まず、XC8と同じように動作クロック周波数がいくつなのかを指定・確認する。

MCCのシステムクロック設定画面だと、FORC、FORC/2、USB Clockと3つあるが、FORC/2の値が該当する。

下記例では、セラロック4MHzを外付けしてUSBホスト機能を持たせたときの設定になる。USBホスト機能を満たすため、48MHzになるようにプリスケーラなどの倍数を調整している。(PIC24FJ64GB002を使用)

pic_delay01

libpic30.hのインクルードと、FCYマクロ(サイクルクロック周波数)を定義すると使用できる。FCYは、クロック周波数FORCが2カウントあたり1サイクルなので、1/2した値を指定する。

// Instruction cycle frequency, Hz - required for __delayXXX() to work
// FCY = FOSC/2, FORC=32MHz => FCY=32/2=16MHz
#define FCY 16000000UL 
#include <libpic30.h>

下記の例では、RB15に接続したLEDを500msごとに点滅させるプログラムになる。PICに書き込むと、0.5secごとに点滅するはず。実際のクロック周波数とFCYの計算値が合ってないと、指定した時間よりも早かったり、遅く点滅する。

// RB15 Led Blinking

int main(void)
{
    SYSTEM_Initialize();
    
    IO_RB15_SetHigh();
    
    while(1){
        __delay_ms(500);
        IO_RB15_Toggle();
    }
    return -1;
}

cropped_20180922085351_IMG_20180922_085215