ホームに戻る
 PIC16F84a でI2C通信(24LC64 を使う)

0、はじめに

PICはI2C通信によってデータの送受信を行うことができます。
(ただし、I2C通信機能の無いPICもあるので注意)
I2C通信は主に基盤上などの短い距離の通信を想定しており長距離通信には向かないようです。
I2C通信はマスターとスレーブに分かれます。
マスターに対応したPIC、スレーブに対応したPICがあります。
PIC16F84a はI2Cのマスターにもスレーブにも対応していません。
今回は PIC16F84a でI2Cの信号を自力で書き出しマスターとして使います。

加えて、今回は 24LC64 をIC2通信のスレーブで使います。
24LC64 は64Kビットの記録容量を持つ EEPROM です。
24LC シリーズはIC2のスレーブに対応しています。

余談ですが、25LC シリーズはSPI通信に対応しています。

1、PIC16F84a について

1個200円くらいで売っています。
PIC16F84a はI2C通信に対応していません。
I2C通信で使うために以下のように定義します。

RB0:LED 1
RB1:LED 2
RB2:LED 3
RB3:LED 4
RA0:SDA
RA1:SCL

2、I2C通信について

I2C通信はマスターとスレーブ間で通信します。
複数のPICで通信する場合マスターは必ず1つです。
マスター1つで複数のスレーブと通信が可能です。
スレーブにはスレーブのアドレスを決めるピンがいくつかあります。
マスターが送るデータのアドレスとスレーブのアドレスが一致すると通信ができます。
データの通信をしたいスレーブをマスターが選択できるのです。
マスターはアドレスによって区別し複数のスレーブを扱うことができます。

通信そのものには SDA と SCL の2本の経路が必要です。
SDA がデータで、SCL はクロックです。

I2C通信では SDA、SCL に必ずプルアップ抵抗が必要になります。

SDA----+----SDA
       |
       R (1kΩ程度)
       | 
       V

3、24LC64 について

1個100円くらいで買えると思います。
記録できるのは64kビットです。
ピンは全部で8本。

1:アドレス指定用
2:アドレス指定用
3:アドレス指定用
4:GND
5:SDA
6:SCL
7:ライトプロテクト
8:Vcc

今回はアドレスは使用しません。
ライトプロテクトも使用しません。
よって、3、4、5、7ピンを使うことになります。

また、24LC64 は PICKit2 で書き込みもできます。
以下のように繋ぎます。

PICKit2 --- 24LC64

2:Vdd   --- 8:Vcc
3:GND   --- 4:Vcc
5:PGC   --- 6:SCL
6:AUX   --- 5:SDA

※この場合も SDA と SCL のプルアップは必須です。

また、電源は3.6V以上無いといけないという情報もあります。

4、回路設計

16f64a について

RB0-3 をLEDにつなぐ。
RA0 は SDA、RA1 は SCL として使う。

24LC64 について

アドレスとライトプロテクトは何も繋がない。
繋ぐ場合には GND にしておいてください。
ほか、SDA、SCL、電源、GND を繋ぎます。

SDA、SCL にはプルアップ抵抗をつけます。

5、動作の詳細

実際の通信は以下の手順で信号を送ります。

スタートビット:1ビット
コントロールビット:4ビット
I2Cアドレス:3ビット
書き込み、読み込み:1ビット
ACKビット:1ビット

ダミー:3ビット
ROM内上位アドレス:5ビット
ACKビット:1ビット
ROM内下位位アドレス:8ビット
ACKビット:1ビット

コントロールビットは 1010 です。
I2Cアドレスは今回は 000 にします。
読み込みなので読み書きのビットは 0 とします。
ROM内アドレスは8ビット単位でアクセスできます。
13ビットでアドレスを指定します。

このあたりは 24LC64 のデータシートに説明があります。

6、サンプルコード

; PIC16F84A で 24LC64 のデータを読み込む
; RA0 をSDAとする
; RA1 をSCLとする
; RB0-RB7 をLEDの点灯用とする
; SDAとSCLには1kΩほどのプルアップ抵抗が必須
;
; 24LC64 のデータを最初から読み込み
; データ通りに1秒ごとで LED を点灯
;

 LIST P=PIC16F84A
 INCLUDE P16F84A.INC

__CONFIG _HS_OSC & _WDT_OFF & _PWRTE_ON & _CP_OFF

