« GPS受信モジュールGE-612Tのタイムパルス(Time Pulse)機能 | トップページ | 「写真から撮影方向を分析する」アプリ (2) »

2014年12月 2日 (火)

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) »

趣味の電子工作」カテゴリの記事

コメント

コメントを書く

(ウェブ上には掲載しません)

トラックバック

この記事のトラックバックURL:
http://app.f.cocolog-nifty.com/t/trackback/1994983/58156897

この記事へのトラックバック一覧です: PIC18F26K22でSPI - 8ch/ADコンバータ MCP3208の使い方(ソース付き):

« GPS受信モジュールGE-612Tのタイムパルス(Time Pulse)機能 | トップページ | 「写真から撮影方向を分析する」アプリ (2) »

フォト

サイト内検索

  • 記事を探されるんでしたらこれがいちばん早くて確実です。私も使ってます (^^;; 検索窓が表示されるのにちょっと時間がかかるのはどうにかしてほしいです。

新着記事

リンク元別アクセス数

  • (アクセス元≒リンク元、原則PCのみ・ドメイン別、サイト内等除く)

人気記事ランキング

  • (原則PCのみ、直近2週間)
無料ブログはココログ