AVR程序释疑.docx

上传人:b****3 文档编号:4169552 上传时间:2023-05-06 格式:DOCX 页数:26 大小:22.79KB
下载 相关 举报
AVR程序释疑.docx_第1页
第1页 / 共26页
AVR程序释疑.docx_第2页
第2页 / 共26页
AVR程序释疑.docx_第3页
第3页 / 共26页
AVR程序释疑.docx_第4页
第4页 / 共26页
AVR程序释疑.docx_第5页
第5页 / 共26页
AVR程序释疑.docx_第6页
第6页 / 共26页
AVR程序释疑.docx_第7页
第7页 / 共26页
AVR程序释疑.docx_第8页
第8页 / 共26页
AVR程序释疑.docx_第9页
第9页 / 共26页
AVR程序释疑.docx_第10页
第10页 / 共26页
AVR程序释疑.docx_第11页
第11页 / 共26页
AVR程序释疑.docx_第12页
第12页 / 共26页
AVR程序释疑.docx_第13页
第13页 / 共26页
AVR程序释疑.docx_第14页
第14页 / 共26页
AVR程序释疑.docx_第15页
第15页 / 共26页
AVR程序释疑.docx_第16页
第16页 / 共26页
AVR程序释疑.docx_第17页
第17页 / 共26页
AVR程序释疑.docx_第18页
第18页 / 共26页
AVR程序释疑.docx_第19页
第19页 / 共26页
AVR程序释疑.docx_第20页
第20页 / 共26页
亲,该文档总共26页,到这儿已超出免费预览范围,如果喜欢就下载吧!
下载资源
资源描述

AVR程序释疑.docx

《AVR程序释疑.docx》由会员分享,可在线阅读,更多相关《AVR程序释疑.docx(26页珍藏版)》请在冰点文库上搜索。

AVR程序释疑.docx

AVR程序释疑

把寄存器R0~R29置$FF,把SRAM$0060~$006F单元清0,把$0070~$007F单元置$FF,把$0080~$008F单元分别设置为0~F

.include"m8def.inc";包含m8def.inc文件

.org$0000;代码起始端定位

rjmpMAIN;跳转到主程序

.equdata1=$00ff;设置符号项等于一个表达式

.org$0013;代码段定位,跳过中断向量区

MAIN:

;初始化堆栈指针,对所有带SRAM的AVR单片机,堆栈指针必须设置在SRAM最后的地址

ldir16,high(RAMEND);取RAMEND的高位字节到r16

outSPH,r16;将RAMEND的高位送堆栈寄存器SP高位字节中

ldir16,low(RAMEND);取RAMEND的低位字节到r16

outSPL,r16;将RAMEND的低位送堆栈寄存器SP低位字节中

;把寄存器R0~R29置0xFF

Ldir16,low(data1);取data1的低位字节到r16

part1:

stz+,r16;加载间接寻址数据,然后地址加一,即(Z)←Rr,Z←Z+1。

Z的初始指向是R0

cpr29,r16;比较,r29-r16

brnepart1;如果不相等,转到part1

;把SRAM0x60~0x6F单元清0。

为什么这里的X寄存器需要分高位和低位?

.setdatad=$0060;设置一个与表达式值相等的符号,能在后面的程序中重新改变设置

.setdatau=$006f

ldir30,high(data1);取data1的高位字节到r30,r30是Z寄存器低字节

ldixl,low(datad);取datad低位字节到X寄存器低字节,就是r26

ldixh,high(datad);取datad高位字节到X寄存器高字节,就是r27

ldir16,low(datau);取datau的低位字节到r16

part2:

cpxl,r16;比较xl和r16

stx+,r30;以间接寻址方式存储数据,然后地址加一,(X)←Rr,X←X+1

brnepart2;如果不相等转到part2

;把0x70~0x7F单元置0xFF

.setdatad=$0070

.setdatau=$007f

ldir31,low(data1);R31是Z寄存器高字节,纯粹用作数据寄存,因为R0~R29已被设置了

