RS232cで信頼性の有る通信A
PIC16F84を使った通信


前回は受信部分を作りましたので送信部分を作ります

■送信を確認するためのWindowsアプリケーションを作成

前回作成したWindowsアプリケーションを少し変更します

#include <stdio.h>
#include "RS232c.h" //このヘッダーを取り込みます。

int main(int argc, char* argv[])
{
	RS232c rs;
	rs.Connect("COM1",
		300,
		8,
		NOPARITY,
		ONESTOPBIT,
		RTS_CONTROL_DISABLE,
		DTR_CONTROL_DISABLE,
		0,
		1000   
		);  //接続します

	unsigned char data[5]="";
	char c;

	while(1){
		c=0;
		rs.Read(&c,1);  //文字列の受信 Read(char配列,読み込む文字数)
		if(c) printf("read 0x%x\n",(unsigned char)c);
		if(c>>7){
			data[0]=~c;
			data[1]='\0';
			rs.Send((char*)data); //文字列を送信 Send(送信文字列)
			printf("send 0x%x\n",(unsigned char)data[0]);
		}
	}
	//クローズする必要はありません、オブジェクトが破棄された時、クローズされます
	return 0;
}

RS232cから一文字ずつデータを受信して先頭ビットが立っているデータを受信した場合には
そのデータを反転して送信するプログラムです



■マイコンからデータを送信するトリガーを作る

まずは、ポートAのビット2,3,4の位置の端子を100KΩでマイナス側に吊って
スイッチを取り付けました
これで、プログラムでビット2,3,4のスイッチの状態を読み取れます



▼前回作成したプログラムのメインループを修正して
スイッチの変化をそのまま送信できるようにしたいと思います


;PORTAの2,3,4ビット目が変化した時、送信処理を行うために使用するメモリ
PA_NEW		equ	0x19
PA_OLD		equ	0x1A


▲以上のメモリを使いポートの変化を読み取りたいと思います


main

		MOVFW	PORTA		;FレジスタからWレジスタに代入
		ANDLW	0x1C		;11100でアンドを取る
		MOVWF	PA_NEW		;WレジスタからFレジスタに代入
		SUBWF	PA_OLD,0		;FレジスタからWレジスタを引く
		BZ	main		;結果が0のときジャンプ

;-------------------------------------
;送信中の場合は待機するループ
;-------------------------------------
SEND_WAIT
		TSTF	SEND_BUF		;SEND_BUFがゼロかテストする
		BNZ	SEND_WAIT		;ゼロ以外のときジャンプ
SEND_WAIT_END
;-------------------------------------
		MOVFW	PA_NEW		;FレジスタからWレジスタに代入
		MOVWF	PA_OLD		;WレジスタからFレジスタに代入
		MOVWF	SEND_BUF		;WレジスタからFレジスタに代入

		goto	main


ポートAのビット 2,3,4 に変化が起きた場合には、ビット2,3,4 の情報をそのまま
RS232cで送信したいと思います

上記プログラムをPICに書き込み、パソコンとRS232cで接続しました
確認用プログラムを実行して2ビット目のスイッチから順に押してみました

c:\>■■■.exe
read 0x4
read 0x8
read 0x10

▲スイッチの入力がRS232cで正しく出力されている事が確認できました



■自作プロトコル送信

main部分を次のように修正しました


main
		CLRWDT			;ウォッチドックタイマとプリスケーラをクリア
		;自作プロトコル受信で受け取った値をPORTBに出力する
		MOVFW	TRUST_DATA	;FレジスタからWレジスタに代入
		MOVWF	PORTB		;WレジスタからFレジスタに代入

自作プロトコル受信したデータをポートBに出力しています
今回の変更とはあまり関係がない所です

;----------------------------------------------------------------------------
;PORTA bit2,3,4が変化した場合、状態を自作プロトコル送信で送信する処理
;----------------------------------------------------------------------------
		MOVLW	0x00		;Wレジスタに値を代入 
		MOVWF	PA_NEW		;WレジスタからFレジスタに代入

		;PORTAの値を左に2シフトする
		BTFSC	PORTA,2		;Fレジスタの指定ビットが0ならスキップ
		BSF	PA_NEW,0		;指定ビットに1を立てる
		BTFSC	PORTA,3		;Fレジスタの指定ビットが0ならスキップ
		BSF	PA_NEW,1		;指定ビットに1を立てる
		BTFSC	PORTA,4		;Fレジスタの指定ビットが0ならスキップ
		BSF	PA_NEW,2		;指定ビットに1を立てる

送信のトリガーとなるポートAのビットを取得しています
シフト演算が無いためビット操作でシフトを行っています

		;送信ノードIDを取り付ける
		;ノードID+1を送信ノードIDとする
		MOVFW	NODE_ID		;FレジスタからWレジスタに代入
		;0x08は左に3ビットシフトさせるため
		ADDLW	0x01*0x08		;Wレジスタに値を加算
		IORWF	PA_NEW,1		;ORを取りFレジスタに結果を代入

