第30回 温湿度・気圧センサ(BME280) 〜動作確認概要〜

目次

SPI通信確認方法

温湿度・気圧データの取得するプログラムは、データ校正部分が結構複雑になります。最初からそのプログラムを作成すると全体の見通しが悪くなってしまいます。そこで、最初はSPI通信の動作確認を行うためのシンプルなプログラムを作成することにします。

センサのメモリマップを見ると、0xD0番地にセンサのIDが保存されています。ここに保存されている値は0x60で固定となっています。

Pic practice 30 chip id

そこで、0xD0番地のデータをSPI通信で読み取るプログラムを作成し、0x60が正しく取得できるか確認することによりSPI通信の動作確認を行いたいと思います。

ところで、プログラムで0xD0番地のデータを読み取るのはいいとしても、まだLCDモジュールは動いていませんので、読み取った値をLCDモジュールに表示して確認することはできません。

そこでセンサから取得した値を確認するために、MPLABX IDEの「デバッグ機能」を使用します。デバッグ機能については、実際に使用する際に詳しく説明しますので、ここでは簡単に説明します。

今まで、PICマイコンを動作させる場合の手順は、MPLABX IDE上でプログラムを作成→ビルド→PICマイコンに書き込み→動作、というステップでした。

このような手順では、PICマイコンが思った通りに動作する場合は問題ないですが、うまく動かない場合、PICマイコンの中で何が起こっているのか知りたいですよね。

MPLABX IDEのデバッグ機能を使うと、PICマイコン内部で動作しているプログラムを指定した行で動作を止めたりして、その結果を確認しながら動作させることができます。

言葉ではなかなかイメージがつかないと思いますので、プログラム作成後、実際に手を動かして確認してみてください。

使用するピンの確認

SPI通信を行うために、PICマイコンとセンサモジュールは以下のように接続しました。

Pic practice 30 spi connection

このように接続すると、PICマイコン側のSPI通信用のピンは以下のように割り当てることになります。

ピン番号 ポート名 SPI信号線 PICマイコン入出力設定
15 RC4 CSB(チップセレクト) 出力
16 RC5 MOSI(マスター→スレーブ) 出力
17 RC6 MISO(スレーブ→マスター) 入力
18 RC7 SCK(クロック) 出力

SPI通信は、RC4〜RC7のピンをデジタル制御しながら行います。プログラムではこれらのピンは、

LATC4、RC6 (またはLATCbits.LATC4、PORTCbits.RC6)

などの記述になりますが、どのピンがどの信号線か分かりづらくなりますので、以下のように#defineすることにします。

// SPI通信ピン定義
#define SPI_SCK    LATCbits.LATC7  // クロック
#define SPI_MISO   PORTCbits.RC6   // スレーブ→マスター
#define SPI_MOSI   LATCbits.LATC5  // マスター→スレーブ
#define SPI_CSB    LATCbits.LATC4  // チップセレクト

PICマイコンのピン入出力設定は、SCK(クロック)、MOSI(マスター→スレーブ)、SS(スレーブセレクト/チップセレクト)は出力、MISO(スレーブ→マスター)は入力になります。PICマイコン全般に言えることですが、出力値制御はLATレジスタ、入力値制御はPORTレジスタを使用します。そのため、MISOのみPORTCレジスタ、それ以外はLATCレジスタを使用しています。

0xD0番地の読み出し

SPI通信で0xDO番地の読み出す場合、以下のように通信を行います。

Pic practice 30 id

また、SPI通信手順は以下のようになります。

Pic practice 30 chip id transmission

SPI通信の基本関数作成

SPI通信手順が確認できたところで、プログラムを作成します。

SPI通信は以下の部分の8ビット送信と8ビット受信の部分を関数として作成しておきます。

Pic practice 30 spi function part

8ビット送信関数

8ビット送信の部分は、以下のようにプログラムを作成します。8ビットの送信と受信の関数内部では、チップセレクト信号の制御は行わないことにします。チップセレクト信号はこの関数を使用する側で制御することにします。

Pic practice 30 spi process send

この図のように、

  1. SCKピン(クロック)を0にする
  2. MOSIピン(マスター→データ)に送信するビットデータをセットする
  3. SCKピン(クロック)を1にする

という制御を8回繰り返せばSPIデータ送信ができます。プログラムとしては以下のように作成してみました。

