ホームに戻る
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