取得したビット情報に送信ノードIDを取り付けています
送信ノードIDは受信ノードID+1とします
(ホストがPCのため、各々のノードに送信IDを振らないと複数のノードを識別できない)

		;前回値との判定
		MOVFW	PA_NEW		;FレジスタからWレジスタに代入
		SUBWF	PA_OLD,0		;FレジスタからWレジスタを引く
		BZ	main		;結果が0のときジャンプ

前回値と比較して、変化が無かった場合はラベルmainにジャンプします

		;前回と比較して状態が変化したため、送信処理を行う
		call	SEND_WAIT		;送信完了待ち
		MOVFW	PA_NEW		;FレジスタからWレジスタに代入
		MOVWF	SEND_BUF		;送信  WレジスタからFレジスタに代入
		call	SEND_WAIT		;送信完了待ち
		COMF	PA_NEW,0		;Fレジスタを反転してWレジスタに格納
		MOVWF	SEND_BUF		;送信  WレジスタからFレジスタに代入
		call	SEND_WAIT		;送信完了待ち

前回値と比較して差異があるため自作プロトコルでデータを送信します

		;通信相手の受信成功パケットを確認する
		call	wait_loop		;ウエイト
		call	READ_WAIT		;受信完了待ち
		MOVFW	PA_NEW		;FレジスタからWレジスタに代入
		SUBWF	TRUST_BUF,0	;FレジスタからWレジスタを引く
		BNZ	main		;結果が0以外のときジャンプ
		;受信成功パケットの確認がとれた
		MOVFW	PA_NEW		;FレジスタからWレジスタに代入
		MOVWF	PA_OLD		;WレジスタからFレジスタに代入

受信成功パケットを確認します、受信成功パケットが受信できた場合には
前回値データを更新します

		goto	main





■上記プログラムをPICに書き込み、パソコンとRS232cで接続しました
確認用プログラムを実行して2ビット目のスイッチから順に押してみました

c:\>■■■.exe
read 0x10←初期状態はスイッチは何も押されていないためその旨を送信
read 0xef
send 0x10
read 0x11←2ビット目のスイッチが押された
read 0xee
send 0x11
read 0x10←何もスイッチが押されていない状態になった
read 0xef
send 0x10
read 0x12←3ビット目のスイッチが押された
read 0xed
send 0x12
read 0x10←何もスイッチが押されていない状態になった
read 0xef
send 0x10
read 0x14←4ビット目のスイッチが押された
read 0xeb
send 0x14
read 0x10←何もスイッチが押されていない状態になった
read 0xef
send 0x10



正しく動作しているようです
ちなみに、パソコンが受信完了を送信しない、もしくは受信完了のビットが違っている
場合においては、マイコンがエラーと判定して受信完了が来るまでパケットを送り続けます




■ここまでで作った全ソースコード



;---------------------------------------------------------------
	LIST      P=16F84
	#include <p16F84.inc>

	__CONFIG _CP_OFF & _HS_OSC & _PWRTE_ON & _WDT_OFF
;---------------------------------------------------------------
;アドレスに名前を付ける
;---------------------------------------------------------------
;割り込み時にレジスタを退避させるメモリ
w_temp		equ	0x0C
status_temp	equ	0x0D

;ウェイト用メモリ
wait_val1		equ	0x0E
wait_val2		equ	0x0F

;RS232c 受信用メモリ
READ_TMR		equ	0x10
READ_COUNTER	equ	0x11
READ_BUF		equ	0x12

;RS232c 送信用メモリ
SEND_TMR		equ	0x13
SEND_COUNTER	equ	0x14
SEND_BUF		equ	0x15

;自作プロトコル受信のためのメモリ
TRUST_BUF		equ	0x16
TRUST_DATA	equ	0x17

;ノードID
NODE_ID		equ	0x18

;PORTAの2,3,4ビット目が変化した時送信処理を行うために使用するメモリ
PA_NEW		equ	0x19
PA_OLD		equ	0x1A

;PIC16F84では0x0Cから0x4Fまでが使用可能
;***************************************************************
;リセットベクタ
;***************************************************************
		org	0
		goto	start
;***************************************************************
;割り込みベクタ
;***************************************************************
		org	4

		;レジスタの退避
		movwf	w_temp
		movf	STATUS,w
		clrf	STATUS
		movwf	status_temp
		
		;各割り込みに対して適切なアドレスにジャンプさせる
		btfsc	INTCON,0
		goto	int0
		btfsc	INTCON,1
		goto	int1
		btfsc	INTCON,2
		goto	int2
intret
		;レジスタの復帰
		clrf	STATUS
		movf	status_temp,w
		movwf	STATUS
		swapf	w_temp,f
		swapf	w_temp,w
		retfie			;割り込みから復帰

