找回密码
 注册
关于网站域名变更的通知
查看: 313|回复: 2
打印 上一主题 下一主题

为何AVR使用写1作为清0中断标志位的手段

[复制链接]

该用户从未签到

跳转到指定楼层
1#
发表于 2021-9-13 10:17 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

EDA365欢迎您登录!

您需要 登录 才可以下载或查看,没有帐号?注册

x
关于“为何AVR使用写1作为清0中断标志位的手段”这个问题我看过很多的相关资料。在AVR的手册中并没有给出为什么的解释,只是强调了“写1清0中断标志位”。同时我也看到很多新的芯片,如DSP等,也是采用写1清零标志位的。但没有找到更专业的,或从根源上的说明,如果那位有这方面的知识或资料,欢迎深入的讨论学习。) P8 ^2 M+ s- O) S
! E, q, O  A  D9 s% `/ Z; z: w8 h% u

$ S; E. R- K; ]+ V1 V2 ^% k下面是我个人的分析和解释,供参考。' R6 W+ D% N' I; u* I& \

$ M9 `; s$ E& k1。首先从硬件上的考虑,通常的读写处理单元是以8BIT字节为单位的,因为数据总线一般是8位的倍数。这样对位的操作就不方便,不能直接写1位(会改变其它的位),需要先读到寄存器,然后改动1位,最后回写,需要更多的时间。
9 b! Z9 t8 U0 Y- D! H: i+ r9 e3 J3 s; x
2。对于RAM操作一般采用直接写的方式,所以对RAM基本上没有直接的位操作指令。而对于寄存器是可以直接位操作的,但如果对所有的寄存器都能实现位操作,那么硬件结构上就非常复杂和庞大了,所以必须采用一种折中的处理方法。
, K0 m4 _* X' x2 s
$ ^8 p" C3 R- w3 e2 y7 W3 I3。现在的趋势是采用C语言编写系统程序,而标准的C中,没有位变量的概念,最小的单位也是字节。因此硬件的设计上面也要考虑能发挥C语言的优势。
. a) S# m; t- [$ L4 h# y# A- Y3 g& Q1 o. U6 g, R0 ]# h
以上是我分析的原因。因为已经超出了我研究的方向(我侧重于应用),可能不全面或有偏差。下面回到AVR本身。0 m/ R! Z$ T& r& i
3 \: Z2 U% j  b1 T5 t) ^
我们可以注意到:; P6 Y9 t" J8 p4 d* u) w" e  w1 Y
1。AVR没有“位”空间,也就是说没有单独的“位”地址,所有的位寻址是基于8位的寄存器的,所以基本寻址方式是以寄存器为主的。
2 k6 V, o( z) `! `( k3 K/ W$ a4 A/ e! g. @  E4 {# C
2。因此AVR没有专门的位寻址指令,它本身的位操作指令很少,都是在寄存器寻址的基础上,对寄存器的某位进行操作。8 I3 B+ g: \0 _' L8 Z0 E

$ o* H$ @" I& ]# Z2 {3。除了对状态寄存器SREG中的位有直接的操作指令外(SREG太特殊了,必须要有专用的位操作指令),能够对其它寄存器的位操作的指令只有2个。/ B7 j3 }5 @' D
a)BST、BLD。这个指令的周期是1CK,他是将SREG中的T标志位与32个通用寄存器的位之间交换数据的指令。如果要对32个寄存器的1位进行设置的话(比如置1),必须先使用指令将SREG中的T置1,然后使用BLD指令将T的值写到寄存器的某位。需要2个CK时间。% J3 P: ~4 W1 y8 E4 W) l& t, H9 Y
b)SBI、CBI。这2条指令是对前32个(注意:仅对前32个I/O空间!)I/O空间的寄存器的位进行设置的指令。这2个指令的执行时间是2个CK。AVR对寄存器操作的指令大多数都是1个CK,而这2个指令为何需要2个CK?原因在与写的时候还是8位一起写,因此改变1位需要先读,修改1位,再回写。这样保证了其它位不变,但时间需要2个CK了。2 z0 {: c! h8 m3 e% Y/ e8 d1 ~
# R  k  _' U, W$ b
4。正是由于第3点(b),所以PA、PB、PC、PD等I/O口的寄存器均在前32个I/O空间,这样就实现了方便的单独的按位控制I/O口了。
8 j9 I; i0 @, ~( N1 B/ u$ R( U* a. U$ L5 V0 I% x  g
5。不同C编译器,位处理是不同的。ICC、IAR基本没有扩展位处理,按标准C来处理,因为他们考虑的可移植性更加多些。而CVAVR扩展了位变量(放在32个工作寄存器中)和位操作(仅能对I/O空间前32个寄存器),因此用户使用起来更方便些。但要注意,对I/O空间后32个寄存器,CVAVR也不能实现位操作的。
7 b% _% j6 ~) F2 p/ ~
% N$ c0 }: j7 q1 R) k+ r最后看一下中断标志位的处理。在AVR中对中断标志位的处理是根据不同情况采用不同的处理方法的,在上面的英文说明中已经给出了解释。有的是进入执行中断由硬件清除,有的是读某个寄存器后由硬件清除。而软件清除通常是写“1”,为什么?
% L2 j* ?6 [! I' [& s; b0 f/ h
: ~* L" c) B* D1 @3 F4 k% f# h3 J看一下M16的手册,发现外部中断标志寄存器GIFR(0X3A)、和T/C的中断标志寄存器TIFR(0X38),都在I/O空间的后32个地址中,而且全部是中断标志寄存器。因此不管是ICC、IAR、还是CVAVR,肯定不能使用SBI、CBI指令对位操作了,只能是对1个寄存器8位同时写操作了。! R+ r8 j2 a7 G0 s3 |. P0 ~6 p9 ^

+ W7 X; p/ v) a% |4 K9 C9 s那么,通常在C中如何改变1位置1呢?通常大家认为正确的语句是:XXXX |= 0B00000001;其功能是将XXXX先读出,然后同0B00000001或,使最低位为1,其它位保持不变。实际需要3条汇编指令的。改变1位置0:XXXX &= 0B11111110;同样需要3条汇编指令的。
$ `- }; m, x: a; C- e* A4 e
/ f/ b7 v0 k! T/ O) ?5 D1 ~AVR采用写“1”清“0”中断标志位(写“0”不影响标志位),那么语句就可以直接使用TIFR = 0B00000001了,只需要2条汇编。将最低位的标志位清“0”,同时保证了其它标志位的不变。(!!!注意,反而使用TIFR |= 0B00000001是错误的!!!因为,如果其它的位本身是1的话,这样反而也被清掉了)9 X4 C6 A1 \+ u( O

! Y; d/ w" f9 R+ X1 G/ Q- A1 e另外,写“0”清“0”中断标志位的话,那么写“1”到中断标志位的话应该如何定义呢?中断标志位应该是硬件置1的,如果软件可以置1,会带来更多的麻烦。+ [( U2 }, v) Z3 y  o" n

" A9 c$ [# f" a2 e2 ]# n) p实际上,上面的英文解释还是不全面的,容易引起一些误解。# ?' Q( A! e6 e  _9 R8 Y1 C
a)只能对于TIFR、GIFR使用TIFR = 0B00000001这样的语句,因为只有这两个寄存器中,全部都是中断标志位。5 z* r2 ?  e5 V7 N  j( a# t4 S3 A
b)而对于一些其它的中断标志位,如果它所在的寄存器中还有一些是非中断标志位的,就必须使用XXXX |= 0B00000001的写法了。0 t. ?; w7 \0 E9 ^# Z5 l+ t5 \
c)对于非中断标志位的设置,还是必须使用XXXX |= 0B00000001这样的形式的。
+ u* Q+ G/ S( @) ]  ~1 I

该用户从未签到

2#
发表于 2021-9-13 13:42 | 只看该作者
很实用  感谢分享7 K+ N% V$ b, B2 j% X

该用户从未签到

3#
发表于 2021-9-13 13:56 | 只看该作者
DSP也是采用写1清零标志位的
您需要登录后才可以回帖 登录 | 注册

本版积分规则

关闭

推荐内容上一条 /1 下一条

EDA365公众号

关于我们|手机版|EDA365电子论坛网 ( 粤ICP备18020198号-1 )

GMT+8, 2025-6-22 03:27 , Processed in 0.093750 second(s), 23 queries , Gzip On.

深圳市墨知创新科技有限公司

地址:深圳市南山区科技生态园2栋A座805 电话:19926409050

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