Top Page cwbufkey の製作
自作工程のメモとして
2006.Jul.29


 この前のページで、PIC 12F629 を使ったエレキーを掲載しましたが、その後せっかく覚えた命令を忘れないうちに使ってみようということで、次のテーマに取り組むことにしました。

 よく、パソコン(以下、PC)でコンテストログソフトを動かしてCWを運用するインターフェースが紹介されていますが、送出速度の設定はPC上で実行する タイプがほとんどで、パドルが使えない、パドルとPCからの送出速度が違う、等々の制約があります。
次のアイデアは、そのソフト毎の制約をPICマイコンで吸収してやり、パドルの速度調節(ボリューム)で全ての速度をコントロールできる、CW- BUFFER-Key( cwbufkey )という物で、PCからのCW速度を一定にしておけば、記憶して順次指定速度で送り出すことが可能としています。

続編 cwbufkey2 を掲載しました。(2006/08/06)

1.なぜ cwbufkey か

今まで作ってきたエレキーも、自作のログソフト(MS−DOS)からRS232C経由で送られてきた文字を受け、Z80やPIC等のMPUで処理してい ました。
現在は、そのような処理をするログソフトも少なく(国内では見当たりません)、操作感の好みもあることから、自作のログソフトを使わなくなってからは、旧 作のエレキーはほとんど使っていませんでした。
また、6年ほど移動運用にも行っていませんし、記念局を時々呼ぶぐらいのアクティビティでした。

旧作のエレキー

        

今回、PICの命令を覚えているうちに、同じようなものを実現してみようと考えてみました。
よく考えると、PC側のソフトからCW信号は共通して送出されていますので、その信号を処理して速度調節を手元で調節できるもとしています。

 

2.動作の概要 cwbufkey

全体のイメージをつかんでいただくために動作は、WMVファイルにして動画再生で示しま す。(音声は出ません)

左にあるUSBIF4CWのKey−LED (一番右側)の点滅速度で送り出されたCW信号を、右側の cwbufkey で受け取り、cwbufkey の設定速度(必ず入力速度より遅くする)で再出力しています。

この再出力速度は、パドル( cwbufkey 側に接続中)を操作したときの速度と同じになります。

  <===ページ内で表示するよう変更しました(2013/05/19)
Windows Media Player Firefox Plugin のインストールは、こ ちらを参照しました。TKS(2015/04/26)

以下のPC側のソフトでCQを送出しました。

 

 

3.入力信号の確認

PC上の簡易オシロで見たCW入力波形です。
信号が遅いため、High・Lowを保持できずゼロ点へ回帰していますが、符号比率等は確認できます。
30WPMの速度ですから、ドット(ON部のみ)が約40mS、文字間が約120mSあり、当たり前ですが計算どおりとなっています。

送出したCW信号のPC上の画面

 

 

4.ケースへの実装

実験だけでは、アイデアだけとなりますので、実装(インプリメンテーション、implementation)してみました。

簡単な回路なので、プリンタで穴あき基板のイメージを作り、ボールペンと鉛筆で部品の配線を書いていきます。
CW信号の出力は、フォトカプラのダイオードを、直接ポートからのHigh信号で駆動し、トランシーバ側とは、絶縁処理しました。

フォトカプラのダイオード側に、直列に入れた抵抗は300オームで、5mA程度を流すことになります。

実際の配線は若干違いますが、何回か書き直すうちにまとまってきます。

 

小PCBに組み上げて、配線をした様子が次のようになります。
昔から、PCB上での接続は、丸ピンのICソケット(1列もの)を切って使い、ソケットとプラグに使っています。
Z80を使ったエレキーの頃から使っていますが、トラブルは有りません。

また、ボリュームは当初50KΩで実験していましたが、20KΩで充分な速度範囲が確保できました。

消費電流は、ソースファイル中にも記しましたが、待機時は1mA以下で、動作時はフォトカプラを駆動する関係で実測 5.05mAとなります。

 

ケースはタカチのSW−85を使いました。その外観、裏面からと

前面からです。

 

次の構想があるため簡単に作って、IC−7000Mにつないで実験してみましたが、回り込み等は起きていないようです。

この cwbufkey で使ってみたいソフトは、次のCTESTWINで、私の好みに合いそうで期待しています。

 

5.ソースファイル

 先月に掲載したソースファイルに、追記した形になり若干の相違があるかも 知れませんが、タイマ0を使ってCW入力をサンプリングし、リングバッファに取り込んで、指定速度で送り出しています。
また、今までのエレキー(Z8016F8416C73B使 用)と同様に、リングバッファのクリヤは、パドル操作で行うようにしています。

特に旧作は、1文字を1バイトとしてバッファで記憶していましたが、今回は符号(ダッシュ・ドット・文字間・スペース)を2ビットに置換えて記憶してい ます。

PARISコードで記憶効率を試算してみますと、文字記憶で6バイト、符号記憶で40ビット(5バイト)となり、記憶効率は悪くは無いようです。
1語=(PARIS+スペース)

なお、入力速度(PC側からの出力速度)への許容範囲は有る程度ありますので、汎用性は高いと考えます。

(エディタ上でTAB間隔を8文字に設定し直しましたが、これでもコメント等の位置がずれています。)

--------------------------------------------------------------------

;
;PICマイコンによる、CWバッファ付キーヤープログラム
;cwbufkey
;
;製作過程の掲載は、 http://jlb.jp/jlb/jisaku/cwbufkey/
;
;V1.00:2006/06/25:(C)JE3JLB (最下部へコード埋め込みあり)
;      2006/07/02:ソースファイルのコメント記述を整理した。
;                :8文字TABに変更した。
;V1.01:2006/07/29:ダッシュの先頭から約1/3間は、パドルのドットを記憶しない。
;
;
;
;
;CWコードの定数を確認
;PARISコードの1ワード(W)は、14+8+10+6+8+(4)=50ドット
;1分間に 5W( 25文字)送出するには、  250ドット/分
;				(4.2dot/Sec  240ms/dot)短点連続周波数= 2.1Hz
;1分間に10W( 50文字)送出するには、  500ドット/分
;				(8.3dot/Sec  120ms/dot)短点連続周波数= 4.2Hz
;1分間に20W(100文字)送出するには、1,000ドット/分
;				(16.7dot/Sec  60ms/dot)短点連続周波数= 8.3Hz
;1分間に30W(150文字)送出するには、1,500ドット/分
;				(25.0dot/Sec  40ms/dot)短点連続周波数=12.5Hz
;1分間に40W(200文字)送出するには、2,000ドット/分
;				(33.3dot/Sec  30ms/dot)短点連続周波数=16.7Hz
;
;
;----------------------------------------------------------------
;◆回路構成の概略(全半角等幅文字)
;
;
;                    PIC 12F629            3V  3V
;            3V  3V  ┌──V──┐        │  │
;            │  │  │          │     10K│  │10K
;            │  └─┤1        8├─┐    (R) (R)
;            │      │          │  E    │  │
;  CW出力 <─────┤2        7├────┴────(パドル:ドット)
;            │      │          │            │
;        100K│ NC:<-┤3        6├──────┴──(パドル:ダッシュ)
;            (R)     │          │              10K
;  CW入力 >─┴───┤4        5├───┬──(R)-┐
;                    │          │      (C)      (VR) 50K
;                    └─────┘      │103     │
;                                        E        E
;
;     Eはアース、NC:は未接続。
;
;GP0=1 入力		パドル ドット
;GP1=1 入力		パドル ダッシュ
;GP2=1 出力		初期は出力で、1を出力指定しておく。
;			外部のボリュームを読み込む時は、瞬間入力に設定して
;			放電時間経過後のLowエッジ割込みを待つ。
;GP3=1 入力		CW信号入力ポート(Lowアクティブ)
;GP4=0 出力		未使用
;GP5=0 出力		キー出力(ハイアクティブ)