;---------------------------------------------------------------
;RB0/INT割り込みにより実行
;---------------------------------------------------------------
int0					;RB4~RB7割り込み

		;割り込み時の処理をここに記述

		bcf	INTCON,0		;RB4~RB7割り込みフラグリセット
		goto	intret
;---------------------------------------------------------------
;RB4〜RB7割り込みにより実行
;---------------------------------------------------------------
int1					;RB0/INT割り込み

		;割り込み時の処理をここに記述

		bcf	INTCON,1		;RB0/INT割り込みフラグリセット
		goto	intret
;---------------------------------------------------------------
;タイマー割り込みにより実行
;---------------------------------------------------------------
int2		;タイマー割り込み
		;タイマーにはクロックが1/4周期で供給されるため、
		;10MHzクロックでは 1/2500000secとなる
		;1/19200 sec(52 usec)毎にタイマー割り込みを入れるために
		;減算タイマー値に256-130=0x7Eを設定
		;しかし、割り込みから、ここまでに0x0Eほどかかるため加算する
		movlw	0x7E+0x0E		;タイマー値リセット
		movwf	TMR0
		bcf	INTCON,2		;タイマー割り込みフラグリセット

		;割り込み時の処理をここに記述
;****************************************************************************
;RS232c送信処理
;****************************************************************************
SEND_START
		TSTF	SEND_BUF		;SEND_BUFがゼロかテストする
		BZ	SEND_END		;ゼロのときジャンプ

		;1/19200を32分周して1/600を作り出す
		decfsz	SEND_TMR,F	;Fレジスタを‐1して0ならスキップ
		goto	SEND_END		;ジャンプ
		MOVLW	0x1F		;Wレジスタに値を代入
		MOVWF	SEND_TMR		;WレジスタからFレジスタに代入
		;送信カウンタのセット
		TSTF	SEND_COUNTER	;SEND_COUNTERがゼロかテストする
		BNZ	SEND_COUNTER_SET_END	;ゼロ以外のときジャンプ
SEND_COUNTER_SET
		MOVLW	0x13+0x01		;Wレジスタに値を代入 
		MOVWF	SEND_COUNTER	;WレジスタからFレジスタに代入
SEND_COUNTER_SET_END
		DECF	SEND_COUNTER	;Fレジスタを-1する
;-----------------------------------------------------------------------
;スタートビットを立てる
;-----------------------------------------------------------------------
SEND_START_BIT
		MOVFW	SEND_COUNTER	;WレジスタにFレジスタを代
		SUBLW	0x13		;Wレジスタから値を引く
		BNZ	SEND_0_BIT	;結果が0以外ならジャンプ
		BCF	PORTA,1		;指定ビットに0を立てる
;-----------------------------------------------------------------------
;0ビット目の送信
;-----------------------------------------------------------------------
SEND_0_BIT
		MOVFW	SEND_COUNTER	;WレジスタにFレジスタを代
		SUBLW	0x11		;Wレジスタから値を引く
		BNZ	SEND_0_BIT_END	;結果が0以外ならジャンプ
		BTFSS	SEND_BUF,0	;指定ビットがゼロ以外ならスキップ
		goto	SEND_0_OFF	;ジャンプ
SEND_0_ON
		BSF	PORTA,1		;指定ビットに1を立てる
		goto	SEND_0_BIT_END
SEND_0_OFF
		BCF	PORTA,1		;指定ビットに0を立てる
SEND_0_BIT_END
;-----------------------------------------------------------------------
;1ビット目の送信
;-----------------------------------------------------------------------
SEND_1_BIT
		MOVFW	SEND_COUNTER	;WレジスタにFレジスタを代
		SUBLW	0x0F		;Wレジスタから値を引く
		BNZ	SEND_1_BIT_END	;結果が0以外ならジャンプ
		BTFSS	SEND_BUF,1	;指定ビットがゼロ以外ならスキップ
		goto	SEND_1_OFF	;ジャンプ
SEND_1_ON
		BSF	PORTA,1		;指定ビットに1を立てる
		goto	SEND_1_BIT_END
SEND_1_OFF
		BCF	PORTA,1		;指定ビットに0を立てる
SEND_1_BIT_END
;-----------------------------------------------------------------------
;2ビット目の送信
;-----------------------------------------------------------------------
SEND_2_BIT
		MOVFW	SEND_COUNTER	;WレジスタにFレジスタを代
		SUBLW	0x0D		;Wレジスタから値を引く
		BNZ	SEND_2_BIT_END	;結果が0以外ならジャンプ
		BTFSS	SEND_BUF,2	;指定ビットがゼロ以外ならスキップ
		goto	SEND_2_OFF	;ジャンプ
SEND_2_ON
		BSF	PORTA,1		;指定ビットに1を立てる
		goto	SEND_2_BIT_END
SEND_2_OFF
		BCF	PORTA,1		;指定ビットに0を立てる
