怎么访问l6位寄存器
TCNTn、OCRnA/B/C与ICRn是AVR CPU通过8位数据总线可以访问的1 6位寄存器。读/写l6位寄存器需要两次操作。每个16位计数器都有一个8位临时寄存器用来存放其高8位数据。每个l 6位定时器所属的1 6位寄存器共用相同的临时寄存器。访问低字节会触发16位读或写操作。当CPU写数据到l 6位寄存器的低字节时,写入的8位数据与存放在临时寄存器中的高8位数据组成一个16位数据,同步写入到1 6位寄存器中。当CPU读取l 6位寄存器的低字节时,高字节内容在读低字节操作的同时被放置于临时辅助寄存器中。
并非所有的l 6位访问都涉及临时寄存器.对OCRnA/B/C寄存器的读操作就不涉及临时寄存器。
写l6位寄存器时,应先写入该寄存器的高位字节;而读l 6位寄存器时,应先读取该寄存器的低位字节。
下面的例程说明了如何访问16位定时器寄存器.前提是假设不会发生更新临时寄存器内容的中断。同样的原则也适用于对0CRnA/B/C与ICRn寄存器的访问。使用C语言时,编译器会自动处理l6位操作。
汇编代码例程:
.....
设置TCNTn为0x01FF
idi rl7.0xol
idi rl6,0xFF
out TCNTnH,rl7
out TCNTnL,rl6
;将TCNTn读入7:rl6
in rl6,TCNTnL
in rl7,TCNTnH
.....
C代码例程(1):
unsigned int i;
/*设置TCNTD为OxOIFF*/
姗n=OxlFFl
/*将TCNTn读人i*/
i=TCNTn;
注:本代码假定已经包含了合适的头文件。当I/O寄存器为扩展I/O寄存器时,必须用诸如LDS、STS、SBRS、SBRC、SBR与CBR等可访问扩展I/O寄存器的指令代替IN、OUT、SBIS、SBIC、CBI与SBI指令。
汇编代码例程中TCNTn的返回值在r17:r16寄存器对中。
16位寄存器的访问是一个基本操作,认识这一点是非常重要的。在对16位寄存器操作时,最好首先屏蔽中断响应,防止在主程序读/写16位寄存器的两条指令之间发生这样的中断-它也访问同样的寄存器或其他的16位寄存器,从而改了临时寄存器。如果这种情况发生,那么中断返回后临时寄存器中的内容已经改变,造成主程序对l 6位寄存器的读/写错误。
下面的例程给出了读取TCNTn寄存器内容的基本操作。对0CRnA/B/C或ICRn的读操作可以使用相同的方法。
汇编代码例程:
TIMl 6一ReadTCNTn:
;保存全局中断标志
in rl8,SREG
;禁用中断
cli
;将TCNTn读入rl7:rl6
in rl6,TCNTnL
in rl7,TCNTnH
;恢复全局中断标志
out SREG,rl8
ret
C代码例程注:
uns igned int TIMl 6——ReadTCNTn(void)
uns igned char sreg
unsigned int i;
/*保存全局中断标志*/
sreg=SREG;
/*禁用中断*/
-CLI();
/*将TCNTn读入i*/
i=TCNTn;
/*恢复全局中断标志*/
SREG=sre9;
return i:
)
注:本代码假定已经包含了合适的头文件。当I/O寄存器为扩展I/O寄存器时.必须用诸如LDS、STS、SBRS、SBRC、SBR与CBR等可访问扩展I/O寄存器的指令代替IN、OUT、SBIS、SBIC、CBl与SBl指令。汇编代码例程中r17:rl6寄存器对保存的是TCNTn的写人数据。
如果对不止一个16位寄存器写入数据而且所有的寄存器高字节相同,则只须写一次高字节。前面讲到的基本操作在这种情况下同样适用。
【电子街】推荐阅读: