16F18325のMaster Synchronous Serial Port (MSSP) を使うと周辺機器と簡単にシリアル通信を行うことができます。MSSPは、SPIとI2Cという2種類の方式をサポートしていまが、ここでは、SPIを利用したD/A変換IC MCP4822 のインターフェースだけを取り上げます。このため、SPI マスターモードが対象です。 SCK SDI SDO SS の4本のピンがSPIで使用されます。これら4本のピンの入出力をTRISレジスタで適切に設定しておく必要があります。ただし、その機能を使用しない場合には、TRISをSPIで使用する方向と反対に設定することで、SPI設定とは反対の汎用入力または出力ピンとして使用することができます。たとえば、SPIマスターモードの送信専用としSPI入力がいらない場合、SDI(RC1)のTRISを出力[0]に設定すれば、汎用出力ピンとして使用可能です。SPIに関連するレジスター一覧を下表に示します。
				| レジスタ | bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 | 
|---|---|---|---|---|---|---|---|---|
| INTCON | GIE | PEIE | - | - | - | - | - | INTEDG | 
| PIE1 | TMR1GIE | ADIE | RCIE | TXIE | SSP1IE | BCL1IE | TMR2IE | TMR1IE | 
| PIR1 | TMR1GIF | ADIF | RCIF | TXIF | SSP1IF | BCL1IF | TMR2IF | TMR1IF | 
| PIE2 | TMR6IE | C2IE | C1IE | NVMIE | SSP2IE | BLC2IE | TMR4IE | NCO1IE | 
| PIR2 | TMR6IF | C2IF | C1IF | NVMIF | SSP2IF | BLC2IF | TMR4IF | NCO1IF | 
| SSPxCON1 | WCOL | SSPOV | SSPEN | CKP | SSPM<3:0> | |||
| SSPxCON3 | ACKTIM | PCIE | SCIE | BOEN | SDAHT | SBCDE | AHEN | DHEN | 
| SSPxSTAT | SMP | CKE | D/nA | P | S | R/nW | UA | BF | 
| SSPxADD | baud レートクロック分周値 | |||||||
| SSPxBUF | 同期シリアルポート受信バッファ/ 送信レジス | |||||||
| SSPxCLKPPS | - | - | - | SSPxCLKPPS<4:0> | ||||
| SSPxDATPPS | - | - | - | SSPxDATPPS<4:0> | ||||
| SSPxSSPPS | - | - | - | SSPxSSPPS<4:0> | ||||
| RxyPPS | - | - | - | RxyTPPS<4:0> | ||||
| レジスタ | BIT | 名 | 説明 | 1 | 0 | 
|---|---|---|---|---|---|
| INTCON | 7 | GIE | 全インタラプトの使用許可 | 許可 | 否 | 
| 6 | PEIE | 周辺機能インタラプトの使用許可 | 許可 | 否 | |
| PIE1 | 3 | SSP1IE | SSP インタラプトを使用許可 | 許可 | 否 | 
| PIR1 | 3 | SSP1IF | SSP インタラプト フラグ | 発生 | 未発生 | 
| SSPCON1 | 7 | WCOL | 送信時Bus衝突 | 発生 | なし | 
| 6 | SSPOV | 受信時SSPBUFオーバーラン | 発生 | なし | |
| 5 | SSPOV | MSSPの動作 | ON | OFF | |
| 4 | CKP | クロックのアイドル状態を指定 | Hi | Low | |
| <3:0> | SSPM | ISSPM ModeSelect Bits:: SPI モード(下記参照) | |||
| SSPCON3 | 4 | BOEN | SSPBUFの上書き(Slaveのみ) | 許可 | 禁止 | 
| SSPSTAT | 7 | SMP | 入力データサンプル時期(データ出力との関係) | 終点 | 中間 | 
| 6 | CKE | 送信開始クロックエッジ指定 | Act→Idl | Idl→Act | |
| 0 | BF | (Read only) SSPBUF状況 | フル | 空 | 
| SSPM ModeSelect Bits: SPI モード | ||
|---|---|---|
| 設定値 | モード | クロック | 
| 1010 | マスタ | FOSC/ (4x(SSPADD+1)) | 
| 0101 | スレーブ | SCK、SS はI/O ピンに使用可能 | 
| 0100 | スレーブ | SCK、SS ピン制御有効 | 
| 0011 | マスタ | TMR2 出力/2 | 
| 0010 | マスタ | FOSC/64 | 
| 0001 | マスタ | FOSC/16 | 
| 0000 | マスタ | FOSC/4 (初期値) | 
SSPCON1 の SSPM<3:0> 設定値と
機能、クロックソースの一覧
| クロックの状態 | ||||
|---|---|---|---|---|
| バスモード | CKP | CKE | アイドル状態 | 送信タイミング | 
| MODE_00 | 0 | 1 | Low | クロックの↓ | 
| MODE_01 | 0 | 0 | Low | クロックの↑ | 
| MODE_10 | 1 | 1 | Hight | クロックの↑ | 
| MODE_11 | 1 | 0 | Hight | クロックの↓ | 
クロック(SCK)とデータ(SDO)の関係
相対関係はCKPとCKEの2Bitで決定されます。
			マイクロチップ社のSPI 12bit DACを接続し、1KHzの正弦波を出力します。 RC1(pin 9)は、SPIのSDI端子ですが、このテスト回路では、PICから一方的にデータをDACに送信し、DACからのデータ受信は行わないため、SDI端子をCS出力に使用しています。
 PICから、16KHzの周期で360度を16分割した正弦波波高データをDACに送信して疑似正弦波を出力しています。左図は、出力をオシロスコープで観測したものです。一周期が16段の階段状に変化しているのが確認できます。
			
			<プログラム>