SEND_2_BIT_END
;-----------------------------------------------------------------------
;3ビット目の送信
;-----------------------------------------------------------------------
SEND_3_BIT
		MOVFW	SEND_COUNTER	;WレジスタにFレジスタを代
		SUBLW	0x0B		;Wレジスタから値を引く
		BNZ	SEND_3_BIT_END	;結果が0以外ならジャンプ
		BTFSS	SEND_BUF,3	;指定ビットがゼロ以外ならスキップ
		goto	SEND_3_OFF	;ジャンプ
SEND_3_ON
		BSF	PORTA,1		;指定ビットに1を立てる
		goto	SEND_3_BIT_END
SEND_3_OFF
		BCF	PORTA,1		;指定ビットに0を立てる
SEND_3_BIT_END
;-----------------------------------------------------------------------
;4ビット目の送信
;-----------------------------------------------------------------------
SEND_4_BIT
		MOVFW	SEND_COUNTER	;WレジスタにFレジスタを代
		SUBLW	0x09		;Wレジスタから値を引く
		BNZ	SEND_4_BIT_END	;結果が0以外ならジャンプ
		BTFSS	SEND_BUF,4	;指定ビットがゼロ以外ならスキップ
		goto	SEND_4_OFF	;ジャンプ
SEND_4_ON
		BSF	PORTA,1		;指定ビットに1を立てる
		goto	SEND_4_BIT_END
SEND_4_OFF
		BCF	PORTA,1		;指定ビットに0を立てる
SEND_4_BIT_END
;-----------------------------------------------------------------------
;5ビット目の送信
;-----------------------------------------------------------------------
SEND_5_BIT
		MOVFW	SEND_COUNTER	;WレジスタにFレジスタを代
		SUBLW	0x07		;Wレジスタから値を引く
		BNZ	SEND_5_BIT_END	;結果が0以外ならジャンプ
		BTFSS	SEND_BUF,5	;指定ビットがゼロ以外ならスキップ
		goto	SEND_5_OFF	;ジャンプ
SEND_5_ON
		BSF	PORTA,1		;指定ビットに1を立てる
		goto	SEND_5_BIT_END
SEND_5_OFF
		BCF	PORTA,1		;指定ビットに0を立てる
SEND_5_BIT_END
;-----------------------------------------------------------------------
;6ビット目の送信
;-----------------------------------------------------------------------
SEND_6_BIT
		MOVFW	SEND_COUNTER	;WレジスタにFレジスタを代
		SUBLW	0x05		;Wレジスタから値を引く
		BNZ	SEND_6_BIT_END	;結果が0以外ならジャンプ
		BTFSS	SEND_BUF,6	;指定ビットがゼロ以外ならスキップ
		goto	SEND_6_OFF	;ジャンプ
SEND_6_ON
		BSF	PORTA,1		;指定ビットに1を立てる
		goto	SEND_6_BIT_END
SEND_6_OFF
		BCF	PORTA,1		;指定ビットに0を立てる
SEND_6_BIT_END
;-----------------------------------------------------------------------
;7ビット目の送信
;-----------------------------------------------------------------------
SEND_7_BIT
		MOVFW	SEND_COUNTER	;WレジスタにFレジスタを代
		SUBLW	0x03		;Wレジスタから値を引く
		BNZ	SEND_7_BIT_END	;結果が0以外ならジャンプ
		BTFSS	SEND_BUF,7	;指定ビットがゼロ以外ならスキップ
		goto	SEND_7_OFF	;ジャンプ
SEND_7_ON
		BSF	PORTA,1		;指定ビットに1を立てる
		goto	SEND_7_BIT_END
SEND_7_OFF
		BCF	PORTA,1		;指定ビットに0を立てる
SEND_7_BIT_END
;-----------------------------------------------------------------------
;ストップビットの送信
;-----------------------------------------------------------------------
SEND_STOP_BIT
		MOVFW	SEND_COUNTER	;WレジスタにFレジスタを代
		SUBLW	0x01		;Wレジスタから値を引く
		BNZ	SEND_STOP_BIT_END	;結果が0以外ならジャンプ
		BSF	PORTA,1		;指定ビットに1を立てる
SEND_STOP_BIT_END
;-----------------------------------------------------------------------
;送信完了のため、送信バッファのクリア
;-----------------------------------------------------------------------
SEND_BUF_CLEAR
		TSTF	SEND_COUNTER	;SEND_COUNTERがゼロかテストする
		BNZ	SEND_END		;ゼロ以外のときジャンプ
		;送信バッファをクリアする
		MOVLW	0x00		;Wレジスタに値を代入 
		MOVWF	SEND_BUF		;WレジスタからFレジスタに代入
SEND_END
;----------------------------------------------------------------------------

;****************************************************************************
;RS232c受信処理
;****************************************************************************
;1/19200 secでタイマー割り込み
;スタートビットが立ったことを検出する
;READ_COUNTER	ビット数をカウントするメモリ
;READ_TMR	タイマー割り込みを分周するためのメモリ
COUNTSET_START
		TSTF	READ_COUNTER	;READ_COUNTERがゼロかテストする
		BNZ	COUNTSET_END	;ゼロでないときジャンプ
