2020.10.10
2021.02.18
クロックは内部発振器を使う。
LIST P=PIC12F1840,ST=OFF,R=DEC INCLUDE "p12f1840.inc" __CONFIG _CONFIG1 , _FOSC_INTOSC & _WDTE_OFF & _PWRTE_ON & _MCLRE_OFF & _CP_OFF & _CPD_OFF & _BOREN_ON & _CLKOUTEN_OFF & _IESO_OFF & _FCMEN_OFF __CONFIG _CONFIG2 , _WRT_OFF & _PLLEN_OFF & _STVREN_ON & _BORV_HI & _LVP_OFF ;CONFIG1の設定 ;_FOSC_INTOSC 内部クロック使用(INTOSC),_WDTE_OFF WatchDogTimer無し, _PWRTE_ON 電源ONから64ms後プログラム開始 ;_MCLRE_OFF 外部リセット信号使用しない RA3はデジタルピン _CP_OFF プログラムメモリの保護無 _CPD_OFF dataメモリ保護無し ;_BOREN_ON 電源電圧降下常時監視機能ON _CLKOUTEN_OFF ClockoutピンをRA4ピンで使用 ;_IESO_OFF 外部・内部クロックの切り替えでの起動なし _FCMEN_OFF 外部クロック監視無し |
OSCCONレジスタに値を設定してCPUのクロックを2MHzに設定する。(スレーブ側ではサーボモータSG-90をPWM制御するの
に、これ以上高い 周波数は使えない。)
BANKSEL
OSCCON MOVLW 60H ; 内部クロック2MHzの設定 MOVWF OSCCON |
マスター側PICもスレーブ側PICもi2cのポートとなるSCL(RA1),SDA(RA2)はデジタルピンの入力に設定す
る
;PORTAをディジタルI/Oにする BANKSEL PORTA CLRF PORTA BANKSEL LATA CLRF LATA BANKSEL ANSELA ; digital I/O CLRF ANSELA ; BANKSEL TRISA MOVLW B'00000110' ; SCL,SDAのRA2,RA1入力, MOVWF TRISA |
BANKSEL SSP1STAT MOVLW 80H MOVWF SSP1STAT ; SMP=ON MOVLW 028H ;SSP1EN=ON I2C master mode MOVWF SSP1CON1 CLRF SSP1CON2 MOVLW 04H ; 2MHz/((04H+1)*4)=100kHz MOVWF SSP1ADD ;100KBps設定 ; BANKSEL PIR1 BCF PIR1,SSP1IF BANKSEL PORTA ;BANK0へ切り替え |
Fig2はi2c通信の7bitアドレス方式のデータの流れである。
上段がマスターからスレーブへのデータ書き込みである。
マスターが開始条件を送信したのち7bitのスレーブアドレスにWrite=0のフラグを付加して8bitにして送信する。
バス上のアドレスが一致したスレーブからACKが返信された後マスター側は8bit毎にデータを送る。
送信データが尽きたら終了条件を送信する。
下段はマスターがスレーブからデータを受信する場合である。
マスターが開始条件を送信したのち7bitのスレーブアドレスにRead=1のフラグを付加して8bitにして送信する。
バス上のアドレスが一致したスレーブからAckが返信される。その後、スレーブが8ビットのデータをが送られるのでマスターは受信の都度
ACKを返す。
i2cモードで動作している場合はデータの送受信はSSP1BUFを介して自動で行われる。送受信の完了はそれぞれ関連するフ
ラグをチェックすることで判定できる。
;========================================================================= ; I2C 制御モジュール群(マスター側) ;========================================================================= ;********************************************************************** ; 開始条件送信 ; (1)通信状態ではないときSDA,SCLともにHIGH状態(22KΩの抵抗でこの2本をプルアップ ; (2) SCLがHのままSDAがH --> L に変化したときが開始状態 ;********************************************************************** I2CSTART BANKSEL SSP1CON1 BCF SSP1CON1,WCOL ; SSPCONの衝突フラグクリア BSF SSP1CON2,SEN ; 開始条件送信 BTFSC SSP1CON1,WCOL ; 衝突あり? GOTO I2CSTART ; 衝突あり BTFSC SSP1CON2,SEN ; スタート終了? GOTO $-1 BANKSEL PORTA ;BANK0へ切り替え RETURN ;********************************************************************** ; 受信処理の再開始条件送信 ;********************************************************************** I2CRESTART BANKSEL PIR1 BCF PIR1,SSP1IF ;割り込みフラグクリア BANKSEL SSP1CON2 ;BANK切り替え BSF SSP1CON2,RSEN ; 再開始条件送信 BTFSC SSP1CON2,RSEN ; 再開始条件出力? GOTO $-1 BANKSEL PORTA ;BANK0へ切り替え RETURN ;********************************************************************** ; 入力 W: 送信データ ;; 終了時BANK0のままになっていることに注意 ;********************************************************************** I2CSEND BCF PIR1,SSP1IF ; 割り込みフラグクリア BANKSEL SSP1BUF MOVWF SSP1BUF ; 送信 BANKSEL PIR1 BTFSS PIR1,SSP1IF ; 送信完了? GOTO $-1 ; BANKSEL SSP1CON2 ;BANKへ切り替え BTFSC SSP1CON2,ACKSTAT ; ACK受信? GOTO $-1 ; ; BANKSEL PORTA ;BANK0へ切り替え RETURN ;********************************************************************** ; 1バイトデータ受信 ; 出力 W 受信データ ;********************************************************************** I2CRCV BCF PIR1,SSP1IF ; 割り込みフラグクリア BANKSEL SSP1CON2 ;BANKへ切り替え BSF SSP1CON2,RCEN ; 受信許可 BTFSC SSP1CON2,RCEN ; 受信完了か? GOTO $-1 BCF SSP1CON2,ACKDT ;0:ACKをセット BSF SSP1CON2,ACKEN ;ACK送信 BTFSC SSP1CON2,ACKEN ;ACK送信完了? GOTO $-1 BANKSEL SSP1BUF ;BANK切り替え MOVF SSP1BUF,W ;データ取得 BANKSEL PORTA RETURN ;********************************************************************** ; 最終バイト受信 (最終バイトを受信して終了の時はCPUからNACKを送信) ; 出力 W 受信データ ;********************************************************************** I2CREND BCF PIR1,SSP1IF ; 割り込みフラグクリア BANKSEL SSP1CON2 ;BANKへ切り替え BSF SSP1CON2,RCEN ; 受信許可 BTFSC SSP1CON2,RCEN ; 受信完了か? GOTO $-1 BSF SSP1CON2,ACKDT ;1:NACKをセット BSF SSP1CON2,ACKEN ;NACK送信 BTFSC SSP1CON2,ACKEN ;NACK送信完了? GOTO $-1 BANKSEL SSP1BUF ;BANK切り替え MOVF SSP1BUF,W ;データ取得 BANKSEL PORTA RETURN ;********************************************************************** ; 終了条件送信 ;********************************************************************** I2CEND BCF PIR1,SSP1IF ; 割り込みフラグクリア BANKSEL SSP1CON2 ;BANK1へ切り替え BSF SSP1CON2,PEN ; ストップ出力 BTFSC SSP1CON2,PEN ; 出力完了か? GOTO $-1 BANKSEL PORTA ;BANK0へ切り替え BCF PIR1,SSP1IF ; 割り込みフラグクリア RETURN |
LCDADR EQU 7CH
; i2c LCD AQM1602XAのアドレス+R/wビット ; Arduinoで使う場合はたぶん3EH 以下中略 CBLOCK 020H CNT0 ;タイマ用カウンタ CNT1 ;タイマ用カウンタ CNT2 ;タイマ用カウンタ CNT3 ;汎用カウンタ、信号解析、LCD表示用など HEX2_WRK ; HEX2LCDモジュールWRK LCDWBF ; LCD書き込み用バッファ 以下 略 ENDC |
;+++++++++++++++++++++++++++++++++++++++++++++ ;+ LCD初期化処 理 + ;+++++++++++++++++++++++++++++++++++++++++++++ LCD_INIT CALL TIM_50ms ; 40ms以上待つ CALL I2CSTART ;開始条件送信 MOVLW LCDADR ;スレーブアドレス+Wセット CALL I2CSEND ; スレーブアドレス+W送信 ; Function set #1 MOVLW 80H ;Co=ON RS=0 CALL I2CSEND ;control byte 送信 ; MOVLW 38H ;Function Set(instruction table #0) CALL I2CSEND; Instruction 送信 CALL TIM_10us ;30μS待つ CALL TIM_10us CALL TIM_10us ; Function set #2 MOVLW 80H ;Co=ON RS=0 CALL I2CSEND ;Control byte 送信 ; MOVLW 39H ;Function Set(instruction table #1) CALL I2CSEND; Instruction 送信 CALL TIM_10us ;30μS待つ CALL TIM_10us CALL TIM_10us ; Internal OSC Frequency MOVLW 80H ;Co=ON RS=0 CALL I2CSEND ;control byte 送信 ; MOVLW 16H ; CALL I2CSEND; Instruction 送信 CALL TIM_10us ;30μS待つ CALL TIM_10us CALL TIM_10us ; Contrast set MOVLW 80H ;Co=ON RS=0 CALL I2CSEND;control byte 送信 ; MOVLW 73H ; CALL I2CSEND; Instruction 送信 CALL TIM_10us ;30μS待つ CALL TIM_10us CALL TIM_10us ; Power /Con /Contrast MOVLW 80H ;Co=ON RS=0 CALL I2CSEND;control byte 送信 ; MOVLW 54H ; CALL I2CSEND; Instruction 送信 CALL TIM_10us ;30μS待つ CALL TIM_10us CALL TIM_10us ; Follower Control MOVLW 80H ;Co=ON RS=0 CALL I2CSEND;control byte 送信 ; MOVLW 6CH ; CALL I2CSEND; Instruction 送信 CALL TIM_100ms ;200ms待つ CALL TIM_100ms ; Function set MOVLW 80H ;Co=ON RS=0 CALL I2CSEND;control byte 送信 ; MOVLW 38H ;Function Set(instruction table #0に戻す) CALL I2CSEND; Instruction 送信 CALL TIM_10us;30μS待つ CALL TIM_10us CALL TIM_10us ; Clear Display MOVLW 80H ;Co=ON RS=0 CALL I2CSEND;control byte 送信 ; MOVLW 01H ; CALL I2CSEND; Instruction 送信 CALL TIM_10us;30μS待つ CALL TIM_10us CALL TIM_10us ; Display ON/OFF control MOVLW 00H ;Co=OFF RS=0 CALL I2CSEND;control byte 送信 ; MOVLW 0CH ; CALL I2CSEND ; Instruction 送信 CALL TIM_10us;30μS待つ CALL TIM_10us CALL TIM_10us GOTO I2CEND; I2C終了条件送信の処理をしてリターン ;+++++++++++++++++++++++++++++++ ; LCD COMMAND 実行 コマンド1個 ; 入力 W ;+++++++++++++++++++++++++++++++ LCD_EXE BANKSEL PORTA MOVWF LCDWBF ;データ退避 CALL I2CSTART ;i2cスタート条件送信 ; MOVLW LCDADR ;LCDスレーブアドレス+W CALL I2CSEND ;スレーブアドレス送信B MOVLW 00H ; Co=OFF RS=0 CALL I2CSEND ;control byte 送信 MOVF LCDWBF,W CALL I2CSEND ; Instruction(=コマンド) 送信 GOTO I2CEND; I2C終了条件送信の処理をしてリターン ;+++++++++++++++++++++++++++++++ ; LCD DATA WRITE ; 入力 W : (データ値) ;+++++++++++++++++++++++++++++++ LCD_WRITE BANKSEL PORTA MOVWF LCDWBF ;データ退避 CALL I2CSTART ;i2cスタート条件送信 ; MOVLW LCDADR ;LCDスレーブアドレス+W CALL I2CSEND ;スレーブアドレス送信 MOVLW 40H ; Co=OFF RS=1 CALL I2CSEND ;control byte 送信 MOVF LCDWBF,W CALL I2CSEND ;data 送信 GOTO I2CEND ; I2C終了条件送信の処理をしてリターン ;+++++++++++++++++++++++++++++++ ; LCD OFF ;+++++++++++++++++++++++++++++++ LCD_OFF MOVLW 08H GOTO LCD_EXE ;+++++++++++++++++++++++++++++++ ; LCD ON ; 表示ON カーソルはoff (カーソルonの場合は0EHを設定) ;+++++++++++++++++++++++++++++++ LCD_ON MOVLW 0CH GOTO LCD_EXE ;+++++++++++++++++++++++++++++++ ; LCD CLEAR ;+++++++++++++++++++++++++++++++ LCD_CLEAR MOVLW 01H CALL LCD_EXE CALL TIM_600us GOTO TIM_1ms ;+++++++++++++++++++++++++++++++++++ ; カーソルの位置を1行目の先頭にセット ;+++++++++++++++++++++++++++++++++++ LCD_L1 ;MSB=1 +DDRAMADDRESS(000 0000) MOVLW 80H GOTO LCD_EXE ;+++++++++++++++++++++++++++++++++++ ; カーソルの位置を2行目の先頭にセット ;+++++++++++++++++++++++++++++++++++ LCD_L2 ; MSB=1 +DDRAMADDRESS(100 0000) MOVLW 0C0H GOTO LCD_EXE ;+++++++++++++++++++++++++++++++++++ ; カーソルの位置を右シフト(つかってないけど) ;+++++++++++++++++++++++++++++++++++ LCD_RIGHT MOVLW 14H CALL LCD_EXE GOTO TIM_50us ;************************ ; 16進数--> LCD 表示 ; 例 3AH --> 3A とカレントのカーソル位置から表示 ; 入力 W レジスタ ;************************* HEX2LCD MOVWF HEX2_WRK ; W 退避 SWAPF HEX2_WRK,W ; 上位4ビット ANDLW 0FH ; SUBLW 09H ; 09H - W --> W BTFSC STATUS,C ; 9よりおおきいとCはOffで次をスキップ GOTO HEX2_01 ; 上位4bit9以下 ; 上位4bit 10以上 SUBLW 40H GOTO HEX2_02 HEX2_01 ; 上位4ビット 9以下 SUBLW 39H HEX2_02 CALL LCD_WRITE MOVF HEX2_WRK,W ANDLW 0FH SUBLW 09H ; 09H - W --> W BTFSC STATUS,C ; 9よりおおきいとCはOffで次をスキップ GOTO HEX2_03 ; 上位4bit9以下 ; 上位4bit 10以上 SUBLW 40H GOTO HEX2_04 HEX2_03 ; 上位4ビット 9以下 SUBLW 39H HEX2_04 GOTO LCD_WRITE ; TIM_50us等の時間稼ぎモジュールはマスタープログラム全体のところを参照 |
LCDADR
EQU 7CH ; i2c LCD
AQM1602XAのアドレス+R/wビット ADTADR_W EQU 90H ; ADT7410スレーブアドレス書き込みモード ADTADR_R EQU 91H ; ADT7410スレーブアドレス読み込みモード CBLOCK 020H CNT0 ;タイマ用カウンタ CNT1 ;タイマ用カウンタ CNT2 ;タイマ用カウンタ CNT3 ;汎用カウンタ、信号解析、LCD表示用など HEX2_WRK ; HEX2LCDモジュールWRK TEMPH ;温度上位バイト TEMPL ;温度下位バイト ONDO2 ; 10進温度の + - の符号 ONDO1 ; 10進温度の2桁目 ONDO0 ; 10進温度の1桁目 T_WRKH ; 温度計算ワーク T_WRKL ; 温度計算ワーク ; (TEMPH,TEMPL) 10℃=0500H,1℃=0080H,0.5℃=0040H LCDWBF ; LCD書き込み用バッファ ENDC |
MAINLOOP ; 温度計測&表示 CALL ADT_READ; 温度取得 ---> TEMPH,TEMPL MOVLW 0C0H ;LCD 2行目0文字目に位置設定 CALL LCD_EXE MOVF TEMPH,W CALL HEX2LCD MOVF TEMPL,W CALL HEX2LCD ; CALL T_CAL; 温度の10進数変換--->ONDO2,ONDO1,ONDO0 CALL T_MOD ; 温度表示調整 ; CALL LCD_L2 ; LCD 2行目 MOVLW 0C8H ;2行目8文字目に位置設定 CALL LCD_EXE MOVF ONDO2,W CALL LCD_WRITE MOVF ONDO1,W CALL LCD_WRITE MOVF ONDO0,W CALL LCD_WRITE MOVLW 0F2H ;℃ CALL LCD_WRITE MOVLW "C" CALL LCD_WRITE CALL TIM_500ms CALL TIM_500ms CALL TIM_500ms CALL TIM_500ms ; ; Serbo motorモジュールからDuty値受信 GOTO MAINLOOP ;***************************** ; ADT7410から温度を読み込む ;***************************** ADT_READ CALL I2CSTART ;開始条件送信 MOVLW ADTADR_W ;スレーブアドレスセット書き込みモード CALL I2CSEND ; MOVLW 0 ;温度レジスタHigh 0番地 CALL I2CSEND ; CALL I2CRESTART ; 開始条件再送信 MOVLW ADTADR_R ;スレーブアドレスセット(読み出しモード) CALL I2CSEND CALL I2CRCV ;ADTより温度上位バイトを受信 --> W MOVWF TEMPH ;温度をTEMPHに格納 ; CALL I2CREND ;ADTより温度下位を受信 --> W MOVWF TEMPL GOTO I2CEND ;************************************************************* ; 温度計算 ; (TEMPH,TEMPL)から10進数の温度(ONDO2,ONDO1,ONDO0)に変換 ; (1)ONDO2にスペース20H,ONDO1,ONDO0はそれぞれ0クリア ; (2)TEMPHのMSBが1なら ONDO2に"-"を入れる ; (3)TEMPHのMSBが1なら (TEMPH,TEMPL)の0と1をひっくり返して+1する ; (4)(TEMPH,TEMPL)を2倍(左シフト)してT_WRKH,T_WRKLに入れる ; (5)T_WRKLのMSBが1なら小数点以下0.5以上なのでT_WRKHに+1する。 ; (6)T_WRKHを10進数にして十の位をONDO1に、一の位をONDO0に入れる ; (7)ONDO1,ONDO0の数字を文字に変換 ;************************************************************* T_CAL MOVLW 20H MOVWF ONDO2 ;十進温度の符号 CLRF ONDO1 ;十進温度十の位 CLRF ONDO0 ;十進温度一の位 ;計算ワークに転送 MOVF TEMPH,W MOVWF T_WRKH MOVF TEMPL,W MOVWF T_WRKL ; BTFSS TEMPH,7 ; マイナス(氷点下) GOTO T_CAL1 ;(2)の処理 MOVLW "-" MOVWF ONDO2 ;(3)の処理 ひっくり返して+1 COMF T_WRKH,F COMF T_WRKL,F INCF T_WRKL,F BTFSC STATUS,Z INCF T_WRKH,F T_CAL1 ;(4)の処理 RLF T_WRKL,F RLF T_WRKH,F ;(5)の処理 BTFSC T_WRKL,7 ; 0.5以上は四捨五入 INCF T_WRKH,F ; ;(6)の処理 T_CAL2 MOVLW 0AH SUBWF T_WRKH,F ; T_WRKH - W ---> T_WRKH BTFSS STATUS,C GOTO T_CAL3 ; T_WRKH -W <0 ; T_WRKH - W >=0 INCF ONDO1,F GOTO T_CAL2 T_CAL3 MOVLW 0AH ADDWF T_WRKH,F ; 引きすぎたので戻す BTFSC STATUS,Z GOTO T_CAL5 ; ちょうど10の倍数だった T_CAL4 INCF ONDO0,F DECFSZ T_WRKH,F GOTO T_CAL4 T_CAL5 ; 文字に変換 MOVLW 30H ADDWF ONDO1,F MOVLW 30H ADDWF ONDO0,F RETURN ;*************************************************** ; 温度表示補正 ; ONDO1が0はスペースに置き換える ; ONDO1がスペースかつONDO0が0かつONDO2がマイナスの ; のときはマイナス表示をしない - 0 を 0の表示にする ;**************************************************** T_MOD MOVLW 30H SUBWF ONDO1,W BTFSS STATUS,Z GOTO T_MOD1 ; ONDO1 == 0 MOVLW 20H MOVWF ONDO1 ; スペースを入れる MOVLW 30H SUBWF ONDO0,W BTFSS STATUS,Z GOTO T_MOD1 ; ONDO0 == 0 かつONDO0 == 0 だった MOVLW 20H MOVWF ONDO2 ; 氷点下でも氷点下でなくても符号をとる - 0 表示をしない T_MOD1 RETURN |
LCDADR
EQU 7CH ; i2c LCD
AQM1602XAのアドレス+R/wビット ADTADR_W EQU 90H ; ADT7410スレーブアドレス書き込みモード ADTADR_R EQU 91H ; ADT7410スレーブアドレス読み込みモード SERVOADR_W EQU 0B6H ;サーボモータモジュール書き込みアドレス SERVOADR_R EQU 0B7H ; サーボモータモジュール読み込みアドレス D_RIGHT EQU 0FH ; Duty 2.5% Servo Left D_CENTER EQU 2FH ; Duty 7.25% Servo Center D_LEFT EQU 4EH ; Duty 12% Servo Right CBLOCK 020H CNT0 ;タイマ用カウンタ CNT1 ;タイマ用カウンタ CNT2 ;タイマ用カウンタ CNT3 ;汎用カウンタ、信号解析、LCD表示用など HEX2_WRK ; HEX2LCDモジュールWRK D_VAL ; Duty 5%〜10% 初期値 7.25% TEMPH ;温度上位バイト TEMPL ;温度下位バイト ONDO2 ; 10進温度の + - の符号 ONDO1 ; 10進温度の2桁目 ONDO0 ; 10進温度の1桁目 T_WRKH ; 温度計算ワーク T_WRKL ; 温度計算ワーク ; (TEMPH,TEMPL) 10℃=0500H,1℃=0080H,0.5℃=0040H LCDWBF ; LCD書き込み用バッファ ENDC |
MAINLOOP ; 温度計測&表示 CALL ADT_READ; 温度取得 ---> TEMPH,TEMPL MOVLW 0C0H ;LCD 2行目0文字目に位置設定 CALL LCD_EXE MOVF TEMPH,W CALL HEX2LCD MOVF TEMPL,W CALL HEX2LCD ; CALL T_CAL; 温度の10進数変換--->ONDO2,ONDO1,ONDO0 CALL T_MOD ; 温度表示調整 MOVLW 0C8H ;2行目8文字目に位置設定 CALL LCD_EXE MOVF ONDO2,W CALL LCD_WRITE MOVF ONDO1,W CALL LCD_WRITE MOVF ONDO0,W CALL LCD_WRITE MOVLW 0F2H ;℃ CALL LCD_WRITE MOVLW "C" CALL LCD_WRITE ; ONDO0が偶数ならサーボを右いっぱいに、偶数なら左いっぱいに動かす BANKSEL PORTA MOVLW D_RIGHT BTFSC ONDO0,0 ;偶数? MOVLW D_LEFT ;奇数 MOVWF D_VAL CALL SEND_DUTY ;SLAVEにDuty値を送信 ; D_VAL 送信値の表示 MOVLW 080H ; 表示位置セット CALL LCD_EXE MOVLW "T" CALL LCD_WRITE MOVLW "X" CALL LCD_WRITE MOVLW ":" CALL LCD_WRITE MOVF D_VAL,W CALL HEX2LCD ;D_VALを表示 CALL TIM_500ms CALL TIM_500ms CALL TIM_500ms CALL TIM_500ms ; ; Serbo motorモジュールからDuty値受信 CALL RECEIVE_DUTY ;duty値-->RCV_WRK MOVLW 088H ; 表示位置セット CALL LCD_EXE MOVLW "R" CALL LCD_WRITE MOVLW "X" CALL LCD_WRITE MOVLW ":" CALL LCD_WRITE MOVF RCV_WRK,W CALL HEX2LCD ;受信D_VALを表示 GOTO MAINLOOP ;************************************************ ; DUTY値送信 ;************************************************ SEND_DUTY BANKSEL PORTA CALL I2CRESTART ;開始条件送信 MOVLW SERVOADR_W ;スレーブアドレスセット書き込みモード CALL I2CSEND ; BANKSEL PORTA MOVF D_VAL,W ;D_VAL送信 CALL I2CSEND GOTO I2CEND ;************************************************ ; DUTY値受信 ;************************************************ RECEIVE_DUTY BANKSEL PORTA CALL I2CRESTART ;開始条件送信 MOVLW SERVOADR_R ;スレーブアドレスセット読み込みモード CALL I2CSEND ; BANKSEL PORTA CALL I2CREND MOVWF RCV_WRK ; 受信用WRKに退避 GOTO I2CEND |
; CPU ピン配置 ; |--u--| ; VDD=|1 8|=VSS ; PWM(RA5)=|2 7|=(RA0) ; (RA4)=|3 6|=(RA1)SCL ; (RA3)=|4 5|=(RA2)SDA ; ~~~~~~ LIST P=PIC12F1840,ST=OFF,R=DEC INCLUDE "p12f1840.inc" __CONFIG _CONFIG1 , _FOSC_INTOSC & _WDTE_OFF & _PWRTE_ON & _MCLRE_OFF & _CP_OFF & _CPD_OFF & _BOREN_ON & _CLKOUTEN_OFF & _IESO_OFF & _FCMEN_OFF __CONFIG _CONFIG2 , _WRT_OFF & _PLLEN_OFF & _STVREN_ON & _BORV_HI & _LVP_OFF ;CONFIG1の設定 ;_FOSC_INTOSC 内部クロック使用(INTOSC),_WDTE_OFF WatchDogTimer無し, _PWRTE_ON 電源ONから64ms後プログラム開始 ;_MCLRE_OFF 外部リセット信号使用しない RA3はデジタルピン _CP_OFF プログラムメモリの保護無 _CPD_OFF dataメモリ保護無し ;_BOREN_ON 電源電圧降下常時監視機能ON _CLKOUTEN_OFF ClockoutピンをRA4ピンで使用 ;_IESO_OFF 外部・内部クロックの切り替えでの起動なし _FCMEN_OFF 外部クロック監視無し ;CONFIG2の設定 ;_WRT_OFF flashmemory保護無し _PLLEN_OFF 32MHzでは動作させない _STVREN_ON stack overはリセットする ;_BORV_HI 電源電圧降下常時監視電圧2.5V設定 _LVP_OFF 低電圧プログラミング機能不使用 LCDADR EQU 7CH ; i2c LCD AQM1602XAのアドレス+R/wビット ADTADR_W EQU 90H ; ADT7410スレーブアドレス書き込みモード ADTADR_R EQU 91H ; ADT7410スレーブアドレス読み込みモード SERVOADR_W EQU 0B6H ;サーボモータモジュール書き込みアドレス SERVOADR_R EQU 0B7H ; サーボモータモジュール読み込みアドレス D_RIGHT EQU 0FH ; Duty 2.5% Servo Left D_CENTER EQU 2FH ; Duty 7.25% Servo Center D_LEFT EQU 4EH ; Duty 12% Servo Right CBLOCK 020H CNT0 ;タイマ用カウンタ CNT1 ;タイマ用カウンタ CNT2 ;タイマ用カウンタ CNT3 ;汎用カウンタ、信号解析、LCD表示用など HEX2_WRK ; HEX2LCDモジュールWRK D_VAL ; Duty 5%〜10% 初期値 7.25% TEMPH ;温度上位バイト TEMPL ;温度下位バイト ONDO2 ; 10進温度の + - の符号 ONDO1 ; 10進温度の2桁目 ONDO0 ; 10進温度の1桁目 T_WRKH ; 温度計算ワーク T_WRKL ; 温度計算ワーク ; (TEMPH,TEMPL) 10℃=0500H,1℃=0080H,0.5℃=0040H RCV_WRK ;受信用Wrk (Duty値受信処理用) LCDWBF ; LCD書き込み用バッファ ENDC RES_VECT CODE 0x0000 ; processor reset vector GOTO MAIN_START ; go to beginning of program ;=================================== ; 今回は割り込みは使わないけれど ; PICの割り込みはすべてここにくる ;================================== ORG 4 GOTO INTERRUPT ;=================================== ; 割り込み処理 ;=================================== INTERRUPT ;-----レジスタ退避-------------------- ;コンテキスト自動保存 GOTO GAIBU_INT ; 外部割り込み INTEND ; 割り込み処理の終了処理 BCF INTCON,INTF ; 割り込みフラグクリア ;-----レジスタ復帰------------------- ;コンテキスト自動復帰 ;------------------------------------ RETFIE ; 割り込み許可で戻る ;============================= ; 外部割り込み(今回使っていないから何もしない) ;============================= GAIBU_INT GOTO INTEND MAIN_START BANKSEL OSCCON MOVLW 60H ; 内部クロック2MHzの設定 MOVWF OSCCON BANKSEL INTCON BCF INTCON,GIE ; 割り込み禁止 BCF INTCON,PEIE ; 割り込み禁止 ;PORTAをディジタルI/Oにする BANKSEL PORTA CLRF PORTA BANKSEL LATA CLRF LATA BANKSEL ANSELA ; digital I/O CLRF ANSELA ; BANKSEL TRISA MOVLW B'00000110' ; SCL,SDAのRA2,RA1入力,RA5出力 MOVWF TRISA ;ここからI2Cの設定 BANKSEL SSP1STAT MOVLW 80H MOVWF SSP1STAT ; SMP=ON MOVLW 028H ;SSP1EN=ON I2C master mode MOVWF SSP1CON1 CLRF SSP1CON2 MOVLW 04H ; 2MHz/((04H+1)*4)=100kHz MOVWF SSP1ADD ;100KBps設定 ; BANKSEL PIR1 BCF PIR1,SSP1IF BANKSEL PORTA ;BANK0へ切り替え ;ここまでi2cの設定 CALL LCD_INIT CALL LCD_ON MAINLOOP ; 温度計測&表示 CALL ADT_READ; 温度取得 ---> TEMPH,TEMPL MOVLW 0C0H ;LCD 2行目0文字目に位置設定 CALL LCD_EXE MOVF TEMPH,W CALL HEX2LCD MOVF TEMPL,W CALL HEX2LCD ; CALL T_CAL; 温度の10進数変換--->ONDO2,ONDO1,ONDO0 CALL T_MOD ; 温度表示調整 ; CALL LCD_L2 ; LCD 2行目 MOVLW 0C8H ;2行目8文字目に位置設定 CALL LCD_EXE MOVF ONDO2,W CALL LCD_WRITE MOVF ONDO1,W CALL LCD_WRITE MOVF ONDO0,W CALL LCD_WRITE MOVLW 0F2H ;℃ CALL LCD_WRITE MOVLW "C" CALL LCD_WRITE ; ONDO0が偶数ならサーボを右いっぱいに、偶数なら左いっぱいに動かす BANKSEL PORTA MOVLW D_RIGHT BTFSC ONDO0,0 ;偶数? MOVLW D_LEFT ;奇数 MOVWF D_VAL CALL SEND_DUTY ;SLAVEにDuty値を送信 ; D_VAL 送信値の表示 MOVLW 080H ; 表示位置セット CALL LCD_EXE MOVLW "T" CALL LCD_WRITE MOVLW "X" CALL LCD_WRITE MOVLW ":" CALL LCD_WRITE MOVF D_VAL,W CALL HEX2LCD ;D_VALを表示 CALL TIM_500ms CALL TIM_500ms CALL TIM_500ms CALL TIM_500ms ; ; Serbo motorモジュールからDuty値受信 CALL RECEIVE_DUTY ;duty値-->RCV_WRK MOVLW 088H ; 表示位置セット CALL LCD_EXE MOVLW "R" CALL LCD_WRITE MOVLW "X" CALL LCD_WRITE MOVLW ":" CALL LCD_WRITE MOVF RCV_WRK,W CALL HEX2LCD ;受信D_VALを表示 GOTO MAINLOOP ;***************************** ; ADT7410から温度を読み込む ;***************************** ADT_READ CALL I2CSTART ;開始条件送信 MOVLW ADTADR_W ;スレーブアドレスセット書き込みモード CALL I2CSEND ; MOVLW 0 ;温度レジスタHigh 0番地 CALL I2CSEND ; CALL I2CRESTART ; 開始条件再送信 MOVLW ADTADR_R ;スレーブアドレスセット(読み出しモード) CALL I2CSEND CALL I2CRCV ;ADTより温度上位バイトを受信 --> W MOVWF TEMPH ;温度をTEMPHに格納 ; CALL I2CREND ;ADTより温度下位を受信 --> W MOVWF TEMPL GOTO I2CEND ;************************************************************* ; 温度計算 ; (TEMPH,TEMPL)から10進数の温度(ONDO2,ONDO1,ONDO0)に変換 ; (1)ONDO2にスペース20H,ONDO1,ONDO0はそれぞれ0クリア ; (2)TEMPHのMSBが1なら ONDO2に"-"を入れる ; (3)TEMPHのMSBが1なら (TEMPH,TEMPL)の0と1をひっくり返して+1する ; (4)(TEMPH,TEMPL)を2倍(左シフト)してT_WRKH,T_WRKLに入れる ; (5)T_WRKLのMSBが1なら小数点以下0.5以上なのでT_WRKHに+1する。 ; (6)T_WRKHを10進数にして十の位をONDO1に、一の位をONDO0に入れる ; (7)ONDO1,ONDO0の数字を文字に変換 ;************************************************************* T_CAL MOVLW 20H MOVWF ONDO2 ;十進温度の符号 CLRF ONDO1 ;十進温度十の位 CLRF ONDO0 ;十進温度一の位 ;計算ワークに転送 MOVF TEMPH,W MOVWF T_WRKH MOVF TEMPL,W MOVWF T_WRKL ; BTFSS TEMPH,7 ; マイナス(氷点下) GOTO T_CAL1 ;(2)の処理 MOVLW "-" MOVWF ONDO2 ;(3)の処理 ひっくり返して+1 COMF T_WRKH,F COMF T_WRKL,F INCF T_WRKL,F BTFSC STATUS,Z INCF T_WRKH,F T_CAL1 ;(4)の処理 RLF T_WRKL,F RLF T_WRKH,F ;(5)の処理 BTFSC T_WRKL,7 ; 0.5以上は四捨五入 INCF T_WRKH,F ; ;(6)の処理 T_CAL2 MOVLW 0AH SUBWF T_WRKH,F ; T_WRKH - W ---> T_WRKH BTFSS STATUS,C GOTO T_CAL3 ; T_WRKH -W <0 ; T_WRKH - W >=0 INCF ONDO1,F GOTO T_CAL2 T_CAL3 MOVLW 0AH ADDWF T_WRKH,F ; 引きすぎたので戻す BTFSC STATUS,Z GOTO T_CAL5 ; ちょうど10の倍数だった T_CAL4 INCF ONDO0,F DECFSZ T_WRKH,F GOTO T_CAL4 T_CAL5 ; 文字に変換 MOVLW 30H ADDWF ONDO1,F MOVLW 30H ADDWF ONDO0,F RETURN ;*************************************************** ; 温度表示補正 ; ONDO1が0はスペースに置き換える ; ONDO1がスペースかつONDO0が0かつONDO2がマイナスの ; のときはマイナス表示をしない - 0 を 0の表示にする ;**************************************************** T_MOD MOVLW 30H SUBWF ONDO1,W BTFSS STATUS,Z GOTO T_MOD1 ; ONDO1 == 0 MOVLW 20H MOVWF ONDO1 ; スペースを入れる MOVLW 30H SUBWF ONDO0,W BTFSS STATUS,Z GOTO T_MOD1 ; ONDO0 == 0 かつONDO0 == 0 だった MOVLW 20H MOVWF ONDO2 ; 氷点下でも氷点下でなくても符号をとる - 0 表示をしない T_MOD1 RETURN ;************************************************ ; DUTY値送信 ;************************************************ SEND_DUTY BANKSEL PORTA CALL I2CRESTART ;開始条件送信 MOVLW SERVOADR_W ;スレーブアドレスセット書き込みモード CALL I2CSEND ; BANKSEL PORTA MOVF D_VAL,W ;D_VAL送信 CALL I2CSEND GOTO I2CEND ;************************************************ ; DUTY値受信 ;************************************************ RECEIVE_DUTY BANKSEL PORTA CALL I2CRESTART ;開始条件送信 MOVLW SERVOADR_R ;スレーブアドレスセット読み込みモード CALL I2CSEND ; BANKSEL PORTA CALL I2CREND MOVWF RCV_WRK ; 受信用WRKに退避 GOTO I2CEND ;========================================================================= ; I2C 制御モジュール群 ;========================================================================= ;********************************************************************** ; 開始条件送信 ; (1)通信状態ではないときSDA,SCLともにHIGH状態(22KΩの抵抗でこの2本をプルアップ ; (2) SCLがHのままSDAがH --> L に変化したときが開始状態 ;********************************************************************** I2CSTART BANKSEL SSP1CON1 BCF SSP1CON1,WCOL ; SSPCONの衝突フラグクリア BSF SSP1CON2,SEN ; 開始条件送信 BTFSC SSP1CON1,WCOL ; 衝突あり? GOTO I2CSTART ; 衝突あり BTFSC SSP1CON2,SEN ; スタート終了? GOTO $-1 BANKSEL PORTA ;BANK0へ切り替え RETURN ; ;********************************************************************** ; 受信処理の再開始条件送信 ;********************************************************************** I2CRESTART BANKSEL PIR1 BCF PIR1,SSP1IF ;割り込みフラグクリア BANKSEL SSP1CON2 ;BANK切り替え BSF SSP1CON2,RSEN ; 再開始条件送信 BTFSC SSP1CON2,RSEN ; 再開始条件出力? GOTO $-1 BANKSEL PORTA ;BANK0へ切り替え RETURN ;********************************************************************** ; データ送信 ; 入力 W: 送信データ ;********************************************************************** I2CSEND BCF PIR1,SSP1IF ; 割り込みフラグクリア BANKSEL SSP1BUF MOVWF SSP1BUF ; 送信 BANKSEL PIR1 BTFSS PIR1,SSP1IF ; 送信完了? GOTO $-1 ; BANKSEL SSP1CON2 ;BANKへ切り替え BTFSC SSP1CON2,ACKSTAT ; ACK受信? GOTO $-1 ; ; BANKSEL PORTA ;BANK0へ切り替え RETURN ;********************************************************************** ; 1バイトデータ受信 ; 出力 W 受信データ ;********************************************************************** I2CRCV BCF PIR1,SSP1IF ; 割り込みフラグクリア BANKSEL SSP1CON2 ;BANKへ切り替え BSF SSP1CON2,RCEN ; 受信許可 BTFSC SSP1CON2,RCEN ; 受信完了か? GOTO $-1 BCF SSP1CON2,ACKDT ;0:ACKをセット BSF SSP1CON2,ACKEN ;ACK送信 BTFSC SSP1CON2,ACKEN ;ACK送信完了? GOTO $-1 BANKSEL SSP1BUF ;BANK切り替え MOVF SSP1BUF,W ;データ取得 BANKSEL PORTA RETURN ;********************************************************************** ; 最終バイト受信 (最終バイトを受信して終了の時はCPUからNACKを送信) ; 出力 W 受信データ ;********************************************************************** I2CREND BCF PIR1,SSP1IF ; 割り込みフラグクリア BANKSEL SSP1CON2 ;BANKへ切り替え BSF SSP1CON2,RCEN ; 受信許可 BTFSC SSP1CON2,RCEN ; 受信完了か? GOTO $-1 BSF SSP1CON2,ACKDT ;1:NACKをセット BSF SSP1CON2,ACKEN ;NACK送信 BTFSC SSP1CON2,ACKEN ;NACK送信完了? GOTO $-1 BANKSEL SSP1BUF ;BANK切り替え MOVF SSP1BUF,W ;データ取得 BANKSEL PORTA RETURN ;********************************************************************** ; 終了条件送信 ;********************************************************************** I2CEND BCF PIR1,SSP1IF ; 割り込みフラグクリア BANKSEL SSP1CON2 ;BANK1へ切り替え BSF SSP1CON2,PEN ; ストップ出力 BTFSC SSP1CON2,PEN ; 出力完了か? GOTO $-1 BANKSEL PORTA ;BANK0へ切り替え BCF PIR1,SSP1IF ; 割り込みフラグクリア RETURN ;======================================================================= ; LCD制御モジュール群 ;======================================================================= ;+++++++++++++++++++++++++++++++++++++++++++++ ;+ LCD初期化処 理 + ;+++++++++++++++++++++++++++++++++++++++++++++ LCD_INIT CALL TIM_50ms ; 40ms以上待つ CALL I2CSTART ;開始条件送信 MOVLW LCDADR ;スレーブアドレス+Wセット CALL I2CSEND ; スレーブアドレス+W送信 ; Function set #1 MOVLW 80H ;Co=ON RS=0 CALL I2CSEND ;control byte 送信 ; MOVLW 38H ;Function Set(instruction table #0) CALL I2CSEND; Instruction 送信 CALL TIM_10us ;30μS待つ CALL TIM_10us CALL TIM_10us ; Function set #2 MOVLW 80H ;Co=ON RS=0 CALL I2CSEND ;Control byte 送信 ; MOVLW 39H ;Function Set(instruction table #1) CALL I2CSEND; Instruction 送信 CALL TIM_10us ;30μS待つ CALL TIM_10us CALL TIM_10us ; Internal OSC Frequency MOVLW 80H ;Co=ON RS=0 CALL I2CSEND ;control byte 送信 ; MOVLW 16H ; CALL I2CSEND; Instruction 送信 CALL TIM_10us ;30μS待つ CALL TIM_10us CALL TIM_10us ; Contrast set MOVLW 80H ;Co=ON RS=0 CALL I2CSEND;control byte 送信 ; MOVLW 73H ; CALL I2CSEND; Instruction 送信 CALL TIM_10us ;30μS待つ CALL TIM_10us CALL TIM_10us ; Power /Con /Contrast MOVLW 80H ;Co=ON RS=0 CALL I2CSEND;control byte 送信 ; MOVLW 54H ; CALL I2CSEND; Instruction 送信 CALL TIM_10us ;30μS待つ CALL TIM_10us CALL TIM_10us ; Follower Control MOVLW 80H ;Co=ON RS=0 CALL I2CSEND;control byte 送信 ; MOVLW 6CH ; CALL I2CSEND; Instruction 送信 CALL TIM_100ms ;200ms待つ CALL TIM_100ms ; Function set MOVLW 80H ;Co=ON RS=0 CALL I2CSEND;control byte 送信 ; MOVLW 38H ;Function Set(instruction table #0に戻す) CALL I2CSEND; Instruction 送信 CALL TIM_10us;30μS待つ CALL TIM_10us CALL TIM_10us ; Clear Display MOVLW 80H ;Co=ON RS=0 CALL I2CSEND;control byte 送信 ; MOVLW 01H ; CALL I2CSEND; Instruction 送信 CALL TIM_10us;30μS待つ CALL TIM_10us CALL TIM_10us ; Display ON/OFF control MOVLW 00H ;Co=OFF RS=0 CALL I2CSEND;control byte 送信 ; MOVLW 0CH ; CALL I2CSEND ; Instruction 送信 CALL TIM_10us;30μS待つ CALL TIM_10us CALL TIM_10us GOTO I2CEND; I2C終了条件送信の処理をしてリターン ;+++++++++++++++++++++++++++++++ ; LCD COMMAND 実行 コマンド1個 ; 入力 W ;+++++++++++++++++++++++++++++++ LCD_EXE BANKSEL PORTA MOVWF LCDWBF ;データ退避 CALL I2CSTART ;i2cスタート条件送信 ; MOVLW LCDADR ;LCDスレーブアドレス+W CALL I2CSEND ;スレーブアドレス送信B MOVLW 00H ; Co=OFF RS=0 CALL I2CSEND ;control byte 送信 MOVF LCDWBF,W CALL I2CSEND ; Instruction(=コマンド) 送信 GOTO I2CEND; I2C終了条件送信の処理をしてリターン ;+++++++++++++++++++++++++++++++ ; LCD DATA WRITE ; 入力 W : (データ値) ;+++++++++++++++++++++++++++++++ LCD_WRITE BANKSEL PORTA MOVWF LCDWBF ;データ退避 CALL I2CSTART ;i2cスタート条件送信 ; MOVLW LCDADR ;LCDスレーブアドレス+W CALL I2CSEND ;スレーブアドレス送信 MOVLW 40H ; Co=OFF RS=1 CALL I2CSEND ;control byte 送信 MOVF LCDWBF,W CALL I2CSEND ;data 送信 GOTO I2CEND ; I2C終了条件送信の処理をしてリターン ;+++++++++++++++++++++++++++++++ ; LCD OFF ;+++++++++++++++++++++++++++++++ LCD_OFF MOVLW 08H GOTO LCD_EXE ;+++++++++++++++++++++++++++++++ ; LCD ON ; 表示ON カーソルはoff (カーソルonの場合は0EHを設定) ;+++++++++++++++++++++++++++++++ LCD_ON MOVLW 0CH GOTO LCD_EXE ;+++++++++++++++++++++++++++++++ ; LCD CLEAR ;+++++++++++++++++++++++++++++++ LCD_CLEAR MOVLW 01H CALL LCD_EXE CALL TIM_600us GOTO TIM_1ms ;+++++++++++++++++++++++++++++++++++ ; カーソルの位置を1行目の先頭にセット ;+++++++++++++++++++++++++++++++++++ LCD_L1 ;MSB=1 +DDRAMADDRESS(000 0000) MOVLW 80H GOTO LCD_EXE ;+++++++++++++++++++++++++++++++++++ ; カーソルの位置を2行目の先頭にセット ;+++++++++++++++++++++++++++++++++++ LCD_L2 ; MSB=1 +DDRAMADDRESS(100 0000) MOVLW 0C0H GOTO LCD_EXE ;+++++++++++++++++++++++++++++++++++ ; カーソルの位置を右シフト(つかってないけど) ;+++++++++++++++++++++++++++++++++++ LCD_RIGHT MOVLW 14H CALL LCD_EXE GOTO TIM_50us ;************************ ; 16進数--> LCD 表示 ; 例 3AH --> 3A とカレントのカーソル位置から表示 ; 入力 W レジスタ ;************************* HEX2LCD MOVWF HEX2_WRK ; W 退避 SWAPF HEX2_WRK,W ; 上位4ビット ANDLW 0FH ; SUBLW 09H ; 09H - W --> W BTFSC STATUS,C ; 9よりおおきいとCはOffで次をスキップ GOTO HEX2_01 ; 上位4bit9以下 ; 上位4bit 10以上 SUBLW 40H GOTO HEX2_02 HEX2_01 ; 上位4ビット 9以下 SUBLW 39H HEX2_02 CALL LCD_WRITE MOVF HEX2_WRK,W ANDLW 0FH SUBLW 09H ; 09H - W --> W BTFSC STATUS,C ; 9よりおおきいとCはOffで次をスキップ GOTO HEX2_03 ; 上位4bit9以下 ; 上位4bit 10以上 SUBLW 40H GOTO HEX2_04 HEX2_03 ; 上位4ビット 9以下 SUBLW 39H HEX2_04 GOTO LCD_WRITE ;************************ ; TIM_10us 10μ秒待ち ;************************ TIM_10us ; CALLで2 GOTO $+1 ;2 GOTO $+1 ;2 GOTO $+1 ;2 RETURN ;2 ;************************ ; TIM_50us 50μ秒待ち ;************************ TIM_50us ;2 MOVLW 7 ;1 MOVWF CNT0 ;1 DECFSZ CNT0,F ;1(2) GOTO $-1 ;2 NOP ;1 RETURN ;2 ;*************************** ; TIM_100us 100μ秒待ち ;*************************** TIM_100us ;100 micro sec timer ;2 MOVLW 15 ;1 MOVWF CNT0 ;1 DECFSZ CNT0,F ;1(2) GOTO $-1 ;2 GOTO $+1 ;2 RETURN ;2 ;**************************** ; TIM_170us 170μ秒待ち ;**************************** TIM_170us ;2 MOVLW 26 ;1 MOVWF CNT0 ;1 DECFSZ CNT0,F ;1(2) GOTO $-1 ;2 GOTO $+1 ;2 NOP ;1 RETURN ;2 ;**************************** ; TIM_220us 220μ秒待ち ;**************************** TIM_220us ;2 MOVLW 35 ;1 MOVWF CNT0 ;1 DECFSZ CNT0,F ;1(2) GOTO $-1 ;2 RETURN ;2 ;**************************** ; TIM_276us 276μ秒待ち ;**************************** TIM_276us ;2 MOVLW 44 ;1 MOVWF CNT0 ;1 DECFSZ CNT0,F ;1(2) GOTO $-1 ;2 NOP ;1 RETURN ;2 ;**************************** ; TIM_300us 300μ秒待ち ;**************************** TIM_300us ;2 MOVLW 48 ;1 MOVWF CNT0 ;1 DECFSZ CNT0,F ;1(2) GOTO $-1 ;2 NOP ;1 RETURN ;2 ;**************************** ; TIM_450us 450μ秒待ち ;**************************** TIM_450us MOVLW 73 ;1 MOVWF CNT0 ;1 DECFSZ CNT0,F ;1(2) GOTO $-1 ;2 GOTO $+1 ;2 NOP ;1 RETURN ;2 ;**************************** ; TIM_500us 500μ秒待ち ;**************************** TIM_500us ;2 MOVLW 81 ;1 MOVWF CNT0 ;1 GOTO $+1 ;2 DECFSZ CNT0,F ;1(2) GOTO $-1 ;2 RETURN ;2 ;**************************** ; TIM_550us 550μ秒待ち ;**************************** TIM_550us ;2 MOVLW 89 ;1 MOVWF CNT0 ;1 GOTO $+1 ;2 DECFSZ CNT0,F ;1(2) GOTO $-1 ;2 NOP ;1 RETURN ;2 ;**************************** ; TIM_600us 600μ秒待ち ;**************************** TIM_600us ;2 MOVLW 97 ;1 MOVWF CNT0 ;1 GOTO $+1 ;2 DECFSZ CNT0,F ;1(2) GOTO $-1 ;2 GOTO $+1 ;2 RETURN ;2 ;**************************** ; TIM_900us 900μ秒待ち ;**************************** TIM_900us ; 2 MOVLW 147 ;1 MOVWF CNT0 ;1 DECFSZ CNT0,F ;1(2) GOTO $-1 ;2 GOTO $+1 ;2 GOTO $+1 ;2 RETURN ;2 ;************************* ; TIM_1ms 1m秒待ち ;************************* TIM_1ms ;2 MOVLW 164 ;1 MOVWF CNT0 ;1 DECFSZ CNT0,F ;1(2) GOTO $-1 ;2 GOTO $+1 ;2 NOP ;1 RETURN ;2 ;+++++++++++++++++++++++++ ; TIM_5ms 5m秒待ち ;************************* TIM_5ms ;2 MOVLW 249 ;1 MOVWF CNT0 ;1 GOTO $+1 ;2 GOTO $+1 ;2 GOTO $+1 ;2 NOP ;1 DECFSZ CNT0,F ;1(2) GOTO $-5 ;2 GOTO $+1 ;2 RETURN ;2 ;*************************** ; TIM_10ms 10mS秒待ち ;*************************** TIM_10ms ; 10mili sec timer CALL TIM_5ms GOTO TIM_5ms ;*************************** ; TIM_50ms 50mS秒待ち ;*************************** TIM_50ms ; 50mili sec timer MOVLW 10 MOVWF CNT1 CALL TIM_5ms DECFSZ CNT1,F GOTO $-2 RETURN ;*************************** ; TIM_100ms 100mS秒待ち ;*************************** TIM_100ms ; 100ms timer MOVLW 20 MOVWF CNT1 CALL TIM_5ms DECFSZ CNT1,F GOTO $-2 RETURN ;*************************** ; TIM_250ms 250mS待ち ;*************************** TIM_250ms ; 250msec timer MOVLW 50 MOVWF CNT1 CALL TIM_5ms DECFSZ CNT1,F GOTO $-2 RETURN ;*************************** ; TIM_500ms 500mS待ち ;*************************** TIM_500ms ; 500msec timer MOVLW 100 MOVWF CNT1 CALL TIM_5ms DECFSZ CNT1,F GOTO $-2 RETURN ;*************************** ; TIM_1S 1秒待ち ;*************************** TIM_1S ; 1sec timer MOVLW 0C8H MOVWF CNT1 CALL TIM_5ms DECFSZ CNT1,F GOTO $-2 RETURN END |
BANKSEL
INTCON BCF INTCON,GIE ; 割り込み禁止 BCF INTCON,PEIE ; 割り込み禁止 ;PORTAをディジタルI/Oにする BANKSEL PORTA CLRF PORTA BANKSEL LATA CLRF LATA BANKSEL ANSELA ; digital I/O CLRF ANSELA ; ;SCL,SDAのRA1,RA2も入力 ;RA5はPWMの出力 BANKSEL TRISA MOVLW B'00000110' ; RA2,RA1入力,RA5出力 MOVWF TRISA ;ここからI2Cの設定 BANKSEL SSP1STAT MOVLW 80H MOVWF SSP1STAT ; SMP=ON MOVLW 36H ;SSP1EN=ON I2C slave mode 7bit Address MOVWF SSP1CON1 MOVLW SLVADR ;スレーブアドレスセット MOVWF SSP1ADD BSF SSP1CON2,SEN ;stretch enabled BSF SSP1CON1,CKP ;stretch enabled ; MOVLW 04H ; 2MHz/((04H+1)*4)=100kHz <=この設定はマスターモード ; MOVWF SSP1ADD ;100KBps設定 ; BANKSEL PIR1 BCF PIR1,SSP1IF BANKSEL PORTA ;BANK0へ切り替え ;ここまでi2cの設定 ; ここに割り込み許可をしてからメインループへ BANKSEL INTCON CLRF INTCON BSF INTCON,INTE ;外部割込み許可 BSF INTCON,PEIE ;周辺割込許可 BSF INTCON,GIE ;周辺割込許可 BANKSEL PIE1 BSF PIE1,SSP1IE ; i2c 割り込み 許可 Enables the MSSP interrupt BANKSEL PORTA |
;=================================== ; PICの割り込みはすべてここにくる ;================================== ORG 4 GOTO INTERRUPT ;=================================== ; 割り込み処理 ;=================================== INTERRUPT ;-----レジスタ退避-------------------- ;コンテキスト自動保存 BANKSEL SSP1STAT BTFSS SSP1STAT,3 ; Start ? BRA INTEND BTFSC SSP1STAT,5 ; DATA ? (0:Address,1:DATA) BRA INTEND BTFSS SSP1STAT,2 ; R/W (1:Write(送信要求),0:Read(受信要求)) BRA I_READ BRA I_WRITE INTEND ; 割り込み処理の終了処理 BANKSEL INTCON BCF INTCON,INTF ; 割り込みフラグクリア BCF PIR1,SSP1IF ; 割込フラグクリア ;-----レジスタ復帰------------------- ;コンテキスト自動復帰 ;------------------------------------ RETFIE ; 割り込み許可で戻る ;*******割り込み(受信要求処理)********** I_READ BANKSEL SSP1BUF MOVF SSP1BUF,W ; 最初は読み捨てる R_LOOP ; 受信ループ BANKSEL SSP1CON1 BSF SSP1CON1,CKP ; stretch Enable BANKSEL PIR1 BCF PIR1,SSP1IF ;割り込みフラグクリア BANKSEL SSP1STAT BTFSC SSP1STAT,BF ;データ受信待ち? BRA DATAGET ;受信有り BTFSS SSP1STAT,P ;STOP検出? BRA R_LOOP;受信待ちへ BRA INTEND; 終了 DATAGET ;----データ受信処理 BANKSEL SSP1BUF MOVF SSP1BUF,W BANKSEL PORTA MOVWF D_VAL ; Duty値セット SUBLW D_RIGHT ; D_RIGHT - D_VAL --> W BTFSC STATUS,C ; CがOFFなら D_RIGHT < D_VALなので次とばす BRA R_LIMIT ; D_RIGHT >= D_VAL L_CHK MOVF D_VAL,W SUBLW D_LEFT ; D_LEFT - D_VAL --> W BTFSS STATUS,C ; CがONなら D_LEFT > D_VALなので次とばす BRA L_LIMIT ; D_LEFT < D_VAL DUTYSET CALL D_SET BRA R_LOOP R_LIMIT ;右限界値オーバー ,修正 MOVLW D_RIGHT MOVWF D_VAL BRA L_CHK L_LIMIT ; 左限界値オーバー、修正 MOVLW D_LEFT MOVWF D_VAL BRA DUTYSET ;*******割り込み(送信要求処理)********** I_WRITE BANKSEL PORTA MOVF D_VAL,W ;duty値取り出し ; XORLW 0FFH ;0,1反転 BANKSEL SSP1BUF MOVWF SSP1BUF ;I2Cにduty値送信 BSF SSP1CON1,CKP ; Stretch 解除 BANKSEL PIR1 BCF PIR1,SSP1IF ;割り込みフラグクリア BTFSC PIR1,SSP1IF ; Ready ? BRA I_WRITE BANKSEL SSP1STAT BTFSS SSP1STAT,P ;STOP? BRA I_WRITE BRA INTEND |
; TODO INSERT CONFIG CODE
HERE USING CONFIG BITS GENERATOR ; CPU ピン配置 ; |--u--| ; VDD=|1 8|=VSS ; PWM(RA5)=|2 7|=(RA0) ; (RA4)=|3 6|=(RA1)SCL ; MCLR(RA3)=|4 5|=(RA2)SDA ; ~~~~~~ LIST P=PIC12F1840,ST=OFF,R=DEC INCLUDE "p12f1840.inc" __CONFIG _CONFIG1 , _FOSC_INTOSC & _WDTE_OFF & _PWRTE_ON & _MCLRE_OFF & _CP_OFF & _CPD_OFF & _BOREN_ON & _CLKOUTEN_OFF & _IESO_OFF & _FCMEN_OFF __CONFIG _CONFIG2 , _WRT_OFF & _PLLEN_OFF & _STVREN_ON & _BORV_HI & _LVP_OFF ;CONFIG1の設定 ;_FOSC_INTOSC 内部クロック使用(INTOSC),_WDTE_OFF WatchDogTimer無し, _PWRTE_ON 電源ONから64ms後プログラム開始 ;_MCLRE_OFF 外部リセット信号使用しない RA3はデジタルピン _CP_OFF プログラムメモリの保護無 _CPD_OFF dataメモリ保護無し ;_BOREN_ON 電源電圧降下常時監視機能ON _CLKOUTEN_OFF ClockoutピンをRA4ピンで使用 ;_IESO_OFF 外部・内部クロックの切り替えでの起動なし _FCMEN_OFF 外部クロック監視無し ;CONFIG2の設定 ;_WRT_OFF flashmemory保護無し _PLLEN_OFF 32MHzでは動作させない _STVREN_ON stack overはリセットする ;_BORV_HI 電源電圧降下常時監視電圧2.5V設定 _LVP_OFF 低電圧プログラミング機能不使用 SLVADR EQU 0B6H ; このプログラムのスレーブアドレス; 1011011+0 ; R_BTN EQU 0 ; Right tact ボタン A port ビット L_BTN EQU 4 ; Left Tact ボタン A port ビット PWMPRD EQU 159 ; PWM period for PR2 D_LEFT EQU 4EH ; Duty 2.5% Servo Left D_CENTER EQU 2FH ; Duty 7.25% Servo Center D_RIGHT EQU 0FH ; Duty 12% Servo Right CBLOCK 020H CNT0 ;タイマ用カウンタ CNT1 ;タイマ用カウンタ CNT2 ;タイマ用カウンタ CNT3 ;汎用カウンタ、信号解析、LCD表示用など HEX2_WRK ; HEX2LCDモジュールWRK D_VAL ; Duty 5%〜10% 初期値 7.25% D_VAL_WRK ; Duty wrk G_WRK ; 汎用WRK W_SAVE ; 割り込み処理 W退避 PL_SAVE ; 割り込み処理 PCLATH 退避 FS_SAVE ; 割り込み処理 FSR退避 S_SAVE ; 割り込み処理 STATUS退避 ENDC RES_VECT CODE 0x0000 ; processor reset vector GOTO MAIN_START ; go to beginning of program ;=================================== ; PICの割り込みはすべてここにくる ;================================== ORG 4 GOTO INTERRUPT ;=================================== ; 割り込み処理 ;=================================== INTERRUPT ;-----レジスタ退避-------------------- ;コンテキスト自動保存 BANKSEL SSP1STAT BTFSS SSP1STAT,3 ; Start ? BRA INTEND BTFSC SSP1STAT,5 ; DATA ? (0:Address,1:DATA) BRA INTEND BTFSS SSP1STAT,2 ; R/W (1:Write(送信要求),0:Read(受信要求)) BRA I_READ BRA I_WRITE INTEND ; 割り込み処理の終了処理 BANKSEL INTCON BCF INTCON,INTF ; 割り込みフラグクリア BCF PIR1,SSP1IF ; 割込フラグクリア ;-----レジスタ復帰------------------- ;コンテキスト自動復帰 ;------------------------------------ RETFIE ; 割り込み許可で戻る ;*******割り込み(受信要求処理)********** I_READ BANKSEL SSP1BUF MOVF SSP1BUF,W ; 最初は読み捨てる R_LOOP ; 受信ループ BANKSEL SSP1CON1 BSF SSP1CON1,CKP ; stretch Enable BANKSEL PIR1 BCF PIR1,SSP1IF ;割り込みフラグクリア BANKSEL SSP1STAT BTFSC SSP1STAT,BF ;データ受信待ち? BRA DATAGET ;受信有り BTFSS SSP1STAT,P ;STOP検出? BRA R_LOOP;受信待ちへ BRA INTEND; 終了 DATAGET ;----データ受信処理 BANKSEL SSP1BUF MOVF SSP1BUF,W BANKSEL PORTA MOVWF D_VAL ; Duty値セット SUBLW D_RIGHT ; D_RIGHT - D_VAL --> W BTFSC STATUS,C ; CがOFFなら D_RIGHT < D_VALなので次とばす BRA R_LIMIT ; D_RIGHT >= D_VAL L_CHK MOVF D_VAL,W SUBLW D_LEFT ; D_LEFT - D_VAL --> W BTFSS STATUS,C ; CがONなら D_LEFT > D_VALなので次とばす BRA L_LIMIT ; D_LEFT < D_VAL DUTYSET CALL D_SET BRA R_LOOP R_LIMIT ;右限界値オーバー ,修正 MOVLW D_RIGHT MOVWF D_VAL BRA L_CHK L_LIMIT ; 左限界値オーバー、修正 MOVLW D_LEFT MOVWF D_VAL BRA DUTYSET ;*******割り込み(送信要求処理)********** I_WRITE BANKSEL PORTA MOVF D_VAL,W ;duty値取り出し BANKSEL SSP1BUF MOVWF SSP1BUF ;I2Cにduty値送信 BSF SSP1CON1,CKP ; Stretch 解除 BANKSEL PIR1 BCF PIR1,SSP1IF ;割り込みフラグクリア BTFSC PIR1,SSP1IF ; Ready ? BRA I_WRITE BANKSEL SSP1STAT BTFSS SSP1STAT,P ;STOP? BRA I_WRITE BRA INTEND ;============================== ; MAIN START ;============================== MAIN_START BANKSEL OSCCON MOVLW 60H ; 内部クロック2MHzの設定 MOVWF OSCCON BANKSEL INTCON BCF INTCON,GIE ; 割り込み禁止 BCF INTCON,PEIE ; 割り込み禁止 ;PORTAをディジタルI/Oにする BANKSEL PORTA CLRF PORTA BANKSEL LATA CLRF LATA BANKSEL ANSELA ; digital I/O CLRF ANSELA ; ;SCL,SDAのRA1,RA2も入力 ;RA5はPWMの出力 BANKSEL TRISA MOVLW B'00000110' ; RA2,RA1入力,RA5出力 MOVWF TRISA ;ここからI2Cの設定 BANKSEL SSP1STAT MOVLW 80H MOVWF SSP1STAT ; SMP=ON MOVLW 36H ;SSP1EN=ON I2C slave mode 7bit Address MOVWF SSP1CON1 MOVLW SLVADR ;スレーブアドレスセット MOVWF SSP1ADD BSF SSP1CON2,SEN ;stretch enabled BSF SSP1CON1,CKP ;stretch enabled ; MOVLW 04H ; 2MHz/((04H+1)*4)=100kHz <=この設定はマスターモード ; MOVWF SSP1ADD ;100KBps設定 ; BANKSEL PIR1 BCF PIR1,SSP1IF BANKSEL PORTA ;BANK0へ切り替え ;ここまでi2cの設定 ; Servo initialize BANKSEL APFCON BSF APFCON,CCP1SEL ; 1:RA5をPWM出力PINに設定 BANKSEL CCP1CON ; CCP1CONの下位4ビットに1100をセットしてPWMを有効にする MOVLW 0CH MOVWF CCP1CON ;pwmの周期20msを設定 BANKSEL PR2 MOVLW PWMPRD MOVWF PR2 BANKSEL T2CON ;T2CONのb1,b0を11(プリスケーラ64) BSF T2CON,0 BSF T2CON,1 BANKSEL PORTA ; Duty値設定 MOVLW D_CENTER ;Duty Center MOVWF D_VAL ; CALL D_SET ;Duty値をセット ;PWMスタート BANKSEL T2CON BSF T2CON,TMR2ON BANKSEL PORTA ; ここに割り込み許可をしてからメインループへ BANKSEL INTCON CLRF INTCON BSF INTCON,INTE ;外部割込み許可 BSF INTCON,PEIE ;周辺割込許可 BSF INTCON,GIE ;周辺割込許可 BANKSEL PIE1 BSF PIE1,SSP1IE ; i2c 割り込み 許可 Enables the MSSP interrupt BANKSEL PORTA MAINLOOP ;i2c割込待ち とくにメインループの処理はなし BANKSEL PORTA CALL TIM_500ms CALL TIM_500ms GOTO MAINLOOP ;******************************** ; D_VALの値をCCPR1L:CCP1CON<5:4> ; に転送 ;******************************** D_SET BANKSEL CCP1CON BCF CCP1CON,4 ;4ビット目クリア BCF CCP1CON,5 ;5ビット目クリア BANKSEL PORTA BTFSC D_VAL,0 GOTO D_SET0 D_SET1 BANKSEL PORTA BTFSC D_VAL,1 GOTO D_SET2 D_SET_H ; High 側の設定 BANKSEL PORTA MOVF D_VAL,W MOVWF D_VAL_WRK BCF STATUS,C RRF D_VAL_WRK,F BCF STATUS,C RRF D_VAL_WRK,F MOVF D_VAL_WRK,W BANKSEL CCPR1L MOVWF CCPR1L BANKSEL PORTA RETURN D_SET0 BANKSEL CCP1CON BSF CCP1CON,4 GOTO D_SET1 D_SET2 BANKSEL CCP1CON BSF CCP1CON,5 GOTO D_SET_H ;====================================================================== ; タイマーモジュール群 ;====================================================================== ; 命令1cycleは4クロック 4/2MHz=2μS ; CALLやRETURN、DECFSZのスキップするときなどPCLを変化させる命令は2cyles ; 他の命令は1cyles ; 上位モジュールのCALL命令も考慮するとn μS のウエイトでセットするときの ; カウンタの初期値はloop(a)の場合 (n/0.5 - 10)/3+1 ; loop(b)の場合 ;************************ ; TIM_10us 10μ秒待ち ;************************ TIM_10us ; CALLで2 GOTO $+1 ;2 GOTO $+1 ;2 GOTO $+1 ;2 RETURN ;2 ;************************ ; TIM_50us 50μ秒待ち ;************************ TIM_50us ;2 MOVLW 7 ;1 MOVWF CNT0 ;1 DECFSZ CNT0,F ;1(2) GOTO $-1 ;2 NOP ;1 RETURN ;2 ;*************************** ; TIM_100us 100μ秒待ち ;*************************** TIM_100us ;100 micro sec timer ;2 MOVLW 15 ;1 MOVWF CNT0 ;1 DECFSZ CNT0,F ;1(2) GOTO $-1 ;2 GOTO $+1 ;2 RETURN ;2 ;**************************** ; TIM_170us 170μ秒待ち ;**************************** TIM_170us ;2 MOVLW 26 ;1 MOVWF CNT0 ;1 DECFSZ CNT0,F ;1(2) GOTO $-1 ;2 GOTO $+1 ;2 NOP ;1 RETURN ;2 ;**************************** ; TIM_220us 220μ秒待ち ;**************************** TIM_220us ;2 MOVLW 35 ;1 MOVWF CNT0 ;1 DECFSZ CNT0,F ;1(2) GOTO $-1 ;2 RETURN ;2 ;**************************** ; TIM_276us 276μ秒待ち ;**************************** TIM_276us ;2 MOVLW 44 ;1 MOVWF CNT0 ;1 DECFSZ CNT0,F ;1(2) GOTO $-1 ;2 NOP ;1 RETURN ;2 ;**************************** ; TIM_300us 300μ秒待ち ;**************************** TIM_300us ;2 MOVLW 48 ;1 MOVWF CNT0 ;1 DECFSZ CNT0,F ;1(2) GOTO $-1 ;2 NOP ;1 RETURN ;2 ;**************************** ; TIM_450us 450μ秒待ち ;**************************** TIM_450us MOVLW 73 ;1 MOVWF CNT0 ;1 DECFSZ CNT0,F ;1(2) GOTO $-1 ;2 GOTO $+1 ;2 NOP ;1 RETURN ;2 ;**************************** ; TIM_500us 500μ秒待ち ;**************************** TIM_500us ;2 MOVLW 81 ;1 MOVWF CNT0 ;1 GOTO $+1 ;2 DECFSZ CNT0,F ;1(2) GOTO $-1 ;2 RETURN ;2 ;**************************** ; TIM_550us 550μ秒待ち ;**************************** TIM_550us ;2 MOVLW 89 ;1 MOVWF CNT0 ;1 GOTO $+1 ;2 DECFSZ CNT0,F ;1(2) GOTO $-1 ;2 NOP ;1 RETURN ;2 ;**************************** ; TIM_600us 600μ秒待ち ;**************************** TIM_600us ;2 MOVLW 97 ;1 MOVWF CNT0 ;1 GOTO $+1 ;2 DECFSZ CNT0,F ;1(2) GOTO $-1 ;2 GOTO $+1 ;2 RETURN ;2 ;**************************** ; TIM_900us 900μ秒待ち ;**************************** TIM_900us ; 2 MOVLW 147 ;1 MOVWF CNT0 ;1 DECFSZ CNT0,F ;1(2) GOTO $-1 ;2 GOTO $+1 ;2 GOTO $+1 ;2 RETURN ;2 ;************************* ; TIM_1ms 1m秒待ち ;************************* TIM_1ms ;2 MOVLW 164 ;1 MOVWF CNT0 ;1 DECFSZ CNT0,F ;1(2) GOTO $-1 ;2 GOTO $+1 ;2 NOP ;1 RETURN ;2 ;+++++++++++++++++++++++++ ; TIM_5ms 5m秒待ち ;************************* TIM_5ms ;2 MOVLW 249 ;1 MOVWF CNT0 ;1 GOTO $+1 ;2 GOTO $+1 ;2 GOTO $+1 ;2 NOP ;1 DECFSZ CNT0,F ;1(2) GOTO $-5 ;2 GOTO $+1 ;2 RETURN ;2 ;*************************** ; TIM_10ms 10mS秒待ち ;*************************** TIM_10ms ; 10mili sec timer CALL TIM_5ms GOTO TIM_5ms ;*************************** ; TIM_50ms 50mS秒待ち ;*************************** TIM_50ms ; 50mili sec timer MOVLW 10 MOVWF CNT1 CALL TIM_5ms DECFSZ CNT1,F GOTO $-2 RETURN ;*************************** ; TIM_100ms 100mS秒待ち ;*************************** TIM_100ms ; 100ms timer MOVLW 20 MOVWF CNT1 CALL TIM_5ms DECFSZ CNT1,F GOTO $-2 RETURN ;*************************** ; TIM_250ms 250mS待ち ;*************************** TIM_250ms ; 250msec timer MOVLW 50 MOVWF CNT1 CALL TIM_5ms DECFSZ CNT1,F GOTO $-2 RETURN ;*************************** ; TIM_500ms 500mS待ち ;*************************** TIM_500ms ; 500msec timer MOVLW 100 MOVWF CNT1 CALL TIM_5ms DECFSZ CNT1,F GOTO $-2 RETURN ;*************************** ; TIM_1S 1秒待ち ;*************************** TIM_1S ; 1sec timer MOVLW 0C8H MOVWF CNT1 CALL TIM_5ms DECFSZ CNT1,F GOTO $-2 RETURN END |