ldiyl,low(datad)

ldiyh,high(datad)

ldir17,low(datau)

part3:

cpyl,r17

sty+,r31

brnepart3

;nop

;0x80~0x8F单元分别设置为0~F

.setdatad=$0080

.setdatau=$0090

Ldir16,$00

ldizl,low(datad)

ldizh,high(datad)

ldir17,low(datau)

part4:

stz+,r16;加载间接寻址数据,然后地址加一,即(Z)←Rr,Z←Z+1。

Z的初始地址是R0

incr16;r16←r16+1

cpzl,r17

brnepart4

;nop

here:

rjmphere

把SRAM地址为$0060开始的256个单元内容依次复制到地址为$0100开始的单元(注意两数据区有部分重叠)

include"m8def.inc"

.org$0000

rjmpMAIN

.setsrm1=$0160;注意这是十六进制

.setsrm2=$0200

.org$0013

MAIN:

;初始化堆栈指针

ldir16,low(ramend)

outspl,r16

ldir16,high(ramend)

outsph,r16

;设置指针地址

ldizl,low(srm1)

ldizh,high(srm1)

ldixl,low(srm2)

ldixh,high(srm2)

ldir16,-1;因为立即数最大只能设255,要复制256个数据,只能初始设为-1

rcallsubroutine

here:

rjmphere

;调用子程序完成复制

subroutine:

ldr0,-z;地址减一后加载间接寻址数据Z←Z-1,R0←(Z).

;为什么减一呢,因为复制的数据有重叠,为了完整复制,就从末尾往前,避免遗失数据。

st-x,r0;地址减一后以间接寻址方式存储数据X←X-1,(X)←R0

incr16

cpir16,255

brnesubroutine

ret

把Flash程序存储器中地址为0x003开始的10个字单元内容传送到SRAM(先低字节,后高字节)。

.include"m8def.inc"

.org$0000

rjmpMAIN

.setflh=$0003

.setsrm=$0070

.org$0013

MAIN:

Ldir16,low(ramend)

outspl,r16

ldir16,high(ramend)

outsph,r16

;设置Z指针对应于flash地址的值

ldizl,low(flh*2);一个单位的flash存储位置,其实占用两个位置的地址栏

ldizh,high(flh*2)

ldixl,low(srm)

ldixh,high(srm)

ldir16,0

subroutine:

lpmr0,z+;加载程序空间的数据,然后地址加一R0←(Z),Z←Z+1

lpmr1,z+;正因为是16位,每次的赋值只能赋8位,所以要赋2次才能完成8+8=16的赋值过程

stx+,r0;因为atmega系列的单片机不支持内存to内存的赋值方式,所以要用寄存器做中继,可以看到,不管是从flash到reg,还是reg到sram,每一个值都用了两步

stx+,r1

incr16

cpir16,10

brnesubroutine

here:

rjmphere

用I/O引脚驱动若干个LED,编写跑马灯程序

.include"m8def.inc"

.org$0000

.setleft=1;left=1就是left=0b00000001,也就是八个led灯仅有最右一个是高电平,我估计你们那块板子的灯是高电平点亮的,这样的话如果让left生效则点亮最右一盏灯,这样往后向左一步步循环嘛.

.setright=0b10000000;同上,这就是点亮最左一盏灯,这样向右才能做

rjmpMAIN

.org$0013

MAIN:

ldir16,low(ramend);设置堆栈地址

outspl,r16

ldir16,high(ramend)

outsph,r16

;设置D端口为输出

ldir19,$ff

outddrd,r19

ldir21,right

ldir20,left

;实现LED灯从左到右依次闪烁

part1:

outportd,r20

rcalldelay;延时,避免移太快,眼睛有视觉延迟,太快了看上去就是全亮的

lslr20;这条命令是r20循环左移一位,换一个灯

brccpart1

;实现LED灯从右到左依次闪烁

part2:

outportd,r21

rcalldelay

