编写你的第一行代码 经过上面的步骤,AVR Studio 打开了一个空的文件,文件的名字是Leds.asm。可能你注意到Leds.asm这个文件没有出现在左边的栏目中,这是因为这个文件还没有保存过。现在在文件中输入:“;My Very First AVR Project”,“;”的作用是注释,在编译时,分号以后的内容被忽略。
在File菜单中按下Save按钮,文件被保存。同时,文件也出现在左边栏目中。 好了,现在我们的AVR Studio 可以工作了,下面让我们再来关注AVR Studio 4的界面。
AVR Studio 4 的用户图形界面(GUI)
让我们来自己观察一下AVR Studio 4 的用户图形界面(GUI)。
我们把用户图形界面划分成了6个部分。在AVR Studio 4系统中包括了AVR Studio 的帮助文件,在这里,我们着重介绍AVR Studio 4的框架和一些要注意的事项。
(1)第一行是菜单栏。这与标准的Windows程序差不多,包括打开/保存文件、剪贴/复制,这个栏目还包含了Studio的一些特殊功能,如仿真等。 (2)第二行是快捷方式栏,这一栏存储了一些常用命令,包括保存/打开文件,设置断点等等。 (3)第三部分为工作台窗口,在这里显示项目文件、IO状态以及项目选用AVR器件的信息 (4)第四是编辑窗口。在这里可以编辑你的源代码。对于熟练的用户,在这里也可以嵌入C代码 (5)第五是输出窗口,状态信息在这里显示 (6)第六是系统状态条。这里显示AVR Studio 软件工作的模式,例如我们选用了AT90S8515芯片在仿真模式下工作,这些信息就会在系统状态条中显示。
用户图形界面深层指南 AVR Studio 的用户图形界面制作的非常友好,用户不需要太多的知识就可以使用。但是,我们建议用户还是参看一下AVR Studio 自带的HTML帮助文件。用户可以从AVR Studio 软件的help->AVR Studio User Guide打开帮助文件。
编写你的第一个别AVR程序
下面,我们继续完成我们的第一个AVR程序。到目前为止,我们安装了开发软件,创建了“Leds”项目,下面,我们就开始编写AVR代码了。 在AVR Studio 的编辑窗口,继续完成代码,需要添加的代码如下(可以运用复制/粘贴方式将代码复制到编辑窗口):
.include "8515def.inc"
.def Temp = R16
.org 0x0000
rjmp RESET ;Take a Relative Jump to the RESET Label
RESET: ;Reset Label
ldi Temp, 0xFF ;Store 255 in R16 (Since we have defined R16 = Temp)
out DDRB, Temp ;Store this value in The PORTB Data direction
Register
Loop:
out PORTB, Temp ;Write all highs (255 decimal) to PORTB
dec Temp
rjmp Loop ;Take a relative jump to the Loop label
注意到在编辑窗口,代码的颜色发生了变化。这是编辑窗口的语法高亮功能,这个功能非常有利于增强代码的可读性能。代码输入完毕后,按CTRL+F7或者是Project菜单-〉Build and Run。
在输出窗口中(在屏幕的左下角),你将会看到项目编译,同时报告没有发现错误,同时,我们也看到我们的程序编译后代码包括6个字(12个Byte)。 恭喜,现在你已经编写了第一个AVR程序了,下面我们着重研究这段代码。 注意:如果你的代码不能编译,请检查汇编文件。特别是你可能将引用文件“8515def.inc”放在了别的目录,请在文件中加入完整路径,如“.include “c:\complete path\8515def.inc” ”。
理解源代码
理解源代码 到目前为止,我们编写的第一个程序编译没有问题,这是非常大的成就。但是我们还是来看看这段代码的含义。完整的代码如下:
.include "8515def.inc"
.def Temp = R16
.org 0x0000
rjmp RESET ;Take a Relative Jump to the RESET Label
RESET: ;Reset Label
ldi Temp, 0xFF ;Store 255 in R16 (Since we have defined R16 = Temp)
out DDRB, Temp ;Store this value in The PORTB Data direction
Register
Loop:
out PORTB, Temp ;Write all highs (255 decimal) to PORTB
dec Temp
rjmp Loop ;Take a relative jump to the Loop label
现在,让我们一行一行来看这段代码
; My Very First AVR Project 分号(;)开始的行是代码的注释。注释可以加在任何行的后面,如果注释超过了一行,每一行注释都要以分号开头.include "8515def.inc" 不同的AVR器件还是有一些区别的,比如说PORTB就对应着不同的存储地址,.inc文件存储这种信息,在应用了这个文件以后,就可以把PORTB标号和具体的存储地址相对应(在AT90S8515芯片中,对应是OX18)。.def Temp=R16 .def命令可以创建一个容易记忆的标号(如Temp)代替寄存器名称(如R16)。在项目中使用大量通用寄存器的时候,这个命令非常有效。(在芯片数据手册中有通用寄存器的介绍).org 0x0000 这个命令的作用是将下条指令定位在Flash存储器中地址为0x0000的单元,比如在这个例子中,下条指令RJMP指令就定位在0x0000地址(在Flash的开始)。这样做的原因在于芯片上电复位、复位信号有效后或是看门狗有效以后,芯片从0x0000开始执行指令。当然,这里也可以存放中断跳转指令。在这个例子中,我们没有利用中断,所以就存放了RJMP指令。Rjmp RESET 前面我们介绍过了指令定位在0x0000,相对跳转指令(RJMP)指令就被存放在0x0000单元中,这条指令被首先执行。如果参看芯片说明书,你会发现AT90S8515不支持JMP指令,芯片只有RJMP指令。这原因是我们不需要JMP指令。如果你比较JMP 和RJMP指令,会发现JMP指令更长,这将使得器件执行速度变慢、代码变大,而用RJMP也可以访问到所有的Flash存储器,因此,芯片不支持JMP指令。RESET: 这个是标号。你可以把标号放在代码中任何地方。标号的作用在于区分跳转指令的不同分支。标号使用是必要及方便的,在编译的时候,编译器自动运算标号的正确地址。Ldi Temp,0xFF 这是一个立即读取(Load Immediate)指令,这个命令将读取一个立即数,写入指定的寄存器。在上面,我们定义了Temp是R16,所以这条指令的动作是将立即数0xff放入寄存器R16。Out DDRB,Temp 为什么我们不写成“Ldi DDRB,Temp”?这是个好问题,现在来让我们参看命令手册。找到LDI和OUT指令,用户会发现LDI的语法是:“LDI Rd, K”,这就表明这个命令只能使用通用寄存器的R16到R31。参看OUT命令的语法:“OUT A,Rr”,则表明这个命令可以使用R0到R31。 执行了这条指令以后,DDRB寄存器被置高。DDRB寄存器被置高,表明PORTB管脚被定义成输出脚。Loop: 还是一个标号out PORTB , Temp 现在我们把0xFF写入PORTB,如果现在有个真实的器件的话,我们去测量芯片的PORTB,会发现管脚为5V。值得注意的是这10个IO管脚是芯片经常使用的,所以有必要在芯片说明书中参看这部分管脚的资料。从芯片说明书中我们可以看到PORTB包括3个寄存器:PORTB、PINB和DDRB。PORTB为写入寄存器,PINB为读入寄存器,DDRB寄存器控制管脚是输入还是输出。Dec Temp DEC为减法指令,这个指令表明对R16寄存器减一操作,经过这个指令,Temp寄存器(也就是R16寄存器)里面的内容为0xFE。DEC是一条算术指令,AVR芯片支持广泛的算术指令。完整的指令列表请参看芯片说明书中的指令列表。Rjmp Loop 通过这条指令,我们将程序跳转到Loop标号处,在每一次循环中,都把Temp的数值赋给PORTB。 到目前为止,我猜想你已经知道这段程序大体的功能了:我们做了一个计数器,这个计数器从255递减到0。那么到0后会怎么样呢?