ディジタル温度センサー Sー5851




 Arduinoの項でも扱っていますが、同じ温度センサーS-5851をR8C/M12Aでも試してみました。思った以上にすんなりとはいきませんでしたが、何とか温度を読み取ることができました。エイブリックのマニュアルには「2ワイヤシリアル入出力のデジタル温度センサ」と記されていますが、何故I2Cとは記載されていないのかはよくわかりません。温度レジスタは2バイト連続で読み取るように記載されていますが、Readの連続読み込みができずに悩んでいたのですが、もう一度、ReadとWriteの基本事項を確認してみます。


     T.温度センサーS-5851Aの概要

     U.パソコン画面に温度表示する

     V.SPI LCD画面に温度表示する


T.温度センサーS-5851Aの概要

1)I2C Readの連続読み込みをするには

◎I2C Writeの手順

◎I2C Readの手順


以上を図示化すると下のようになります


 温度データは最初の1バイト(8ビット)と次の1バイト(上位4ビット)の合計12ビットデータ長です。12ビット補数形式の温度データで最小単位で0.0625℃の分解能と記述されていますので、12ビットのMSB(最下位ビット)が0.0625℃となります。2バイト目に読み込む上位4ビットデータが小数点以下の桁を表示することになります。

 温度レジスタのデータは必ずしもすべてを受信する必要はないとのことです。通常は小数点以下の温度データが必要ない場合が多いと思います。最初の1バイト目を読み取った後、マスタデバイスからのACK信号を返さずに、続けてストップコンディションを入力することで通信を終了することができます。この場合は、読み取った最初の8ビット(16進2桁)データを10進数に変換するだけで直接の温度データということになります(0.0625×16=1)。+−1℃程度の誤差はありますが、厳密さを求めないのであれば、これで十分だと思います。


2)レジスタの構成

◎ポインタレジスタ
 ポインタレジスタは8ビットの読み出しまたは書き込みを行うレジスタを指定するレジスタです。ポインタレジスタへ00hを書き込むと温度レジスタを読み出すことができます。
P0
MSB                  LSB

◎温度レジスタ
 温度レジスタは2バイトに別れており、連続で読み取りを行います。最初の1バイト目の8ビットと2バイト目の上位4ビットの合計12ビットが温度データになります。補数形式のデータで収納されており、最初の1バイト目のMSBが1のときは負、0のときは正の温度データになります。分解能は0.0625℃です。

温度レジスタ 1バイト目
T11 T10 T9 T8 T7 T6 T5 T4
MSB                  LSB
 最上位ビット(T11)は温度の正負を表します

温度レジスタ 2バイト目
T3 T2 T1 T0
MSB                  LSB




◎コンフィギュレーションレジスタ
 コンフィギュレーションレジスタは8ビットの読み書き可能なレジスタで、S-5851Aシリーズの動作モードを制御するビットを格納しています。

  SDビット・・・シャットダウンモード(SD)ビットに1を書き込むと、シリアルインターフェイス以外の回路が停止するため消費電力を節約できます。


  OSビット・・・ワンショットモード(OS)ビットに1を書き込むと、1回のみの温度変換が始まります。この1回の温度変換が終了し、
         温度レジスタのデータを更新すると、再びシャットダウン状態に戻ります。

OS SD
MSB                  LSB
 


U.パソコン画面に温度表示する

◎結線図

                               
 S-5851側  
R8C/M12A側
 1 SCL P3_4に接続
 2 VSS  GNDに接続
 3 AD1 GNDに接続
 4 SDA 10KΩでプルアップP3_3に接続
 5 AD0 GNDに接続
 6 VDD 5V
P1_4(TXDに接続)
P1_5(RXDに接続)

P1_4、P1_5はUSB-シリアル変換モジュール(FT231X)に接続してパソコン画面に表示しています


結 線 図(表 面)






◎プログラム構成

 プログラムは以下の3部から構成されています

 EM_S8551_2.c ・・・メインプログラム
 i2c_ctrl.c    ・・・コントロール関数
 i2c_ctrl.h    ・・・ヘッダーファイル



1)EM_S8551_2.c ・・・メインプログラム