lsrr21;这就是循环右移一位,其他的和part1一样,你看两条命令就很明显l代表left,r代表right

brccpart2

;初始化寄存器状态并循环

ldir21,right;赋值,把right变量的赋给r21,left赋给20

ldir20,left

;初始化寄存器状态并循环

ldir21,right

ldir20,left

here:

rjmppart1

;延时程序

delay:

ldir16,0x00;赋值

ldir17,0x00

ldir18,0x00

delay1:

incr16

;delay1做到的就是进来的时候,r16是00.先做一步自增一,变成01,然后每次和r18相比(00),如果不同则继续循环delay1,这就意味着r16要从00自增到ff然后继续自增1才会跳转到00,这不就执行了ff次的delay1么

cpr16,r18

brnedelay1

incr17

;做到了ff次的delay1的前三句之后,让r17自增1,然后同上,需要r17自增到ff再自增一次跳转到00才能结束延时程序,就是说要做ff*ff次的delay1前三句才能完成延时子程序噻~这就是延时的真谛

cpr17,r18

brnedelay1

clc;清零C标志位

ret

把Flash中地址为$013开始的20个字单元内的数据代码作为20个16位二进制符号数,将它们分别取绝对值后存储到SRAM中起始地址为$0100的区域,要求低字节在前,高字节在后。

.include"m8def.inc"

.org$0000

.equflh=$013

.equsrm=$100

rjmpmain

.org$0013

main:

ldir16,low(ramend);设置堆栈地址

outspl,r16

ldir16,high(ramend)

outsph,r16

ldizl,low(flh*2)

ldizh,high(flh*2)

ldixl,low(srm)

ldixh,high(srm)

ldir18,0

part1:

lpmr22,z+;取数后,Z加一

lpmr23,z+

rcallpart2;调用取绝对值子程序

store:

stx+,r22;存数后,X加一

stx+,r23

incr18

cpir18,20

brnepart1

here:

rjmphere

part2:

TSTR23;测寄存器为零或者负

BRPLstore;为正转移

SUBIR22,1;r22里面存的是负数的补码,补码是原码取反加一,所以要减去这个加上去的一,然后获得负数的原码

SBCIR23,0;这个是此负数的高八位,因为负数比较大所以需要两个寄存器存储

COMR22;对高位取反

COMR23;对低位取反,取反后得到负数的正数形式的原码,正数的补码即为其原码,所以得到绝对值

Ret

已知SRAMADDR($0062)为起始地址的数据块的数据是无符号数,块长在LEN($0061)单元。

求最大值并存入MAX($0060)单元

.include"m16def.inc"

.SETLEN=$0061

.SETADDR=$0062

.SETMAX=$0060

.ORG$000

RJMPSTART

.ORG0X002A

START:

LDSR20,LEN;r20存入数据块长

CLRR16;r16清零

LDIXL,LOW(ADDR);X指针指向数据起始

LDIXH,HIGH(ADDR)

LOOP:

LDR18,X+;X件址取数后加一

CPR18,R16;比较R18和R16,如果R18小于R16,则跳转到next,否则R18数据送到R16

BRCSNEXT;BRLO

MOVR16,R18

NEXT:

DECR20;r20减一,数据块长减一

BRNELOOP;跳回loop,没有遍历所有数据则跳回loop继续

STSMAX,R16;R16的数据送max

here:

rjmphere

.exit

无符号数求最小值

.include"m16def.inc"

.SETLEN=$0061

.SETADDR=$0062

.SETMIN=$0060

.ORG$000

RJMPSTART

.ORG0X002A

START:

LDSR20,LEN

SERR16;设置最大值,R16置为255,即11111111

LDIXL,LOW(ADDR)

LDIXH,HIGH(ADDR)

LOOP:

LDR18,X+

CPR16,R18

BRCSNEXT;比较R18和R16,如果R16大于R18,则R18送R16,否则跳转至next

;够减则C位为1,BRCS是进位标志位C为1转移

