PIC18F14K50の基本動作から応用プログラムまでを学びます。

ホーム
16F18313
16F18325
16F18346
16F1619
Curiosity
---
---
    
12F1822
16F1455
16F1459
18F14K50
18F26J50
dsPIC
その他
MSSP SPI

18F14K50のMaster Synchronous Serial Port (MSSP) を使うと周辺機器と簡単にシリアル通信を行うことができます。MSSPは、SPIとI2Cという2種類の方式をサポートしていまが、ここでは、SPIを利用したD/A変換器のインターフェースだけを取り上げます。このため、SPI マスターモードが対象です。 SCK(RB6) SDI(RB4) SDO(RC7) SS(RC6)の4ピンが対応しています。

SPIモードで使うときには、この4つのピンはの入出力をTRISレジスタで適切に設定しておく必要があります。

<TRISにセットする値>
SPIモード SCK
TRISB6
SDI
TRISB4
SDO
TRISC7
SS
TRISC6
マスター 0 1 0 -
スレーブ 1 1 0 1

SPIモードの機能を使用しないピンは、TRISをSPI機能の反対に設定することで、SPIでの設定と反対の汎用I/Oピンとして使用することができます。たとえば、SPIマスターモードで、送信専用としSPI入力がいらない場合、SDI(RB4)のTRISを出力[0]に設定すれば、汎用出力ピンとして使用することが可能です。

高低2レベルの優先度を使用するI2C に関連するレジスターを一覧で説明します。

レジスタ bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0
RCON IPEN SBOREN RI TO PD POR BOR
INTCON GIE/GIEH PEIE/GIEL TMR0IE INTIE RABIE TMR0IF INT0IF RABIF
PIR1 - ADIF RCIF TXIF SSP1IF CCP1IF TMR2IF TMR1IF
PIE1 - ADIE RCIE TXIE SSP1IE CCP1IE TMR2IE TMR1IE
IPR1 ADIP RCIP TXIP SSPIP CCP1IP TMR2IP TMR1IP
SSPCON1 WCOL SSPOV SSPEN CKP SSPM<3:0>
SSPSTAT SMP CKE D/A P S WnR UA BF
SSPADD ADD<7:0>
SSPBUF MSSP Receive Buffer/Transmit Register
TRISB TRISB7 TRISB6 TRISB5 TRISB4
TRISC TRISC7 TRISC6 TRISC5 TRISC4 TRISC3 TRISC2 TRISC1 TRISC0
レジスタ BIT 説明 1 0
RCON 7 IPEN 2レベルのインタラプト優先度 使用
INTCON 7 GIEH 高優先度インタラプトを使用許可 許可
6 GIEL 低優先度インタラプトを使用許可 許可
PIR1 3 SSPIF SSP フラグ 発生 待ち
PIE1 3 SSPIE SSP インタラプトを使用許可 許可
IPR1 3 SSPIP SSP インタラプト優先度
SSPCON1 7 WCOL 送信時バス衝突 発生 なし
6 SSPOV 受信時SSPBUFオーバーラン 発生 なし
5 SSPEN MSSPの動作許可 許可
4 CKP クロックのアイドル状態を指定 High Low
3 SSPM3 SSPM ModeSelect Bits:: SPIマスターモード
SSPMクロック SSPMクロック
0000OSC / 4 (初期値) 0010FOSC / 64
0001FOSC / 16 0011TMR2 出力 / 2
2 SSPM2
1 SSPM1
0 SSPM0
SSPSTAT 7 SMP 入力データサンプル時期 最後 途中
6 CKE クロックエッジ指定(A:active I:idle) A→I I→A
0 BF SSPBUF状況 (Read Only) フル
SPIバスモード
<SPIバスモードに対する設定ビット値>
バスモード CKP CKE アイドル状態 送信タイミング
MODE_00 0 1 Low クロックの↓
MODE_01 0 0 Low クロックの↑
MODE_10 1 1 Hight クロックの↑
MODE_11 1 0 Hight クロックの↓

SPIのクロックとデータ変化タイミングの相対的関係とデータを送信していないアイドル時のクロックの状況からSPIには4種類のバスモードがあります。
これらバスモードは、接続するデバイスに適合するように、SSPCON1 CKP と SSPSTAT CKE の2Bitで指定します(右表)。
各バスモードのクロックとデータの関係をロジックアナライザーで観察した波形を以下に示します。