ROM_CHIP  EQU  0CH ; EEPROM のデバイスアドレス設定用
ROM_ADD_H EQU  0DH ; EEPROM の上位アドレス設定用
ROM_ADD_L EQU  0EH ; EEPROM の下位アドレス設定用
BUFFER    EQU  0FH ; 入出力用バッファ
DATA_IN   EQU  10H ; 入力データ記録用
DATA_OUT  EQU  11H ; 出力データ記録用
BITCOUNT  EQU  12H ; カウント用

; 遅延タイマー用
T0 EQU 13H
T1 EQU 14H
T2 EQU 15H
T3 EQU 16H

; 定数
SCL     EQU  1  ; SCL端子とする端子番号
SDA     EQU  0  ; SDA端子とする端子番号
DO      EQU  0
DI      EQU  1
ACK_BIT EQU  2  ; ACK信号の有無

; メイン
MAIN
  BSF    STATUS,RP0    ; BANK1
  CLRF   TRISA
  CLRF   TRISB
  CLRF   OPTION_REG
  BCF    STATUS,RP0    ; BANK0

  ; RB0を点灯
  MOVLW  h'0001'
  MOVWF  PORTB

  CALL   TIME1000

  ; RB1を点灯
  MOVLW    h'0002'
  MOVWF    PORTB

  CALL TIME1000

  MOVLW  h'0000'
  MOVWF  ROM_CHIP    ;デバイスアドレスを指定
  MOVLW  h'0000'
  MOVWF  ROM_ADD_H   ;アドレス上位1バイトを指定
  MOVLW  h'0000'
  MOVWF  ROM_ADD_L   ;アドレス下位1バイトを指定
  CALL   ROM_READ    ;ROM読み出しルーチンへ
LOOP1
  GOTO   LOOP1

; I2CEEPROM 読み出し
ROM_READ
  CALL   SDA_IN      ;SDA端子を入力モードにする

  CALL   START_CON   ;スタートシーケンスへ
  CALL   ROM_TIM

  MOVLW  h'00A0'     ;コントロールビット+書き込みビット
  IORWF  ROM_CHIP,W  ;上記にデバイスアドレスを加える
  MOVWF  DATA_OUT    ;DATA_OUTレジスタに移動
  CALL   BYTE_OUT    ;コントロールシーケンス(1バイト)の送出
  CALL   ROM_TIM

  MOVF   ROM_ADD_H,W
  MOVWF  DATA_OUT    ;アドレス上位をDATA_OUTレジスタに移動
  CALL   BYTE_OUT    ;アドレス上位送信
  CALL   ROM_TIM

  MOVF   ROM_ADD_L,W
  MOVWF  DATA_OUT    ;アドレス下位をDATA_OUTレジスタに移動
  CALL   BYTE_OUT    ;アドレス下位送信
  CALL   ROM_TIM

  CALL   START_CON   ;スタートシーケンスへ
  CALL   ROM_TIM

  MOVLW  h'00A1'     ;コントロールビット+読み込みビット
  IORWF  ROM_CHIP,W  ;上記にデバイスアドレスを加える
  MOVWF  DATA_OUT    ;DATA_OUTレジスタに移動
  CALL   BYTE_OUT    ;コントロールシーケンス(1バイト)の送出
  CALL   ROM_TIM

SEQ_READ
  BSF    BUFFER,ACK_BIT ;ACKビットを立てて連続読み出しにする
  CALL   BYTE_IN     ;1バイトを受信(受信後にACKを送出する)

  ; 読み込んだデータをもとにPORTBを点灯
  MOVF   DATA_IN,W
  MOVWF  PORTB

  CALL   TIME1000

  GOTO   SEQ_READ

LAST_READ
  BCF    BUFFER,ACK_BIT ;ACKビットを送出しないで最終読み出し
  CALL   BYTE_IN     ;1バイトを受信(受信後にACKは送出しない)
  CALL   ROM_TIM

  CALL   STOP_CON    ;ストップシーケンスへ

  RETURN             ;このサブルーチンから抜ける

; I2C EEPROM スタートシーケンス
START_CON
  BSF    PORTA,SCL
  CALL   ROM_TIM
  CALL   SDA_OUT
  BCF    PORTA,SDA
  CALL   ROM_TIM
  BCF    PORTA,SCL
  CALL   SDA_IN
  RETURN

; I2C EEPROM ストップシーケンス
STOP_CON
  CALL   SDA_OUT
  BCF    PORTA,SDA
  BSF    PORTA,SCL
  CALL   ROM_TIM
  CALL   SDA_IN
  RETURN
  