COUNTSET
		BTFSC	PORTA,0		;指定ビットがゼロならスキップ
		goto	COUNTSET_END	;ジャンプ
		BTFSC	PORTA,0		;指定ビットがゼロならスキップ
		goto	COUNTSET_END	;ジャンプ;
		BTFSC	PORTA,0		;指定ビットがゼロならスキップ
		goto	COUNTSET_END	;ジャンプ
		BTFSC	PORTA,0		;指定ビットがゼロならスキップ
		goto	COUNTSET_END	;ジャンプ

		MOVLW	0x12+0x01		;Wレジスタに値を代入 
		MOVWF	READ_COUNTER	;WレジスタからFレジスタに代入


COUNTSET_END

		TSTF	READ_COUNTER	;READ_COUNTERがゼロかテストする
		BZ	intret		;ゼロのときジャンプ

		;1/19200を32分周して1/600を作り出す
		decfsz	READ_TMR,F	;Fレジスタを‐1して0ならスキップ
		goto	intret		;ジャンプ
		MOVLW	0x1F		;Wレジスタに値を代入
		MOVWF	READ_TMR		;WレジスタからFレジスタに代入

		DECF	READ_COUNTER	;Fレジスタを-1する

;----------------------------------------------------------------------
;Startビットの確認
;----------------------------------------------------------------------
READ_ST_INIT
		MOVFW	READ_COUNTER	;WレジスタにFレジスタを代
		SUBLW	0x12		;Wレジスタから値を引く
		BNZ	READ_ST_END	;結果が0以外ならジャンプ
READ_ST_START
		BTFSC	PORTA,0		;指定ビットがゼロならスキップ
		goto	READ_ST_ERR	;ジャンプ
		BTFSC	PORTA,0		;指定ビットがゼロならスキップ
		goto	READ_ST_ERR	;ジャンプ;
		;StartREADが立っている事を確認
		goto	READ_0_END	;ジャンプ;
READ_ST_ERR
		;StartREADが立っていない ノイズであるため受信処理をリセット
		MOVLW	0x00		;Wレジスタに値を代入 
		MOVWF	READ_COUNTER	;WレジスタからFレジスタに代入
READ_ST_END
;----------------------------------------------------------------------
;0ビット目の取得
;----------------------------------------------------------------------
READ_0_INIT
		MOVFW	READ_COUNTER	;WレジスタにFレジスタを代
		SUBLW	0x10		;Wレジスタから値を引く
		BNZ	READ_0_END	;結果が0以外ならジャンプ
READ_0_START
		BTFSC	PORTA,0		;指定ビットがゼロならスキップ
		goto	READ_0_ON		;ジャンプ
		BTFSC	PORTA,0		;指定ビットがゼロならスキップ
		goto	READ_0_ON		;ジャンプ;
READ_0_OFF
		BCF	READ_BUF,0	;指定ビットに0を立てる
		goto	READ_0_END	;ジャンプ;
READ_0_ON
		BSF	READ_BUF,0	;指定ビットに1を立てる
READ_0_END
;----------------------------------------------------------------------
;1ビット目の取得
;----------------------------------------------------------------------
READ_1_INIT
		MOVFW	READ_COUNTER	;WレジスタにFレジスタを代入
		SUBLW	0x0E		;Wレジスタから値を引く
		BNZ	READ_1_END	;結果が0以外ならジャンプ
READ_1_START
		BTFSC	PORTA,0		;指定ビットがゼロならスキップ
		goto	READ_1_ON		;ジャンプ
		BTFSC	PORTA,0		;指定ビットがゼロならスキップ
		goto	READ_1_ON		;ジャンプ;
READ_1_OFF
		BCF	READ_BUF,1	;指定ビットに0を立てる
		goto	READ_1_END	;ジャンプ;
READ_1_ON
		BSF	READ_BUF,1	;指定ビットに1を立てる
READ_1_END
;----------------------------------------------------------------------
;2ビット目の取得
;----------------------------------------------------------------------
READ_2_INIT
		MOVFW	READ_COUNTER	;WレジスタにFレジスタを代入
		SUBLW	0x0C		;Wレジスタから値を引く
		BNZ	READ_2_END	;結果が0以外ならジャンプ
READ_2_START
		BTFSC	PORTA,0		;指定ビットがゼロならスキップ
		goto	READ_2_ON		;ジャンプ
		BTFSC	PORTA,0		;指定ビットがゼロならスキップ
		goto	READ_2_ON		;ジャンプ;
READ_2_OFF
		BCF	READ_BUF,2	;指定ビットに0を立てる
		goto	READ_2_END	;ジャンプ;
READ_2_ON
		BSF	READ_BUF,2	;指定ビットに1を立てる
