前回アセンブラで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の間隔で点滅します。