前回に引き続き、AT89S52のシリアル通信に挑戦してみました。

シリアル通信で重要な、クロック原ですが、AT80S52の水晶原発振は12MHzとしました。本来は、11.0592MHzなどが一番いいと思いますが、手持ちがなかったので、12MHz水晶発振子で行くことにしました。

8051オリジナルでは、原発振の12クロックを1マシンサイクルとしてタイマ回路につなぎます。AT89S52では、6クロックを1マシンサイクルとしてタイマー回路に送ります。

12MHzでの上限値ボーレート4800bpsに設定し、8データビット、パリティなし、1ストップビットの8N1の設定としています。

シリアル通信UARTのモードをモード1にSCONの設定を行います。

	mov	SCON,	#0x50			;UARTはモード1に設定、受信イネーブル
						;SCON=01010000B		

タイマー回路の先頭では原発振を1/1あるいは1/2に切り替えるSMOD1があります。PCONの7ビット目に当たります。デフォルトは"0"(1/2)ですが、4800bpsにするためにSMOD1を"1"(1/1)設定します。

	mov	PCON,	#0x90			;PCON SMOD1(7bit目)="1" 1*12MHz
						;PCON=10X10000B

シリアル通信では、タイマー1を占有します。タイマー1(TMODで)は8ビット自動リドードモードに設定します。

	mov	TMOD,	#0x20			;タイマー1を8ビット自動リロードモードに設定
						;TMOD=00100000B

分周器TH1及びTL1の値は次の式で求められます。

分周値=256-(SMOD1:1or2)×原発振)/(6*32*ボーレート)

256を引いている意味は、カウント値はカウントアップしてオーバーフローし、カウント値を再読み込みしカウントアップを繰り返すためです。

6の値は、前述の6クロックを1マシンサイクルで実行するためです。
分周値=256-(1*12000000)/(6*32*4800)=256-13(13.02)=243
16進に変換して、0xf3(243)

	mov	a,	#0xf3			;タイマーカウンターセット f3H=256-(1*12000000)/(6*32*4800bps)
	mov	TH1,	a
	mov	TL1,	a

送受信方式は、ポーリング方式で、受信フラグ(RI=SCON(B0))及び送信フラグ(TI=SCON(B1))を常にチェックする方式です。
なお、チェックフラグ RI,TIは手動でクリアする必要があります。
入出力するデータは、SBUF(0x99)にセットされます。
1文字入力、1文字出力は次ようになりました。

getchar:					;1文字シリアル入力
	jnb	ri,	.			;SCONのRI(0bit目)が"1"なるまでループ
	mov	a,	SBUF			;SBUFバッファーからaに格納
	clr	ri				;SCONのRI(0bit目)をクリア
	ret					;復帰

putchar:					;1文字シリアル出力

	clr	ti				;SCONのTI(1bit目)をケリア
	mov	SBUF,	a			;aからSBUFバッファーに格納
	jnb	ti,	.			;SCONのTI(1bit目)が"1"なるまでループ
	ret					;復帰

なお、 jnb ri, . は loop: jnb ri, loop  と同じです

回路図は下記の通りです。
USB-シリアル通信アダプターは、以前使用した「KKHMF 2個 USB to UART TTL RS232 PL2303HX ワイヤーアダプタ変換ケーブルRaspberry Pi Arduino用(amazon)」を使用しました。

下記のプログラムは、シリアル端末にメッセージを出力したのち、>の後、入力された文字をエコーバックします。
ボーレートは4800bps、8N1設定です。

; AT89S52  Serial communication by Pinecone 2024/10/09
;
; AT89S52   cpu
; Flash ROM 8Kbyte
; RAM       256byte
; External clock 12MHz
 
; assembler
;  program start 000H
;  main          100H
;
; assemblers  ASxxxx and ASlink V5.50
; file name AT89S52_serial01.asm
; $ as8051 -l -s -o AT89S52_serial01.asm
; $ aslink -i AT89S52_serial01
;   program download  $sudo avrdude -C avrdude.AT89 -p s52 -c usbasp -P usb -U flash:w:AT89S52_serial01.hex:i   
;

	.area	TEST(ABS)

	.org	0x0000

	ljmp	main

	.org	0x0100
						;ボーレート4800bps 8N1