READ_2_END
;----------------------------------------------------------------------
;3ビット目の取得
;----------------------------------------------------------------------
READ_3_INIT
		MOVFW	READ_COUNTER	;WレジスタにFレジスタを代入
		SUBLW	0x0A		;Wレジスタから値を引く
		BNZ	READ_3_END	;結果が0以外ならジャンプ
READ_3_START
		BTFSC	PORTA,0		;指定ビットがゼロならスキップ
		goto	READ_3_ON		;ジャンプ
		BTFSC	PORTA,0		;指定ビットがゼロならスキップ
		goto	READ_3_ON		;ジャンプ;
READ_3_OFF
		BCF	READ_BUF,3	;指定ビットに0を立てる
		goto	READ_3_END	;ジャンプ;
READ_3_ON
		BSF	READ_BUF,3	;指定ビットに1を立てる
READ_3_END
;----------------------------------------------------------------------
;4ビット目の取得
;----------------------------------------------------------------------
READ_4_INIT
		MOVFW	READ_COUNTER	;WレジスタにFレジスタを代入
		SUBLW	0x08		;Wレジスタから値を引く
		BNZ	READ_4_END	;結果が0以外ならジャンプ
READ_4_START
		BTFSC	PORTA,0		;指定ビットがゼロならスキップ
		goto	READ_4_ON		;ジャンプ
		BTFSC	PORTA,0		;指定ビットがゼロならスキップ
		goto	READ_4_ON		;ジャンプ;
READ_4_OFF
		BCF	READ_BUF,4	;指定ビットに0を立てる
		goto	READ_4_END	;ジャンプ;
READ_4_ON
		BSF	READ_BUF,4	;指定ビットに1を立てる
READ_4_END
;----------------------------------------------------------------------
;5ビット目の取得
;----------------------------------------------------------------------
READ_5_INIT
		MOVFW	READ_COUNTER	;WレジスタにFレジスタを代入
		SUBLW	0x06		;Wレジスタから値を引く
		BNZ	READ_5_END	;結果が0以外ならジャンプ
READ_5_START
		BTFSC	PORTA,0		;指定ビットがゼロならスキップ
		goto	READ_5_ON		;ジャンプ
		BTFSC	PORTA,0		;指定ビットがゼロならスキップ
		goto	READ_5_ON		;ジャンプ;
READ_5_OFF
		BCF	READ_BUF,5	;指定ビットに0を立てる
		goto	READ_5_END	;ジャンプ;
READ_5_ON
		BSF	READ_BUF,5	;指定ビットに1を立てる
READ_5_END
;----------------------------------------------------------------------
;6ビット目の取得
;----------------------------------------------------------------------
READ_6_INIT
		MOVFW	READ_COUNTER	;WレジスタにFレジスタを代入
		SUBLW	0x04		;Wレジスタから値を引く
		BNZ	READ_6_END	;結果が0以外ならジャンプ
READ_6_START
		BTFSC	PORTA,0		;指定ビットがゼロならスキップ
		goto	READ_6_ON		;ジャンプ
		BTFSC	PORTA,0		;指定ビットがゼロならスキップ
		goto	READ_6_ON		;ジャンプ;
READ_6_OFF
		BCF	READ_BUF,6	;指定ビットに0を立てる
		goto	READ_6_END	;ジャンプ;
READ_6_ON
		BSF	READ_BUF,6	;指定ビットに1を立てる
READ_6_END
;----------------------------------------------------------------------
;7ビット目の取得
;----------------------------------------------------------------------
READ_7_INIT
		MOVFW	READ_COUNTER	;WレジスタにFレジスタを代入
		SUBLW	0x02		;Wレジスタから値を引く
		BNZ	READ_7_END	;結果が0以外ならジャンプ
READ_7_START
		BTFSC	PORTA,0		;指定ビットがゼロならスキップ
		goto	READ_7_ON		;ジャンプ
		BTFSC	PORTA,0		;指定ビットがゼロならスキップ
		goto	READ_7_ON		;ジャンプ;
READ_7_OFF
		BCF	READ_BUF,7	;指定ビットに0を立てる
		goto	READ_7_END	;ジャンプ;
READ_7_ON
		BSF	READ_BUF,7	;指定ビットに1を立てる
READ_7_END
;----------------------------------------------------------------------
;自作プロトコル受信のための操作
;----------------------------------------------------------------------
READ_TRUST_INIT
		MOVFW	READ_COUNTER	;WレジスタにFレジスタを代入
		SUBLW	0x01		;Wレジスタから値を引く
		BNZ	READ_TRUST_END	;結果が0以外ならジャンプ
READ_TRUST_START
		;受信バッファの7ビット目が0ならばデータ、1ならばミラー
		BTFSC	READ_BUF,7	;指定ビットがゼロならスキップ
		goto	READ_TRUST_MIRROR	;ジャンプ
