PIC24Eシリアル通信(I2C/SPI/UART)について

〔PICの動かせ方入門に戻る〕


このページでは24EP256MC202で動作するI2C/SPI/UARTのライブラリについて書いて置きます。
尚、dsPIC33E/PIC24Eファミリのデバイスで利用可能と思われますがぁ....

ピンの構成図

MPLAB X V2.15MPLAB(R) XC16 C Compiler Version 1.24コンパイラ を使用しての記事です。

《I2C》

I2Cの基本話はこちらを参考にして下さい。
I2CのPIC24E用日本語リファレンスマニュアルはこちらを参照下さい。

PIC24EのI2C特徴は
 ・独立したマスタロジックとスレーブロジック
 ・アドレスに関係なく、モジュールを全てのメッセージに応答させるバスリピータモード(IPM I)
  (スレーブ時のみですが、ジェネラルコールとは又、別な話の様です)

I2Cは、I2C1とI2C2のモジュールが2個有ります。
I2CのSDA/SCLはピンに直接割り当てられています(PPS機能でピンを割当てる事は出来ません)、

ピンの代替え機能はコンフィギュレーションビットの"ALTI2C1/2"で行います。
 ALTI2Cx : I2Cxで使用するピンの選択を行う
        ON =ASDAx/ASCLxを使用  OFF =SDAx/SCLxを使用(24EP256MC202は選択不可)

I2C用プルアップ抵抗をPIC内蔵で行う場合はCNPUBレジスターで行います。
 CNPUB = 0b0000001100000000 ; // RB9(ASDA1)/RB8(ASCL1)プルアップを行う
 ポートBのレジスタ用で1でプルアップするです。

※ I2Cで使用するピン(SDA/SCL)はANSELB/TRISBレジスターでデジタル入力にする必要が有ります

↓ここからI2Cライブラリのソースファイルをダウンロードして下さい。
skI2Clib.zip(16ビットMCU専用) *4)

skI2Clib.h

I2C通信の関数ライブラリ用ヘッダファイルです。
"skI2Clib.c"を利用する場合に
#include "skI2Clib.h" をプログラムの先頭で記述しないとだめです。

デフォルトではI2C1を使う様になりますが、I2C2側を使う場合は、
"#define I2C_MSSP2_USE"を記述して下さい。(コメントになっているので外す)

skI2Clib.c

このライブラリはI2Cデバイス(RTC/EEPROM等)と接続を行う為の関数集です。
この関数集は”16ビットMCU専用”ですが、
24EP256MC202と24FJ64GB002でしか動作させていません。 *4)
dsPIC33E/PIC24EファミリとPIC24Fファミリのデバイスで使用出来ると思われますがぁ...
I2C通信の関数ライブラリの使い方を説明します。(マスターモードのみ対応)

InitI2C_Master(speed)
 I2C通信のマスターモードで初期化を行う処理です。
 I2C通信用の速度クロック周波数は100KHz/400KHzでの設定です、
 この速度は命令サイクルクロック周波数:FCY(FOSC/2)60MHzの場合で初期化されています。
 FCYを変えた場合は、I2CxBRGレジスタを変えて下さい。
  speed  : I2Cの通信速度を指定します。(0=100KHz 1=400KHz)
 I2CxBRGレジスタの参考値(0x1FFまで設定できます)
  FCY     10MHz   20MHz   40MHz   60MHz   70MHz
  100KHz   0x0B2   0x0C5   0x18B  (0x1FFまでの設定となる)
  400kHz   0x017   0x02F   0x05F   0x08F   0x0A7
  I2CxBRGレジスの設定は"#define FCY"を見てプログラムを切替える様にしています。 (*4)
  60MHz以上での100KHz速度は、0x1FFまでなので使用には注意が必要です、
   60MHz/I2CxBRG=0xFFと設定した場合は、約112KHz程の通信速度が出ます。

ans = I2C_Start(adrs,rw)
 スレーブにスタートコンディションを発行する処理です。
  adrs  :スレーブのアドレスを指定します
  rw     :スレーブに対する動作の指定をします
       0 = スレーブに書込みなさい要求  1 = スレーブに送信しなさい要求
  ans   :0 = 正常 1 = 異常(相手からACKが返ってこない)

