前回に引き続き、SDCCによるC言語でAT89S52のシリアル通信に挑戦してみました。
回路図は、「8051コアに萌えたい AT89S52 シリアル通信」で作成したものです。

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

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

RaspberryPi3自体のOSが古くなってきたので、RaspberryPi3用のOSを「RaspberryPi OS(Legacy,32-bit)」に(バックアップを取ったうえで)、変更しました。それに伴い、SDCCのバージョンが更新されました。

OSのバージョン

$  lsb_release -a
No LSB modules are available.
Distributor ID: Raspbian
Description:    Raspbian GNU/Linux 11 (bullseye)
Release:        11
Codename:       bullseye

SDCCのバージョン(SDCC 4.0.0)

$ sudo apt-get install sdcc
パッケージリストを読み込んでいます... 完了
依存関係ツリーを作成しています... 完了
状態情報を読み取っています... 完了
sdcc はすでに最新バージョン (4.0.0+dfsg-2) です。
アップグレード: 0 個、新規インストール: 0 個、削除: 0 個、保留: 40 個。

$ sdcc -v
SDCC : mcs51/z80/z180/r2k/r3ka/gbz80/tlcs90/ez80_z80/ds390/TININative/ds400/hc08/s08/stm8/pdk13/pdk14/pdk15 4.0.0 #11528 (Linux)
published under GNU General Public License (GPL)

SDCC-4.0.0のインクルードファイルは下記の場所にあります

$ cd /usr/share/sdcc/include/mcs51
$ ls
8051.h        C8051F336.h  SST89x5xRDx.h   ax8052f143.h   p89lpc935_6.h
8052.h        C8051F340.h  XC866.h         ax8052f151.h   p89lpc938.h
ADuC84x.h     C8051F350.h  at89S8252.h     cc1110.h       p89v51rd2.h
AT89C513xA.h  C8051F360.h  at89Sx051.h     cc2430.h       p89v66x.h
C8051F000.h   C8051F410.h  at89c51ed2.h    cc2510fx.h     reg51.h
C8051F018.h   C8051F520.h  at89c51id2.h    cc2530.h       reg764.h
C8051F020.h   C8051F920.h  at89c51snd1c.h  compiler.h     regc515c.h
C8051F040.h   C8051T600.h  at89c55.h       lint.h         sab80515.h
C8051F060.h   C8051T610.h  at89s53.h       mcs51reg.h     ser.h
C8051F120.h   C8051T630.h  at89s8253.h     msc1210.h      ser_ir.h
C8051F200.h   EFM8BB1.h    at89x051.h      msm8xc154s.h   serial.h
C8051F300.h   P89LPC901.h  at89x51.h       p89c66x.h      serial_IO.h
C8051F310.h   P89LPC922.h  at89x52.h       p89lpc9321.h   stc12.h
C8051F320.h   P89LPC925.h  ax8052.h        p89lpc9331.h   uPSD32xx.h
C8051F326.h   P89LPC932.h  ax8052f131.h    p89lpc933_4.h  uPSD33xx.h
C8051F330.h   P89c51RD2.h  ax8052f142.h    p89lpc9351.h   w7100.h

まず最初は、前回、アセンブラで作成しているので、アセンブラでリンクした形で、C言語で作成してみます。

必要とされるものは、
シリアルを初期化するための「uart_init.rel」
1文字入力するための「getchar.rel」
1文字出力するための「putchar.rel」

です。putchar.relを作成すれば、printf関数が使用できるようになります。

シリアルを初期化するための「uart_init.rel」を作成します。
前回にアセンブラで作成した初期化部分を抜き出したものになります。

; AT89S52 uart init  アセンブラリンクルーチン
;
; AT89S52   cpu
; Flash ROM 8Kbyte
; RAM       256byte
; External	clock 12MHz
;
; SDCC 4.0.0
;
; file name AT89S52_uart_init.asm
; $ sdas8051 -losg AT89S52_uart_init.asm 
;
; ボーレート4800bps 8N1 初期化
;
; extern void uart_init(void);
;

	.area	CSEG(CODE)
	
	.globl 	_uart_init

_uart_init:

	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スタート
	ret
	

アセンブルします。

$ sdas8051 -losg AT89S52_uart_init.asm

同様に、「getchar.rel」を作成します。
getcharで入力された文字データは、DPLレジスタに格納します。(戻り値)