READ_TRUST_DATA
		;データのため、バッファに退避させる
		MOVFW	READ_BUF		;WレジスタにFレジスタを代入
		MOVWF	TRUST_BUF		;FレジスタにWレジスタを代入
		goto	READ_TRUST_END	;ジャンプ;
READ_TRUST_MIRROR
		;ミラーデータの受信
		COMF	READ_BUF,0	;Fレジスタを反転しWレジスタへ転送
		SUBWF	TRUST_BUF,0	;Wレジスタから値を引く
		BNZ	READ_TRUST_END	;結果が0以外ならジャンプ
		;受信データが正しいことを確認できたためノードIDを確認する
CHECK_NODE_ID
		COMF	READ_BUF,1	;Fレジスタを反転しFレジスタへ転送
		;READ_BUFにはこの時点でTRUST_BUFと同じ値が入っている
		MOVFW	NODE_ID		;WレジスタにFレジスタを代入
		XORWF	READ_BUF,1	;XORをとり結果をFレジスタに代入
		BTFSC	READ_BUF,3	;3bit目が0ならばスキップ
		goto	READ_TRUST_END	;IDが違ったため受信データを無視する
		BTFSC	READ_BUF,4	;4bit目が0ならばスキップ
		goto	READ_TRUST_END	;IDが違ったため受信データを無視する
		BTFSC	READ_BUF,5	;5bit目が0ならばスキップ
		goto	READ_TRUST_END	;IDが違ったため受信データを無視する
		BTFSC	READ_BUF,6	;6bit目が0ならばスキップ
		goto	READ_TRUST_END	;IDが違ったため受信データを無視する
CHECK_NODE_ID_END
		;IDおよび受信データが正しいことを確認
		MOVFW	TRUST_BUF		;WレジスタにFレジスタを代入
		MOVWF	TRUST_DATA	;FレジスタにWレジスタを代入
		;受信データを返信する
		MOVFW	TRUST_BUF		;WレジスタにFレジスタを代入
		MOVWF	SEND_BUF		;FレジスタにWレジスタを代入
READ_TRUST_END

;		COMF	PORTB,1		;Fレジスタを反転
		goto	intret		;ジャンプ
;***************************************************************
;スタート
;***************************************************************
start
;---------------------------------------------------------------
;ポートの設定
;---------------------------------------------------------------
		clrf	PORTA
		clrf	PORTB
		bsf	STATUS,5		;ページを1に切り替え
		movlw	0x1D
		movwf	TRISA		;portAをbit 11101 を入力に設定
		movlw	0x00
		movwf	TRISB		;portBを出力に設定
		bcf	STATUS,5		;ページを0に切り替え

;---------------------------------------------------------------
;RB0/INT割り込みの設定
;---------------------------------------------------------------
		bsf	STATUS,5		;ページを1に切り替え
		bcf	OPTION_REG,6	;RB0のエッジ設定は立ち上がり
		bcf	STATUS,5		;ページを0に切り替え
;		bsf	INTCON,4		;RB0/INT割り込み発生許可
;---------------------------------------------------------------
;RB4〜RB7割り込みの設定
;---------------------------------------------------------------
;		bsf	INTCON,3		;RB4〜RB7割り込み発生許可
;---------------------------------------------------------------
;タイマー割り込みの設定
;---------------------------------------------------------------
		movlw	0x00		;タイマー値リセット
		movwf	TMR0
		bsf	STATUS,5		;ページを1に切り替え
		;ウオッチドックタイマは約18msでタイムアウトするため
		;プリスケーラで分周して128倍の時間、約2秒にする
		bsf	OPTION_REG,0	;PS0	プリスケーラの設定
		bsf	OPTION_REG,1	;PS1	
		bsf	OPTION_REG,2	;PS2	
		bsf	OPTION_REG,3	;PSA	プリスケーラをTMRで使用する場合は0,WDTで使用する場合は1
		bcf	OPTION_REG,5	;T0CS	タイマ0の入力先 1でRA4ピン入力,0でクロック1/4入力
		bcf	STATUS,5		;ページを0に切り替え
		bsf	INTCON,5		;タイマ割り込み発生許可
;---------------------------------------------------------------
;割り込みの開始
;---------------------------------------------------------------
		bsf	INTCON,7		;割り込み許可

;***************************************************************
;メイン
;***************************************************************
APP_INIT
		;所定の変数を初期化しておかないと起動時に意図しない動作をする可能性がある
		MOVLW	0x00		;Wレジスタに値を代入 
		MOVWF	READ_BUF		;WレジスタからFレジスタに代入
		MOVWF	SEND_BUF		;WレジスタからFレジスタに代入
		MOVWF	SEND_COUNTER	;WレジスタからFレジスタに代入
		;MAX3232への出力は反転しているため、最初はHiを出力しておく必要がある
		BSF	PORTA,1		;指定ビットに1を立てる

		;自作プロトコル受信のための初期化処理
		MOVLW	0x00		;Wレジスタに値を代入 
		MOVWF	TRUST_BUF	;WレジスタからFレジスタに代入
		MOVWF	TRUST_DATA	;WレジスタからFレジスタに代入
		;ノードIDの設定 ID * 0x08は左に3ビットシフトさせるため
		MOVLW	0x01*0x08		;Wレジスタに値を代入 
		MOVWF	NODE_ID		;WレジスタからFレジスタに代入

		;自作プロトコル送信のための初期化処理
		MOVLW	0x00		;Wレジスタに値を代入 
		MOVWF	PA_OLD		;WレジスタからFレジスタに代入

