PIC18F SFR設定
PICマイコンのマニュアルを読んでSFRの設定をする作業は、結構面倒なものです。しかも、この作業はプログラム作成の最初に行う必要があります。もっと言えば、回路設計の際にも、必要な機能を確保出来ることを確認している必要があります。
私がPIC18F23K22 , PIC18F46K22 以外のCPUを滅多に使わなくなったのも、出来るだけ面倒な作業を避けたい一心でした。
この記事ではPIC18F23K22 を例に、私が普段使っているプログラムのファイル構造とSFR設定の様子を紹介します。
ファイルの構造
私が作るプログラムのファイル構造は以下のようなものです。
1.main.c メイン
2.configuration_bits.c MPLAB-Xからコピー
3.appdef.c SFR設定
4.subs.c 関数群
5.inthigh.c 高位割り込み関数
6.intlow.c 低位割込み関数
ファイル名は以前に決めたもので、appdef.c のように意味不明のものもありますが、そのまま使い続けています。
main.c
C言語(XC8)で、こんな構造です。
/******************************************************************************/
/* Files to Include */
/******************************************************************************/
#include <stdio.h>
#include <stdlib.h>
/******************************************************************************/
/* Configuration Bits */
/******************************************************************************/
#include "configuration_bits.c" //
/******************************************************************************/
/* User Global Variable Declaration */
/******************************************************************************/
/* i.e. uint8_t <variable_name>; */
//#define qtys 2 //子機の数
unsigned char ii = 0 ; //汎用ループカウンター
unsigned char jj = 0 ; //汎用ループカウンター
#include "subs.c" //サブルーチン集
/******************************************************************************/
/* Main Program */
/******************************************************************************/
int main(int argc, char** argv) {
/* Refer to the device datasheet for information about available
oscillator configurations. */
#include "appdef.c" //Oscillator A/D Ports Peripherals Int. Def.
/* Enable interrupts */
INTCONbits.TMR0IF = 0 ; //TIMER0 割り込みフラグクリア
INTCONbits.TMR0IE = 1 ; //TIMER0 割り込み許可
// PIR5bits.TMR4IF = 0 ; //TIMER4 割り込みフラグクリア
// PIE5bits.TMR4IE = 1 ; //TIMER4 割り込み許可
// PIR1bits.TMR2IF = 0 ; //TIMER2 割り込みフラグクリア 送信期間中に限る
// PIE1bits.TMR2IE = 1 ; //TIMER2 割り込み許可 送信期間中に限る
PIR2bits.TMR3IF = 0 ; //TIMER3 割り込みフラグクリア
PIE2bits.TMR3IE = 1 ; //TIMER3 割り込み許可
// PIR1bits.RC1IF = 0 ; //RC1 割り込みフラグクリア PC
// PIE1bits.RC1IE = 1 ; //RC1 割り込み許可
// PIR3bits.RC2IF = 0 ; //RC2 割り込みフラグクリア
// PIE3bits.RC2IE = 1 ; //RC2 割り込み許可
// 初期動作
// ループ
while(1)
{
}
return (EXIT_SUCCESS);
}
/******************************************************************************/
/* Interrupt Routines */
/******************************************************************************/
/* High-priority service */
#include "inthigh.c" //高位割り込み処理
/* Low-priority interrupt routine */
#include "intlow.c" //低位割り込み処理
先程の6ファイルの内 main.c を除く5ファイルを include しています。
/* Enable interrupts */ の部分は、一度確認したものを並べ、必要に応じてコメントON/OFFして使っています。
割り込み関数
次のように記述して期待した通りに動作しているのですが、行頭に ! マークが出てカーソルを合わせると Unable to resolve identifier interrupt. と表示されます。
解決方法をご存知の方がいらしたら、教えていただけると助かります。
inthigh.c
void interrupt high_isr (void)
{
}
intlow.c
void interrupt low_priority low_isr (void)
{
{
SFR設定
クロックの設定に始まり、割り込みの設定まで記述し、必要に応じてコメントON/OFFしたり値を変えて使っています。
/* Refer to the device datasheet for information about available
oscillator configurations. */
/* TODO Add clock switching code if appropriate. */
OSCCON = 0b01110010 ; //内部16MHzにクロック切替
// OSCCON = 0b01111000 ; //外部 Primaryクロックに切替
/* TODO Initialize User Ports/Peripherals/Project here */
/* Setup analog functionality and port direction */
ANSELA = 0b00000000 ;
ANSELB = 0b00000000 ;
ANSELC = 0b00000000 ;
// ANSELD = 0b00000000 ;
// ANSELE = 0b00000000 ; //全てデジタル
// ANCON0 = 0b00000000 ;
// ANCON1 = 0b00000000 ;
// ANCON2 = 0b00000000 ; //全てデジタル
LATA = 0b00000000 ; //LATA = 0
TRISA = 0b00000000 ; //PortA 入出力設定
LATB = 0b00000000 ; //LATB = 0
TRISB = 0b11000111 ; //PortB 入出力設定
LATC = 0b00000000 ; //LATC = 0
TRISC = 0b00000000 ; //PortC 入出力設定
/* Initialize peripherals */
//USART1
// TXSTA1 = 0b00100110 ; //TXSTA1 8bit 非同期許可 BRGH=1
// RCSTA1 = 0b10010000 ; //TCSTA1 8bit シリアル許可
// BAUDCON1bits.BRG16 = 1 ; //16bit ボーレートジェネレーター使用
// SPBRGH1 = 0 ;
// SPBRG1 = 34 ; //115.2kbps -0.79%
// SPBRGH1 = 0x01 ;
// SPBRG1 = 0xA0 ; //9600bps -0.08%
//USART2
// TXSTA2 = 0b00100110 ; //TXSTA1 8bit 非同期許可 BRGH=1
// RCSTA2 = 0b10010000 ; //TCSTA1 8bit シリアル許可
// BAUDCON2bits.BRG16 = 1 ; //16bit ボーレートジェネレーター使用
// SPBRGH2 = 0 ;
// SPBRG2 = 34 ; //115.2kbps -0.79%
//TIMER0 50msec 汎用イベントタイマー
T0CON = 0b10000011 ; //T0CON = Enable,16bits,PSon,1/16
TMR0H = tim0defh ; //12500カウント 50msec 10000h-12500d
TMR0L = tim0defl ; //0.25usec x 16 x 12500 = 50msec
evtcnt = evtcntini ;
//TIMER1 センサー駆動用、CCP5 でトグル出力 ×ハードでTIMER1クリア出来ない → 不採用
// T1CON = 0b00000011 ; //Fosc/4 1/1プリスケーラー使用 16bitモード
// TMR1H = 0 ;
// TMR1L = 0 ;
//割り込みは使用しない
//TIMER3 RCサーボ制御タイマー 1.0usec/count
T3CON = 0b00100011 ; //Fosc/4 1/4プリスケーラー使用 16bitモード
TMR3H = 0 ;
TMR3L = 0 ;
//高位割り込み
//TIMER2 センサー駆動用周期設定 PR2 、CCP5でPWM(デューティー50% → CCPR5L)
// PR2 = pr2a40 ; //40kHz
// TMR2 = 0 ;
// T2CON = 0b00000100 ; //Fosc/4 PreS=1/1 PostS=1:1 Timer ON
//TIMER4 UART2送信用タイマー 2msec
// PR4 = 50 ; //0.25 * 16 * 50 * 10 = 2 msec
// TMR4 = 0 ;
// T4CON = 0b01001110 ; //Fosc/4 PreS=1/16 PostS=1:10 Timer ON
//RB CHANGE
// IOCB = 0b00110000 ; //RB4,RB5 使用
//SPI1
// SSP1STAT = 0b01000000 ; //CKE = 1
// SSP1CON1 = 0b00100010 ; //Enable SPI Master Fosc/644
//CCP5
// CCPTMRS1 = CCPTMRS1 & 0b11110011 ; //CCP5 PWM Timer2
// CCP5CON = 0b00001100 ; //CCP5 PWM mode
// CCPR5L = pr2a40 >> 1 ; //周期の半部 (周期 PR2 は偶数が望ましい)
/* Configure the IPEN bit (1=on) in RCON to turn on/off int priorities */
RCONbits.IPEN = 1 ; //割り込み優先順位有効
INTCONbits.GIE = 1 ; //高位割り込み有効
INTCONbits.PEIE = 1 ; //低位割り込み有効
// IPR1bits.SSP1IP = 1 ; //SSP1 を高位割り込みに設定
// IPR1bits.RC1IP = 0 ; //RX1 を低位割り込みに設定
// IPR3bits.RC2IP = 1 ; //RX2 を高位割り込みに設定
INTCON2bits.TMR0IP = 0 ; //TIMER0 を低位割り込みに設定
// IPR1bits.TMR2IP = 0 ; //TIMER2 を低位割り込みに設定
// IPR5bits.TMR4IP = 0 ; //TIMER4 を低位割り込みに設定
IPR2bits.TMR3IP = 1 ; //TIMER3 を高位割り込みに設定
まとめ
SFR設定を毎回調べるのが面倒なので、一つのファイルの記述を加減して、「秘伝のたれ」のように使っています。
私のソースについて改善すべき点や、皆さんの工夫をお聞かせいただければ幸いです。