//
// SPIデータ8ビット書き込み
//   SCK/MOSI制御のための関数であるため
//   スレーブセレクト信号はこの関数の前後で制御すること
void spiSend8bit(uint8_t data) {

    // 8ビット分繰り返す
    for (int8_t i=7; i>=0; i--) {

        // (1)クロックを0にする
        SPI_SCK = 0;
        
        // (2)MOSIにデータをセットする
        if( data & (1<<i) ) {
            SPI_MOSI = 1;
        } else {
            SPI_MOSI = 0;
        }
      
        // (3)クロックを1にする
        SPI_SCK = 1;
    }

}

2点補足いたします。

1点目は変数型についてです。基礎編と応用編では、変数の宣言として一般的なC言語(ANSI C)に沿って「unsigned char」などを使用して変数宣言していました。実践編では、変数のビット数が分かりやすいint_t型を使用することにしました。なお、この変数型を使用する場合、stdint.hをインクルードする必要があります。

以下はその変数型になります。

変数型 意味
int8_t 符号付き8ビット
uint8_t 符号なし8ビット
int16_t 符号付き16ビット
uint16_t 符号なし16ビット
int32_t 符号付き32ビット
uint32_t 符号なし32ビット

符号付きが「int」(integer)、符号なしが「uint」(unsigned integer)、数字がビット数を表しますので、かなり分かりやすいと思います。またArduinoではこの変数型を使用することが一般的なようです。

2点目はビット演算についてです。最近のiOSやAndroidなどのプログラミングではあまりビット演算が必要な場面は出てこないと思います。一方で電子工作で使用するPICマイコンやArduinoでは、意外にビット演算が必要な場合があります。

実践編のプログラムの中では、「<<」や「|」などの記号がよく出てきますので、よくわからない場合はもう一度ビット演算全般を復習されてみてください。

8ビット受信関数

8ビット受信の部分は、以下のようにプログラムを作成します。

Pic practice 30 spi process receive

この図のように、

  1. SCKピン(クロック)を0にする
  2. SCKピン(クロック)を1にする(この段階でスレーブのデータが読めるようになっている
  3. MISO(スレーブ→マスター)のデータを読む

という制御を8回繰り返せばSPIデータ送信ができます。プログラムとしては以下のように作成してみました。

//
// SPIデータ8ビット読み込み
//   SCK/MOSI制御のための関数であるため
//   スレーブセレクト信号はこの関数の前後で制御すること
//
uint8_t spiReceive8bit(void) {

    // 受信データ格納変数
    uint8_t read_data = 0;

    // 8ビット分繰り返す
    for (int8_t i=7; i>=0; i--) {

        // 受信データ変数を1ビット左シフト
        read_data <<= 1;

        // (1)クロックを0にする
        SPI_SCK = 0;
        
        // (2)クロックを1にする
        SPI_SCK = 1;

        // (3)この時点でセンサからのデータを読めるので、MISOのピン状態を読む
        if(SPI_MISO){
            read_data |= 1;
        }
    }

    // 受信したデータを返す
    return read_data;

}

8ビットの送信、受信関数ができましたので、これらの関数を利用して0xD0番地のデータを読み取るプログラムを作成します。

更新履歴

日付 内容
2018.4.27 新規投稿
2019.4.20 ソースコード文字化け修正
通知の設定
通知タイミング
guest
6 コメント
新しい準
古い順 一番投票が多い
本文中にフィードバック
全てのコメントを見る
aaa
aaa
3 年 前

お世話になります
// 受信データ変数を1ビット左シフト
        

read_data <<= 1;
の個所ですが
1ビットシフトしたら2番目に行くのではと思って
シフト無しで確認しても結果は同じでした
初期値は0でも1シフトでも同じという事で良いんですかね
デバックが使えだして理解が深まりそうです

aaa
aaa
返信  管理者
3 年 前

返信ありがとうございます
昨日やってたことが今日見たら分からない状況で
酒飲みながら朦朧としながらやってるんで
物凄い勘違いしてたような気がします

初学者
初学者
4 年 前

読んでいて自己解決しました。
ビット位置をずらすためですね。
申し訳ありませんでした。

初学者
初学者
4 年 前

上記プログラム(8ビット受信関数)で初歩的ではありますが質問があります。

14行名
// 受信データ変数を1ビット左シフト
read_data <<= 1; と記載がありますがこの理由を詳しく聞きたく。

目次