|
发表于 2005-6-13 13:02:48
|
显示全部楼层
1.什么是加1计数器
T/C1是16位的,它在工作时,每一个计数脉冲到后,其TCNT1将自动加1(减1),这个过程是硬件完成的。请仔细学习T/C的工作原理。
2.这个TEMP是自己定义的还是实际存在的
3.这个过程我不是很理解,是高位放入TEMP,再放入TCNT1H,低位直接放入TCNT1吗?总线是8位的怎么实现同时放入16位的数据呢?
正是由于AVR数据总线为8位,而TCNT1是16位,所以AVR读写16位的寄存器需要分成两次。但如果在两次读或写的过程中,寄存器的数据发生变化,那么你两次读的数据就不是16位寄存器的真实数据了。
所以,AVR的硬件内部为16位的寄存器的高8位配备了一个辅助8位寄存器TEMP,TEMP不能通过指令直接读写,是由内部硬件处理的。用户程序只要按照规范操作16位寄存器即可。
以下摘自《M128》,但对所有AVR读写16位寄存器都一样。
===============================================================================
16位计数器T/C1和T/C3使用多个16位的寄存器:TCNTn、OCRnA/B/C、ICRn。由于AVR的内部数据总线为8位,因此读写16位的寄存器需要分两次操作。为了能够同步读写16位寄存器,每一个16位寄存器分别配有一个8位的临时辅助寄存器(Temporary register),用于保存16位寄存器的高8位数据。要同步读写这些16位的寄存器,读写操作应遵循以下特定的步骤:
(1)16位寄存器的读操作
当MCU读取16位寄存器的低字节(低8位)时,16位寄存器低字节内容被送到MCU,而高字节(高8位)内容在读低字节操作的同时被放置于临时辅助(TEMP)寄存器中;当MCU读取高字节时,读到的是TEMP寄存器中的内容。因此,要同步读取16位寄存器中的数据,应先读取该寄存器的低位字节,再立即读取其高位字节。
(2)16位寄存器的写入操作
当MCU写入数据到16位寄存器的高位字节时,数据是写入到TEMP寄存器中;当MCU写入数据到16位寄存器的低位字节时,写入的8位数据与TEMP寄存器中的8位数据组合成一个16位数据,同步写入到16位寄存器中。因此,要同步写16位寄存器时,应先写入该寄存器的高位字节,再立即写入它的低位字节。
用户编写汇编程序时,如要对16位寄存器进行读写操作,应遵循以上特定的步骤。采用C等高级语言编写程序则可以直接对16位的寄存器进行操作,因为这些高级语言的编译系统会根据16位寄存器的操作步骤生成正确的执行代码。此外,在对16位寄存器操作时,最好将中断响应屏蔽,防止在主程序读写16位寄存器的两条指令之间插入一个含有对该寄存器操作的中断服务。如果这种情况发生,那么中断返回后,寄存器中的内容已经改变,会造成主程序中对16位寄存器的读写失误。
下面是读写16位寄存器的程序示例。
汇编代码:
TIME16_Read_WriteTCNT1:
;Save global interrupt flag
in r18,SREG
;Disable interrupts
cli
;Read TCNT1 into r17:r16
in r16,TCNT1L
in r17,TCNT1H
;Set TCNT1 to 0x01FF
ldi r17,0x01
ldi r16,0xFF
out TCNT1H,r17
out TCNT1l,r16
;Restore global interrupt flag
out SREG,r18
ret
C程序代码:
unsigned int TIME16_Read_WriteTCNT1( void )
{
unsigned char sreg;
unsigned int i;
/* Save global interrupt flag */
sreg = SREG;
/* Disable interrupts */
_CLI();
/* Read TCNT1 into i */
i = TCNT1;
/* Set TCNT1 to 0x01FF */
TCNT1 = 0x01FF;
/* Restore global interrupt flag */
SREG = sreg;
return i;
}
需要注意的是,如果寄存器的地址处于扩展的I/O空间(如M128),应使用“LDS”、“STS”、“SBRS”、“SBRC”、“SBR”、“CBR”指令来替代原程序中使用的汇编指令“IN”、“OUT”、“SBIS”、“SBIC”、“CBI”和“SBI”。 |
|