//  File name: SPI
//  Description: SPI 16bits example
//  SPI 12 bit DAC MCP4822 を接続
//  正弦波周波数は
//  クロック16MHzで 1KHz、 4MHzで250Hz
//     RC1  SPI_CS
//     RC2  SPISDO
//     RC0  SPISCK
//    Language: MPLABX XC8
//    Target: PIC16F18325
// Copyright (c) 2012 iwamoto All Rights Reserved
//*********************************************************
#include <xc.h>
#define SPI_CS     LATC1
//************* Config  ***********************************
#pragma config FOSC  = INTOSC, WDTE = OFF, PWRTE = OFF, MCLRE = OFF, CP  = OFF
#pragma config BOREN = ON, CLKOUTEN = OFF, IESO  = OFF, FCMEN = OFF
#pragma config WRT = OFF, CPUDIV = NOCLKDIV, USBLSCLK = 48MHz, PLLMULT = 3x
#pragma config PLLEN = DISABLED, STVREN = ON, BORV = LO, LPBOR = OFF, LVP = OFF
//********************************************************
// 正弦波定数 Ach Gain 1x
const unsigned char wavA1[] = {  // 上位8bit
           0x37,0x3B,0x3D,0x3F,0x3F,0x3F,0x3D,0x3B,
           0x37,0x34,0x32,0x30,0x30,0x30,0x32,0x34};
const unsigned char wavA2[] = {  // 下位8bit
           0xFF,0x0E,0xA6,0x62,0xFE,0x62,0xA6,0x0E,
           0xFF,0xF0,0x58,0x9C,0x00,0x9C,0x58,0xF0};
//////////// Main //////////////////////////////////
void main(void){
    unsigned char var,wcnt;
    OSCCON = 0b00111100;         // 内部クロック16Mhz
    ANSELC = 0;                  // PortCをデジタルI/Oにする
    SPI_CS = 1;                  // SPI_CSを「1」にする
    TRISC1 = 0;                  // SPI_CSを出力に設定
    TRISC2 = 0;                  // SPISDOを出力に設定
    TRISC0 = 0;                  // SPISCKを出力に設定
                            // SPI Master FOSC/16 MODE_00
    SSPSTAT = 0b11000000;        //  SMPEND CKE=1
    SSPCON1 = 0b00100001;        //  SPEN=1 CKP=0 SSP=0001
                            // Timer2 16KHz(16MHz/4/250)毎にリセット
    T2CON = 0b00000100;          // PS_1/1 POST_1/1
    PR2 = 249;                   // PR設定
    wcnt = 0;
    while(1){               // 繰り返しループ
        while(! TMR2IF);         // Timer2 のタイムアップを待つ
        TMR2IF = 0;              // Timer2 フラッグをクリア
        SPI_CS = 0;              // SPI_CSを「0」にする
        SSPBUF = wavA1[wcnt];    // MSBデータの送信を開始
        while(!SSP1IF);          // 送信完了を待つ
        SSP1IF=0;
        SSPBUF = wavA2[wcnt];    // LSBデータの送信を開始
        while(!SSP1IF);          // 送信完了を待つ
        SSP1IF=0;
        SPI_CS = 1;              // SPI_CSを「1」にする
        if(++wcnt > 15)wcnt = 0; // 16回でリセットする
   }                             // ここまで繰り返し
}
			
*注意*
pin10
pin 9
pin 8
pin 7
pin 3
pin 4
(1) APFCONの SDOSEL をセット「1」すると、
SDO 代替ピンが選ばれます。
(2) APFCONの SSSEL をセット「1」すると、
SS 代替ピンが選ばれます。