ADT7410 温度測定モジュール (for PIC)

ADT7410 温度測定器 (for Arduino)のPIC版です。

ハードの準備

使用したPICはPIC24FJGB002です。ADT7410のみの接続で良いのですが、測定値表示用に AQM1248A グラフィックLCD (for PIC) のLCDを使用しています。回路的にはLCDの回路にADT7410を追加した形になっています。

  • インターフェイスはI2Cなので SDA->RB9。SCL->RB8 は固定
  • ポートの設定でRB,9にプルアップを適応しても良いのですが、プルアップの値が分からないので10kオームを外付けしています。

ソフトの説明

いつもの通りMCCでI2Cの設定をしたのですが、デバイスからの読み込みが上手く行きません。MCCが作成したプログラムは問題無い様に見えるのですが結局原因が分かりませんでした。そこで今回はI2Cの部分をMCCの作成では無く自分で作成することにしました。結局 MCCでは AQM1248A グラフィックLCD (for PIC) と同じ設定を行ったのみです。

今回追加したプログラムは、

  • ADT7410用のプログラム
    • ADT7410_PIC.c:本体
    • ADT7410_PIC.h:ヘッダー
  • I2C関係のプログラム
    • i2c1_PIC.c:本体
    • i2c1_PIC.h:ヘッダー
    • PIC24FJGB002はI2Cを2つ持っていますが今回はI2C1を使用しています。
  • デモプログラム main.c:下記を行いLCDに表示します。
    • ADT7410へのレジスタの読み込み書き込み
    • 測定温度の読み込み

ADT7410.cの説明:製作した関数は3個です。

ADT7410_PIC.c

#include "xc.h"

#include "ADT7410_PIC.h"
#include "i2c1_PIC.h"
//#include "mcc_generated_files/i2c1.h"

void ADT7410_get_temp(uint8_t addr, float * f_data)
{  
  int data;
  uint8_t t_data[4];
  
  ADT7410_Read(addr, 0, t_data, 2);
  data = t_data[0]  << 8;  
  data |= t_data[1];  

  data >>= 3; 
  *f_data = data  / 16.0;      
}

//-----------------------------------------------------------------------
//  指定個数のデータを読み込む                       
//                                                                            
//    uint8_t addr      : I2Cアドレス             
//    uint8_t adrs_pt   : 読出すデータのレジスターアドレス                  
//    uint8_t *data     : 読出したデータの格納先                             
//    uint8_t len       : 読出すデータのバイト数                             
//-----------------------------------------------------------------------
void ADT7410_Read(uint8_t addr, uint8_t adrs_pt, uint8_t *data, uint8_t len)
{
    int  ack;

    I2C_Start(addr,0);                  // スタートコンディション
    I2C_Send(adrs_pt);                  // レジスタアドレスを指定
    I2C_Start(addr,1);                  // リスタートコンディション
    while(len --) 
    {
        ack = ACK;
        if (len == 0) ack = NOACK ;
        *data = I2C_Receive(ack);       // 指定個数分読み出す(受信する)
        data++ ;
    }
    I2C_Stop() ;                        // ストップコンディション
}

//-----------------------------------------------------------------------
//  指定したデータの書き込み                         
//    uint8_t addr      : I2Cアドレス             
//    uint8_t adrs_pt   : 書き込むデータのレジスターアドレス                  
//    uint8_t *data     : 書き込み用バッファーポインター                             
//    uint8_t len       : 書き込むデータのバイト数                             
//-----------------------------------------------------------------------
void ADT7410_Write(uint8_t addr, uint8_t adrs_pt, uint8_t *data, uint8_t len)
{
     int  a;

    I2C_Start(addr,0);                  // スタートコンディション
    I2C_Send(adrs_pt) ;                 // レジスタアドレスを指定
    for (a = 0 ; a < len ; a ++) 
    {
        I2C_Send(*data) ;               // 指定個数分書き込む(送信する)
        data++ ;
    }
    I2C_Stop() ;                        // ストップコンディション
}

  1. void ADT7410_get_temp(uint8_t addr, float * f_data):温度データの読み込み
    • 引数:ADT7410のI2Cアドレスと温度データを保管するfloat型の変数のポインター
    • float型の変数に測定値が保存されます。
    • (戻り値にfloatを設定したら上手く動かなかったのでこの方式にしました)
  2. void ADT7410_Read(uint8_t addr, uint8_t adrs_pt, uint8_t *data, uint8_t len)
    • 指定個数のデータを読み込む
    • 引数:
      • uint8_t addr :   I2Cアドレス
      • uint8_t adrs_pt :  読出すデータのレジスターアドレス
      • uint8_t *data :   読出したデータの格納先
      • uint8_t len :    読出すデータのバイト数
  3. void ADT7410_Write(uint8_t addr, uint8_t adrs_pt, uint8_t *data, uint8_t len)
    • 指定したデータの書き込み
    • 引数:
      • uint8_t addr :   I2Cアドレス
      • uint8_t adrs_pt :  書き込むデータのレジスターアドレス
      • uint8_t *data :   書き込むデータの格納先
      • uint8_t len :    書き込むデータのバイト数

i2c1_PIC.cの説明:I2C通信に必要な部分のみ書いています。

i2c1_PIC.c

#include <xc.h>
#include "i2c1_PIC.h"