;----------------------------------------------------------------
;◆動作について
;SQUEEZE Key  二枚羽のパドルを持つキーヤー の、
;アイアンビック mode B の動作になるとは思いますが、明確には不明です。
;
;◆CW Bufferの動作概要
;パソコン(以下:PC)から送り出される一定速度のCW信号を、
;それ以下の速度に減速して送り出す。(ボリューム調整)
;(例)
;1.ezkey 等で、速度を30W(150文字)に設定する。(要調整)
;2.PCからのCW出力を、cwbufkey のCW入力へ入れる。
;3.rig へのCW出力は、cwbufkey のCW出力を使用する。
;4.その結果、PCからのCW出力もパドルからの送出速度と一緒になる。
;5.送出待ちの符号群がバッファに残っている時にパドルを操作すると、
; その時点でバッファをクリヤする。
;6.入力速度を 30WPM で設定しているが、20 〜 40WPM 程度の許容あり。
; 
;----------------------------------------------------------------
;◆参考書籍
;中尾真治氏著  オーム社 (平成17年3月20日 第1版)
;おもしろいPICマイコン −PIC12F675 を使いこなす−
;
;固有定数のメモ:3474
;固有定数のメモ:3468
;
;
;----------------------------------------------------------------

;■◆■◆■◆■◆■◆■◆■◆■◆■◆■◆■◆■◆■◆■◆■◆
;
	LIST	P=12F629
	INCLUDE	P12F629.INC

	ERRORLEVEL -302		;アセンブル時に 302(バンク切替え)警告を出さない。

INDF	equ	H'0000'		;間接読出し・書込み時の仮想レジスター
FSR	equ	H'0004'		;間接データメモリ・ポインタ



CB = _CPD_OFF			;データEEPROMもプログラム・メモリも
CB &= _CP_OFF			;コード・プロテクトしない。
CB &= _BODEN_ON			;ブラウンアウト・リセットを使う。
CB &= _MCLRE_OFF		;MCLRリセットを使わない。
CB &= _PWRTE_ON			;パワーアップ・タイマを使う。
CB &= _WDT_OFF			;ウォッチドッグ・タイマを使わない。
CB &= _INTRC_OSC_NOCLKOUT	;内部発振器を使う。

	__CONFIG CB

	__IDLOCS H'0101'	;IDロケーションへ、バージョン1.00

	CBLOCK	H'20'

	GPIO_OUT		;GPIOポートの出力データ

	W_TEMP			;割込み処理用
	S_TEMP			;割込み処理用

	CCC			;カウンタ
	CCC256			;カウンタ上位

	PAD_MEMO		;パドルの状態をメモしておく(Hi アクティブ)
;				;bit1   1=ダッシュ が押された。
;				;bit0   1=ドット が押された。

	RUN_MEMO		;実行中の状態をメモ(Hi アクティブ)

;bit5	1=スペース信号 (CWバッファで使用)
;bit4	1=文字間信号  (CWバッファで使用)
;bit3	1=ダッシュ信号 0=ダッシュ後の間隔(1ドット分)
;bit2	1=ドット信号  0=ドット後の間隔(1ドット分)
;bit1   1=ダッシュ送出中
;bit0   1=ドット送出中
;

;	DM_GPIO			;★★★   debug  ★★★
				;MPLAB SIM(debugger)使用時に、入力ポートの代替とする。

;-----------------------;◆ここから CW-buffer用
	CB_BIT_INPOS		;CWバッファのビット単位格納の入力位置
	CB_BYT_INPOS		;CWバッファのバイト単位格納の入力位置

	CB_BIT_OTPOS		;CWバッファのビット単位格納の出力位置
	CB_BYT_OTPOS		;CWバッファのバイト単位格納の出力位置

	CB_CW_CNT		;CW信号入力数のカウント

	CB_TMP			;CWバッファの入出力TMP
;				;■bit 1.0 を使用する。■
;				;(11=ダッシュ符号、10=ドット符号、
;				;            01=文字間、00=スペース)

	CW_CLK			;CW信号を2mSのインターバルで
;				;確認した回数をカウント

	CW_IN_STA		;CW符号の入力状態を表す。
;				;■bit 2〜0 を使用する。■
;				;  101=CW信号有り、110=CW信号が途切れた状態、
;				;  100=符号間を確認済み状態
;				;  (後は、文字間とスペースの判断のみ残る)

	CW_BUFF			;CW符号を格納するバッファ
;				;この位置から最終番地まで使う。(0x5f)

;-----------------------;◆ここまで CW-buffer用

	ENDC

;-----------------------	;CW-buffer用
CB_POS_ST	equ	CW_BUFF	;バッファのスタートアドレス
CB_POS_END	equ	H'5F'	;バッファのエンドアドレス(0x5f)
;-----------------------	;

;----------------------------------------------------------------
DEF_OP_REG	equ	B'10000010'	;割込みのオプションレジスタ

;bit7	ウィーク・プルアップ使わない=1
;bit6	INTピン立下りエッジを使うので=0
;bit5	タイマ0の入力を命令クロック使う=0
;bit4	タイマ0の外部クロック時の設定 X
;bit3	プリスケーラをタイマ0で使う=0
;bit2	bit 2〜0 でプリスケーラの分周比を設定する。
;           bit->  2 1 0
;bit1              0 1 0 =1:8
;bit0                             256uS X 8 = 2.048mS
;
;タイマ0の動作イメージ
;     ←2.048mS→ 毎の割込み
;    │     │               
;    ┌──┐  ┌──┐  ┌──┐  ┌─  
;    │  │  │  │  │  │  │   
;    ┘  └──┘  └──┘  └──┘   
;                          
;■■実測周波数=491Hz  2.037mS 
;
;----------------------------------------------------------------
GPIO_MODE   equ	B'00001011'
;					;GP0-1.3 をインプット
;					;GP2.4-5 をアウトプットに設定する。

