PIC18F26K22でSPI - 8ch/ADコンバータ MCP3208の使い方(ソース付き)
I2Cの記事もいろいろ書いたので今度はSPIの記事です。I2Cと同じとは言ってもやっぱり違うところはあります。複数のデバイスを使うときI2Cだとバスにつぎつぎにぶらさげていくわけですが、SPIだとデイジーチェーンでつないでいくことになります(ふつうはI2Cと違いプルアップ抵抗は不要です) <== ここの記述は不正確でした。すみません。複数のSPIデバイスを接続する話はまた別に記事にしたいと思います。
==> 解決はしましたが....
「SPI接続でトラブル! 複数のデバイスが使えない」
今回は最初なのでSPIと(LCD表示のための)I2Cが別々に使えるPIC18F26K22でやってみました。このシリーズPIC18F23K22、PIC18F24K22、PIC18F25K22、PIC18F26K22、PIC18F43K22、PIC18F44K22、PIC18F45K22、PIC18F46K22とあるわけですが、どれもゴツくて小さいブレッドボードじゃ使いにくいです。
ひと通りやってみて結論としてはI2Cと同じでなんてことはなかったということになるのですが、いろいろたいへんでした。たとえばPICのSDOをMCP3208のDoutとつないでしまって動かないことに悩んだり.... (^^;;
だから疲れてしまって今日はソースだけです。と言ってもいつもどおり肝心なところはきむしげさん(きむ茶工房ガレージハウス)の丸パクリです。今回は「MMC/SDカードを接続し読書きを行って見ます」にあるソースを参考にさせていただきました。参考というかそのまま使わせていただきました m(._.)m
======
今はADコンバータはMCP3425(「MCP3425のもうちょっと詳しい使い方(ソース付き)」)を使っています。16bitの分解能があり精度もなかなかのものです。ただ同時にいくつかの場所の電圧あるいは電流を測りたいときがあり、そういうときは二つ必要です。アドレスが同じになりますので「同じアドレスのI2Cデバイスを使う」に書いたような方法をとる必要があり面倒です。あるいはこの記事に書いたアナログ・スイッチを使って一台のMCP3425の入力を切り替えるという方法もありますが、これはこれで実際にやってみるとちょっと問題がありました。
そこで8チャンネル(擬似差動4チャンネル__擬似というのはふつうの差動入力とは違ってGNDレベルの補正用みたいです。Vin-の入力範囲は限定的です)使えるMCP3208に目をつけてやってます。ただデータシートを見ると不安材料もあります。
今回の実験(?)の本題はじつはそこにあるのですが、そこらあたりの事情はまた記事にしたいと思います。
-------
回路図を書くのが面倒なのでどういう具合に接続されているかだけ書いておきます。
カッコつきの数字はPickKit3のピン番号です。
// 01 /MCLR .....(1)
// 02 RA0/AN0 ====> MCP3208のNo.10 /CS/SHDN
// 14 RC3/SCL1 =====> I2Cバス
// 15 RC4/SDA1 =====> I2Cバス
// 19 VSS .....(3)
// 20 VDD .....(2)
// 22 RB1/INT1/P1C/SCK2/SCL2/C12IN3-/AN10 =====> MCP3208のNo.13 CLK
// 23 RB2/INT2/CTED1/P1B/SDI2/SDA2/AN8 =====> MCP3208のNo.12 DOUT
// 24 RB3/CTED2/P2A/CCP2/SDO2/C12IN2-/AN9 =====> MCP3208のNo.11 DIN
// 27 RB6/TX2/PGC .....(5)
// 28 RB7/RX2/PGD .....(4)
今は電源電圧3.3Vで両方を使っておりMCP3208のNo.15 VrefもVDDに接続しています。
ソースでVref=3.3 となっているのはそのためです。
MCP3208/MCP3204はデジタルのグランドとアナログが別になっており今はどちらもVSSのラインに接続してテストしていますが本格的に使うときはそれなりの配慮が必要になっています。
------
関連
趣味の電子工作
PIC
「PICでSPI SDカードを読み書きする」
「PICでSPI - 超高精度SPIバスRTC(リアルタイムクロック)DS3234Sの使い方」(ソース付き)
「PICでSPI - 超高精度SPIバスRTC(リアルタイムクロック)DS3234Sの実装」
--------
main.c
「I2Cのソース - PIC12F1822/16F1705/16F1938/18F26K22 - LCD(ACM1602)を例にして」のときと同様に“至れり尽くせり”じゃなくて“最低限何が必要か”という視点でコーディングしてあります。
データを得るためのコマンドは5ビットだけです。スタートビット(“1”)、シングルエンド入力(“1”)か(仮想)差動入力(“0”)を示すビットのあとにチャンネルを示す3ビットの5ビットから構成されています。ただしこの5ビットの上位3ビットを最初のバイトの下位に、下位2ビットを次のバイトの上位にセットします。この二つのバイトにダミーの1バイトを含む3バイトを送信します。MCP3208からはこれに対して同じく3バイトの返信があるのですが、こちらはに2イト目の下位4ビットに3バイトの8ビットをつないだ12ビットが電圧データということになります。
下記のソースでは“i”の下位3ビットでチャンネルを選択しながらシングルエンドの八つの入力を順次測っています。結果はLCDに四つずつ2画面に分けて表示しています。
#include <xc.h> #include <stdio.h> #include "MyDef.h" #include "I2CLib.h" #include "SPILib.h" #include "ACM1602lib.h" // C:\Program Files (x86)\Microchip\xc8\v1.32\docs\chips\18f26k22.html #pragma config FOSC = INTIO67 #pragma config WDTEN = OFF void putLCDhex(unsigned char ch) { char hex[]="0123456789SBCDEF"; LCD_Putc(hex[ch>>4]) ; LCD_Putc(hex[ch & 0x0f]) ; } void interrupt InterFunction( void ) { // I2C関連の割り込み処理 InterI2C() ; } void main() { unsigned short i=0; int j; unsigned char d1,d2,d3; float Vref=3.3; float value; char buf[20]; OSCCON = MyOSCCON ; // for I2C ANSELCbits.ANSC3 = 0; ANSELCbits.ANSC4 = 0; // for SPI ANSELBbits.ANSB2 = 0; ANSELBbits.ANSB1 = 0;ANSELAbits.ANSA0 = 0;TRISB1 = 0; TRISB3 = 0; // /CS TRISA0 = 0; PORTAbits.RA0 = 1; SPI_Init(SPI_MODE0,SPI_CLOCK_DIV64) ; InitI2C_Master() ; LCD_Init() ; LCD_Clear(); while(1) { PORTAbits.RA0 = 0; d1=SPI_transfer(0x06 | ((i >> 2) & 0x01) ) ; d2=SPI_transfer( i << 6 ); d3=SPI_transfer(0x00); PORTAbits.RA0 = 1; // LCD_SetCursor(0, 1); // putLCDhex(d1); // putLCDhex(d2); // putLCDhex(d3); value = (float)(d2 & 0x0F)*256.0 + (float)d3; value = Vref * value/4096.0; sprintf(buf,"%4.1f",value); LCD_SetCursor((i << 2) & 0x0f, (i >> 2) & 0x01 ); LCD_Puts(buf); for( j=0; j < 12; j++ ) __delay_ms(40); i++; } }
SPIlib.h
ここはきむしげさん(きむ茶工房ガレージハウス)のソースと同じです。
/******************************************************************************* * skSPIlib.h - SPI通信を行う関数のインクルードファイル * * (16F1938/19xxシリーズ用) * * * * ============================================================================ * * VERSION DATE BY CHANGE/COMMENT * * ---------------------------------------------------------------------------- * * 1.00 2012-04-30 きむ茶工房 Create * * 1.11 2014-06-21 きむ茶工房(きむしげ) SPI_MODEのコメントを変更 * * 2.00 2014-09-03 きむ茶工房(きむしげ) 割込み処理止めた * *******************************************************************************/ #ifndef _SKSPILIB_H_ #define _SKSPILIB_H_ #define LOW 0 #define HIGH 1 #define SPI_MODE0 0 // クロック極性(0:LOW) クロック位相(0:アイドル0Vで、0V->5Vに変化で転送) #define SPI_MODE1 1 // クロック極性(0:LOW) クロック位相(1:アイドル0Vで、5V->0Vに変化で転送) #define SPI_MODE2 2 // クロック極性(1:HIGH) クロック位相(0:アイドル5Vで、5V->0Vに変化で転送) #define SPI_MODE3 3 // クロック極性(1:HIGH) クロック位相(1:アイドル5Vで、0V->5Vに変化で転送) #define SPI_CLOCK_DIV4 0x0 // 通信速度 Fosc/4 #define SPI_CLOCK_DIV16 0x1 // 通信速度 Fosc/16 #define SPI_CLOCK_DIV64 0x2 // 通信速度 Fosc/64 #define SPI_CLOCK_DIVT2 0x3 // 通信速度 TMR2の出力の1/2 void SPI_Init(char mode,char divider) ; char SPI_transfer(char dt) ; #endif
SPIlib.c
ここもきむしげさん(きむ茶工房ガレージハウス)のソースと同じですが、レジスタ名はPIC18F16K22に合わせてあります。
/******************************************************************************* * skSPIlib.c - SPI通信を行う関数ライブラリ(16F1938/19xxシリーズ用) * * * * SPI_Init - SPIモード(マスター)の設定と初期化を行う処理 * * SPI_transfer - SPI通信でのデータ送信とデータ受信を行う処理 * * * * メモ:SDIピンは必ず「デジタル入力ピン」に設定を行って下さい。 * * ============================================================================ * * VERSION DATE BY CHANGE/COMMENT * * ---------------------------------------------------------------------------- * * 1.00 2012-04-30 きむ茶工房(きむしげ) Create * * 1.01 2013-01-15 きむ茶工房(きむしげ) XC8 C Compiler 対応に変更 * * 1.11 2014-06-21 きむ茶工房(きむしげ) SPI_Init関数のコメントを変更 * * 2.00 2014-09-03 きむ茶工房(きむしげ) 割込み処理止めた * * 2.10 2014-09-27 きむ茶工房(きむしげ) SPI_Init関数を変更 * * x.xx 2014-12-02 Seppina PIC18F26K22対応 * * ============================================================================ * * PIC 16F1938/19xx * * MPLAB IDE(V8.84) MPLAB X(V2.15) * * MPLAB(R) XC8 C Compiler Version 1.00/1.32 * *******************************************************************************/ #include <xc.h> #include "MyDef.h" #include "SPIlib.h" /******************************************************************************* * SPI_Init(mode,divider) * * SPIモードの設定と初期化を行う処理 * * 割り込みでの処理を止めて直接"SSP1IF"を見る様にしています * * * * mode : SPIの転送モードを設定します(クロック極性とクロック位相の組合せ) * * SPI_MODE0 = 極性(0:LOW) 位相(0:アイドル0Vで、0V->5Vに変化で転送)* * SPI_MODE1 = 極性(0:LOW) 位相(1:アイドル0Vで、5V->0Vに変化で転送)* * SPI_MODE2 = 極性(1:HIGH) 位相(0:アイドル5Vで、5V->0Vに変化で転送)* * SPI_MODE3 = 極性(1:HIGH) 位相(1:アイドル5Vで、0V->5Vに変化で転送)* * divider : SPIの通信速度を設定します * * SPI_CLOCK_DIV4 = Fosc/4 * * SPI_CLOCK_DIV16 = Fosc/16 * * SPI_CLOCK_DIV64 = Fosc/64 * * SPI_CLOCK_DIVT2 = TMR2の出力の1/2 * *******************************************************************************/ void SPI_Init(char mode,char divider) { char con , stat ; con = 0b00100000 ; // クロック極性はLOW マスタモードでFOSC/4のクロックに設定 stat = 0b00000000 ; // クロック位相は立下りでデータを送信 con = con | divider ; // 指定のクロック速度を設定する if (mode == SPI_MODE1 || mode == SPI_MODE3) { stat = stat | 0x40 ; // 指定のクロック位相を設定する } if (mode == SPI_MODE2 || mode == SPI_MODE3) { con = con | 0x10 ; // 指定のクロック極性を設定する } SSP2CON1 = con ; SSP2STAT = stat ; SSP2IF = 0 ; // SPIの割込みフラグを初期化する } /******************************************************************************* * ans = SPI_transfer(dt) * * SPI通信でのデータ送信とデータ受信を行う処理 * * * * dt : 8ビットの送信するデータを指定します * * ans : 8ビットの受信したデータを返します * *******************************************************************************/ char SPI_transfer(char dt) { SSP2BUF = dt ; // データの送信 while(SSP2IF == 0) ; // 受信待ち SSP2IF = 0 ; // フラグクリア return SSP2BUF; }
I2CとLCD表示のライブラリは「I2Cのソース - PIC12F1822/16F1705/16F1938/18F26K22 - LCD(ACM1602)を例にして」と同じです。 MyDef.hはクロックを変えたとき関連箇所の直し忘れがないようにちょっと変更しました。
/* * File: MyDef.h * Author: Seppina * * Created on 2014/11/22, 14:38 */ #ifndef MYDEF_H #define MYDEF_H // http://www.microchip.jp/docs/41406B_JP.pdf #ifdef _12F1822 #define _XTAL_FREQ 16000000 #define MySSPADD 0x27 #define SSPIE SSP1IE #define SSPIF SSP1IF #define BCLIE BCL1IE #define BCLIF BCL1IF #endif // http://ww1.microchip.com/downloads/en/DeviceDoc/40001729A.pdf // http://ww1.microchip.com/downloads/jp/DeviceDoc/40001722A_JP.pdf // (下は16F1703のものですが参考になります。これもきむしげさん情報です) #ifdef _16F1705 #define _XTAL_FREQ 8000000 #define MySSPADD 0x13 #define SSPIE SSP1IE #define SSPIF SSP1IF #define BCLIE BCL1IE #define BCLIF BCL1IF #endif // http://ww1.microchip.com/downloads/en/DeviceDoc/40001574C.pdf #ifdef _16F1938 #define _XTAL_FREQ 8000000 #define MySSPADD 0x13 #endif // http://ww1.microchip.com/downloads/en/DeviceDoc/41412F.pdf #ifdef _18F26K22 #define MyOSCCON 0b01110010 #define _XTAL_FREQ 16000000#define MySSPiADD 0x27#define MySSPsADD 0x27#define MySSPADD 0x27 #endif #endif /* MYDEF_H */
« GPS受信モジュールGE-612Tのタイムパルス(Time Pulse)機能 | トップページ | 「写真から撮影方向を分析する」アプリ (2) »
「趣味の電子工作」カテゴリの記事
- PICで作る100MHz周波数カウンタ検証用XOR(エクスクルーシブオア)逓倍器(2016.03.08)
- 150MHz(~200MHz?)周波数カウンター用プリスケーラー(1/4分周器)(2016.03.06)
- 測温抵抗体(Pt100、白金薄膜温度センサー)の抵抗値を温度に変換する(平方根を使わない)計算式(2016.03.01)
- GPS/JJY(標準電波)を基準周波数源とするためのPLLの詳細(2016.02.27)
- GPS受信モジュール1PPS対決 - GE-612T vs GM-5157A(2016.02.21)
コメント
この記事へのコメントは終了しました。
« GPS受信モジュールGE-612Tのタイムパルス(Time Pulse)機能 | トップページ | 「写真から撮影方向を分析する」アプリ (2) »
ブランドコピーブランドN級品専門店
史上最も激安ブランドコピー-即日 配送可,100%入荷。
当店は正規品と同等品質は品質3年保証でご注文から5 日でお届け致します。
レディースとメンズ激安通販専門店!品質と本物は同様です。ブランドコピー時計
全て新品、高い品質、激安 、送料は無料です( 日本全国)すべての商品は品質2年無料
投稿: ロレックス 偽物 販売 大阪 | 2021年12月 5日 (日) 15時44分