ans = I2C_rStart(adrs,rw)
 スレーブにリピート・スタートコンディションを発行する処理です。
  adrs  :スレーブのアドレスを指定します
  rw     :スレーブに対する動作の指定をします
       0 = スレーブに書込みなさい要求  1 = スレーブに送信しなさい要求
  ans   :0 = 正常 1 = 異常(相手からACKが返ってこない)

I2C_Stop()
 スレーブにストップコンディションを発行する処理です。

ans = I2C_Send(dt)
 スレーブにデータを1バイト送信する処理です。
  dt     :送信するデータを指定します
  ans   :0 = 正常 1 = 異常(相手からACKが返ってこない又はNOACKを返した)
 例)slave_adrsへの2バイト送信
   ans = I2C_Start(slave_adrs,RW_0);  // スタートコンディションを発行する
   if (ans == 0) {
        I2C_Send(dt) ;                // 1バイト目を送信する
        I2C_Send(dt) ;                // 2バイト目を送信する
   } else 異常 ;
   I2C_Stop() ;                       // ストップコンディションを発行する
c = I2C_Receive(ack)
 スレーブからデータを1バイト受信する処理です。
  ack    :スレーブからデータを受信した後に返答するデータを指定します
       0 = ACKをスレーブに返す 1 = NOACKをスレーブに返す(受信データが最後なら1)
  c       :受信した1バイトのデータを返す
 例)slave_adrsから2バイト受信する
   ans = I2C_Start(slave_adrs,RW_1) ;  // スタートコンディションを発行する
   if (ans == 0) {
        dt1 = I2C_Receive(ACK) ;       // 1バイト目を受信する
        dt2 = I2C_Receive(NOACK) ;     // 2バイト目を受信する
   } else 異常 ;
   I2C_Stop() ;                        // ストップコンディションを発行する
ans = I2C_SlaveRead(slv_adrs,reg_adrs,*data,kosu) *2)
 スレーブのデバイスから指定個数のデータを読み込む処理です。
 センサー等のデバイスのレジスターから値を読み取ります
 マルチマスターに対応しています。
  slv_adrs  :スレーブのデバイスアドレスを指定します(7bitで指定)
  reg_adrs :読出すデータのレジスターアドレスを指定します
        連続的に読出す場合は、読出すレジスターの先頭アドレスを指定
  *data     :読出したデータの格納先を指定します
  kosu      :読出すデータのバイト数を指定します
   ans       :0=正常 1=異常(相手からACKが返ってこない)
        -1=他のマスターとのバス衝突が発生してリトライオーバー

ans = I2C_SlaveWrite(int slv_adrs,char reg_adrs,unsigned char *data,char kosu) *2)
 スレーブのデバイスに指定個数のデータを書き込む処理です。
 センサー等のデバイスのレジスターに値を書き込みます
 マルチマスターに対応しています。
  slv_adrs  :スレーブのデバイスアドレスを指定します(7bitで指定)
  reg_adrs :書出すデータのレジスターアドレスを指定します
        連続的に書出す場合は、書出すレジスターの先頭アドレスを指定
  *data     :書出すデータの格納先を指定します
  kosu      :書出すデータのバイト数を指定します
   ans       :0=正常 1=異常(相手からACKが返ってこない)
        -1=他のマスターとのバス衝突が発生してリトライオーバー

I2Cスレーブアドレスについて

このライブラリは7ビットアドレスのみ対応です。
アドレス設定  アドレスは7ビットで表します、左図の1〜7ビットです。
 0ビット目はR/Wでこれはスレーブに対する読書き指示ビットです。
 R/W=0 : 書き込み要求です(スレーブは受信モード)
 R/W=1 : 読み込み要求です(スレーブは送信モード)


割り込み処理について

このライブラリを使うには"main.c"で以下の様に割込み許可を行います。
  _IPL = 0 ;      // CPUの割込み優先レベルを設定(優先レベル0以上を許可)
  _GIE = 1 ;      // 全割り込み処理を許可する
