前回アセンブラでLチカを実行しましたが、今回SDCCによるC言語で実行したいと思います。
回路図は、アセンブラでLチカを実行ものと同じです。

SDCCをインストールします。(下記ではすでにインストール済となっています。)

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

開発環境は、Raspberry Pi3 上のRaspbianで、SDCCのバージョンは下記のとおりです。

$ sdcc -v
SDCC : mcs51/z80/z180/r2k/r3ka/gbz80/tlcs90/ds390/TININative/ds400/hc08/s08/stm8 3.8.0 #10562 (Linux)
published under GNU General Public License (GPL)

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

$ 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

今回使用しているAT89S52では、at89x52.hが該当すると思われます。

下記のプログラムは、for文で時間稼ぎして、P1.0端子を点滅するプログラムです。

// AT89S52 LED 点滅 (P1.0)
//
// AT89S52   cpu
// Flash ROM 8Kbyte
// RAM       256byte
// External clock 12MHz
//
// SDCC 3.8.0
//
// file name AT89S52_led_blink.c
// $ sdcc AT89S52_led_blink.c 
// or $ sdcc -mmcs51 --model-small AT89S52_led_blink.c
// $ packihx AT89S52_led_blink.ihx > AT89S52_led_blink.hex
// $ sudo avrdude -C avrdude.AT89 -p s52 -c usbasp -P usb -U flash:w:AT89S52_led_blink.hex:i
//

#include <at89x52.h>	//at89S52用のインクルードファイル読み込み
 
void wait_time(void);	//時間待ち関数宣言
 
void main(void)			//main関数
{
    while(1)			//無限ループ
    {
         P1_0 = 1;		//ポートP10をハイレベルにする
         wait_time();	//時間待ち
         P1_0 = 0;		//ポートP10をローレベルにする
         wait_time();	//時間待ち
    }
}
 
void wait_time(void)	//時間待ち関数
{
    int	i,j;			//forループによる時間待ち
    for(i=0;i < 255;i++)
         for(j=0;j < 255;j++);
}

コンパイルします

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

SDCCはデフォリトでMCS51系列をコンパイルしますので下記の実行も可能です。

$ sdcc AT89S52_led_blink.c

今回は、-mmcs51 を指定してコンパイルしました。

SDCCは吐き出すヘキサコード(ihx)をインテルヘキサコード(hex)に変換します。

$ packihx AT89S52_led_blink.ihx > AT89S52_led_blink.hex
packihx: read 13 lines, wrote 17: OK.

AT89S52へ書き込みします。(avrdude.AT89を書き込みするディレクトリーにコピーしてください)

$ sudo avrdude -C avrdude.AT89 -p s52 -c usbasp -P usb -U flash:w:AT89S52_led_blink.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_led_blink.hex"
avrdude: writing flash (156 bytes):

Writing | ################################################## | 100% 0.19s

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

Reading | ################################################## | 100% 0.05s

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

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

avrdude done.  Thank you.

P1.0に接続したLEDが点滅します。

続いて、インラインアセンブラを使用して、点滅速度を指定できるようにしました。
指定できる時間は10ms(1*10ms)~2550ms(255*10ms)です。
大もとの100usを約100usになるように調整しました(12MHzでr0が0x2fとなりました)

wait_time関数の引数waitは、DPLレジスターに引き継ぎられます。
プログラムは下記のとおりです。
インラインアセンブラ内のコードは__asm ~ __endasmで囲みます。

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

#include <at89x52.h>	//at89S52用のインクルードファイル
void wait_time(unsigned char);	//時間待ち関数宣言
 
void main(void)			//main関数
{
    while(1)			//無限ループ
    {
         P1_0 = 1;		//ポートP10をハイレベルにする
        wait_time(100);//時間待ち(100*10ms)
         P1_0 = 0;		//ポートP10をローレベルにする
        wait_time(100);//時間待ち(100*10ms)
    }
}

void wait_time(unsigned char wait)	//時間待ち関数(wait * 10ms)
{
	wait;
	__asm
		mov		r3,DPL
	delay:
		lcall	delay10ms
		djnz	r3,delay
		ret
	
	delay10ms:
		mov		r2,#10
    delay10msloop:		
		lcall	delay1ms
		djnz	r2,delay10msloop
		ret
		
	delay1ms:
		lcall	delay500us
		lcall	delay500us
		ret

	delay500us:
		mov		r1,#0x05
	delay500uloop:
		lcall	delay100us
		djnz	r1,delay500uloop
		ret

	delay100us:
		mov	r0,#0x2f
	delay1:
		djnz	r0,delay1
		ret
	__endasm;
}