MOVR16,R18

NEXT:

DECR20

BRNELOOP

STSMIN,R16

here:

rjmphere

.exit

已知SRAMADDR($0062)为起始地址的数据块的数据是符号数,块长在LEN($0061)单元。

求最大值并存入MAX($0060)单元

.include"m16def.inc"

.SETLEN=$0061

.SETADDR=$0062

.SETMAX=$0060

.ORG$000

RJMPSTART

.ORG0X002A

START:

LDSR20,LEN

LDIR16,$80;八位有符号数的范围是-128~+128,怎么判断我这里存入的比较数值是-128?

LDIXL,LOW(ADDR)

LDIXH,HIGH(ADDR)

LOOP:

LDR18,X+

CPR18,R16

BRLTNEXT;如果R18小于R16,则跳转next,否则R18送R16

MOVR16,R18

NEXT:

DECR20

BRNELOOP

STSMAX,R16

here:

rjmphere

.exit

有符号数求最小值

.include"m8def.inc"

.SETLEN=$0061

.SETADDR=$0062

.SETMIN=$0060

RJMPSTART

.ORG0X002A

START:

LDSR20,LEN

LDIR16,$7F;设置最大值,$7F=127

LDIXL,LOW(ADDR)

LDIXH,HIGH(ADDR)

LOOP:

LDR18,X+

CPR16,R18;如果R18小于R16,则跳转next,否则R18送R16

BRLTNEXT;BRLT小于转移

MOVR16,R18

NEXT:

DECR20

BRNELOOP

STSMIN,R16

here:

rjmphere

.exit

 

设SRAM中有个数据块(起始地址为$0061,块长放在$0060单元),数据块内每个字节单元含有两个十六进制数(高4位和低4位),试分别求出这些十六进制数的ASCII码,并放在SRAM中以$0163为起始地址的区域,要求低4位数的ASCII码在前,高4位数的ASCII码在后。

.include"m8def.inc"

.SETLEN=$0060

.SETBLOCK1=$0061

.SETBLOCK2=$0163

.ORG$000

RJMPMAIN

ASCTAB:

.DB$30,$31,$32,$33,$34,$35,$36,$37,$38,$39,$41,$42,$43,$44,$45,$46

.ORG0X002A

;十六进制和ASCII码的转换,30H-39H为0-9的Ascii码,41H-46H为A-F的Ascii码,将十六进制对应地加上去就是了

MAIN:

ldir16,low(ramend)

outspl,r16

ldir16,high(ramend)

outsph,r16

LDSR25,LEN

LDIXL,LOW(BLOCK1)

LDIXH,HIGH(BLOCK1)

LDIYL,LOW(BLOCK2)

LDIYH,HIGH(BLOCK2)

LOOP:

LDIZL,LOW(ASCTAB*2)

LDIZH,HIGH(ASCTAB*2)

CLRR18

LDR17,X

ANDIR17,$0F;取十六进制数低位

;andi是"与立即数,这个语句的目的就是把R17里面的低位留下,高位清零,比如R17=$23,andi之后,R17=$03

ADDZL,R17;低位,无进位加法

ADCZH,R18;高位,带进位加法,其实R18就是0,这里是保险的做法

LPMR17,Z;转换为ASCII码

STY+,R17

LDR17,X+

ANDIR17,$F0;取十六进制数高位

SWAPR17;半字节交换,因为后面的加法运算不能直接跳过低位在高位运算,所以必须交换,而两个十六进制数(高4位和低4位),只需要转换后按照高低顺序存入新的区域便可,转换后的是ascii码要用8位来存,所以不存在交换的问题。

LDIZL,LOW(ASCTAB*2)

LDIZH,HIGH(ASCTAB*2)

ADDZL,R17

ADCZH,R18

LPMR17,Z

STY+,R17

DECR25

BRNELOOP

HERE:

RJMPHERE

