; ; 学習リモコンソースプログラム Ver1.0 ; ; for PIC16F84@10MHz ; ; その他 赤外線受光モジュール:CRVP1738 ; EEPROM:24LC64 ; ; またまた例のごとく本ソースは秋月のPA.EXE拡張インストラクションを使用して ; おりますのであしからず。 2000.8 (c) RUU ; ; 注意 ; 本リモコンで記録・送信できる赤外線リモコンの種類は、リモコンの家電標準方式を採用 ; している機種とSONYの一部機器です。実際に動作を確認したコマンドは、松下製TV・照明 ; ・VTR・CATVターミナルの一部、およびaiwa製TVの一部、SONY製VTRの一部、パイオニア製 ; ミニコンポ・LDの一部のみです。また、上記の機器でも正しく学習や操作できないコマ ; ンドが存在する場合があります。 ; これは私の調査・解析不足(あるいはバグ・・・)によるところですが、本プログラムおよ ; びハードウェアの使用によって損害が発生したとしても私は一切の責任を負わないものと ; します。 ; .include 16F84.h .osc hs .wdt off .pwrt on .protect off trisa equ 5 trisb equ 6 SCLIO equ trisa.2 ; I2C SCL I/O bit = trisa.2 SDAIO equ trisa.3 ; I2C SDA I/O bit = trisa.3 IR_OUT equ ra.0 ; 赤外線出力ピン PWR equ ra.1 ; 周辺モジュール用電源 SCL equ ra.2 ; 24LC64 SCL SDA equ ra.3 ; 24LC64 SDA IR_IN equ ra.4 ; 赤外線入力(CRVP1738) L_STATUS equ rb.3 ; ステータス表示LED SAVE_ADR equ 0ch ; SAVE/LOADメモリアドレス SAVE_LEN equ 25 ; LOAD/SAVEバイト数 BUF_ADR equ 15h ; バッファアドレス BUF_LEN equ 16 ; バッファ長 D_HI equ 4 ; 'Hi'信号時間許容差 TM0MAX equ 193 ; タイマしきい値(タイムアウト=5秒) org 0ch ;; データメモリ(SAVE/LOAD対象分) modeflg ds 1 ; ビット転送方式.0/リザルトコード.7/status.6 他 bit_len ds 1 ; データビット総数 start_hi ds 1 ; 以下、リモコンデータ各Hi/Lo長カウンタ start_lo ds 1 min_hi ds 1 max_hi ds 1 min_lo ds 1 max_lo ds 1 stop_hi ds 1 data_buf ds 16 ; リモコンデータ本体 (adr=15hから16bytes) ;; データメモリ(その他) cnt ds 1 ; カウンタ(汎用) timecnt ds 1 ; 信号長カウンタ work_hi ds 1 ; カウント待避用/ワーク(汎用) work_lo ds 1 ; 〃 threshold ds 1 ; 1/0判定用しきい値 param ds 1 ; サブルーチンインタフェース work ds 1 ; いろいろつかう work2 ds 1 ; 〃 bit_cnt ds 1 ; リモコンデータbitカウンタ hi_1 ds 1 ; 以下、ビット送信インタフェース hi_0 ds 1 lo_1 ds 1 lo_0 ds 1 hi_time ds 1 lo_time ds 1 ;; 24LC64アクセス用 byte_buf ds 1 ; read/write用バッファ cnt_bit ds 1 ; 送受ビットカウンタ rw_dat ds 1 ; 送受信バイトデータ i2c_stat ds 1 ; status .. bit0 = acknowledge (0:ACK 1:NAK) adr_h ds 1 ; Address High byte adr_l ds 1 ; Address Low byte adrmax ds 1 ; メモリ最大adr上位1バイト(1Fh=24xx64, 7Fh=24xx256) ctrl_byte ds 1 ; control code + chip select + r/w keycode ds 1 ; キー押下発生コード crnt_page ds 1 ; メモリ現在ページ tm0cnt ds 1 ; タイマ割り込み回数 wsave ds 1 ; Wレジスタ待避 stsave ds 1 ; STATUS待避 org 0 goto main org 4 goto intproc ;;;;;;;;;;;; main ;;;;;;;;;;;; main ;; 初期化 clr crnt_page ; カレントページクリア mov adrmax,#1Fh ; タイプ:24LC64 mov ctrl_byte,#10100000b ; コントロールバイト init ;; I/Oポート設定 mov !ra,#00011000b ; IR_IN,SDAをINに、IR_OUT,PWR,SCLをOUTに mov !rb,#11110000b ; KeyXを入力,KeyYを出力に clr ra clr rb ;; TMR0設定 setb rp0 mov option,#00000111b ; ポートBプルアップ、プリスケーラ=1:256 clrb rp0 ;; 割り込み設定 mov intcon,#00001000b ; ポートB割り込み許可,タイマ0およびグローバル割り込み禁止 clr tmr0 ; タイマ0割り込み=約26ms周期 ;; スリープ mov modeflg,#01000000b ; スリープフラグON,エラーフラグクリア clrb PWR ; メモリ,受信モジュール パワーOFF sleep ; システムクロック停止、省電力モードで待機 nop ;; wakeup (キー入力でプログラム再開) mov intcon,#10100000b ; グローバル割り込み,タイマ0割り込み許可,ポートB割り込み禁止 setb PWR ; メモリ,受信モジュール パワーON mov cnt,#200 ; 周辺回路安定待ち call wait100 tm_rst_loop clr tm0cnt mainloop cje tm0cnt,#TM0MAX,init ; タイムオーバー call get_keycode ; キーコード取得 call disp_page ; ページLED点灯 cje keycode,#0FFh,mainloop ; キー入力なし then goto mainloop ;; キー処理 cjne keycode,#0F0h,key_page ;; メモリクリアJP-ON (rb6=rb7=GND ; EEPROMクリア処理) mov rb,#00001000b ; STATUS LEDだけON call ee_clr call ready_status goto init key_page cjne keycode,#0Fh,key_e ;; #15 (ページキー) jb modeflg.6,un_slp ; 再開直後? call pageup ; else ページインクリメント goto tm_rst_loop un_slp clr modeflg call wait05s goto tm_rst_loop key_e clrb modeflg.6 cjne keycode,#0Eh,key_send ;; #14 (メモリキー) call buf_clr call ready_status ; ready 表示 call analyze ; リモコンデータ解析 jb modeflg.7,error ; エラー表示 call set_timing ; パラメータ設定 call ready_status ; ready 表示 jb modeflg.0,get_s_type get_n_type call get_data_n ; 標準モードデータ取得 goto get_n_s_e get_s_type call get_data_s ; SONYモードデータ取得 get_n_s_e jb modeflg.7,error ; エラー表示 call ready_status ; ready 表示 clr tm0cnt ; setb gie key_loop cje tm0cnt,#TM0MAX,init ; タイムオーバー call get_keycode ; キーコード取得 call disp_page ; ページLED点灯 cjae keycode,#0F0h,key_loop ; キー入力なし then goto key_loop clr tm0cnt cje keycode,#0Eh,init ; メモリキーの場合sleep cjne keycode,#0Fh,key_save call pageup ; ページキー goto key_loop key_save clrb gie call save_data ; key#0〜13 --> データセーブ call ready_status ; ready 表示 setb gie goto tm_rst_loop key_send clrb gie ;; #0-13 (送信キー) call load_data ; key1-13 --> データロード cje bit_len,#0,error ; データなし? call send_data ; データ送信 jnb modeflg.0,send_nxt mov cnt,#200 ; SONYモードは2回送信 call wait100 call send_data send_nxt mov cnt,#200 ; 適当なインターバル call wait100 mov cnt,#200 call wait100 setb gie goto tm_rst_loop error ; エラー call err_status goto init ;;;;;;;;;;;; save_data ;;;;;;;;;;;;;;;; save_data call set_mem_addr ; SAVE_ADRからSAVE_LENバイトのレジスタ内容を mov fsr,#SAVE_ADR ; EEPROMの指定アドレス以降に書き込む mov cnt,#SAVE_LEN save_loop mov byte_buf,indirect call byte_write call adr_inc inc fsr djnz cnt,save_loop ret ;;;;;;;;;;;; load_data ;;;;;;;;;;;;;;;; load_data call set_mem_addr ; EEPROMの指定アドレスからSAVE_LENバイトの内容 mov fsr,#SAVE_ADR ; をSAVE_ADR以降のレジスタにロードする mov cnt,#SAVE_LEN load_loop call random_read mov indirect,byte_buf call adr_inc inc fsr djnz cnt,load_loop ret ;;;;;;;;;;;; set_mem_addr ;;;;;;;;;;;;;;;; set_mem_addr ; PAGEとキー番号をEEPROMアドレスにマッピングする mov adr_h,crnt_page rl adr_h and adr_h,#0FEh ; adr_h <- page * 2 mov adr_l,keycode swap adr_l rl adr_l and adr_l,#0E0h ; adr_l <- keycode<<5 cjbe keycode,#7,set_mem_end inc adr_h set_mem_end ret ;;;;;;;;;;;; ee_clr ;;;;;;;;;;;;;;;; ee_clr ; メモリをヌルクリアする clr adr_h clr adr_l clr byte_buf ee_loop call byte_write call adr_inc cjne adr_l,#0,ee_loop cjne adr_h,#0,ee_loop ret ;;;;;;;;;;;; ready_status ;;;;;;;;;;;;;;;; ready_status ; Ready = 短く2回点滅 mov timecnt,#2 turn_loop1 clrb L_STATUS mov work2,#15 call loop05s setb L_STATUS mov work2,#15 call loop05s decsz timecnt goto turn_loop1 ret ;;;;;;;;;;;; err_status ;;;;;;;;;;;;;;;; err_status ; Error = ゆっくり3回点滅 mov timecnt,#3 turn_loop2 clrb L_STATUS call wait05s setb L_STATUS call wait05s decsz timecnt goto turn_loop2 ret ;;;;;;;;;;; pageup ;;;;;;;;;;;;;;; pageup inc crnt_page cjne crnt_page,#7,end_pageup clr crnt_page end_pageup call disp_page call wait05s ret ;;;;;;;;;;;; intproc ;;;;;;;;;;;;;; intproc ; 割り込み処理 mov wsave,w ; Wレジスタ待避 mov stsave,status ; STATUS待避 jnb t0if,int_end cje tm0cnt,#TM0MAX,int_end ; tm0割り込み毎にtm0cntカウントアップ inc tm0cnt ; 最大193(=5sec) int_end clrb t0if ; 割り込み要因クリア clrb rbif clr tmr0 ; tmr0リセット mov status,stsave ; STATUS戻す mov w,wsave ; W戻す retfie ; 復帰 ;;;;;;;;;;;; disp_page ;;;;;;;;;;;;;; disp_page mov work,crnt_page inc work setb work.3 mov rb,work ret ;;;;;; get_keycode 押下キー番号を得る(keycode=0xFFは押下なし,=0xF0はメモリリセット) ;;;;;;;;; get_keycode ; キーはrb.0〜3とrb.4〜7のマトリクススイッチ clr rb mov keycode,rb swap keycode not keycode and keycode,#0Fh cje keycode,#0,key_void ; key入力なし mov !rb,#00001111b ; KeyYを入力,KeyXを出力に nop ; KeyY入力確定までwait nop nop mov work,rb mov !rb,#11110000b ; KeyXを入力,KeyYを出力に not work and work,#0Fh cje work,#0,key_void cje keycode,#1,key0 cje keycode,#2,key4 cje keycode,#4,key8 mov keycode,#0ch goto keynxt key0 clr keycode goto keynxt key4 mov keycode,#4h goto keynxt key8 mov keycode,#8h keynxt cje work,#1,key_end cje work,#2,key_1 cje work,#4,key_2 add keycode,#3 goto key_end key_1 add keycode,#1 goto key_end key_2 add keycode,#2 goto key_end key_void cje keycode,#0ch,key_rst mov keycode,#0FFh ; いずれのキーも押されていない場合 goto key_end key_rst mov keycode,#0F0h ; rb6と7同時にGND接続(リセットJP)の場合 key_end ret ;;;;;;;;;;;; set_timing ;;;;;;;;;;;; set_timing mov param,start_hi ; カウント値を40/38kキャリア用に変換 call set_sub mov start_hi,param mov param,start_lo call set_sub mov start_lo,param mov param,max_hi call set_sub mov max_hi,param mov param,max_lo call set_sub mov max_lo,param mov param,min_hi call set_sub mov min_hi,param mov param,min_lo call set_sub mov min_lo,param mov param,stop_hi call set_sub mov stop_hi,param ret ;;;;;;;;;;;; set_sub ;;;;;;;;;;;; set_sub jnb modeflg.0,set_38 call set40k goto set_sub_end set_38 call set38k set_sub_end ret ;;;;;;;;;;;; set40k ;;;;;;;;;;;; set40k ; 40kHzキャリアのリモコンでは mov cnt,param ; 送信のためにカウント値を1.053倍にする cv40loop cjb cnt,#20,set40end inc param sub cnt,#20 goto cv40loop set40end ret ;;;;;;;;;;;; set38k ;;;;;;;;;;;; set38k ; 元々38kHz用にカウントしているので nop ; 変換の必要なし ret ;;;;;;;;;;;; buf_clr ;;;;;;;;;;;; buf_clr ; データバッファをクリアする mov cnt,#BUF_LEN mov fsr,#BUF_ADR b_clr_loop clr indirect inc fsr djnz cnt,b_clr_loop ret ;;;;;;;;;;;; analyze ;;;;;;;;;;;; analyze ; 赤外線受信データのフォーマット解析を行う(Pass1) mov min_hi,#255 mov min_lo,#255 clr max_hi clr max_lo clr modeflg clr tm0cnt ; clrb gie ; 以降、データ受信完了まで割り込み禁止 wait_ir cje tm0cnt,#TM0MAX,cnt_err ; タイムオーバー jb IR_IN,wait_ir ; 赤外線入力あり? clrb gie ; 以降、データ受信完了まで割り込み禁止 call count_hi ; start hiまたは最初のHi信号長 cje timecnt,#0ffh,cnt_err mov start_hi,timecnt call count_lo ; start loまたは最初のlo信号長 cje timecnt,#0ffh,cnt_err mov start_lo,timecnt check_hi call count_hi ; dataのHiレベル信号長 cje timecnt,#0ffh,cnt_err mov work_hi,timecnt check_lo call count_lo ; dataのLoレベル信号長 cje timecnt,#0ffh,cnt_end mov work_lo,timecnt cmp_hi ; High最大/最小を取得 cja work_hi,max_hi,set_max_hi cja min_hi,work_hi,set_min_hi goto cmp_lo set_max_hi mov max_hi,work_hi goto cmp_lo set_min_hi mov min_hi,work_hi cmp_lo ; Low最大/最小を取得 cja work_lo,max_lo,set_max_lo cja min_lo,work_lo,set_min_lo goto check_hi set_max_lo mov max_lo,work_lo goto check_hi set_min_lo mov min_lo,work_lo goto check_hi cnt_end mov stop_hi,work_hi ; stop hiまたは最後のhi信号長 mov threshold,max_hi ; データフォーマットの判定 sub threshold,min_hi cjb threshold,#D_HI,mode_std ; Hi(max,min)時間にD_HI以上の差があれば setb modeflg.0 ; SONY方式とみなす rr threshold ; threshold <- 1or0判定の'Hi'しきい値 and threshold,#7Fh add threshold,min_hi goto analyze_end mode_std clrb modeflg.0 ; 標準方式 mov threshold,max_lo ; threshold <- 1or0判定の'Lo'しきい値 sub threshold,min_lo rr threshold and threshold,#7Fh add threshold,min_lo goto analyze_end cnt_err setb modeflg.7 ; エラーコード analyze_end setb gie ; 割り込み可 ret ;;;;;;;;;;;; get_data_n ;;;;;;;;;;;; get_data_n ; 赤外線リモコンデータの取得(Pass2/Normal) clr tm0cnt n_get_data_l cje tm0cnt,#TM0MAX,n_get_err ; タイムオーバー jb IR_IN,n_get_data_l ; startbit読み飛ばし clrb gie ; 以降、データ受信完了まで割り込み禁止 clr bit_len ; bit_len = データbit総数 (クリアする) clr work mov bit_cnt,#8 mov fsr,#BUF_ADR call count_hi call count_lo n_get_loop call count_hi call count_lo ; 標準:Lo長さで0/1決定 cje timecnt,#0ffh,n_recv_end ; 標準:受信終了? rl work cjb timecnt,threshold,n_bit_0 n_bit_1 setb work.0 goto n_get01 n_bit_0 clrb work.0 n_get01 dec bit_cnt inc bit_len cja bit_len,#BUF_LEN*8,n_get_err ; データバッファオーバーフロー cjne bit_cnt,#0,n_get_loop mov bit_cnt,#8 mov indirect,work ; 8bit(1byte)毎にバッファへ書き込み inc fsr clr work goto n_get_loop n_recv_end cje bit_cnt,#8,n_get_end ; バイト単位なら終了 n_recv_sft rl work clrb work.0 djnz bit_cnt,n_recv_sft mov indirect,work goto n_get_end n_get_err setb modeflg.7 n_get_end setb gie ; 割り込み可 ret ;;;;;;;;;;;; get_data_s ;;;;;;;;;;;; get_data_s ; 赤外線リモコンデータの取得(Pass2/SONY) clr tm0cnt s_get_data_l cje tm0cnt,#TM0MAX,s_get_err ; タイムオーバー jb IR_IN,s_get_data_l ; startbit読み飛ばし clrb gie ; 以降、データ受信完了まで割り込み禁止 clr bit_len ; bit_len = データbit総数 (クリアする) clr work mov bit_cnt,#8 mov fsr,#BUF_ADR call count_hi call count_lo s_get_loop call count_hi ; SONY:Hi長さで0/1決定 rl work cjb timecnt,threshold,s_bit_0 s_bit_1 setb work.0 goto s_get01 s_bit_0 clrb work.0 s_get01 dec bit_cnt inc bit_len cja bit_len,#BUF_LEN*8,s_get_err ; データバッファオーバーフロー cjne bit_cnt,#0,s_get02 mov bit_cnt,#8 mov indirect,work ; 8bit(1byte)毎にバッファへ書き込み inc fsr clr work s_get02 call count_lo cje timecnt,#0ffh,s_recv_end ; SONY:受信終了 goto s_get_loop s_recv_end cje bit_cnt,#8,s_get_end ; バイト単位なら終了 s_recv_sft rl work clrb work.0 djnz bit_cnt,s_recv_sft mov indirect,work goto s_get_end s_get_err setb modeflg.7 s_get_end setb gie ; 割り込み可 ret ;;;;;;;;;;;; send_data ;;;;;;;;;;;; send_data ; データバッファ内容を赤外線LEDで送信する mov work2,bit_len mov fsr,#BUF_ADR mov bit_cnt,#8 mov work,indirect jnb modeflg.0,set_normal mov hi_1,max_hi mov hi_0,min_hi mov lo_1,max_lo mov lo_0,max_lo goto send_main set_normal ; mov hi_1,max_hi ; mov hi_0,max_hi mov hi_1,min_hi ; こっち(min)の方がよさそう mov hi_0,min_hi mov lo_1,max_lo mov lo_0,min_lo add lo_0,#2 ; ちょっと補正 send_main mov hi_time,start_hi mov lo_time,start_lo call send_bit send_loop jb work.7,send_1 send_0 mov hi_time,hi_0 mov lo_time,lo_0 call send_bit goto byte_e_chk send_1 mov hi_time,hi_1 mov lo_time,lo_1 call send_bit byte_e_chk djnz bit_cnt,send_sft inc fsr mov work,indirect mov bit_cnt,#8 goto send_e_chk send_sft rl work send_e_chk djnz work2,send_loop jb modeflg.0,send_end ; SONY:stopbitなし mov hi_time,stop_hi mov lo_time,stop_hi call send_bit send_end ret ;;;;;;;;;;;; send_bit ;;;;;;;;;;;; send_bit ; 1bit分のデータを送信する send_b_hi ; 'Hi'信号 setb IR_OUT call wait_carrier clrb IR_OUT call wait_carrier setb IR_OUT call wait_carrier clrb IR_OUT call wait_carrier djnz hi_time,send_b_hi send_b_lo ; 'Lo' call wait_carrier call wait_carrier call wait_carrier call wait_carrier nop nop nop nop djnz lo_time,send_b_lo ret ;;;;;;;;;;;; wait_carrier ;;;;;;;;;;;; wait_carrier ; 赤外線キャリアの半サイクル時間を消費 btfsc modeflg.0 goto c40k mov cnt,#7 nop nop goto loop_carr c40k mov cnt,#7 nop loop_carr decsz cnt goto loop_carr ret ;;;;;;;;;;;; count_hi ;;;;;;;;;;;; count_hi ; 'Hi'信号時間をカウントする clr timecnt h_cnt_loop jb IR_IN,h_cnt_end call wait526 ; 2cycle(@38kHz)wait inc timecnt cjne timecnt,#0ffh,h_cnt_loop ; 最大255(=13.4ms) h_cnt_end ret ;;;;;;;;;;;; count_lo ;;;;;;;;;;;; count_lo ; 'Lo'信号時間をカウントする clr timecnt l_cnt_loop jnb IR_IN,l_cnt_end call wait526 ; 2cycle(@38kHz)wait inc timecnt cjne timecnt,#0ffh,l_cnt_loop ; 最大255(=13.4ms) l_cnt_end ret ;;;;;;;;;;;; wait526 ;;;;;;;;;;;; wait526 ; 52.6μsを消費(38kHzの2cycle分) mov cnt,#42 loop526 decsz cnt goto loop526 ret ;;;;;;;;;;;; wait100;;;;;;;;;;;; wait100 ; 100μs * cnt 時間を消費 loop_n mov work,#81 loop100 decsz work goto loop100 decsz cnt goto loop_n ret ;;;;;;;;;;;; wait05s ;;;;;;;;;;; wait05s ; 0.5秒くらい消費 mov work2,#50 loop05s mov cnt,#100 call wait100 decsz work2 goto loop05s ret ; i2c_start ; Start Conditionを出力する i2c_start setb rp0 ; Bank1 clrb SDAIO ; SDAを出力にする clrb rp0 ; Bank0 clrb SCL ; SCL=L nop ; setup time wait nop setb SDA ; SDA=H nop nop setb SCL ; SCL=H nop ; (TSU:STA) nop clrb SDA ; SCL=HでSDAがH->L : start condition nop ; (THD:STA) nop clrb SCL ; SCL=L setb rp0 ; Bank1 setb SDAIO ; SDAを開放(入力)にする clrb rp0 ; Bank0 ret ; i2c_stop ; Stop Conditionを出力する i2c_stop setb rp0 ; Bank1 clrb SDAIO ; SDAを出力にする clrb rp0 ; Bank0 clrb SCL ; SCL=L nop ; setup time wait nop clrb SDA ; SDA=L nop nop setb SCL ; SCL=H nop ; (TSU:STO) nop setb SDA ; SCL=HでSDAがL->H : stop condition nop nop clrb SCL ; SCL=L setb rp0 ; Bank1 setb SDAIO ; SDAを開放(入力)にする clrb rp0 ; Bank0 ret ; i2c_write (マスタ・トランスミッタ) ; 1バイトのデータを出力する ; 注)送信データrw_datはi2c_writeのcallで破壊される ; 結果(ACK/NAK)はi2c_stat.0に格納される i2c_write setb rp0 ; Bank1 clrb SDAIO ; SDAを出力にする clrb rp0 ; Bank0 mov cnt_bit,#8 ; カウンタセット send_1bit jb rw_dat.7,bit_wh ; dataの7bit目から送信 clrb SDA ; bit=0 goto send_one bit_wh setb SDA ; bit=1 send_one nop ; TSU:DAT setb SCL ; SCL=H nop ; (THIGH > 600ns) rl rw_dat ; bitシフト clrb SCL ; SCL=L djnz cnt_bit,send_1bit ; 7-0bit繰り返し ;; -- ACK -- setb rp0 ; Bank1 setb SDAIO ; SDAを開放(入力)にする clrb rp0 ; Bank0 setb SCL ; SCL=H nop jnb SDA,w_ack setb i2c_stat.0 ; NO ACK goto write_end w_ack clrb i2c_stat.0 ; ACK write_end clrb SCL ret ; i2c_read (マスタ・レシーバ) ; 1バイトのデータを読み込む ; 読み込み後にレシーバから送信するACK/NAKはi2c_stat.0で指定する ; 受信データはrw_datに格納される i2c_read mov cnt_bit,#8 ; カウンタセット read_bit setb SCL ; SCL=H nop jb SDA,bit_rh ; 1bit受信 clrb rw_dat.0 ; bit=0 goto scl_rl bit_rh setb rw_dat.0 ; bit=1 scl_rl clrb SCL ; SCL=L decsz cnt_bit goto read_nxt ; 7-0bit繰り返し goto read_end read_nxt rl rw_dat ; bitシフト goto read_bit read_end ;; -- ACK / NO ACK -- jnb i2c_stat.0,r_ack setb SDA ; NO ACK goto send_ack r_ack clrb SDA ; ACK send_ack setb rp0 ; Bank1 clrb SDAIO ; SDAを出力にする clrb rp0 ; Bank0 setb SCL ; SCL=H nop ; (THIGH) nop clrb SCL setb rp0 ; Bank1 setb SDAIO ; SDAを開放(入力)にする clrb rp0 ; Bank0 ret ;; ******** 24LCxxアクセスサブルーチン ******** ; send_ctrl ; START および Control Byte 送信 + ACK待ち send_ctrl call i2c_start mov rw_dat,ctrl_byte call i2c_write jb i2c_stat.0,send_ctrl ; if NO ACK then retry ret ; adr_inc ; アドレスインクリメント adr_inc cje adr_l,#0FFh,inc_hi inc adr_l goto inc_end inc_hi clr adr_l cje adr_h,adrmax,inc_roll inc adr_h goto inc_end inc_roll clr adr_h inc_end ret ; byte_write ; 1バイトをメモリに書き込む (I:ctrl_byte,adr_h,adr_l,byte_buf) byte_write clrb ctrl_byte.0 ; r/w = 0 (write) call send_ctrl ; START and control byte mov rw_dat,adr_h ; address high call i2c_write mov rw_dat,adr_l ; address low call i2c_write mov rw_dat,byte_buf ; data call i2c_write call i2c_stop ret ; random_read ; 1バイトをメモリから読み出す(I:ctrl_byte,adr_h,adr_l O:byte_buf) random_read clrb ctrl_byte.0 ; r/w = 0 (write) call send_ctrl ; START and control byte mov rw_dat,adr_h ; address high call i2c_write mov rw_dat,adr_l ; address low call i2c_write setb ctrl_byte.0 ; r/w = 1 (read) call send_ctrl ; START and control byte setb i2c_stat.0 ; NAK call i2c_read ; get byte and send NAK mov byte_buf,rw_dat ; get data call i2c_stop ret ;;;;;;;;;;;;;;;;;;; おしまい ;;;;;;;;;;;;;;;;;;;;;;