コンパイルします。

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

hexコード変換します。

$ packihx AT89S52_led_blink_inline.ihx > AT89S52_led_blink_inline.hex
packihx: read 13 lines, wrote 17: OK.

AT89S52へ書き込みします(avrdude.AT89を書き込みするディレクトリーにコピーしてください)

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

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

Writing | ################################################## | 100% 0.19s

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

Reading | ################################################## | 100% 0.05s

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

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

avrdude done.  Thank you.

約1秒間隔で点滅します。

最後に、cとアセンブラのリンク版を作成してみます。

まず最初に、アセンプラのプログラムを作成します。
内容は同様です。Cとの引数の渡しも同様にDPLレジスタで行われます。
関数をグローバル宣言します。また、関数のはじめにアンダーバーを追加します。

; AT89S52 LED 点滅 (P1.0) アセンブラリンクルーチン
;
; AT89S52   cpu
; Flash ROM 8Kbyte
; RAM       256byte
; External clock 12MHz
;
; SDCC 3.8.0
;
; file name AT89S52_led_blink_link.asm
; $ sdas8051 -losg AT89S52_led_blink_link.asm 
; 

	.area	CSEG(CODE)
	
	.globl 	_wait_time		;時間待ち関数(wait * 10ms)

_wait_time:
	mov		r3,DPL
	delay:
		lcall	delay10ms
		djnz	r3,delay
		ret
	
	delay10ms:
		mov		r2,#10
    delay10msloop:		
		lcall	delay1ms
		djnz	r2,delay10msloop
		ret
		
	delay1ms:
		lcall	delay500us
		lcall	delay500us
		ret

	delay500us:
		mov		r1,#0x05
	delay500uloop:
		lcall	delay100us
		djnz	r1,delay500uloop
		ret

	delay100us:
		mov	r0,#0x2f
	delay1:
		djnz	r0,delay1
		ret
		

アセンブリします。
sdcc専用のsdas8051でアセンブルしました。

$ sdas8051 -losg AT89S52_led_blink_link.asm
$ ls
AT89S52_led_blink_link.lst
AT89S52_led_blink_link.rel  
AT89S52_led_blink_link.rst  
AT89S52_led_blink_link.sym

Cとのリンクには、AT89S52_led_blink_link.relを指定します

Cのプログラムは下記のとおりです。
外部関数であるwait_time関数をextern宣言します。

// AT89S52 LED 点滅 (P1.0)アセンプラリンク版
//
// AT89S52   cpu
// Flash ROM 8Kbyte
// RAM       256byte
// External clock 12MHz
//
// SDCC 3.8.0
//
// file name AT89S52_led_blink_asm_link.c
// ($ sdas8051 -losg AT89S52_led_blink_link.asm)
// $ sdcc AT89S52_led_blink_asm_link.c AT89S52_led_blink_link.rel
// or $ sdcc -mmcs51 --model-small AT89S52_led_blink_asm_link.c AT89S52_led_blink_link.rel
// $ packihx AT89S52_led_blink_asm_link.ihx > AT89S52_led_blink_asm_link.hex
// $ sudo avrdude -C avrdude.AT89 -p s52 -c usbasp -P usb -U flash:w:AT89S52_led_blink_asm_link.hex:i
//

#include <at89x52.h>	//at89S52用のインクルードファイル
extern void wait_time(unsigned char);	//時間待ち関数宣言
 
void main(void)			//main関数
{
    while(1)			//無限ループ
    {
         P1_0 = 1;		//ポートP10をハイレベルにする
        wait_time(20);//時間待ち(100*10ms)
         P1_0 = 0;		//ポートP10をローレベルにする
        wait_time(20);//時間待ち(100*10ms)
    }
}

コンパイルします。
コンパイル時に外部関数wait_time関数を含めます。

$ sdcc -mmcs51 --model-small AT89S52_led_blink_asm_link.c AT89S52_led_blink_link.rel

hexコード変換します。

$ packihx AT89S52_led_blink_asm_link.ihx > AT89S52_led_blink_asm_link.hex
packihx: read 13 lines, wrote 17: OK.

AT89S52へ書き込みします(avrdude.AT89を書き込みするディレクトリーにコピーしてください)

$ sudo avrdude -C avrdude.AT89 -p s52 -c usbasp -P usb -U flash:w:AT89S52_led_blink_asm_link.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_led_blink_asm_link.hex"
avrdude: writing flash (156 bytes):

Writing | ################################################## | 100% 0.19s

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

Reading | ################################################## | 100% 0.05s

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

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

avrdude done.  Thank you.

約200msの間隔で点滅します。

おすすめの記事