01:#include "sfr_r8m12a.h"
02:#include "i2c_ctrl.h"
03:void main(void)
04:{
05: unsigned char idt,a,b;
06: unsigned char rdata;
07: unsigned char i;
08: unsigned char add;
09: unsigned long T,afd,abd;// afd:After decimal point小数点以下の値 abd:Above decimal point 小数点以上の値
10: float temp;
11: init();
12: set_UART0();
13: add=0x90; // addr=0x48( 100 1000) → 0x90(1001 0000)
14: UART0_tx_str("S5851 TEST");
15: CRLF();
16: add=0x90; // device address
17: I2C_start(); // startコンディション
18: IO_write(add,0x00); // 0x00 ポインタレジスタ呼び出し
19: while(1){
20:  I2C_start();// 再度startコンディション発行する
21:  do{
22:   idt=I2C_write(add|0x01);// S5851にスレーブアドレス(読み込み時)を送る
23:   delay();
24:  }while(idt !=0);   // ACK信号を待つ
25:  a=I2C_read();    // S5851からデータを読み込み
26:  ACK();        // ACK をdeviceに返す
27:  b=I2C_read();    // 次の1バイト読み込み ACK応答なし
28:  delay();
29:  I2C_stop();     // ACKなし I2Cストップコンディションで読み取り終了
30:  wait_us(1000);
31:  T=((unsigned long)a<<8 | (unsigned long)b)>>4;// 12ビット形式になおす
32:// UART0_tx_hex(T,3);CRLF();
33:  if(T & 0b100000000000 ){  // 負数の場合(最上位ビット1)の処理
34:   T=(0b1000000000000 - T ); // 補数処理
35:   abd = T>>4;        // 小数点以上の値
36:   afd = T & 0b000000001111; // 小数点以下の値
37:   UART0_tx_str("-");
38:   UART0_tx_num((float)abd,2);
39:   UART0_tx_str(".");
40:   UART0_tx_num((float)afd*0.0625*100,2);
41:   UART0_tx_str(" ℃");
42:  }
43:  else{            // 正数の場合(最上位ビット0)の処理
44:   abd = T >>4;       // 小数点以上の値
45:   afd = T & 0b000000001111;// 小数点以下の値
46:   UART0_tx_num((float)abd,2);
47:   UART0_tx_str(".");
48:   UART0_tx_num((float)afd*0.0625*100,2);
49:   UART0_tx_str(" ℃");
50:  }
51:  CRLF();
52:  CRLF();
53:  wait_ms(1000);
54: }
55:}
56:/* I/O 初期化関数 */
57:void init(void)
58:{
59: int i;
60: prc0 = 1;// プロテクトレジスタ解除
61: hocoe = 1;// 高速オンチップオシレータ発振開始
62: for(i=0;i<50;i++);// 発振安定まで待つ
63: hscksel = 1;// 高速オンチップオシレータ選択ビットを1にする
64: scksel = 1;// システム基準クロックを高速にする
65: prc0 = 0;// プロテクトレジスタ禁止
66: pd3 = 0x18; // p3_3,p3_4 出力設定 0001 1000
67:}



2)i2c.ctrl.c ・・・コントロール関数 (I2C関数のみ抜粋)

  ・
46:void I2C_start(void) //start コンディション
47:{
48: I2C_EDA_OUT; // SDA 出力
49: I2C_S_EDA;  // SDA High
50: I2C_H_CLK(); // CLK High
51: delay();
52: I2C_C_EDA;  // SDA Low
53: delay();
54: I2C_L_CLK(); // CLK Low
55:}
  ・
59:void I2C_stop(void) //stop コンディション
60:{
61: I2C_EDA_OUT;// SDA 出力
62: I2C_C_EDA; // SDA Low
63: I2C_H_CLK();// CLK High
64: delay();
65: I2C_S_EDA; // SDA High
66: delay();
67: I2C_L_CLK();// CLK Low
68:}
  ・
  ・
72:void I2C_H_CLK(void) //クロックをHighにする
73:{
74: I2C_S_SCL;
75: delay();
76:}
  ・
  ・
80:void I2C_L_CLK(void) //クロックをLowにする
81:{
82:I2C_C_SCL;
83:delay();
84:}
  ・
  ・
89:void ACK(void) //ACKNOWLEDGE Master → Slave
90:{
91: I2C_EDA_OUT;
92: I2C_C_SCL;
93: I2C_C_EDA;// ack信号
94: I2C_S_SCL;
95: delay();
96: I2C_C_SCL;
97: delay();
98: I2C_EDA_IN;
99:}
  ・
  ・
105:int I2C_write(unsigned char data)// 書き込みの基本関数
106:{
107: int i;
108: int ack;
109: I2C_EDA_OUT;
110: for(i=0;i<8;i++){ // 上位から1ビト毎にクロックと共に送信
111:  if(data & 0x80){ // ビットの値がHigh(=1)だったら
112:   I2C_S_EDA; // データラインをHigh(=1)にする
113:  }
114:  else{
115:   I2C_C_EDA;// ビットの値がLow(=0)データラインをLow
116:  }
117:  delay();
118:  I2C_H_CLK();// クロックを作る
119:  I2C_L_CLK();// 送信
120:  data<<=1;// 次のビットへシフト
121: }// 8ビット繰り返す
122: I2C_EDA_IN;// データラインを入力モードにする
123: I2C_H_CLK(); // クロック信号を作る
124: ack=I2C_EDA_data;// クロックHighの状態でP3_3の値をackに入れる
125: I2C_L_CLK(); // クロックLow
126: delay();
127: I2C_EDA_OUT; // P3_3を出力に戻す
128: return ack; // ACK信号を戻り値
129:}
  ・
  ・