尚、割込み優先レベルを変更したい場合は、InitI2C_Master( )関数内の"I2C_MIP = 5"を変更します。

(参考回路)

I2C回路図  I2C接続小型LCDを使った実態配線図です、
 電源は3.3V。

 アナログ専用電圧AVDD(28番)/AVSS(27番)は
 VDD(13番)/VSS(8・19番)と同じ電源に接続
 しています。

 内蔵のレギュレータ用にVCAP端子(20番)に、10uFの
 コンデンサーを取付けVSSに落とす必要が有ります。

1番ピンはMCLR専用なのでリセット回路を取付けないのなら1K-10KΩ抵抗でVDDに接続します。
I2C1(ASDA1/ASCL1)を使い、I2C接続小型LCDモジュールに接続しています。
また、I2Cのプルアップ抵抗はPIC内蔵プルアップを利用しています。

I2C接続小型LCDモジュールと"skI2CLCDlib"についての詳しい話は、12F1822での記事ですがこちら
参照下さい。

参考回路のサンプルソースファイルは↓ここからダウンロードして下さい。
LCD.zip
 LCD.c・・・・・・・・・・・本体のソースプログラム
 skI2CLCDlib.c・・・・I2C接続LCDライブラリ関数ソースファイル *4)
 skI2CLCDlib.h・・・・I2C接続LCDライブラリ用インクルードファイル *4)

後は、上記の"skI2Clib"と一緒にコンパイルします。

《SPI》

SPIの基本話はこちらを参考にして下さい。
SPIのPIC24E用日本語リファレンスマニュアルはこちらを参照下さい。

PIC24EのSPI特徴は
 ・送受信バッファで8レベルのFIFO拡張バッファモードが設定可能。(本ライブラリは未対応)
 ・SPIの転送データ幅が8ビット(通常)と16ビットで選択可能。(本ライブラリは8ビット)
 ・基本的なフレーム化SPIxプロトコルモードをサポートしています。(本ライブラリは未対応)
 ・DMA機能が利用出来る(本ライブラリは未対応)
  (DMAは、CPUに負荷をかけずに、CPU(メモリー)とSPI 間でデータを転送する機能です。)

SPIは、SPI1とSPI2のモジュールが2個有ります。
SPI1のSDI1/SDO1/SCK1はピンに直接割り当てられていますが、SPI2はPPS機能で割り付けないと
使えません
例えば、下記の様に記述します。
 #include <xc.h>
 #include <PPS.h>                  // Pin Re-Mapping peripheral library

 #pragma config IOL1WAY = OFF      // 周辺機器のピン割り付けは何度でも変更出来る様に許可

   PPSUnLock ;
   iPPSInput(IN_FN_PPS_SDI2,IN_PIN_PPS_RPI44) ;   // RB12(SDI2)
   iPPSOutput(OUT_PIN_PPS_RP43,OUT_FN_PPS_SDO2) ; // RB11(SDO2)
   iPPSOutput(OUT_PIN_PPS_RP42,OUT_FN_PPS_SCK2) ; // RB10(SCK2)
   PPSLock ;
※ SPIで使用するピンSDI1/2はANSELx/TRISxレジスターでデジタル入力にする必要が有ります。
※ マスターでSSピンを使う場合は、デジタルピンの何れでも良いが、初期化時にHIGHにします。
※ スレーブでSSピンを使う場合は、PPSで割り付けてから使用します。
※ "#include <PPS.h>"のライブラリを使う場合はこちらを参照し、インストールを行います。 *3)

↓ここからSPIライブラリのソースファイルをダウンロードして下さい。
skSPIlib.zip(16ビットMCU専用) *1) *4)

skSPIlib.h

SPI通信を行う関数のヘッダファイルです。
"skSPIlib.c"を利用する場合に
#include "skSPIlib.h" をプログラムの先頭で記述して下さい。

デフォルトではSPI1を使う様になりますが、SPI2側を使う場合は、
"#define SPI_MSSP2_USE"を記述して下さい。(コメントになっているので外す)

skSPIlib.c

