前回に引き続き、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