;----------------------------------------------------------------
DEF_INTCON	equ	B'10110000'	;割込みの設定。
;bit7	GIE 割込みを使用する=1
;bit6	PIE1 レジスタの割込みを使わないので=0
;bit5	タイマ0オーバーフロー割込みを使うので=1
;bit4	INTピン入力エッジ割込みを使うので=1
;bit3	◆◆GPIO入力変化割込みを使わないので=0
;bit2	タイマ0オーバーフロー時=1となる。
;bit1	GP2/INTピン入力信号のエッジがあったときだけ=1
;bit0	◆◆GPIOポートで入力データが変化したときだけ=1
;
;----------------------------------------------------------------
PAD_DOT		equ	O'0'		;パドル:ドットのビット位置。
PAD_DAS		equ	O'1'		;パドル:ダッシュのビット位置。
CR_BIT		equ	O'2'		;外部でボリュームをつけている端子
CW_BIT		equ	O'3'		;CW信号入力(バッファで使用)
ST_BIT		equ	O'4'		;ボリュームにHを出力して、
;					;その後Lowにする。(使用せず)
LED_BIT		equ	O'5'		;LEDのビット

DOT_STA		equ	O'2'		;ドット ステータス
DAS_STA		equ	O'3'		;ダッシュ ステータス

;					;次の二つはCWバッファで使用し、
;					;RUN_MEMO の位置を示す。
BIT_MJK		equ	O'4'		;文字間
BIT_SPC		equ	O'5'		;スペース
;
;----------------------------------------------------------------
;
;■■CW信号送出タイミングに使用■■
;
TIME_1		equ	D'20'	;@ドットの長さと符号間(基準:変えない)
TIME_2		equ	D'36'	;A文字間の長さ(好みにより調整)
TIME_3		equ	D'60'	;Bダッシュの長さ(ドット×3倍)
;				;(例)1:3.4 にするなら、20 X 3.4 = 68を
;				; 記述する。
TIME_4		equ	D'72'	;C文字間後のスペース長(好みにより調整)

;      │@│@│<A>│<− C −>│          
;  ┌─┐ ┌─┐             ┌─────┐    
;  │ │ │ │<−− スペース −−−>│     │    
;  ┘ └─┘ └─────────────┘     └─   
;                                 
;  │<符号単位−>│<A>│@│ │<−B−>│        
;  ┌─────┐     ┌─┐ ┌─────┐        
;  │     │<文字間>│ │ │     │        
;  ┘     └─────┘ └─┘     └──      
;               >│ │<             
;                符号間              

;----------------------------------------------------------------
;
;■■CW信号入力タイミングに使用(CW−Buffer)■■
;30WPMの入力をサンプリングするときの理論値は1単位 20
;補正値: 40mS / 2.037mS = 19.6回
;
;40WPMの入力をサンプリングするときの理論値は1単位 15
;補正値: 30mS / 2.037mS = 14.7回

IN_CLK		equ	D'15'		;1単位当りのサンプリング回数
;
CLK_1		equ	D'20'		;20カウント(未使用)
CLK_2		equ	IN_CLK * 2	;A2単位ダッシュとドットの判定
;					;符号間と、文字間の判定に使用する。(2ヶ所)
CLK_3		equ	IN_CLK * 3	;B文字間とスペースの判定(2ヶ所)
CLK_4		equ	D'80'		;80カウント(未使用)
;
;
;        │   │     Bここでスペースと判断    
;  ┌─┐ ┌─┐   │<文字間>│   ┌─────┐    
;  │ │ │ │   │  判定 │   │     │    
;  ┘ └─┘ └─────────────┘     └─   
;        │<−スペース:単位7 −>│          
;        │                        
;  ┌─────┐ ┌─┐ ┌─┐ ┌─────┐        
;  │   │ │ │ │ │ │ │     │        
;  ┘   │ └─────┘ └─┘     └──      
;      │     │                    
; ドット<−A−>   │                    
;     ダッシュ   │                    
;            │                    
;       符号間<−A−>文字間以上             
;
;----------------------------------------------------------------
DEF_CCC		equ	D'240'	;タイミングカウンタ下位の初期値
;				;(CW送出速度に関係する。)
;
;-------------------------------------------------------------------
;///////////////////////////////////////////////////////////////////
;	◆◆◆電源ON時のスタート◆◆◆
;///////////////////////////////////////////////////////////////////
;-------------------------------------------------------------------

	org	0			;電源onスタート

	goto	START_DEF


;-------------------------------------------------------------------
;///////////////////////////////////////////////////////////////////
;	◆◆◆割込み発生時の処理◆◆◆
;///////////////////////////////////////////////////////////////////
;-------------------------------------------------------------------

	org	4			;割込み発生時の処理


	movwf	W_TEMP			;以下の4行は割込み処理前の定型処理。
	movf	STATUS,W		;
	clrf	STATUS			;
	movwf	S_TEMP			;
;
ISR_INT:
	btfss	INTCON,INTF		;INT入力エッジ割込みか?
	goto 	TM0_INT			;それ以外なら、Timer0 割込みの確認へ行く。
;
	bsf	STATUS,RP0		;■バンク 1 にする。
	bcf	TRISIO,CR_BIT		;GP2ビットを出力に戻す。
;					;(High=コンデンサへ充電)
	bcf	STATUS,RP0		;■バンク 0 にする。

;----------------------------充電のための時間稼ぎ(実質不要)

	nop
	nop

;----------------------------割込み発生の再スタート処理
	bsf	STATUS,RP0		;■バンク 1 にする。
	bsf	TRISIO,CR_BIT		;GP2ビットを一時的に入力にする。
	bcf	STATUS,RP0		;■バンク 0 にする。

;----------------------------◆◆ここから割込み処理を書く

	incfsz	CCC,F			;CCC +1 オーバーフローか?:スキップ
	goto	INT_EDG_END		;オーバーフローではないので終了。

	incf	CCC256,F		;上位のカウンタ +1

	movlw	DEF_CCC
	movwf	CCC			;◆タイミングカウンタ下位を初期セット

INT_EDG_END:

;----------------------------◆◆ここまで割込み処理を書く

	bcf	INTCON,INTF		;INTF 入力エッジ割込みフラグを、
					;プログラムでクリヤして復帰する。

;	goto	ISR_INT_END		;◆有っても動作に関係ないが、
;					;INT入力エッジ割込みの確認後に、
;					;次のタイマ割込みをチェックするために
;					;コメント扱いとする。

TM0_INT:				;タイマ0の割込み処理
	btfss	INTCON,T0IF		;Timer 0 割込みか?
	goto 	ISR_INT_END		;それ以外なら、終了へ行く。
;
;----------------------------◆◆ここから割込み処理を書く


	incf	CW_CLK,F		;CW入力信号の読み込みカウンタを+1する


;----------------------------◆◆ここまで割込み処理を書く


	bcf	INTCON,T0IF		;Timer0 の割込みフラグをクリヤ

	goto	ISR_INT_END		;駄目押し的なジャンプ


ISR_INT_END:

	movf	S_TEMP,W		;以下の4行は割込み復帰の定型処理。
	movwf	STATUS			;
	swapf	W_TEMP,F		;
	swapf	W_TEMP,W		;
	
	retfie