このライブラリはSPI通信を行う為の関数集です。
この関数集は”16ビットMCU専用”ですが、
24EP256MC202と24FJ64GB002でしか動作させていません。 *4)
dsPIC33E/PIC24EファミリとPIC24Fファミリのデバイスで使用出来ると思われますがぁ...

SPI通信を行う関数の使い方を説明します。(マスターモードのみ対応)

SPI_Init(mode,divider,sdo)
 SPIモードの設定と初期化を行う処理
 マスターモード、8ビット通信、セカンダリプリスケール 1:1で設定しています。
 セカンダリプリスケールは、SPI_setClockDivider( )関数で変更可能です。
  mode   :SPIの転送モードを設定します(クロック極性とクロック位相の組み合わせ) *1)
        SPI_MODE1 = クロック極性(0:LOW) クロック位相(0:アイドル0Vで、0V->5Vに変化で転送)
        SPI_MODE0 = クロック極性(0:LOW) クロック位相(1:アイドル0Vで、5V->0Vに変化で転送)
        SPI_MODE3 = クロック極性(1:HIGH) クロック位相(0:アイドル5Vで、5V->0Vに変化で転送)
        SPI_MODE2 = クロック極性(1:HIGH) クロック位相(1:アイドル5Vで、0V->5Vに変化で転送)
  divider :SPIの通信速度を設定します(プライマリプリスケール)
        SPI_PPRE_DIV4 = 4:1  (FCY/4)/セカンダリプリスケール
        SPI_PPRE_DIV16 = 16:1 (FCY/16)/セカンダリプリスケール
        SPI_PPRE_DIV64 = 64:1 (FCY/64)/セカンダリプリスケール
  sdo     :(未使用:8ビット版ライブラリとの互換性の為に残しています)

ans = SPI_setDataMode(mode)
 SPIの転送モードの変更を行う処理
 mode値はSPI_Init( )関数を参照。

ans = SPI_setClockDivider(divider1,divider2)
 SPIの通信速度の変更を行う処理
 通信速度 = (FCY/プライマリプリスケール)/セカンダリプリスケール
 プライマリプリスケール 1:1とセカンダリプリスケール 1:1の組み合わせは避ける
  divider1 :プライマリプリスケールを設定します
        3=1:1  2=4:1  1=16:1  0=64:1
  divider2 :セカンダリプリスケールを設定します
        7=1:1  6=2:1  5=3:1  4=4:1  3=5:1  2=6:1  1=7:1  0=8:1

ans = SPI_transfer(dt)
 SPI通信でのデータ送信とデータ受信を行う処理
  dt  :8ビットの送信するデータを指定します
  ans:8ビットの受信したデータを返します

(参考回路)

SPI回路図  3軸加速度センサを使った実態配線図です、
 センサーの値をI2C接続LCD(上記事)に表示させる
 回路で、電源は3.3V。

 アナログ専用電圧AVDD(28番)/AVSS(27番)は
 VDD(13番)/VSS(8・19番)と同じ電源に接続
 しています。

 内蔵のレギュレータ用にVCAP端子(20番)に、10uFの
 コンデンサーを取付けVSSに落とす必要が有ります。

1番ピンはMCLR専用なのでリセット回路を取付けないのなら1K-10KΩ抵抗でVDDに接続します。
I2C接続小型LCDモジュールについての内容は上記事と同じです。
SPI2を使っていますので、 RB12:SDI2(23番)/RB11:SDO2(22番)/RB10:SCK2(21番)にPPS機能で
割り付けています。

3軸加速度センサ(ADXL345)でSPI接続の関連記事は、12F1822での内容ですがこちらを参照下さい。
3軸加速度センサ(ADXL345)でI2C接続の関連記事は、16F1827での内容ですがこちらを参照下さい。