135:unsigned char I2C_read(void)// 読み込み基本関数
136:{
137: int i;
138: unsigned char data;
139: data=0x00;
140: I2C_EDA_IN;
141: for(i=0;i<8;i++){
142:  data<<=1;
143:  I2C_S_SCL;
144:  delay();
145:  data |=(I2C_EDA_data);
146:  I2C_C_SCL;
147:  delay();
148: }
149://ACK();// ACK信号を出力する
150: return data;// data戻り値を返す
151:}
  ・
  ・
153:void IO_write(unsigned char add,unsigned char data)// S5851にデータを出力する関数
154:{
155: unsigned char idt;
156: I2C_start(); // I2Cスタートコンディション
157: do{
158:  idt=I2C_write(add); // S5851にスレーブアドレスを送る
159: }while(idt !=0);// ACK信号を待つ
160: do{
161:  idt=I2C_write(data);// 出力データを送る
162: }while(idt !=0);// ACK信号を待つ
163:}
  ・
  ・
  ・



3)i2c_ctrl.h ・・・ヘッダーファイル

01:/********************************************/
02:/* i2c_ctrl.h */
03:/********************************************/
04:#define I2C_S_SCL p3_4=1 // I2Cクロック p3_4を1にする
05:#define I2C_C_SCL p3_4=0 // I2Cクロック p3_4を0にする
06:#define I2C_S_EDA p3_3=1 // I2Cデータ p3_3を1にする
07:#define I2C_C_EDA p3_3=0 // I2Cデータ p3_3を0にする
08:#define I2C_SCL_OUT pd3_4=1 // p3_4を出力ポートに設定
09:#define I2C_EDA_IN pd3_3=0 // p3_3を入力ポートに設定
10:#define I2C_EDA_OUT pd3_3=1 // p3_3を出力ポートに設定
11:#define I2C_EDA_data p3_3// データポートをp3_3に設定
12:#define DEV_ADD 0x39// アドレス 0B 011 1001+(c/w)
13:#define CLOCK 20000
14:/*======================================*/
15:/* プロトタイプ宣言 */
16:/*======================================*/
17:void init(void); 18:void wait_us(unsigned long usec);// us単位のタイマ
19:void wait_ms(unsigned long msec);// ms単位のタイマ
20:void delay(void); // 6usの遅延関数
21:void I2C_start(void);// I2C開始
22:void I2C_stop(void);// I2Cストップ
23:void ACK(void);// ACKNOWLEDGE信号送信
24:void I2C_H_CLK(void);// クロックHigh
25:void I2C_L_CLK(void);// クロックLow
26:int I2C_write(unsigned char data);// 書き込みの基本関数
27:unsigned char I2C_read(void);// 読み込みの基本関数
28:void IO_write(unsigned char add,unsigned char data);// S5851にデータを出力する関数
29://unsigned long IO_read(unsigned char add);// S8551からデータを受け取る関数
30:void set_UART0(void);
31:int UART0_rx(void);
32:int put_uart0(char r);
33:int UART0_tx_hex(unsigned long value,int keta);
34:void UART0_tx_num(unsigned long value,int keta);
35:void UART0_tx(unsigned int data);
36:void UART0_tx_str(char *str);
37:void CRLF(void);



プロジェクトファイルのダウンロード




V.SPI LCD画面に温度表示する

 パソコン画面に温度表示する場合と基本的な事は変わりません。I2C LCDで表示してみたところ画面のフォントが小さすぎて見づらいこともあり、前節のUARTで表示する部分をSPI LCDに縦横2倍フォントで表示するようにプログラムを改変しただけです。




◎結線図
                                               
 S-5851側  
R8C/M12A側
LCD AQM1248 側
 1 SCL 10KΩでプルアップP3_4に接続
 2 VSS  GNDに接続
 3 AD1 GNDに接続
 4 SDA 10KΩでプルアップP3_3に接続
 5 AD0 GNDに接続
 6 VDD 3.6VVDD 1 VDD
P1_4 2 SDIに接続
3 無接続
P1_3 4 RS(データコマンド識別)
P1_6 5 SCL(クロック)
P1_7 6 /CS(チップセレクト)
GND 7 GND