//-----------------------------------------------------------------------
// バスがアイドルになるまで待機
//-----------------------------------------------------------------------
void I2C_IdleCheck()
{
    // ACKEN RCEN PEN RSEN SEN RBF TBF 全部が 0 
     while (( I2C_CON & 0x1F ) | (I2C_STAT & 0x03)) ;
}

//-----------------------------------------------------------------------
//  割り込みフラグクリア
//-----------------------------------------------------------------------
void __attribute__((interrupt, no_auto_psv)) _MI2C1Interrupt(void)
{
     I2C_MIF = 0 ;                                // フラグクリア
}

//-----------------------------------------------------------------------
//  I2Cマスター設定
//-----------------------------------------------------------------------
void InitI2C_Master()
{
     I2C_CON = 0x8000;              // I2C ON /スルーレート制御ON
     I2C_BRG = 0x13;                // FCY2 MHz I2C通信速度100KHz
     I2C_MIE = 1 ;                  // I2Cマスター割込みを許可する
     I2C_MIF = 0 ;                  // I2Cマスター割込みフラグをクリアする
     I2C_MIP = 3 ;                  // I2Cマスター割込み優先レベル(0-7)を設定する
}

//-----------------------------------------------------------------------
// スタート/リスタート コンディションを発行                            
//    addr : I2C Address                                     
//    sr   : 0: Start   1: Restart       
//-----------------------------------------------------------------------
void I2C_Start(int addr,int sr)              
{
     I2C_IdleCheck();                       // アイドルチェック
     I2C_CON_SEN = 1;                       // スタート出力
     while(I2C_CON_SEN) ;                   // スタート終了待ち
     
     I2C_Send((addr << 1 ) | sr);
}

//-----------------------------------------------------------------------
// ストップコンディションを発行                            
//-----------------------------------------------------------------------
void I2C_Stop()
{
     I2C_IdleCheck();
     I2C_CON_PEN = 1;
     while(I2C_CON_PEN);
}

//-----------------------------------------------------------------------
// 1バイトデータの送信
//       uint8_t dt:送信するデータ
//-----------------------------------------------------------------------
void I2C_Send(uint8_t dt)               
{
    I2C_IdleCheck();                    // アイドルチェック
    I2C_TRN = dt;                       // データをセット
    while(I2C_STAT_TBF);                // バッファーが0になるのを待つ
    while(I2C_STAT_ACKSTAT);            // 相手からのACK返答を待つ
}

//-----------------------------------------------------------------------
// 1バイトデータの受信
//      int ack: ACK or Nack
//      戻り値:データ
//-----------------------------------------------------------------------
uint8_t  I2C_Receive(uint8_t  ack)
{
     I2C_IdleCheck();
     I2C_CON_ACKDT = ack;         // ACKデータのセット
     I2C_CON_RCEN = 1;            // 受信を許可する
     // 受信を待つ
     while( (I2C_STAT_RBF != 1) | (I2C_CON_RCEN != 0) ) ;
     I2C_CON_ACKEN = 1;           // ACKデータを返す
     return I2C_RCV ;
}

main.cの説明:

main.c

/**
  Section: Included Files
*/
#include "mcc_generated_files/system.h"
#include "AQM1248A_PIC.h"
#include "i2c1_PIC.h"
#include "ADT7410_PIC.h"
/*
                         Main application
 */
int main(void)
{
    float h_data[3];
    // initialize the device
    
    uint8_t d_buf[5];
    char c_buf[30];
    
    SYSTEM_Initialize();
    InitI2C_Master();
    Init_LCD();

    while (1)
    {
        LCD_CLS(0);

        ADT7410_Read(0x48, 0x03, d_buf, 1);
        sprintf(c_buf,"State:%X", d_buf[0]);
        LCD_Print_Str(0,0,c_buf,1);
        d_buf[4] = d_buf[0];
        d_buf[0] ++;
        ADT7410_Write(0x48, 0x03, d_buf, 1);
        __delay_ms(50);
        ADT7410_Read(0x48, 0x03, d_buf, 1);
        sprintf(c_buf,"State:%X", d_buf[0]);
        LCD_Print_Str(0,10,c_buf,1);
        ADT7410_Write(0x48, 0x03, &d_buf[4], 1);
    
        __delay_ms(50);
        ADT7410_get_temp(0x48, h_data);
        sprintf(c_buf,"Temp:%0.1f'C", h_data[0]);
        LCD_Print_Str(0,20,c_buf,1);
        
        __delay_ms(1000);
    }

    return 1;
}
  • 20行:I2Cの初期設定
  • 27行:ADT7410のレジスターの読み込み
    • レジスタ0x03は測定モード設定用です。
    • イニシャルの値は、”0”です。
  • 29行:レジスタの値の表示
  • 32行:レジスタへの書き込み
    • 読み込んだ値に1を加えて0x03レジスタに書き込んでいます。
  • 34から36行:サイドの読み込みと表示
    • 0x03レジスタに ”1” を書いているので、今度は ”1”と表示されます。
  • 37行:0x03レジストをもとの値に戻す
  • 39から42行:測定温度を読み込みLCDに表示。

今回使用したADT7410のI2Cアドレスは、0x48.ADT7410の詳細は、ADT7410 温度測定器 (for Arduino)を参照下さい。

実行結果

予定通りに表示されています。

今回使用してプログラムをここに保存します。