;-------------------------------------------------------------------
;///////////////////////////////////////////////////////////////////
;	◆◆◆以下は、電源ON後に1回だけ通過する。◆◆◆
;///////////////////////////////////////////////////////////////////
;-------------------------------------------------------------------
;
MAIN_LOOP0:

	bcf	INTCON,INTF		;INT入力エッジ割込みフラグをクリヤ

;-------------------------------	;INT入力エッジ割込み発生のスタート処理
	bsf	STATUS,RP0		;■バンク 1 にする。
	bsf	TRISIO,CR_BIT		;GP2ビットを一時的に入力にする。
	bcf	STATUS,RP0		;■バンク 0 にする。

;----------------------------------------------------------------

;-------------------------------------------------------------------
;///////////////////////////////////////////////////////////////////
;	◆◆◆メインルーチンの先頭◆◆◆
;///////////////////////////////////////////////////////////////////
;-------------------------------------------------------------------

MAIN_LOOP:

;--------------------------		パドル入力の確認

PAD_CHECK0:

	btfsc	RUN_MEMO,PAD_DOT	;ドット送出中以外ならドットを確認
	goto	PAD_CHECK1		;ダッシュチェックへ
	btfsc	GPIO,PAD_DOT		;ドット側が押されたか?

	goto	PAD_CHECK1		;ダッシュチェックへ
	call	TM0_CLR			;◆パドルが押されたときは、
					;CWバッファーを全クリヤする。
	bsf	PAD_MEMO,PAD_DOT	;パドルメモへドットをセット

PAD_CHECK1:

	btfsc	RUN_MEMO,PAD_DAS	;ダッシュ送出中以外ならダッシュを確認
	goto	PAD_CHECK_E		;パドル確認終了へ
	btfsc	GPIO,PAD_DAS		;ダッシュ側が押されたか?

	goto	PAD_CHECK_E
	call	TM0_CLR			;◆パドルが押されたときは、
;					;CWバッファーを全クリヤする。
	bsf	PAD_MEMO,PAD_DAS	;パドルメモへドットをセット

PAD_CHECK_E:

	goto	RUN_CHECK0		;あえて記述した。(処理に影響なし)

;----------------------------------------------------------------
;-------------------------------	実行中の処理を確認
RUN_CHECK0:

	btfss	RUN_MEMO,PAD_DOT	;ドット送出中か?
	goto	RUN_CHECK1		;次のチェックへ
	goto	RUN_DOT_0		;ドット送出処理へ行く。

RUN_CHECK1:

	btfss	RUN_MEMO,PAD_DAS	;ダッシュ送出中か?
	goto	RUN_CHECK_E		;次のチェックへ
	goto	RUN_DAS_0		;ダッシュ送出処理へ

RUN_CHECK_E:

	btfss	RUN_MEMO,BIT_MJK	;◆文字間送出中か?
	goto	RUN_CHECK_E1		;次のチェックへ
	goto	RUN_MJK_0		;文字間送出処理へ行く。

RUN_CHECK_E1:					;

	btfss	RUN_MEMO,BIT_SPC	;◆スペース送出中か?
	goto	RUN_CHECK_EE		;次のチェックへ
	goto	RUN_SPC_0		;スペース送出処理へ行く。

RUN_CHECK_EE:

	call	MEMO_DOT_CHECK		;サブルーチンでドット押下を確認
	call	MEMO_DAS_CHECK		;サブルーチンでダッシュ押下を確認

;----------------------------------------------------------------
;CW Buffer用

;					;◆◆◆◆CW入力があるか?
	movf	CB_CW_CNT,F		;ゼロか判定(内容に影響しない)
	btfss	STATUS,Z		;入力文字数がゼロならスキップ
	call	CB_CHECK		;CWバッファをチェックに行く

	goto	PAD_LOOP_E		;◆◆パドル処理の最終位置へ
;
;----------------------------------------------------------------
RUN_DOT_0:				;ドット送出処理

	btfss	RUN_MEMO,DOT_STA	;信号部分か判定する。
	goto	RUN_DOT_1

	movlw	TIME_1			;単位時間1を W へ呼び出す。
	subwf	CCC256,W		;CCC256カウンタからTIME_1(ドット時間)を引く。
;					;結果を W レジスタに入れる。
	btfss	STATUS,C		;C=1 で、時間が経過した。
	goto	RUN_DOT_E		;◆RUN_DOT 最終処理へ

	call	CNT_CLR			;タイミングカウンタクリヤ(初期化)

	call	CW_OFF			;信号送出を止める。
	bcf	RUN_MEMO,DOT_STA	;状態を信号送出後の間隔時間にする。
	goto	RUN_DOT_E		;RUN_DOT 最終処理へ

RUN_DOT_1:

	movlw	TIME_1			;単位時間1を W へ呼び出す。
	subwf	CCC256,W		;CCC256カウンタからTIME_1(ドット時間)を引く。
;					;結果を W レジスタに入れる。
	btfss	STATUS,C		;C=1 で、時間が経過した。
	goto	RUN_DOT_E		;◆RUN_DOT 最終処理へ

	call	CNT_CLR			;タイミングカウンタクリヤ(初期化)

	bcf	RUN_MEMO,PAD_DOT	;ドット送出の終了
	bcf	PAD_MEMO,PAD_DOT	;パドルのドットメモをクリヤ
;	bcf	PAD_MEMO,PAD_DAS	;◆これを有効にすると、アイアンビックの
;					; mode A になるはず。(もう一箇所有り)
;
	call	MEMO_DAS_CHECK		;ドット処理直後は、
;					;ダッシュの状態を優先確認する。
;					;(アイアンピック動作)

RUN_DOT_E:

	goto	PAD_LOOP_E		;◆◆パドル処理の最終位置へ

;----------------------------------------------------------------
;-------------------------
RUN_DAS_0:				;ダッシュ送出処理

	btfss	RUN_MEMO,DAS_STA	;信号部分か判定する。
	goto	RUN_DAS_1

;					;----------------------------------
	movlw	TIME_1			;単位時間 1 を W へ呼び出す。
	subwf	CCC256,W		;CCC256カウンタからTIME_1(ドット時間相当)を引く。
;					;結果を W レジスタに入れる。
	btfss	STATUS,C		;C=1 で、時間が経過した。
	bcf	PAD_MEMO,PAD_DOT	;パドルのドットメモをクリヤ
					;◆◆◆ダッシュの先頭から約1/3間は、
					;パドルのドットを記憶しない。
;					;----------------------------------

	movlw	TIME_3			;単位時間3を W へ呼び出す。
	subwf	CCC256,W		;CCC256カウンタからTIME_3(ダッシュ時間)を引く。
;					;結果を W レジスタに入れる。
	btfss	STATUS,C		;C=1 で、時間が経過した。
	goto	RUN_DAS_E		;◆RUN_DAS 最終処理へ

	call	CNT_CLR			;タイミングカウンタクリヤ(初期化)

	call	CW_OFF			;信号送出を止める。

	bcf	RUN_MEMO,DAS_STA	;状態を信号送出後の間隔時間にする。
	goto	RUN_DAS_E		;◆RUN_DAS 最終処理へ

