今回は、インラインアセンブラ表記 及びC言語だけで記述できるか確認したいと思います。

まずは、インラインアセンブラの記述です。

インラインアセンブラ表記の「__asm ~ __endasm;」で前回の外部関数を置き換えています
getcharの戻り値は、「return DPL」でDPLレジスタの値を返しています。

インラインアセンブラで表記したC言語プログラムは下記のとおりです。
以下のプログラムは、printf関数によるメッセージ出力に続いて、getchar関数とputchar関数によるエコーバックをループします。

// AT89S52 printf インラインアセンブラ版
//
// AT89S52   cpu
// Flash ROM 8Kbyte
// RAM       256byte
// External clock 12MHz
//
// SDCC 4.0.0
//
// file name AT89S52_printf_inline.c
// $ sdcc AT89S52_printf_inline.c 
// or $ sdcc -mmcs51 --model-small AT89S52_printf_inline.c
// $ packihx AT89S52_printf_inline.ihx > AT89S52_printf_inline.hex
// $ sudo avrdude -C avrdude.AT89 -p s52 -c usbasp -P usb -U flash:w:AT89S52_printf_inline.hex:i
//

#include <at89x52.h>			//at89S52用のインクルードファイル
#include <stdio.h>

void uart_init(void);			//uart 初期化

void uart_init(void)			//uart 初期化
{
	__asm
	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スタート
	__endasm;
}
int putchar(int data)		//一文字シリアル出力
{
	data;
	__asm
	clr	ti					//SCONのTI(1bit目)をケリア
	mov	SBUF,DPL			//DPLからSBUFバッファーに格納
	jnb	ti,	.				//SCONのTI(1bit目)が"1"なるまでループ
	ret						//復帰
	__endasm;
	return data;
}

int getchar(void)			//1文字シリアル入力
{
	__asm					
	jnb	ri,	.				//SCONのRI(0bit目)が"1"なるまでループ
	mov	DPL,	SBUF		//SBUFバッファーからDPLに格納
	clr	ri					//SCONのRI(0bit目)をクリア
	ret						//復帰
	__endasm;
	return DPL;				//戻り値(DPL)
}

void main(void)					//main関数
{
	uart_init();
	printf_tiny("AT89S52 Uart communication Test !\r\n");
	putchar('>');
	while(1)
		putchar(getchar());
}

コンパイルします。

$ sdcc -mmcs51 --model-small AT89S52_printf_inline.c

hexファイル変換します。

$ packihx AT89S52_printf_inline.ihx > AT89S52_printf_inline.hex
packihx: read 26 lines, wrote 39: OK.

AT89S52に書き込みします。

$ sudo avrdude -C avrdude.AT89 -p s52 -c usbasp -P usb -U flash:w:AT89S52_printf_inline.hex:i

avrdude: AVR device initialized and ready to accept instructions

Reading | ################################################## | 100% 0.00s

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_printf_inline.hex"
avrdude: writing flash (510 bytes):

Writing | ################################################## | 100% 0.41s

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

Reading | ################################################## | 100% 0.09s

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

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

avrdude done.  Thank you.

Serial port Teminal(GTkTerm)で確認

AT89S52 Uart communication Test !
>asdfg

続いて、C言語のみで記述してみます。

uartの初期化は、各レジスタに代入することで、初期化することができます。

1文字シリアル出力は、データをSBUFレジスタに格納し、while文でTIのチェックを行います。

1文字シリアル入力は、while文でRIのチェックを行った後、SBUFをreturn文で返り値として戻します。

C言語プログラムは下記のとおりです。
以下のプログラムは、printf関数によるメッセージ出力に続いて、getchar関数とputchar関数によるエコーバックをループします。

// AT89S52 printf C言語版
//
// AT89S52   cpu
// Flash ROM 8Kbyte
// RAM       256byte
// External clock 12MHz
//
// SDCC 4.0.0
//
// file name AT89S52_printf_c.c
// $ sdcc AT89S52_printf_c.c 
// or $ sdcc -mmcs51 --model-small AT89S52_printf_c.c
// $ packihx AT89S52_printf_c.ihx > AT89S52_printf_c.hex
// $ sudo avrdude -C avrdude.AT89 -p s52 -c usbasp -P usb -U flash:w:AT89S52_printf_c.hex:i
//


#include <at89x52.h>			//at89S52用のインクルードファイル
#include <stdio.h>

// uart 初期化
void uart_init(void) {
	PCON  = 0x90;	//PCON SMOD1(7bit目)="1" 1*12MHz
					//PCON=10X10000B
    SCON  = 0x50;   //UARTはモード1に設定、受信イネーブル
					//SCON=01010000B
    TMOD |= 0x20;   //タイマー1を8ビット自動リロードモードに設定
					//TMOD=00100000B
    TH1   = 0xf3;   //タイマーカウンターセット f3H=256-(1*12000000)/(6*32*4800bps)
	TL1	  = 0xf3;
    TR1   = 1;      // タイマー1スタート

}

// 1文字シリアル出力
int putchar(int data) {
	TI = 0;			//SCONのTI(1bit目)をケリア
	SBUF = data;	//dataからSBUFバッファーに格納
	while (!TI);	//SCONのTI(1bit目)が"1"なるまでループ
	return data;
}

// 1文字シリアル入力
int getchar(void) {
    while (!RI);     //SCONのRI(0bit目)が"1"なるまでループ
    RI = 0;          //SCONのRI(0bit目)をクリア
    return SBUF;     // 受信データ返却
}
void main(void)					//main関数
{
	uart_init();
	printf_tiny("AT89S52 Uart communication Test !\r\n");
	putchar('>');
	while(1)
		putchar(getchar());
}

コンパイルします。

$ sdcc -mmcs51 --model-small AT89S52_printf_c.c

hexファイル変換します。

$ packihx AT89S52_printf_c.ihx > AT89S52_printf_c.hex
packihx: read 26 lines, wrote 39: OK.

AT89S52に書き込みします。

$ sudo avrdude -C avrdude.AT89 -p s52 -c usbasp -P usb -U flash:w:AT89S52_printf_c.hex:i

avrdude: AVR device initialized and ready to accept instructions

Reading | ################################################## | 100% 0.00s

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_printf_c.hex"
avrdude: writing flash (512 bytes):

Writing | ################################################## | 100% 0.42s

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

Reading | ################################################## | 100% 0.09s

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

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

avrdude done.  Thank you.

Serial port Teminal(GTkTerm)で確認

AT89S52 Uart communication Test !
>zxcvbnm

C言語でもいろんな書き方でプログラムを実行できるのが面白いですね。

おすすめの記事