;AT89S52 getchar  アセンブラリンクルーチン
;
; AT89S52   cpu
; Flash ROM 8Kbyte
; RAM       256byte
; External	clock 12MHz
;
; SDCC 4.0.0
;
; file name AT89S52_getchar.asm
; $ sdas8051 -losg AT89S52_getchar.asm 
;
; int getchar(void);     //stdio.h内で定義済み
;


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

アセンブルします。

 $  sdas8051 -losg AT89S52_getchar.asm

同様に、「putchar.rel」を作成します。
putcharで出力する文字データは、DPLレジスタに格納します。(引数値)

; AT89S52 putchar  アセンブラリンクルーチン
;
; AT89S52   cpu
; Flash ROM 8Kbyte
; RAM       256byte
; External	clock 12MHz
;
; SDCC 4.0.0
;
; file name AT89S52_putchar.asm
; $ sdas8051 -losg AT89S52_putchar.asm 
; 
; void putchar(int);	//stdio.h 内で定義済み
;

	.area	CSEG(CODE)
	
	.globl 	_putchar

_putchar:

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

アセンブルします。

$ sdas8051 -losg AT89S52_putchar.asm

これで必要なリンクファイルは揃ったので、C言語の作成を行いと思います。

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

printf関数は、fullのprintf関数、printf_small関数、printf_tiny関数が存在しますが、smallモードで使用可能なprintf_tiny関数を使用しました。

// AT89S52 printf 外部関数版
//
// AT89S52   cpu
// Flash ROM 8Kbyte
// RAM       256byte
// External clock 12MHz
//
// SDCC 4.0.0
//
// file name AT89S52_extern_printf.c
// $ sdcc AT89S52_extern_printf.c AT89S52_uart_init.rel AT89S52_getchar.rel AT89S52_putchar.rel
// or $ sdcc -mmcs51 --model-small AT89S52_extern_printf.c AT89S52_uart_init.rel AT89S52_getchar.rel AT89S52_putchar.rel
// $ packihx AT89S52_extern_printf.ihx > AT89S52_extern_printf.hex
// $ sudo avrdude -C avrdude.AT89 -p s52 -c usbasp -P usb -U flash:w:AT89S52_extern_printf.hex:i
//
#include <stdio.h>
#include <at89x52.h>			//at89S52用のインクルードファイル

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

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

コンパイルします。

$ sdcc -mmcs51 --model-small AT89S52_extern_printf.c AT89S52_uart_init.rel AT89S52_getchar.rel AT89S52_putchar.rel

.hexファイルに変換します。

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

AT89S52に書き込みします。

avrdudeもインストールされていなかったので再インストールしました。

$ sudo apt-get install  avrdude
パッケージリストを読み込んでいます... 完了
依存関係ツリーを作成しています... 完了
状態情報を読み取っています... 完了
avrdude はすでに最新バージョン (6.3-20171130+svn1429-2+b1) です。
アップグレード: 0 個、新規インストール: 0 個、削除: 0 個、保留: 40 個。

バージョン

$ avrdude -v

avrdude: Version 6.3-20171130
         Copyright (c) 2000-2005 Brian Dean, http://www.bdmicro.com/
         Copyright (c) 2007-2014 Joerg Wunsch

         System wide configuration file is "/etc/avrdude.conf"
         User configuration file is "/home/rika/.avrduderc"
         User configuration file does not exist or is not a regular file, skipping


avrdude: no programmer has been specified on the command line or the config file
         Specify a programmer using the -c option and try again

やっと書き込みの準備ができたので、AT89S52に書き込みします。

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

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

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

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

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

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

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

avrdude done.  Thank you.

書き込みの確認ですが、GUI(グラフィカルユーザーインターフェース)ベースのgtktermがインストールされていなかったのでインストールしました。

$ sudo apt-get install gtkterm
パッケージリストを読み込んでいます... 完了
依存関係ツリーを作成しています... 完了
状態情報を読み取っています... 完了
gtkterm はすでに最新バージョン (1.1.1-1) です。
アップグレード: 0 個、新規インストール: 0 個、削除: 0 個、保留: 40 個。

ラズベリーのマークから、アクセサリー → Serial port terminal
configuration → port
port: /dev/ttyUSB0
Band Rate: 4800
でOKキー
下記のメーセージが出力され、任意のキーがエコーバックされたらOKです。

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