RUN_DAS_1:

	movlw	TIME_1			;単位時間1を W へ呼び出す。
	subwf	CCC256,W		;CCC256カウンタからTIME_1(ドット時間)を引く。
;					;結果を W レジスタに入れる。
	btfss	STATUS,C		;C=1 で、時間が経過した。
	goto	RUN_DAS_E		;◆RUN_DAS 最終処理へ

	call	CNT_CLR			;タイミングカウンタクリヤ(初期化)

	bcf	RUN_MEMO,PAD_DAS	;ダッシュ送出の終了
	bcf	PAD_MEMO,PAD_DAS	;パドルのダッシュメモをクリヤ
;	bcf	PAD_MEMO,PAD_DOT	;◆これを有効にすると、アイアンビックの
;					; mode A になるはず。(もう一箇所有り)

	call	MEMO_DOT_CHECK		;ダッシュ処理直後は、
;					;ドットの状態を優先確認する。
;					;(アイアンピック動作)

RUN_DAS_E:

	goto	PAD_LOOP_E		;◆◆パドル処理の最終位置へ

;----------------------------------------------------------------
;-------------------------
RUN_MJK_0:				;文字間送出処理

	movlw	TIME_2			;単位時間 2を W へ呼び出す。
	subwf	CCC256,W		;CCC256カウンタからTIME_2(文字間時間)を引く。
;					;結果を W レジスタに入れる。
	btfss	STATUS,C		;C=1 で、時間が経過した。
	goto	RUN_MJK_E

	call	CNT_CLR			;タイミングカウンタクリヤ(初期化)
	clrf	RUN_MEMO

RUN_MJK_E:

	goto	PAD_LOOP_E		;◆◆パドル処理の最終位置へ

;-------------------------
RUN_SPC_0:				;スペース送出処理

	movlw	TIME_4			;単位時間 4を W へ呼び出す。
	subwf	CCC256,W		;CCC256カウンタからTIME_4(スペース時間)を引く。
;					;結果を W レジスタに入れる。
	btfss	STATUS,C		;C=1 で、時間が経過した。
	goto	RUN_SPC_E

	call	CNT_CLR			;タイミングカウンタクリヤ(初期化)
	clrf	RUN_MEMO

RUN_SPC_E:

	goto	PAD_LOOP_E		;あえて記述した。(処理に影響なし)

PAD_LOOP_E:				;◆◆パドル処理の最終位置◆◆

	goto	CB_LOOP			;あえて記述した。(処理に影響なし)

;----------------------------------------------------------------
;	;ここからCW入力のチェックをする。
;	; ■CW_IN_STAの状態■
;	;  0= 初期値、
;	;  1=CW信号有り、2=CW信号が途切れた状態(文字間待ち)、
;	;  3=文字間を確認中、4=スペース確認中
;-----------------------------------------------------------------

CB_LOOP:

	movf	CW_IN_STA,F		;状態がゼロかを確認
	btfss	STATUS,Z		;ゼロか?
	goto	CB_LOOP1		;入力が有る状態を処理中 goto

	btfsc	GPIO,CW_BIT		;ポートにCW信号有る状態か?

	goto	CB_LOOP_E		;信号無し...

CB_LOOP_0R5:				;◆途中から信号があったときの処理位置。

	movlw	1			; 1 を
	movwf	CW_IN_STA		;状態へセット

	clrf	CW_CLK			;2mSインターバルをクリヤ
	goto	CB_LOOP_E		;LOOP の最後へ。

;---------------------------------------
CB_LOOP1:

	movf	CW_IN_STA,W		;状態を呼び出し
	sublw	D'1'			; 1=CW信号有り
	btfss	STATUS,Z		;
	goto	CB_LOOP2

	btfss	GPIO,CW_BIT		;ポートにCW信号無い状態か?

	goto	CB_LOOP_E		;ポートにCW信号有れば   LOOP の最後へ。
;					;信号が途切れたときに、以下の処理をする。
	movlw	2			;2 を
	movwf	CW_IN_STA		;状態へセット

	movf	CW_CLK,W		;インターバルカウンタ読み出し。
	sublw	CLK_2			;ドットとダッシュの間を判定する。
;					;40 - CW_CLK = マイナス時は、C = 0
	btfsc	STATUS,C		;ダッシュか?  ( C bitは負論理)
	goto	CB_DOT_SET		;ドットをセットする。
	goto	CB_DAS_SET		;ダッシュをセット


;---------------------------------------
CB_LOOP2:

	movf	CW_IN_STA,W		;状態を呼び出し
	sublw	D'2'			; 2=CW信号が途切れた状態(文字間待ち)
	btfss	STATUS,Z		;
	goto	CB_LOOP3

	btfss	GPIO,CW_BIT		;ポートにCW信号無ければスキップ
	goto	CB_LOOP_0R5		;◆次の符号処理のため先頭付近から再スタート

	movf	CW_CLK,W		;インターバルカウンタ読み出し。
	sublw	CLK_2			;符号間と文字間の間を判定する。
;					;40 - CW_CLK = マイナス時は、C = 0
	btfsc	STATUS,C		;文字間か?  ( C bitは負論理)
	goto	CB_LOOP_E		;符号間の扱い(何もしない)

	movlw	3			;3 を(文字間)
	movwf	CW_IN_STA		;状態へセット
	goto	CB_MJK_SET		;文字間をセット

;---------------------------------------
CB_LOOP3:

	movf	CW_IN_STA,W		;状態を呼び出し
	sublw	D'3'			; 3=文字間を確認中
	btfss	STATUS,Z		;
	goto	CB_LOOP_E

	btfss	GPIO,CW_BIT		;ポートにCW信号無ければスキップ
	goto	CB_LOOP_0R5		;◆次の符号処理のため先頭付近から再スタート

	movf	CW_CLK,W		;インターバルカウンタ読み出し。
	sublw	CLK_3			;文字間とスペースの間を判定する。
;					;60 - CW_CLK = マイナス時は、C = 0
	btfsc	STATUS,C		;スペースか?  ( C bitは負論理)
	goto	CB_LOOP_E		;文字間の扱い(何もしない)

	clrf	CW_IN_STA		;状態をクリヤ
	goto	CB_SPC_SET		;スペースセット

;---------------------------------------
CB_LOOP3_A:				;タイマオーバーか?

	movf	CW_CLK,W		;インターバルカウンタ読み出し。
	sublw	CLK_3			;文字間とスペースの間を判定する。
;					;60 - CW_CLK = マイナス時は、C = 0
	btfsc	STATUS,C		;スペースか?  ( C bitは負論理)
	goto	CB_LOOP_E		;文字間の扱い(何もしない)

	clrf	CW_IN_STA		;◆状態をクリヤ
	goto	CB_SPC_SET		;スペースセット

;----------------------------------------------------------------
CB_DAS_SET:				;CW_Buffer にダッシュをセット

	movlw	B'00000011'		;dash
	goto	CB_ALL_SET		;◆符号セットの共通処理へ。

