このドキュメントは http://edu.net.c.dendai.ac.jp/ 上で公開されています。
アセンブリ言語はテキストファイルに記述します。 「ラベル: ニモニック オペランド」 を空白で区切って記述します ( AVR Assembler p. 11 3. Assembler source )。 ラベルの前に空白があってはいけません。 また、セミコロン(;)の後ろはコメントとしてアセンブル時に無視されます。 ニモニックの位置には他にディレクティヴ、マクロなどを置くことができます。
ラベル ニモニック オペランド コメント
.org 0x0013
reset:
ldi r16,low(RAMEND)
out SPL,r16
アセンブリ言語中で定数の演算式を書くことが出来ます。 C 言語で許されて いるような演算子がそのまま使えます (AVR Assembler p.33 7. Expressions )。 但し、レジスタの内容は演算の対象ではありません。
アセンブラとはニモニックとオペランドから機械語を生成するものですが、 利便性を向上するためのアセンブラの機能があります。 ディレクティヴとはアセンブラに対する指示をする命令です。 ディレクティヴはピリオド(.)で始めます。
良く使うディレクティヴを紹介します。
マクロを定義します。 macro のオペランドにマクロ名を指定します。 マクロ定義の中で引数として @0 から @9 の 10 個の仮引数が使えます。 なお、AVR のアセンブラのマクロ中のラベルはローカルにしか使用できません ので、マクロ中に定義したラベルに外部からアクセスすることはできません。 なお、グローバルなラベルを使用するには #define 疑似命令を使用する手が ありますが、こちらこちらで基本的に一行で記述しなければならず、複数行を 書くには(\)を使用した継続行を使用する必要があります。
アセンブリ言語で式を書くことができます。 値はリテラルを使用でき、レジスタやメモリの内容を使うことはできませ ん
なお、これらは一部なので、詳しくは アセンブラマニュアル p.34 7.3 Operator を参照してください。
EQU などで使用できる関数を下記に示します。 なお、これらは一部なので、詳しくは AVR Assembler p.33 7. Expressions を参照してください。
さて、この節では実際にプログラムを作成する手順を説明します。 既に、Microsoft VisualStudio Code に MPLab Extension がインストールされているものとします。
以下のプログラムを program.bat というテキストファイルに収めます。
set root=C:\Users\sakamoto\Downloads\avrdude-v8.3-windows-x64
set dude=%root%\avrdude.exe
set conf=%root%\avrdude.conf
%dude% -C %conf% -p m328p -c arduino -P %1 -D -U flash:w:"default.hex":i
なお、上記にsakamotoという名前が入っています。これを自分のパソコン のアカウント名などに置き換える必要があります。
以下のプログラムを program32u4.bat というテキストファイルに収めます。
set root=C:\Users\sakamoto\Downloads\avrdude-v8.3-windows-x64
set dude=%root%\avrdude.exe
set conf=%root%\avrdude.conf
%dude% -C %conf% -p m32u4 -c avr109 -P %1 -D -U flash:w:"default.hex":i
なお、上記にsakamotoという名前が入っています。これを自分のパソコン のアカウント名などに置き換える必要があります。
以下のプログラムを program4809.ps1 というテキストファイルに収めます。
param(
[string]$COMPORT
)
$root="C:\Users\sakamoto\Downloads\avrdude-v8.3-windows-x64"
$dude = Join-Path $root "avrdude.exe"
$conf = Join-Path $root "avrdude.conf"
$port = new-Object System.IO.Ports.SerialPort $COMPORT,1200,'None',8,'One'
$port.DtrEnable = $true
$port.Open()
Start-Sleep -Milliseconds 100
$port.DtrEnable = $false
$port.Close()
Start-Sleep -Seconds 2
& $dude -C $conf -patmega4809 -cjtag2updi -v -V -P $COMPORT -e -D -U flash:w:"default.hex":i
なお、上記にsakamotoという名前が入っています。これを自分のパソコン のアカウント名などに置き換える必要があります。
サンプルプログラムflashuno.asm の各ディレクティヴがどのような意味か、全て調べなさい。
サンプルプログラムflashuno.asm を機能毎に区分し、各機能を説明しなさい。
サンプルプログラムswitchflasher.asm を動作させなさい。
また、プログラムを読み、どのような動きをするのか、説明しなさい。
サンプルプログラムswitchflasher.asm の各ディレクティヴがどのような意味か、全て調べなさい。
サンプルプログラムswitchflasher.asm を機能毎に区分し、各機能を説明しなさい。
.include "m328Pdef.inc"
.cseg
.org 0x0000
rjmp reset
.org INT_VECTORS_SIZE
reset:
ldi r16,high(RAMEND)
out SPH,r16
ldi r16,low(RAMEND)
out SPL,r16
sbi ddrb,pb5
cbi ddrd,pd4
sbi portd,pd4
main:
sbi portb,pb5
sbis pind,pd4
rjmp onl
rcall shortwait
rjmp off
onl:
rcall longwait
off:
cbi portb,pb5
sbic pind,pd4
rjmp offl
rcall shortwait
rjmp main
offl:
rcall longwait
rjmp main
.equ shorttime = 4
.equ longtime = 40
.def wreg0 = r20
.def wreg1 = r21
.def wreg2 = r22
shortwait:
ldi wreg0,shorttime
rjmp wait0
longwait:
ldi wreg0,longtime
wait0:
ldi wreg1,0
wait1:
ldi wreg2,0
wait2:
nop
dec wreg2
brne wait2
dec wreg1
brne wait1
dec wreg0
brne wait0
ret
.exit
.include "m32U4def.inc"
.cseg
.org 0x0000
rjmp reset
.org INT_VECTORS_SIZE
reset:
ldi r16,high(RAMEND)
out SPH,r16
ldi r16,low(RAMEND)
out SPL,r16
sbi ddrc,pc7
cbi ddrd,pd4
sbi portd,pd4
main:
sbi portc,pc7
sbis pind,pd4
rjmp onl
rcall shortwait
rjmp off
onl:
rcall longwait
off:
cbi portc,pc7
sbic pind,pd4
rjmp offl
rcall shortwait
rjmp main
offl:
rcall longwait
rjmp main
.equ shorttime = 4
.equ longtime = 40
.def wreg0 = r20
.def wreg1 = r21
.def wreg2 = r22
shortwait:
ldi wreg0,shorttime
rjmp wait0
longwait:
ldi wreg0,longtime
wait0:
ldi wreg1,0
wait1:
ldi wreg2,0
wait2:
nop
dec wreg2
brne wait2
dec wreg1
brne wait1
dec wreg0
brne wait0
ret
.exit
.include "m4809def.inc"
.cseg
.org 0x0000
rjmp reset
.org INT_VECTORS_SIZE
reset:
ldi r16,low(RAMEND)
out CPU_SPL,r16
ldi r16,high(RAMEND)
out CPU_SPH,r16
; PE2
lds r16,PORTE_DIR
ori r16,1<<2
sts PORTE_DIR,r16
; PC6
lds r16,PORTC_PIN6CTRL
ori r16,PORT_PULLUPEN_bm
sts PORTC_PIN6CTRL,r16
main:
lds r17,PORTE_OUT
ori r17,1<<2
sts PORTE_OUT,r17
lds r17,PORTC_IN
sbrs r17,6
rjmp onl
rcall shortwait
rjmp off
onl:
rcall longwait
off:
lds r17,PORTE_OUT
andi r17,~(1<<2)
sts PORTE_OUT,r17
lds r17,PORTC_IN
sbrc r17,6
rjmp offl
rcall shortwait
rjmp main
offl:
rcall longwait
rjmp main
.equ shorttime = 1
.equ longtime = 10
.def wreg0 = r20
.def wreg1 = r21
.def wreg2 = r22
shortwait:
ldi wreg0,shorttime
rjmp wait0
longwait:
ldi wreg0,longtime
wait0:
ldi wreg1,0
wait1:
ldi wreg2,0
wait2:
nop
dec wreg2
brne wait2
dec wreg1
brne wait1
dec wreg0
brne wait0
ret
.exit
次の操作をする命令の組を書きなさい
flashuno.asm のプログラムを改造して、点滅の速さが2倍になるようにしよ う
flashuno.asm のプログラムを改造して、点滅の速さが1/2倍になるようにし よう
r16に入れた数だけ、0.1秒ずつLEDを点滅した後、1秒消灯する nblink というサブルーチンを作りなさい。 さらに、 次のプログラムと結合して正常に動作することを確かめなさい。
.include "m328Pdef.inc"
.cseg
.org 0x0000
rjmp reset
.org INT_VECTORS_SIZE
reset:
ldi r16,high(RAMEND)
out SPH,r16
ldi r16,low(RAMEND)
out SPL,r16
sbi ddrb,pb5
main:
ldi r16,0
loop:
inc r16
push r16
rcall nblink
pop r16
cpi r16,4
brne loop
rjmp main
.include "m32U4def.inc"
.cseg
.org 0x0000
rjmp reset
.org INT_VECTORS_SIZE
reset:
ldi r16,high(RAMEND)
out SPH,r16
ldi r16,low(RAMEND)
out SPL,r16
sbi ddrc,pc7
main:
ldi r16,0
loop:
inc r16
push r16
rcall nblink
pop r16
cpi r16,4
brne loop
rjmp main
.include "m4809def.inc"
.cseg
.org 0x0000
rjmp reset
.org INT_VECTORS_SIZE
reset:
ldi r16,low(RAMEND)
out CPU_SPL,r16
ldi r16,high(RAMEND)
out CPU_SPH,r16
; PE2
lds r16,PORTE_DIR
ori r16,1<<2
sts PORTE_DIR,r16
main:
ldi r16,0
loop:
inc r16
push r16
rcall nblink
pop r16
cpi r16,4
brne loop
rjmp main
番兵が0の数列をdbで確保し、各数列の値でblink()メソッドを呼ぶプログラム を書きなさい。
sample:
.db 3,3,7,0
.equ sampleadr = sample<<1
4番とGNDをつないだときだけ、LED が点灯するプログラムを作りなさい。
4番とGNDをつないだときは、1秒おきに2回LEDが点滅、つないでない時は 1秒おきに短くLEDが点滅するプログラムを作りなさい。
4番とGNDをつないだときは、1秒おきにLEDが1回点滅、2回点滅、3回点滅、 1回点滅,2回点滅、3回点滅と繰り返すが、 つないでない時は同じ回数の点滅を繰り返すプログラムを作りなさい。 つまり、3回点滅の時に線を外せば、そのまま3回点滅を繰り返し、 1回点滅の時に線を外すと1回点滅を繰り返すようにしなさい。