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

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

16F145xの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に関連するレジスター一覧を下表に示します。

*注意*

SCK SDI SDO(1) SS(2)
通常ピン RC0
pin10
RC1
pin 9
RC2
pin 8
RC3
pin 7
代替ピン --- --- RA4
pin 3
RA3
pin 4

(1) APFCONの SDOSEL をセット「1」すると、
   SDO 代替ピンが選ばれます。

(2) APFCONの SSSEL をセット「1」すると、
   SS 代替ピンが選ばれます。

レジスタ bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0
INTCON GIE PEIE TMR0IE INTE IOCIE TMR0IF INTF IOCIF
PIE1 TMR1GIE ADIE RCIE TXIE SSP1IE - TMR2IE TMR1IE
PIR1 TMR1GIF ADIF RCIF TXIF SSP1IF - TMR2IF TMR1IF
SSPCON1 WCOL SSPOV SSPEN CKP SSPM<3:0>
SSPCON3 ACKTIM PCIE SCIE BOEN SDAHT SBCDE AHEN DHEN
SSPSTAT SMP CKE D/A P S WnR UA BF
SSPADD ADD<7:0>
SSPBUF MSSP Receive Buffer/Transmit Register
TRISA - - TRISA5 TRISA4 - - - -
TRISC - - TRISC5 TRISC4 TRISC3 TRISC2 TRISC1 TRISC0
レジスタ 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のプログラム例

マイクロチップ社の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: PIC16F1455
// 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回でリセットする
   }                             // ここまで繰り返し
}