◎プログラム構成

 EM_S8551_SPI.C ・・・メインプログラム
 I2C_ctrl.c ・・・I2C関数
 spi_lcd_ctrl.c ・・・SPI LCD関数
 ctrl.h ・・・I2C、SPI関連ヘッダーファイルを1つにしたもの
 font_8x8.h ・・・フォントファイル


1)EM_S8551_SPI.C ・・・メインプログラム
01:#include "sfr_r8m12a.h"
02:#include "ctrl.h"
03:void main(void)
04:{
05: unsigned char idt,a,b;
06: unsigned char rdata;
07: unsigned char i;
08: unsigned char add;
09: unsigned char x,y;
10: unsigned long T,afd,abd;// afd:After decimal point小数点以下 abd:Above decimal point 小数点以上
11: float temp;
12: init();
13: SPI_LCD_init();// LCD AQM1248A-RNの初期化
14: SPI_LCD_clr();// 画面を消去しないとゴミが表示されてしまう
15: add=0x90;// device address addr=0x48( 100 1000) → 0x90(1001 0000)
16: x=0;y=0;
17: x=SPI_LCD_str2("S-5851A",x,y);
18: I2C_start(); // startコンディション
19: IO_write(add,0x00); // 0x00 ポインタレジスタ呼び出し
20: while(1){
21:  I2C_start(); // 再度startコンディション発行する
22:  do{
23:   idt=I2C_write(add|0x01);// S5851にスレーブアドレス(読み込み時)を送る
24:   delay();
25:  }while(idt !=0);// ACK信号を待つ
26:  a=I2C_read();// S5851からデータを読み込み、
27:  ACK();// ACK をdeviceに返す
28:  b=I2C_read();// 次の1バイト読み込み ACK応答なし
29:  delay();
30:  I2C_stop();// ACKなし I2Cストップコンディションで読み取り終了
31:  wait_us(1000);
32:  T=((unsigned long)a<<8 | (unsigned long)b)>>4;// 12ビット形式になおす
33:  if(T & 0b100000000000 ){
34:   T=(0b1000000000000 - T ); // 補数処理
35:    abd = T>>4; // 小数点以上の値
36:    afd = T & 0b000000001111; // 小数点以下の値
37:    x=0;y=3;
38:    x=SPI_LCD_data2('-',x,y);
39:    x=SPI_LCD_num2((float)abd,x,y);
40:    x=SPI_LCD_data2('.',x,y);
41:    x=SPI_LCD_num2((float)afd*0.0625*100,x,y);
42:    x=SPI_LCD_data2('C',x,y);
43:   }
44:   else{
45:    abd = T >>4;// 小数点以上の値
46:    afd = T & 0b000000001111;// 小数点以下の値
47:    x=0;y=3;
48:    x=SPI_LCD_data2('+',x,y);
49:    x=SPI_LCD_num2((float)abd,x,y);
50:    x=SPI_LCD_data2('.',x,y);
51:    x=SPI_LCD_num2((float)afd*0.0625*100,x,y);
52:    x=SPI_LCD_data2('C',x,y);
53:   }
54:   wait_ms(1000);
55: }
56:}
57:/* I/O 初期化関数 */
58:void init(void)
59:{
60: int i;
61: prc0 = 1;// プロテクトレジスタ解除
62: hocoe = 1;// 高速オンチップオシレータ発振開始
63: for(i=0;i<50;i++); // 発振安定まで待つ
64: hscksel = 1;// 高速オンチップオシレータ選択ビットを1にする
65: scksel = 1;// システム基準クロックを高速にする
66: prc0  = 0;// プロテクトレジスタ禁止
67: pd1  = 0xff;// p1_0〜p1_7 出力設定 1011 1000
68: pd3  = 0x18;// p3_3,p3_4 出力設定 0001 1000
69:}

2)spi_lcd_ctrl.c ・・・SPI LCD制御関数
 以前の5章.SPI通信で作成した制御関数に追加した部分のみを記します。

10進数表示関数・・・縦横2倍で表示する(2桁表示のみ)

 unsigned char SPI_LCD_num2(unsigned long value,unsigned char px,unsigned char py)
 {
  int i;
  int a[2];
  int tmp;
  a[0]=value/10;
  a[1] = value % 10;
  for(i=0;i<2;i++){
   px=SPI_LCD_data2((a[i] + 0x30),px+1,py);
  }
  return px;
 }

  ・
  ・
  ・

 I2C_ctrl.cfont_8x8.hは以前使用したものと同じです。 ctrl.hはI2C関連のヘッダーファイルとSPI関連のヘッダーファイルを合わせて一つにしたものです。


プロジェクトファイルのダウンロード




メニューに戻る