C言語

ラズパイでSPI通信に挑戦!(実装編)| C言語

スポンサーリンク

こんにちは!まっきー(@makky_study)です。

ラズパイでSPI通信に挑戦!①に引き続き、SPI通信を学習していきます。

今回は、実際にプログラムを書いて、動かしていきます。

では、早速始めていきましょう!

今回作成するもの

可変抵抗で電圧の値を変え、その値を1秒ごとに出力するプログラムを作成する。こんな感じ↓

準備

用意するもの

  • Raspberry Pi3B+
  • ブレッドボード
  • 10キロΩの可変抵抗
  • A/Dコンバータ(MCP3008)
  • ジャンパー線(オス・メス)
  • ジャンパー線(オス・オス)

今回の目的は、可変抵抗をクルクルと操作することによって、画面にその時の電圧を表示させることです。

そのためには、電圧値を計算しなければいけません。MCP3008のデータシートに基づき、以下に計算方法をまとめました。

  • LSB Size:分解能の値
  • DigitalOutputCode:デジタルの出力値

例えば、基準電圧が3.3V、電源電圧も3.3Vだったとします。その場合、DOCは1023(0も含んでいるため)となります。

可変抵抗によってVinの値を表示させたいので、この式を少し変形し次のようにします。

Vin = Vref / 1024 * DOC

例を見てみましょう。DOCが最大の1,023だったとすると、式より

Vin = 3.3/1024*1023 ≒ 3.297 となります。

この太字の結果をターミナルに表示できるようにプログラムを組んでいきます。

電子回路図を見ていきましょう。

電子回路

まず、ラズパイとA/Dコンバータのピン配置を確認しておきましょう。

回路図のICはMCP3008 ではないですが気にしないでください。

コード

SPI通信用のライブラリ関数を紹介します。

使用するライブラリ関数

  • wiringPiSPI.h:SPIヘッダファイル
  • wiringPiSPISetup(int ssNo,int speed) :SPI通信速度(500kHz~32MHzで設定可能)
  • wiringPiSPIDataRW(int ssNo,unsigned char *data,int len) :送受信するバイト型の配列、送受信するデータの長さ
#include <stdio.h>
#include <string.h>
#include <wiringPi.h>
#include <wiringPiSPI.h>

#define SS0 0
#define SPI_SPEED 500000 //500khz

#define MCP3008_CH3 3

unsigned short Mcp3008RW(int ssNo,unsigned char adcChannel){//スレーブナンバー、アナログ入力チャンネル(3)
	unsigned short doc = 0;//digital output codeの値を戻り値とする
	unsigned char buff[3];//1bit char型
	buff[0]=buff[1]=buff[2]=0;
	buff[0] = 0b00000001;
	buff[1] = 0b10110000;
	buff[2] = 0b00000000;
	wiringPiSPIDataRW(ssNo,buff,sizeof(buff));//これでデータ送信、受信を行う
	doc = (((buff[1]&3) <<8 ) | buff[2] );
	return doc;
}

int main(void){
	unsigned short doc = 0;
	wiringPiSetupGpio();
	wiringPiSPISetup(SS0,SPI_SPEED);
	while(1){
		doc = Mcp3008RW(SS0,MCP3008_CH3);
		printf("CH3 = %3XH",doc);
		printf("\tvoltage = %5.3f V\n",((3.3/1024)*(doc)));
		delay(1000);
	}
	return 0;
}

次に、関数詳細です。前回重要になるといったこのタイミングチャートと表を見比べながら見ていきましょう。

画像に alt 属性が指定されていません。ファイル名: image-10-1024x959.png

1~4行目 ヘッダーファイルインクルード

6~9行目 周波数、スレーブ番号、チャンネルをマクロ定義

11~21行目 A/D変換の通信処理を行う関数(表と見比べながら見てください)

最後の式を詳しく説明します。

doc = (((buff[1]&3) <<8 ) | buff[2] )

結論から言うと、docは出力データですのでB0~B9の10個の情報を格納する処理になります。

例えば、buf[1] = 0b00000010,buff[2]=0b10110010が入っていたとします。B0~B9までの10この値を取り出したいので、buff[1]を3つまり二進数で0b00000011。これを&演算をすることで下位2ビットを取り出せます。8ビット左シフトし、or演算でbuff[2]の値を合わせることで10bitのデータ0b1010110010が取り出せます。

メイン関数では、取り出した値を計算して表示しているだけなので、説明は省略します。

実際にプログラムを動かしてみると…

電圧の値が変わっていることがわかると思います。

目的達成です!

まとめ

  • ラズパイでのA/D変換はSPI8bitセグメント通信で行う
  • データシートを読み込むことで仕組みはある程度理解できる

ブラックボックスだったA/D変換の理解が、個人的にはかなり深まりました。

そろそろ、自分で成果物を決めて作成してみたいですね…

次にやりたい
I2Cを使ってLCDに文字を表示させる!①(C言語)
I2Cを使ってLCDに文字を表示させる!①(C言語)

続きを見る

次にやりたい
I2Cを使ってLCDに文字を表示させる!②(C言語)

続きを見る

スポンサーリンク

-C言語