设SRAM中$0060和$0061单元存储的是一个16位二进制无符号数(高字节在前),试调用代码转换子程序和延时子程序,把这个数转换成十进制数(即BCD码),并把其万、千、百、十、个位用一个数码管轮流显示出来,每位显示时间约1秒钟

.include"m8def.inc"

.equdata=$0060

.org$0000

rjmpmain

tab1:

.db$3f,$06,$5b,$4f,$66,$6d,$7d,$07,$7f,$6f

.org$0013

main:

ldir16,low(ramend)

outspl,r16

ldir16,high(ramend)

outsph,r16

ldir16,$ff

outddrd,r16

ldir16,$64;预设数值为13412

stsdata,r16

ldir16,$34

stsdata+1,r16

ldsr16,data

ldsr17,data+1

rcallb16td5

;显示数字

start:

movr18,r24

rcallcqb

rcalldelay

movr18,r23

rcallcqb

rcalldelay

movr18,r22

rcallcqb

rcalldelay

movr18,r21

rcallcqb

rcalldelay

movr18,r20

rcallcqb

rcalldelay

here:

rjmphere

b16td5:

serr24;r24先送-1

loop1:

incr24;r24增1

subir16,low(10000)

sbcir17,high(10000);(r17:

r16)-10000

brccloop1;够减则返回loop1

subir16,low(-10000)

sbcir17,high(-10000);不够减,加10000恢复余数

serr23

loop2:

incr23

subir16,low(1000)

sbcir17,high(1000)

brccloop2

subir16,low(-1000)

sbcir17,high(-1000)

serr22

loop3:

incr22

subir16,low(100)

sbcir17,high(100)

brccloop3

subir16,low(-100)

sbcir17,high(-100)

serr21

loop4:

incr21

subir16,low(10)

brccloop4

subir16,low(-10)

serr20

loop5:

incr20

subir16,low

(1)

brccloop5

subir16,low(-1);其实个位可以直接送

ret

cqb:

ldizl,low(tab1*2)

ldizh,high(tab1*2)

addzl,r18

lpm

outportd,r0

ret

;延迟0.5S,书上虽然这么说,但是个人认为延迟1.5s了

delay1:

ldir16,100

ldir17,200

ldir25,200

decr25

brnedelay1+3

decr17

brnedelay1+2

decr16

brnedelay1+1

ret

;延迟1S

delay:

rcalldelay1

rcalldelay1

采用外部中断的方式对按键次数实现计数。

计数值由一个共阴数码管来显示,初值为0。

每按键一次,计数值增1……计到F后,再按键一次则回0。

画出电路图。

.include"m8def.inc"

.deftemp=r23;临时变量

.defcounter=r24;计数变量

;中断向量区配置,FLASH空间$000~$028

.org$000

rjmpRESET;复位处理

rjmpEXT_INT0;中断向量

.org$02A

RESET:

;上电初始化程序

ldir16,high(RAMEND)

outSPH,r16

ldir16,low(RAMEND)

outSPL,r16;设置堆栈指针为RAM的顶部

sertemp

outddrb,temp;设置portb为输出,段码输出

outportb,temp;设置portb输出全1

lditemp,0x0a

outmcucr,temp;INT0、INT1下降沿触发

lditemp,0xc0

outgicr,temp;允许INT0、INT1中断

outgifr,temp;清除INT0、INT1中断标志位

cbiddrd,2

clrcounter

sei;使能中断

MAIN:

clrr0

ldizl,low(led_7*2)

ldizh,high(led_7*2);Z寄存器取得7段码组的首指针

addzl,counter;加上要显示的数字

adczh,r0;加上低位进位

lpm;读对应七段码到R0中

outportb,r0;LED段码输出

rjmpMAIN;循环显示

EXT_INT0:

intemp,sreg

pushtemp;中断现场保护

inccounter;计数单元加1

cpicounter,0x10;与16比较

brneEXT_INT0_RET;小于16转中断返回

clrcounter;计数单元清0

EXT_

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 党团工作 > 入党转正申请

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2