搜索
bottom↓
回复: 2

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

[复制链接]

出0入0汤圆

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

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

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

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

阿莫论坛20周年了!感谢大家的支持与爱护!!

一只鸟敢站在脆弱的枝条上歇脚,它依仗的不是枝条不会断,而是自己有翅膀,会飞。

出0入0汤圆

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

出0入0汤圆

 楼主| 发表于 2005-6-13 19:52:16 | 显示全部楼层
作为一个新手还不能完全理解代码,但自己会努力的,谢谢马老师的解析!
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-5-22 16:04

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表