SPIのプログラム例

Microchip社の12bitsSPI DACMCP4822を使い正弦波を出力するプログラムを作成しました。このDACは、16BitのデータをSPIで受け取り、その上位4bitは、DACの制御に、下位12bitが変換するDACのデータに割り当てられています。

PICは16MHzの内部発振クロックで動作し、Timer2は定期的に16KHzでカウントアップします。そのたびに正弦波の波高データをrom定数(wavAx)から読み出しSPIモジュールを介してDACに送信しています。 波高データは16対で360度になるよう設定されているため、1KHzの正弦波がDACから出力されます。DAC出力をオシロスコープで見るときれいな正弦波になっています。

<回路図>

<プログラム>

//  File name: SPI
//  Description: SPI 16bits example
//  正弦波周波数は
//  クロック16MHzで 1KHz、 4MHzで250Hz
//
//     RC6  SPI_CS
//     RC7  SPISDO
//     RB6  SPISCK
//  Language: MPLABX XC8
//  Target: PIC18F14K50

#include <xc.h>

#define SPI_CS LATCbits.LATC6

//-------------- コンフィグレーション --------------------------------
#pragma config MCLRE  = OFF
#pragma config PWRTEN = OFF, BOREN  = OFF, BORV   = 30
#pragma config WDTEN  = OFF, WDTPS  = 32768
#pragma config STVREN = ON
#pragma config FOSC   = IRC  //  内部クロック
#pragma config PLLEN  = ON,  CPUDIV = NOCLKDIV, USBDIV = OFF
#pragma config FCMEN  = OFF, IESO   = OFF, HFOFST = OFF
#pragma config LVP    = OFF, XINST  = OFF, BBSIZ  = OFF
#pragma config CP0    = OFF, CP1 = OFF, CPB = OFF, CPD = OFF
#pragma config WRT0   = OFF, WRT1 = OFF
#pragma config WRTB   = OFF, WRTC = OFF, WRTD = OFF
#pragma config EBTR0  = OFF, EBTR1 = OFF, EBTRB = OFF


// ChA 正弦波定数
const unsigned char wavA1[] = {
           0x37,0x3B,0x3D,0x3F,0x3F,0x3F,0x3D,0x3B,
           0x37,0x34,0x32,0x30,0x30,0x30,0x32,0x34};
const unsigned char wavA2[] = {
           0xFF,0x0E,0xA6,0x62,0xFE,0x62,0xA6,0x0E,
           0xFF,0xF0,0x58,0x9C,0x00,0x9C,0x58,0xF0};

void main(void){
    unsigned char var,wcnt;
    OSCCON = 0b01110010;            // 内部クロック16Mhz
    ANSEL  = 0b00000000;            // デジタル
    ANSELH = 0b00000000;
    LATC   = 0;                     // PortCのすべてのビットを「0」
    SPI_CS = 1;                     // SPI_CSを「1」にする
    TRISCbits.TRISC6 = 0;           // SPI_CSを出力に設定
    TRISCbits.TRISC7 = 0;           // SPISDOを出力に設定
    TRISBbits.TRISB6 = 0;           // SPISCKを出力に設定

    SSPSTAT = 0b11000000;           //  FOSC_4, MODE_00, SMPEND
    SSPCON1 = 0b00100000;

    T2CON = 0b00000100;             //  Timer2  PS_1/1 POST_1/1
    PR2 = 249;                      // Timer2 PR設定

    wcnt = 0;
    while(1){                       // 繰り返しループ
        while(! PIR1bits.TMR2IF);    // Timer2 のタイムアップを待つ
        PIR1bits.TMR2IF = 0;         // Timer2 フラッグをクリア

        SPI_CS = 0;                  // SPI_CSを「0」にする
        SSPBUF = wavA1[wcnt];        // MSBデータの送信を開始
        while(!SSPSTATbits.BF);      // 送信完了を待つ
        var = SSPBUF;                // BFをリセットするため空読み
        SSPBUF = wavA2[wcnt];        // LSBデータの送信を開始
        while(!SSPSTATbits.BF);      // 送信完了を待つ
        var = SSPBUF;                // BFをリセットするため空読み
        SPI_CS = 1;                  // SPI_CSを「1」にする

        if(++wcnt > 15)wcnt = 0;     // 16回でリセットする
   }                                // ここまで繰り返し
}