参考回路のサンプルソースファイルは↓ここからダウンロードして下さい。
ADXL345.zip
 ADXL345.c・・・・・・・・・・本体のソースプログラム
 skADXL345SPI.c・・・・・ADXL345関数ライブラリソースファイル(SPI用) *1)
 skADXL345SPI.h・・・・・ADXL345ライブラリ用インクルードファイル(SPI用)

 ”skI2CLCDlib”と”skI2Clib”に"skSPIlib"を上記事からダウンロードし、一緒にコンパイルします。
 尚、SPI2側を使うので、"skSPIlib.h"の"#define SPI_MSSP2_USE"の行コメントを外します。

 動作は、起動させると[OK!][NG!]が表示されます、[NG!]はセンサーの初期化に失敗しています。
 その後、X軸のみ表示させています。

《UART》

UARTの基本話はこちらを参考にして下さい。
UARTのPIC24E用日本語リファレンスマニュアルはこちらを参照下さい。

PIC24EのUART特徴は
 ・UxCTSおよびUxRTSピンによるハードウェアフロー制御(本ライブラリは未対応)
 ・70MIPSで17.5Mbps〜66bpsのbaudレートレンジ
 ・送受信バッファに4段のFIFOバッファ
 ・診断用ループバックモードをサポート
 ・IrDAエンコーダ/ デコーダロジックをサポート
 ・LINバスをサポート
 ・DMA機能が利用出来る(本ライブラリは未対応)
  (DMAは、CPUに負荷をかけずに、CPU(メモリー)とUART 間でデータを転送する機能です。)

UART、UART1とUART2のモジュールが2個有ります。
UARTの使用するピンU1RX/U1TXとU2RX/U2TXは、PPS機能で割り付けないと使えません。
例えば、下記の様に記述します。
 #include <xc.h>
 #include <PPS.h>                  // Pin Re-Mapping peripheral library

 #pragma config IOL1WAY = OFF      // 周辺機器のピン割り付けは何度でも変更出来る様に許可

   PPSUnLock ;
     iPPSInput(IN_FN_PPS_U1RX,IN_PIN_PPS_RPI44) ;   // RB12(RX1)
     iPPSOutput(OUT_PIN_PPS_RP43,OUT_FN_PPS_U1TX) ; // RB11(TX1)
   PPSLock ;
※ UARTで使用するピンU1RX/U2RXはANSELx/TRISxレジスタでデジタル入力にする必要が有ります
※ "#include <PPS.h>"のライブラリを使う場合はこちらを参照し、インストールを行います。 *3)

↓ここからUARTライブラリのソースファイルをダウンロードして下さい。
skUARTlib.zip(16ビットMCU専用) *4)

skUARTlib.h

USART機能にアクセスする為のライブラリ用のヘッダファイルです。
"skUARTlib.c"を利用する場合に
#include "skUARTlib.h" をメインプログラムの先頭で記述して下さい。

下記の様に記述されています、60MHz以外のFCYクロックに変える場合は変更します。
#ifndef FCY
  // Unless already defined assume 60MHz(60MIPS) system frequency
  #define FCY 60000000UL      // Fosc/2(60MIPS)
  #include 
#endif
受信バッファのサイズを変更する場合は下の行を変更して下さい。
(但し、UART_BUFFER_SIZE - 1 の個数だけ受信可能です、それ以上は読み捨てられます。)

#define UART_BUFFER_SIZE  64   // USARTの受信バッファサイズ

デフォルトではUART1を使う様になりますが、UART2側を使う場合は、
"#define UART2_USE"を記述して下さい。(コメントになっているので外す)
このライブラリでは、UART1又はUART2の何方か一方のみ利用可能です。

パリティビットについて *4)

通常の通信パラメータは"Data=8bit Parity=none Stop=1bit Flow=none"となります。
この設定は、"skUARTlib.h"の"#define UART_8N1"を生かします。
でぇ、パリティ(奇数)有りは"Data=8bit Parity=0dd Stop=1bit Flow=none"となります。
この設定は、"skUARTlib.h"の"#define UART_8O1"を生かします。
又、Parity=Evenの偶数パリティは"#define UART_8E1"を生かします。

パリティビット等のシリアル通信書式についてはこちらを参照下さい。

skUARTlib.c

このライブラリはUART通信を行う為の関数集です。
この関数集は”16ビットMCU専用”ですが、
24EP256MC202と24FJ64GB002でしか動作させていません。 *4)
dsPIC33E/PIC24EファミリとPIC24Fファミリのデバイスで使用出来ると思われますがぁ...
送受信相手がUARTに対応していればこの関数集は利用可能です。

