今回は、インラインアセンブラ表記 及び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言語でもいろんな書き方でプログラムを実行できるのが面白いですね。