main:
	mov	sp,	#0x6f			;RAMエリア0030H-007F スタックポインタSPは上位方向(プラス)に移動
	mov	PCON,	#0x90			;PCON SMOD1(7bit目)="1" 1*12MHz
						;PCON=10X10000B
	mov	SCON,	#0x50			;UARTはモード1に設定、受信イネーブル
						;SCON=01010000B			
	mov	TMOD,	#0x20			;タイマー1を8ビット自動リロードモードに設定
						;TMOD=00100000B
	mov	a,	#0xf3			;タイマーカウンターセット f3H=256-(1*12000000)/(6*32*4800bps)
	mov	TH1,	a
	mov	TL1,	a
	setb	TR1				;タイマー1スタート

	mov	DPTR,	#start_msg		;メーセージ先頭アドレスをDPTRにセット
	lcall	msgout				;メッセージをシリアルで出力
	mov	a,	#'>			;> プロンプトをaにセット
	lcall	putchar				;1文字シリアル出力

loop:						;入力されたデータをエコーバック
	lcall	getchar				;1文字シリアル入力
	lcall	putchar				;1文字シリアル出力
	sjmp	loop				;無限にループ

;    ****** サブルーチン *****

msgout:						;DPTRにセットされたメッセージを0x00になるまでシリアル出力
	clr	a				;オフセットをクリア
	movc	a,	@A+DPTR			;a←a(オフセット)+DPTR
	jz	msgout_end			;a=0x00 goto msgout
	inc	DPTR				;DPTR=DPTR+1
	lcall	putchar				;1文字シリアル出力
	sjmp	msgout				;ループ
msgout_end:
	ret					;復帰

getchar:					;1文字シリアル入力
	jnb	ri,	.			;SCONのRI(0bit目)が"1"なるまでループ
	mov	a,	SBUF			;SBUFバッファーからaに格納
	clr	ri				;SCONのRI(0bit目)をクリア
	ret					;復帰

putchar:					;1文字シリアル出力

	clr	ti				;SCONのTI(1bit目)をケリア
	mov	SBUF,	a			;aからSBUFバッファーに格納
	jnb	ti,	.			;SCONのTI(1bit目)が"1"なるまでループ
	ret					;復帰

start_msg:
	.str	"AT89S52 Uart communication Test !"
	.db	0x0d,0x0a,0x00

	.end

アセンブリ、リンクします。

$ as8051 -l -s -o AT89S52_serial01.asm

$ aslink -i AT89S52_serial01

ASlink >> -i
ASlink >> AT89S52_serial01

書き込みします。

$ sudo avrdude -C avrdude.AT89 -p s52 -c usbasp -P usb -U flash:w:AT89S52_serial01.hex:i
[sudo] **** のパスワード:

avrdude: AVR device initialized and ready to accept instructions

Reading | ################################################## | 100% 0.01s

avrdude: Device signature = 0x1e5206 (probably s52)
avrdude: NOTE: "flash" memory has been specified, an erase cycle will be performed
         To disable this feature, specify the -D option.
avrdude: erasing chip
avrdude: reading input file "AT89S52_serial01.hex"
avrdude: writing flash (358 bytes):

Writing | ################################################## | 100% 0.38s

avrdude: 358 bytes of flash written
avrdude: verifying flash memory against AT89S52_serial01.hex:
avrdude: load data flash data from input file AT89S52_serial01.hex:
avrdude: input file AT89S52_serial01.hex contains 358 bytes
avrdude: reading on-chip flash data:

Reading | ################################################## | 100% 0.10s

avrdude: verifying ...
avrdude: 358 bytes of flash verified

avrdude: safemode: Fuses OK (E:FF, H:FF, L:FF)

avrdude done.  Thank you.

シリアル端末でチェックします。
リセットしたのちメッセージと、入力したキーをエコーバックします。

AT89S52 Uart communication Test !
>abcdefg
おすすめの記事