; I2C EEPROM 1バイト送信
BYTE_OUT
  MOVLW  H'0008'
  MOVWF  BITCOUNT    ;8ループ
BYTE_OUT_2
  BSF    BUFFER,DO
  BTFSS  DATA_OUT,7
  BCF    BUFFER,DO
  CALL   BIT_OUT
  RLF    DATA_OUT,F
  DECFSZ BITCOUNT,F
  GOTO   BYTE_OUT_2
  CALL   BIT_IN
  RETURN

; I2C EEPROM 1バイト受信
BYTE_IN
  CLRF   DATA_IN
  MOVLW  H'0008'
  MOVWF  BITCOUNT    ;8ループ 
  BCF    STATUS,C
BYTE_IN_2
  RLF    DATA_IN,F
  CALL   BIT_IN
  BTFSC  BUFFER,DI
  BSF    DATA_IN,0
  DECFSZ BITCOUNT,F
  GOTO   BYTE_IN_2
  BSF    BUFFER,DO
  BTFSC  BUFFER,ACK_BIT
  BCF    BUFFER,DO
  CALL   BIT_OUT
  RETURN

; I2C EEPROM 1ビット送信
BIT_OUT
  BCF    PORTA,SCL
  BTFSS  BUFFER,DO
  GOTO   BIT_OUT_3
BIT_OUT_2
  BSF    PORTA,SCL
  CALL   ROM_TIM
  BCF    PORTA,SCL
  CALL   SDA_IN
  RETURN
BIT_OUT_3
  CALL   SDA_OUT
  BCF    PORTA,SDA
  GOTO   BIT_OUT_2

; I2C EEPROM 1ビット受信
BIT_IN
  BCF    PORTA,SCL
  CALL   SDA_IN
  BSF    BUFFER,DI
  BSF    PORTA,SCL
  CALL   ROM_TIM
  BTFSS  PORTA,SDA
  BCF    BUFFER,DI
  BCF    PORTA,SCL
  RETURN

; I2C EEPROM SDA入力端子設定
SDA_IN
  BSF    STATUS,RP0  ;BANK1へ移動
  BSF    TRISA,SDA   ;SDA端子を入力設定
  BCF    STATUS,RP0  ;BANK0へ移動
  RETURN

; I2C EEPROM SDA出力端子設定
SDA_OUT
  BSF    STATUS,RP0  ;BANK1へ移動
  BCF    TRISA,SDA   ;SDA端子を出力設定
  BCF    STATUS,RP0  ;BANK0へ移動
  BSF    PORTA,SDA
  RETURN

; I2C EEPROM タイミング調整用
ROM_TIM
  GOTO   $+1         ;2サイクル
  GOTO   $+1         ;2サイクル
  GOTO   $+1         ;2サイクル
  GOTO   $+1         ;2サイクル
  GOTO   $+1         ;2サイクル
  GOTO   $+1         ;2サイクル
  GOTO   $+1         ;2サイクル
  GOTO   $+1         ;2サイクル
  GOTO   $+1         ;2サイクル
  GOTO   $+1         ;2サイクル
  GOTO   $+1         ;2サイクル
  GOTO   $+1         ;2サイクル
  GOTO   $+1         ;2サイクル
  GOTO   $+1         ;2サイクル
  GOTO   $+1         ;2サイクル
; GOTO   $+1         ;2サイクル
; GOTO   $+1         ;2サイクル
; GOTO   $+1         ;2サイクル
; GOTO   $+1         ;2サイクル
; GOTO   $+1         ;2サイクル
; GOTO   $+1         ;2サイクル
  RETURN             ;2サイクル

; 以降、遅延タイマー

; 0.4ms
TIME04
  MOVLW  D'250'
  MOVWF  T1
TIMELOOP1
  NOP
  DECFSZ T1,F
  GOTO   TIMELOOP1
  RETURN

; 20ms
TIME20
  MOVLW  D'50'
  MOVWF  T2
TIMELOOP2
  CALL   TIME04
  DECFSZ T2,F
  GOTO   TIMELOOP2
  RETURN

; 1m
TIME1000
  MOVLW  D'50'
  MOVWF  T3
TIMELOOP3
  CALL   TIME20
  DECFSZ T3,F
  GOTO   TIMELOOP3
  RETURN

  END

inserted by FC2 system