main
		CLRWDT			;ウォッチドックタイマとプリスケーラをクリア
		;自作プロトコル受信で受け取った値をPORTBに出力する
		MOVFW	TRUST_DATA	;FレジスタからWレジスタに代入
		MOVWF	PORTB		;WレジスタからFレジスタに代入

;----------------------------------------------------------------------------
;PORTA bit2,3,4が変化した場合、状態を自作プロトコル送信で送信する処理
;----------------------------------------------------------------------------
		MOVLW	0x00		;Wレジスタに値を代入 
		MOVWF	PA_NEW		;WレジスタからFレジスタに代入

		;PORTAの値を左に2シフトする
		BTFSC	PORTA,2		;Fレジスタの指定ビットが0ならスキップ
		BSF	PA_NEW,0		;指定ビットに1を立てる
		BTFSC	PORTA,3		;Fレジスタの指定ビットが0ならスキップ
		BSF	PA_NEW,1		;指定ビットに1を立てる
		BTFSC	PORTA,4		;Fレジスタの指定ビットが0ならスキップ
		BSF	PA_NEW,2		;指定ビットに1を立てる

		;送信ノードIDを取り付ける
		;ノードID+1を送信ノードIDとする
		MOVFW	NODE_ID		;FレジスタからWレジスタに代入
		;0x08は左に3ビットシフトさせるため
		ADDLW	0x01*0x08		;Wレジスタに値を加算
		IORWF	PA_NEW,1		;ORを取りFレジスタに結果を代入

		;前回値との判定
		MOVFW	PA_NEW		;FレジスタからWレジスタに代入
		SUBWF	PA_OLD,0		;FレジスタからWレジスタを引く
		BZ	main		;結果が0のときジャンプ

		;前回値を破壊する(送受信完了前に状態が戻った場合の対策)
		MOVLW	0x00		;Wレジスタに値を代入 
		MOVWF	PA_OLD		;WレジスタからFレジスタに代入

		;前回と比較して状態が変化したため、送信処理を行う
		call	SEND_WAIT		;送信完了待ち
		MOVFW	PA_NEW		;FレジスタからWレジスタに代入
		MOVWF	SEND_BUF		;送信  WレジスタからFレジスタに代入
		call	SEND_WAIT		;送信完了待ち
		COMF	PA_NEW,0		;Fレジスタを反転してWレジスタに格納
		MOVWF	SEND_BUF		;送信  WレジスタからFレジスタに代入
		call	SEND_WAIT		;送信完了待ち

		;通信相手の受信成功パケットを確認する
		call	wait_loop		;ウエイト
		call	READ_WAIT		;受信完了待ち
		MOVFW	PA_NEW		;FレジスタからWレジスタに代入
		SUBWF	TRUST_BUF,0	;FレジスタからWレジスタを引く
		BNZ	main		;結果が0以外のときジャンプ
		;受信成功パケットの確認がとれた
		MOVFW	PA_NEW		;FレジスタからWレジスタに代入
		MOVWF	PA_OLD		;WレジスタからFレジスタに代入

		goto	main

;---------------------------------------------------------------
;ウエイト
;---------------------------------------------------------------
wait_loop
		MOVLW	0x00
		MOVWF	wait_val1
wait_loop1
		MOVLW	0x00
		MOVWF	wait_val2
wait_loop2	NOP
		decfsz	wait_val2,F
		goto	wait_loop2
		decfsz	wait_val1,F
		goto	wait_loop1

		return
;-------------------------------------
;読み出し中の場合は待機するループ
;--------------------------------------
READ_WAIT
		TSTF	READ_COUNTER	;READ_COUNTERがゼロかテストする
		BNZ	READ_WAIT		;ゼロ以外のときジャンプ
READ_WAIT_END
		return
;-------------------------------------

;-------------------------------------
;送信中の場合は待機するループ
;-------------------------------------
SEND_WAIT
		TSTF	SEND_BUF		;SEND_BUFがゼロかテストする
		BNZ	SEND_WAIT		;ゼロ以外のときジャンプ
SEND_WAIT_END
		return
;-------------------------------------

		END








■上記マイコンと通信するWindowsアプリケーションを作成してみました

画面上のボタンを押すことでマイコンのLEDが点等し、
マイコンのスイッチを操作することにより画面に状態が表示されます。



VisualC++6.0 MFC ソースとソフト



20060919 作成



▲トップページ > マイコンなど