;---------------------------------------
CB_DOT_SET:				;CW_Buffer にドットをセット

	movlw	B'00000010'		;dot
	goto	CB_ALL_SET		;◆符号セットの共通処理へ。

;---------------------------------------
CB_SPC_SET:				;CW_Buffer にスペースをセット

	movlw	B'00000000'		;スペース
	goto	CB_ALL_SET		;◆符号セットの共通処理へ。

;---------------------------------------
CB_MJK_SET:				;CW_Buffer に文字間をセット

	movlw	B'00000001'		;文字間
	goto	CB_ALL_SET		;◆符号セットの共通処理へ。

;---------------------------------------
CB_ALL_SET:				;◆符号セットの共通処理

	clrf	CW_CLK			;2mSインターバルをクリヤ
	movwf	CB_TMP			;テンポラリに置いて
	call	PUT_BUF			;バッファへ格納
	goto	CB_LOOP_E		;LOOP の最後へ。

;----------------------------------------------------------------
CB_LOOP_E:
	nop

MAIN_LOOP_E:

;					;◆命令クロックをタイマ入力にすると、
;					;sleep 中はカウントアップしない。
;					;そのためCWバッファの確認をして、
;					;sleep モードへ入る。
;					;sleep 中は、CRによるINT割込みで再起動する。
;					;(数mS〜約10mS間隔)
	btfss	GPIO,CW_BIT		;ポートにCW信号無い状態か?
	goto	MAIN_LOOP_ESS		;◆(CW信号有り)SleepSkip へ行く。

	movf	CW_IN_STA,F		;状態がゼロか?を確認
	btfss	STATUS,Z		;ゼロならスキップ
	goto	MAIN_LOOP_ESS		;◆(バッファ動作中)SleepSkip へ行く。

	movf	CB_CW_CNT,F		;CW信号入力数のゼロ確認
	btfss	STATUS,Z		;ゼロならスキップ
	goto	MAIN_LOOP_ESS		;◆(バッファに処理待ちの符号有り)SleepSkip へ行く。

	movf	RUN_MEMO,F		;CW信号の送出処理中
	btfss	STATUS,Z		;ゼロならスキップ
	goto	MAIN_LOOP_ESS		;◆(送出処理中)SleepSkip へ行く。

;					;待機時の電流(速度設定により変動)
	sleep				;sleep挿入で 0.20mA 〜0.64mA
;					;sleep挿入しないと 0.62mA 〜0.76mA
	nop				;sleep のおまじない。

MAIN_LOOP_ESS:				;◆SleepSkip の位置。

	goto	MAIN_LOOP


;-------------------------------------------------------------------
;///////////////////////////////////////////////////////////////////
;	◆◆◆初期設定◆◆◆
;///////////////////////////////////////////////////////////////////
;-------------------------------------------------------------------

START_DEF:
;---------------------------;
	bcf	STATUS,RP0		;■バンク 0 にする。
	call	H'3FF'			;内部発振器をキャリブレーションする。
	bsf	STATUS,RP0		;■バンク 1 にする。
	movwf	OSCCAL
	bcf	STATUS,RP0		;■バンク 0 にする。

	movlw	B'00000111'		;コンパレーターoffにする
	movwf	CMCON

	clrwdt				;WDTをクリヤする。(PSAビット関連)

	bsf	STATUS,RP0		;■バンク 1 にする。

	clrf	WPU			;ウィーク・プルアップの各ビット設定無し。

	movlw	DEF_OP_REG		;割込みのオプションレジスタ初期値
	movwf	OPTION_REG		;INTピン入力信号の
;					;立下りエッジ割込み設定、(bank1)
;					;タイマ0の設定、プリスケーラの設定。


;	clrf	ANSEL			;GPIOポートをデジタルI/Oモードにする。
;					;12F675 のみの設定。

	movlw	GPIO_MODE		;先頭の equ 定義  B'00001011'	;GP2 は出力指定。
	movwf	TRISIO

	bcf	STATUS,RP0		;■バンク 0 にする。

;-------------------------------------------------------------------
	movlw	B'00000100'		;GP2 だけはHighを出力指定。Sleep時に注意。
	movwf	GPIO_OUT		;GPIO_OUTの内容を初期化する (レジスター上のポート)
	call	IOPORT			;初期値を出力ポートに書き込み(必須)
;-------------------------------------------------------------------
;
	call	CNT_CLR			;タイミングカウンタクリヤ(初期化)

	call	TM0_CLR			;タイマ0関連のクリヤ

	clrf	RUN_MEMO		;送出中信号メモをクリヤ
	clrf	PAD_MEMO		;パドルの状態をクリヤ


	movlw	DEF_INTCON		;割込みのセット
	movwf	INTCON

	goto	MAIN_LOOP0		;ここに MAIN_LOOP0 部の記述を書いても良いが、
;					;初期化の一部をメインループの中で回せるようにする
;					;プログラム記述上の癖から、このようにした。

;-------------------------------------------------------------------
;///////////////////////////////////////////////////////////////////
;	◆◆◆ここより下は、サブルーチンを記述する。◆◆◆
;///////////////////////////////////////////////////////////////////
;-------------------------------------------------------------------
;					;割込みタイミング用のカウンタクリヤ
CNT_CLR:

	movlw	DEF_CCC			;設定値があるためサブルーチンで定義する。
					;(他にもう一箇所あり)
	movwf	CCC			;タイミングカウンタを初期セット
	clrf	CCC256			;タイミングカウンタ上位を初期セット
	return

;-------------------------------------------------------------------
TM0_CLR:				;CWバッファ機能で使用する。

	movlw	CB_POS_ST		;◆◆◆ スタートアドレスをセット
	movwf	CB_BYT_INPOS		;バイトの入力位置
	movwf	CB_BYT_OTPOS		;バイトの出力位置

	movwf	FSR			;相対アドレス指示
	clrf	INDF			;CWバッファの先頭をクリヤ

	clrf	CB_BIT_INPOS		;ビットの入力位置
	clrf	CB_BIT_OTPOS		;ビットの出力位置

	clrf	CB_CW_CNT		;バッファに入ったCW符号数
	clrf	CB_TMP			;符号入出力のテンポラリ
	clrf	CW_IN_STA		;CW符号の入力状態

	clrf	CW_CLK			;割込みで使うカウンタ

	return

;-------------------------------------------------------------------
;---------------------------------------;■ 何も実行中で無い時に実行する。■
;					;パドルメモの確認
MEMO_DOT_CHECK:

	btfss	PAD_MEMO,PAD_DOT	;ドットが押されているか?
	goto	MEMO_DOT_CHECK_E

	call	CNT_CLR			;タイミングカウンタクリヤ(初期化)

	bsf	RUN_MEMO,DOT_STA	;状態ビットの信号部分処理中にセット
	call	CW_ON			;CW信号ON
	bsf	RUN_MEMO,PAD_DOT	;ドット処理中をセット
	bcf	PAD_MEMO,PAD_DOT	;ドットが押されていたメモをクリヤ

MEMO_DOT_CHECK_E:

	return

;--------------------------------

MEMO_DAS_CHECK:

	btfss	PAD_MEMO,PAD_DAS	;ダッシュが押されているか?
	goto	MEMO_DAS_CHECK_E

	call	CNT_CLR			;タイミングカウンタクリヤ(初期化)

	bsf	RUN_MEMO,DAS_STA	;状態ビットの信号部分処理中にセット
	call	CW_ON			;CW信号ON
	bsf	RUN_MEMO,PAD_DAS	;ダッシュ処理中をセット
	bcf	PAD_MEMO,PAD_DAS	;ダッシュが押されていたメモをクリヤ

MEMO_DAS_CHECK_E:

	return

;-------------------------------------------------------------------
;---------------------------------------;■ 何も実行中で無い時に実行する。■
;     (11=ダッシュ符号、10=ドット符号、01=文字間、00=スペース)
;					;CWバッファーチェック
CB_CHECK:				;CWバッファーチェック

	movf	CB_CW_CNT,F		;ゼロか判定(内容に影響しない)
	btfsc	STATUS,Z		;入力文字数がゼロ以上なら
	goto	CB_CHECK_E		;そのままリターンする。goto

	call	GET_BUF			;◆◆◆◆◆

	movf	CB_TMP,F		;00判定
	btfss	STATUS,Z		;
	goto	CB_CHECK_2		;次のチェックへ

	call	CNT_CLR			;タイミングカウンタクリヤ(初期化)

	bsf	RUN_MEMO,BIT_SPC	;スペース処理中にセット
	goto	CB_CHECK_E

;---------------------------------------
CB_CHECK_2
	movf	CB_TMP,W		;
	sublw	D'1'			;CB_TMP から 1 を引いて(スキップ)
	btfss	STATUS,Z		;ゼロなら?(スキップ)
	goto	CB_CHECK_3		;次のチェックへ

	call	CNT_CLR			;タイミングカウンタクリヤ(初期化)

	bsf	RUN_MEMO,BIT_MJK	;文字間処理中にセット
	goto	CB_CHECK_E

;---------------------------------------
CB_CHECK_3
	movf	CB_TMP,W		;
	sublw	D'2'			;CB_TMP から 2 を引いて(スキップ)
	btfss	STATUS,Z		;ゼロなら?(スキップ)
	goto	CB_CHECK_4		;次のチェックへ

	call	CNT_CLR			;タイミングカウンタクリヤ(初期化)

	bsf	RUN_MEMO,DOT_STA	;状態ビットの信号部分処理中にセット
	call	CW_ON			;CW信号ON
	bsf	RUN_MEMO,PAD_DOT	;ドット処理中をセット

;---------------------------------------
CB_CHECK_4
	movf	CB_TMP,W		;
	sublw	D'3'			;CB_TMP から 3 を引いて(スキップ)
	btfss	STATUS,Z		;ゼロなら?(スキップ)
	goto	CB_CHECK_E		;次のチェックへ

	call	CNT_CLR			;タイミングカウンタクリヤ(初期化)

	bsf	RUN_MEMO,DAS_STA	;状態ビットの信号部分処理中にセット
	call	CW_ON			;CW信号ON
	bsf	RUN_MEMO,PAD_DAS	;ダッシュ処理中をセット


CB_CHECK_E:

	return

;-------------------------------------------------------------------
CW_ON:					;Key出力 ON

	bsf	GPIO_OUT,LED_BIT
	goto	IOPORT

;---------------------------------------
CW_OFF:					;Key出力 OFF

	bcf	GPIO_OUT,LED_BIT
	goto	IOPORT

;---------------------------------------
IOPORT:					;データ出力

	movf	GPIO_OUT,W		;GPIOに出力データを書く。
	movwf	GPIO

	return

;-------------------------------------------------------------------
;
;   ◆入力符号は CB_TMP に格納して、このルーチンを呼び出す。
;     CB_TMP は、最下位側の2ビットに符号を格納する。
;     ■11=ダッシュ符号、10=ドット符号、01=文字間、00=スペース■
;
;   ◆最初の呼び出し時はbuffer先頭部の内容が、未確定なので、
;   起動後のレジクリヤで消す。
;   ◆CB_BIT_INPOS の初期値は、0とする。
;   ◆CB_BIT_INPOS は、3〜0 の値を持って、3はMSB側の2ビットとし、
;            0は、LSB側の2ビットへ格納する。
;
;      bit-> 76│54│32│10
;      POS-> 3│2│1│0
;
;	◆処理の最後に、入力符号数を加算する。
;
;   (メインループの動きを分かりやすくするためにサブルーチン化した。)
;---------------------------------------
PUT_BUF:

	movf	CB_BIT_INPOS,F		;ビット位置を呼び出し
;					;ゼロかを判定

	btfss	STATUS,Z		;同数ならスキップ
	goto	PUT_BUF_1		;

	movf	CB_TMP,W		;
	andlw	B'00000011'		;最下位2ビット
	movwf	CB_TMP			;
	goto	PUT_BUF_E		;復帰処理へ

;---------------------------------------
PUT_BUF_1:

	movf	CB_BIT_INPOS,W		;ビット位置を呼び出し
	sublw	1			;位置 1 か
	btfss	STATUS,Z		;同数ならスキップ
	goto	PUT_BUF_2		;

	rlf	CB_TMP,F		;2回 左へ
	rlf	CB_TMP,F		;
	movf	CB_TMP,W

	andlw	B'00001100'		;下位2ビット
	movwf	CB_TMP			;
	goto	PUT_BUF_E		;復帰処理へ

;---------------------------------------
PUT_BUF_2:

	movf	CB_BIT_INPOS,W		;ビット位置を呼び出し
	sublw	2			;位置 2 か
	btfss	STATUS,Z		;同数ならスキップ
	goto	PUT_BUF_3		;

	rlf	CB_TMP,F		;4回 左へ
	rlf	CB_TMP,F		;
	rlf	CB_TMP,F		;
	rlf	CB_TMP,F		;
	movf	CB_TMP,W

	andlw	B'00110000'		;上位側2ビット
	movwf	CB_TMP			;
	goto	PUT_BUF_E		;復帰処理へ

;---------------------------------------
PUT_BUF_3:

	movf	CB_BIT_INPOS,W		;ビット位置を呼び出し
	sublw	3			;位置 3 か
	btfss	STATUS,Z		;同数ならスキップ
	goto	PUT_BUF_4		;

	rlf	CB_TMP,F		;6回 左へ
	rlf	CB_TMP,F		;
	rlf	CB_TMP,F		;
	rlf	CB_TMP,F		;
	rlf	CB_TMP,F		;
	rlf	CB_TMP,F		;
	movf	CB_TMP,W
	
	andlw	B'11000000'		;最上位2ビット
	movwf	CB_TMP			;
	goto	PUT_BUF_E		;復帰処理へ

;---------------------------------------
PUT_BUF_4:				;◆◆この位置に飛び込んでくることは、
;					;発生しないはず。(不正処理)
	call	TM0_CLR			;タイマ0クリヤへ行って、
	goto	PUT_BUF_END		;初期化後、最初から格納する。
