gllhgpp 发表于 2005-6-8 13:37:25

请问马老师关于同时读写的问题

我在看文献时看到了以下这段描述:定时/计数器1是一个可读写的16位加1计数器。为了确保单片机能对该寄存器的高低位同时进行读写,定时计数器设置了一个TEMP寄存器。当数据写入时,单片机将高位字节写入TCNT1H中(实际上,写入的数据被暂时存放在TEMP中),然后单片机再把低字节写入TCNT1中(此时,TEMP中的数据与当前的写入数据组合,并同时写入两个寄存器中)

      请问马老师:1.什么是加1计数器

                  2.这个TEMP是自己定义的还是实际存在的

                  3.这个过程我不是很理解,是高位放入TEMP,再放入TCNT1H,低位直接放入TCNT1吗?总线是8位的怎么实现同时放入16位的数据呢?

machao 发表于 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”。

gllhgpp 发表于 2005-6-13 19:52:16

作为一个新手还不能完全理解代码,但自己会努力的,谢谢马老师的解析!
页: [1]
查看完整版本: 请问马老师关于同时读写的问题