UARTにアクセスを行う関数の使い方を説明します。

InitUART(rx, tx, brg)
 USART通信の初期化を行う処理
 標準速度モード、8ビット・ノンパリティ・ストップ1ビット、フロー制御無での設定です。
  rx :(未使用:8ビット版ライブラリとの互換性の為に残しています)
  tx :(未使用:8ビット版ライブラリとの互換性の為に残しています)
  brg :ボーレートを指定します(通信速度になります)
     速度が9600ボーレートなら9600と指定します。

  8ビット版ライブラリとボーレートの指定方法が異なります。

UART_Send(dt,num)
 相手に指定した個数のデータを送信する処理
  dt  :送信するデータを格納した配列を指定します
  num:送信するデータの個数を指定します。

UART_Write(dt)
 相手に1バイトのデータを送信する処理
  dt  :送信するデータを指定します

ans = UART_Available( )
 受信したデータの個数を返す処理
  ans:受信したデータの個数を返します

ans = UART_Read( )
 受信したデータを1バイト読み込む処理
  ans:受信したデータを返します、0xffffを返したら受信データは空です
 例)
   char dt ;

   if (UART_Available() != 0) {
        dt = UART_Read() ;    // 1バイトデータを受信する
        UART_Write(dt) ;      // 1バイトデータを送信する
   }
UART_Flush( )
 受信バッファをクリアする処理
 受信バッファにデータを受信していてもこの関数を実行させればデータはなくなります。

割り込み処理について

このライブラリを使うには"main.c"で以下の様に割込み許可を行います。
  _IPL = 0 ;      // CPUの割込み優先レベルを設定(優先レベル0以上を許可)
  _GIE = 1 ;      // 全割り込み処理を許可する
尚、割込み優先レベルを変更したい場合は、InitUART( )関数内の"UEIP/UTXIP/URXIP"を変更します。

skUART2lib.h *5)
skUART2lib.c

"skUARTlib"はUART1/UART2の何れかを利用する用に出来ていましたが、 "skUART2lib"は"skUARTlib"をUART2専用にした物ですので使い方は同じです。
ですので、"skUARTlib"でUART1にして"skUART2lib"でUART2を使用する事が出来ます。

skUARTlib.zip に含めて置きます。

(参考回路)

USARRT回路図  FT234X使用の超小型USBシリアル変換
 モジュール
を使った実態配線図です。
 モジュール側の5V端子は接続しません、
 外部から3.3Vを供給します。
 アナログ専用電圧AVDD(28番)/AVSS(27番)は
 VDD(13番)/VSS(8・19番)と同じ電源に接続
 しています。

 内蔵のレギュレータ用にVCAP端子(20番)に、10uFの
 コンデンサーを取付けVSSに落とす必要が有ります。

1番ピンはMCLR専用なのでリセット回路を取付けないのなら1K-10KΩ抵抗でVDDに接続します。
UART1の端子はRB12:RX1(23番)/RB11:TX1(22番)にPPS機能で割り付けています。

USBシリアル変換モジュール関連の記事は、12F1822での内容ですがこちらを参考にして下さい。

参考回路のサンプルソースファイルは↓ここからダウンロードして下さい。
FT234X.zip
 FT234X.c・・・・・・・・・・・本体のソースプログラム

後は、上記の"skUARTlib"と一緒にコンパイルします。

動作はパソコンのターミナルソフト等からデータを送ります、
PICは1バイト毎に受信し改行を付けて受信データをそのまま返します。



"skUART2lib"を追加(*5) 2020/05/13
ライブラリ更新(*4) 2019/01/24
記事一部追加(*3) 2017/06/08
"skI2Clib"に関数を追加(*2) 2016/09/30
"skSPIlib"のSPI_MODEのCKE(クロック位相)を変更(*1) 2016/06/16


【きむ茶工房ガレージハウス】
Copyright (C) 2006-2020 Shigehiro Kimura All Rights Reserved.