;					;(はき捨て)
;---------------------------------------
PUT_BUF_E:

	movf	CB_BYT_INPOS,W
	movwf	FSR			;間接アドレスセット
	movf	CB_TMP,W		;位置あわせをしたデータを呼び出し。
	iorwf	INDF,F			;DATA 相対アドレス へOR格納する。

	incf	CB_BIT_INPOS,F		;位置を+1
	movf	CB_BIT_INPOS,W		;ビット位置を呼び出し
	sublw	4			;位置がオーバーフローか
	btfss	STATUS,Z		;4だったならスキップ
	goto	PUT_BUF_E2		;4以内なのでバイト位置はそのまま

	clrf	CB_BIT_INPOS		;ビット位置をゼロに

	incf	CB_BYT_INPOS,F		;バイト位置を+1
	movlw	CB_POS_END		;レジスタのエンド位置を呼び出し
	subwf	CB_BYT_INPOS,W		;入力(格納)のアドレスが
	btfss	STATUS,Z		;最終アドレスを超えていないか?
	goto	PUT_BUF_E1		;超えていない。GOTO

	movlw	CB_POS_ST		;超えたので、
	movwf	CB_BYT_INPOS		;スタートアドレスをセット

PUT_BUF_E1:

	movf	CB_BYT_INPOS,W		;バイト位置を呼び出し
	movwf	FSR			;間接アドレスセット
	clrf	INDF			;次の格納位置をクリヤする。

PUT_BUF_E2:

	incf	CB_CW_CNT,F		;入力符号を加算

PUT_BUF_END:

	return

;-------------------------------------------------------------------
;
;   ◆出力符号は、このルーチンを呼び出し CB_TMP に格納して取り出す。
;     CB_TMP は、最下位側の2ビットに符号を格納する。
;     ■11=ダッシュ符号、10=ドット符号、01=文字間、00=スペース■
;
;   ◆CB_BIT_OTPOS の初期値は、0とする。
;   ◆CB_BIT_OTPOS は、3〜0 の値を持って、3はMSB側の2ビットとし、
;            0は、LSB側の2ビットへ格納する。
;
;      bit-> 76│54│32│10
;      POS-> 3│2│1│0
;
;	◆処理の最後に、入力符号数を減算する。
;
;   (メインループの動きを分かりやすくするためにサブルーチン化した。)
;---------------------------------------
;
GET_BUF:

	movf	CB_BYT_OTPOS,W		;バイト位置をセット
	movwf	FSR			;間接アドレスセット
	movf	INDF,W			;間接呼び出し。
	movwf	CB_TMP			;符号(複数)を一時格納

	movf	CB_BIT_OTPOS,F		;ビット位置を呼び出し
;					;位置 0 か
	btfss	STATUS,Z		;同数ならスキップ
	goto	GET_BUF_1		;

	movf	CB_TMP,W		;符号(複数)を呼び出し
	
	andlw	B'00000011'		;下位2ビット指定
	movwf	CB_TMP			;引渡し位置(LSB)にセット

	goto	GET_BUF_E		;復帰処理へ

;---------------------------------------
GET_BUF_1:

	movf	CB_BIT_OTPOS,W		;ビット位置を呼び出し
	sublw	1			;位置 1 か
	btfss	STATUS,Z		;同数ならスキップ
	goto	GET_BUF_2		;

	rrf	CB_TMP,F		; 2回 右へ
	rrf	CB_TMP,F		;
	movf	CB_TMP,W

	andlw	B'00000011'		;下位2ビット指定
	movwf	CB_TMP			;引渡し位置(LSB)にセット

	goto	GET_BUF_E		;復帰処理へ

;---------------------------------------
GET_BUF_2:

	movf	CB_BIT_OTPOS,W		;ビット位置を呼び出し
	sublw	2			;位置 2 か
	btfss	STATUS,Z		;同数ならスキップ
	goto	GET_BUF_3		;

	rrf	CB_TMP,F		; 4回 右へ
	rrf	CB_TMP,F		;
	rrf	CB_TMP,F		;
	rrf	CB_TMP,F		;
	movf	CB_TMP,W

	andlw	B'00000011'		;下位2ビット指定
	movwf	CB_TMP			;引渡し位置(LSB)にセット

	goto	GET_BUF_E		;復帰処理へ

;---------------------------------------
GET_BUF_3:

	movf	CB_BIT_OTPOS,W		;ビット位置を呼び出し
	sublw	3			;位置 3 か
	btfss	STATUS,Z		;同数ならスキップ
	goto	GET_BUF_4		;

	rrf	CB_TMP,F		; 6回 右へ
	rrf	CB_TMP,F		;
	rrf	CB_TMP,F		;
	rrf	CB_TMP,F		;
	rrf	CB_TMP,F		;
	rrf	CB_TMP,F		;
	movf	CB_TMP,W

	andlw	B'00000011'		;下位2ビット指定
	movwf	CB_TMP			;引渡し位置(LSB)にセット

	goto	GET_BUF_E		;復帰処理へ

;---------------------------------------
GET_BUF_4:				;◆◆この位置に飛び込んでくることは、
;					;発生しないはず。(不正処理)
	call	TM0_CLR			;タイマ0クリヤへ行って、
	goto	GET_BUF_END		;初期化後、最初から処理する。
;					;(はき捨て)
;---------------------------------------
GET_BUF_E:

	incf	CB_BIT_OTPOS,F		;位置を+1
	movf	CB_BIT_OTPOS,W		;ビット位置を呼び出し
	sublw	4			;位置がオーバーフローか
	btfss	STATUS,Z		;4だったならスキップ
	goto	GET_BUF_E1		;4以内なのでバイト位置はそのまま

	clrf	CB_BIT_OTPOS		;ビット位置をゼロに

	incf	CB_BYT_OTPOS,F		;バイト位置を+1
	movlw	CB_POS_END		;レジスタのエンド位置を呼び出し
	subwf	CB_BYT_OTPOS,W		;入力(格納)のアドレスが
	btfss	STATUS,Z		;最終アドレスを超えていないか?
	goto	GET_BUF_E1		;超えていない。GOTO

	movlw	CB_POS_ST		;超えたので、
	movwf	CB_BYT_OTPOS		;スタートアドレスをセット

;---------------------------------------
GET_BUF_E1:

	decf	CB_CW_CNT,F		;◆入力文字数を減算


GET_BUF_END:

	return


;-------------------------------------------------------------------
	data	'c','w','b','u','f','f','k','e','y',':'
	data	'V','1','.','0','1'
	data	'(','C',')','2','0','0','6',' ','J','E','3','J','L','B'
;-------------------------------------------------------------------

;	org	3FFH			;念のため用意している、
;	dw	3468H			;チップ固有のキャリブレDATA。

	end

------------------------------------------------------------------------

 

ソースファイル cwbufkey.asm (2006/07/29)

Hexファイル cwbufkey.hex (2006/07/29)