AVR程序释疑Word下载.docx
- 文档编号:20904363
- 上传时间:2023-01-26
- 格式:DOCX
- 页数:22
- 大小:21.84KB
AVR程序释疑Word下载.docx
《AVR程序释疑Word下载.docx》由会员分享,可在线阅读,更多相关《AVR程序释疑Word下载.docx(22页珍藏版)》请在冰豆网上搜索。
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)
part4:
加载间接寻址数据,然后地址加一,即(Z)←Rr,Z←Z+1。
Z的初始地址是R0
incr16;
r16←r16+1
cpzl,r17
brnepart4
here:
rjmphere
把SRAM地址为$0060开始的256个单元内容依次复制到地址为$0100开始的单元(注意两数据区有部分重叠)
include"
.org$0000
rjmpMAIN
.setsrm1=$0160;
注意这是十六进制
.setsrm2=$0200
.org$0013
初始化堆栈指针
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
调用子程序完成复制
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(先低字节,后高字节)。
.setflh=$0003
.setsrm=$0070
Ldir16,low(ramend)
设置Z指针对应于flash地址的值
ldizl,low(flh*2);
一个单位的flash存储位置,其实占用两个位置的地址栏
ldizh,high(flh*2)
ldixl,low(srm)
ldixh,high(srm)
ldir16,0
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
cpir16,10
用I/O引脚驱动若干个LED,编写跑马灯程序
.setleft=1;
left=1就是left=0b00000001,也就是八个led灯仅有最右一个是高电平,我估计你们那块板子的灯是高电平点亮的,这样的话如果让left生效则点亮最右一盏灯,这样往后向左一步步循环嘛.
.setright=0b10000000;
同上,这就是点亮最左一盏灯,这样向右才能做
ldir16,low(ramend);
设置堆栈地址
设置D端口为输出
ldir19,$ff
outddrd,r19
ldir21,right
ldir20,left
实现LED灯从左到右依次闪烁
outportd,r20
rcalldelay;
延时,避免移太快,眼睛有视觉延迟,太快了看上去就是全亮的
lslr20;
这条命令是r20循环左移一位,换一个灯
brccpart1
实现LED灯从右到左依次闪烁
outportd,r21
rcalldelay
lsrr21;
这就是循环右移一位,其他的和part1一样,你看两条命令就很明显l代表left,r代表right
brccpart2
初始化寄存器状态并循环
ldir21,right;
赋值,把right变量的赋给r21,left赋给20
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
clc;
清零C标志位
把Flash中地址为$013开始的20个字单元内的数据代码作为20个16位二进制符号数,将它们分别取绝对值后存储到SRAM中起始地址为$0100的区域,要求低字节在前,高字节在后。
.include"
.equflh=$013
.equsrm=$100
rjmpmain
main:
ldizl,low(flh*2)
ldir18,0
lpmr22,z+;
取数后,Z加一
lpmr23,z+
rcallpart2;
调用取绝对值子程序
store:
stx+,r22;
存数后,X加一
stx+,r23
incr18
cpir18,20
brnepart1
TSTR23;
测寄存器为零或者负
BRPLstore;
为正转移
SUBIR22,1;
r22里面存的是负数的补码,补码是原码取反加一,所以要减去这个加上去的一,然后获得负数的原码
SBCIR23,0;
这个是此负数的高八位,因为负数比较大所以需要两个寄存器存储
COMR22;
对高位取反
COMR23;
对低位取反,取反后得到负数的正数形式的原码,正数的补码即为其原码,所以得到绝对值
Ret
已知SRAMADDR($0062)为起始地址的数据块的数据是无符号数,块长在LEN($0061)单元。
求最大值并存入MAX($0060)单元
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
rjmphere
.exit
无符号数求最小值
.SETMIN=$0060
LDSR20,LEN
SERR16;
设置最大值,R16置为255,即11111111
LDIXL,LOW(ADDR)
LDR18,X+
CPR16,R18
比较R18和R16,如果R16大于R18,则R18送R16,否则跳转至next
够减则C位为1,BRCS是进位标志位C为1转移
DECR20
BRNELOOP
STSMIN,R16
已知SRAMADDR($0062)为起始地址的数据块的数据是符号数,块长在LEN($0061)单元。
LDIR16,$80;
八位有符号数的范围是-128~+128,怎么判断我这里存入的比较数值是-128?
LDR18,X+
CPR18,R16
BRLTNEXT;
如果R18小于R16,则跳转next,否则R18送R16
STSMAX,R16
有符号数求最小值
LDIR16,$7F;
设置最大值,$7F=127
CPR16,R18;
BRLT小于转移
设SRAM中有个数据块(起始地址为$0061,块长放在$0060单元),数据块内每个字节单元含有两个十六进制数(高4位和低4位),试分别求出这些十六进制数的ASCII码,并放在SRAM中以$0163为起始地址的区域,要求低4位数的ASCII码在前,高4位数的ASCII码在后。
.SETLEN=$0060
.SETBLOCK1=$0061
.SETBLOCK2=$0163
RJMPMAIN
ASCTAB:
.DB$30,$31,$32,$33,$34,$35,$36,$37,$38,$39,$41,$42,$43,$44,$45,$46
十六进制和ASCII码的转换,30H-39H为0-9的Ascii码,41H-46H为A-F的Ascii码,将十六进制对应地加上去就是了
LDSR25,LEN
LDIXL,LOW(BLOCK1)
LDIXH,HIGH(BLOCK1)
LDIYL,LOW(BLOCK2)
LDIYH,HIGH(BLOCK2)
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位来存,所以不存在交换的问题。
ADDZL,R17
ADCZH,R18
LPMR17,Z
DECR25
HERE:
RJMPHERE
设SRAM中$0060和$0061单元存储的是一个16位二进制无符号数(高字节在前),试调用代码转换子程序和延时子程序,把这个数转换成十进制数(即BCD码),并把其万、千、百、十、个位用一个数码管轮流显示出来,每位显示时间约1秒钟
.equdata=$0060
tab1:
.db$3f,$06,$5b,$4f,$66,$6d,$7d,$07,$7f,$6f
ldir16,$ff
outddrd,r16
ldir16,$64;
预设数值为13412
stsdata,r16
ldir16,$34
stsdata+1,r16
ldsr16,data
ldsr17,data+1
rcallb16td5
显示数字
start:
movr18,r24
rcallcqb
movr18,r23
movr18,r22
movr18,r21
movr18,r20
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);
其实个位可以直接送
cqb:
ldizl,low(tab1*2)
ldizh,high(tab1*2)
addzl,r18
lpm
outportd,r0
延迟0.5S,书上虽然这么说,但是个人认为延迟1.5s了
ldir16,100
ldir17,200
ldir25,200
decr25
brnedelay1+3
decr17
brnedelay1+2
decr16
brnedelay1+1
延迟1S
rcalldelay1
采用外部中断的方式对按键次数实现计数。
计数值由一个共阴数码管来显示,初值为0。
每按键一次,计数值增1……计到F后,再按键一次则回0。
画出电路图。
.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;
使能中断
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_
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- AVR 程序 释疑
![提示](https://static.bdocx.com/images/bang_tan.gif)