考虑以下AVR汇编代码:
blink: sbi PINA, 0 ; Toggle PINA jmp blink
根据文档,这应该设置端口A上的位0,然而,此代码实际上会导致该位切换。为什么会这样?
pzfprimi1#
为什么?因为硬件布线就可以了。让我们看看IO引脚是如何实现的。x1c 0d1x在这里,您可以看到每个引脚的逻辑图。输出值由PORTA寄存器中的D触发器驱动。DDRA寄存器使能输出值到引脚。PINA是同步器中的第二个D触发器。PINA读取此触发器中的值。正如您所看到的,写入PIN(WPx信号)连接到多路复用器,该多路复用器为PORTA输出触发器选择输入信号。在写入一个的情况下,该多路复用器被切换到连接输出值反相状态的上部信号。同时,生成PORTA触发器的clk脉冲。结果是PORTA改变其逻辑值。sbi PINA, 0指令不触发PINA,但触发PORTA。PINA始终在一个CPU时钟周期后跟随引脚上的信号。如果要设置PORTA的位0,必须使用SBI PORTA, 0I/O端口的详细说明
sbi PINA, 0
SBI PORTA, 0
nimxete22#
为什么会这样?因为这是它在较新的AVR设备上的工作方式:您可以通过对PIN寄存器进行SBI-ing来切换端口引脚。ATmega88就是一个例子,而较老的ATmega8只是在PIN中设置一个位。优点是允许原子地切换端口引脚,而传统的IN-XOR-OUT不是原子的,速度更慢,消耗更多的闪存。要使其原子化,你必须(暂时)禁用IRQ。参见ATmega48/88/168的示例数据手册,第13节I/O端口:
向PINxn写入逻辑1可切换PORTxn的值,与DDRxn的值无关。请注意,SBI指令可用于切换端口中的一个位。
2条答案
按热度按时间pzfprimi1#
为什么?因为硬件布线就可以了。让我们看看IO引脚是如何实现的。x1c 0d1x
在这里,您可以看到每个引脚的逻辑图。输出值由PORTA寄存器中的D触发器驱动。DDRA寄存器使能输出值到引脚。PINA是同步器中的第二个D触发器。PINA读取此触发器中的值。正如您所看到的,写入PIN(WPx信号)连接到多路复用器,该多路复用器为PORTA输出触发器选择输入信号。在写入一个的情况下,该多路复用器被切换到连接输出值反相状态的上部信号。同时,生成PORTA触发器的clk脉冲。结果是PORTA改变其逻辑值。
sbi PINA, 0
指令不触发PINA,但触发PORTA。PINA始终在一个CPU时钟周期后跟随引脚上的信号。如果要设置PORTA的位0,必须使用
SBI PORTA, 0
I/O端口的详细说明
nimxete22#
为什么会这样?
因为这是它在较新的AVR设备上的工作方式:您可以通过对PIN寄存器进行SBI-ing来切换端口引脚。ATmega88就是一个例子,而较老的ATmega8只是在PIN中设置一个位。
优点是允许原子地切换端口引脚,而传统的IN-XOR-OUT不是原子的,速度更慢,消耗更多的闪存。要使其原子化,你必须(暂时)禁用IRQ。
参见ATmega48/88/168的示例数据手册,第13节I/O端口:
向PINxn写入逻辑1可切换PORTxn的值,与DDRxn的值无关。请注意,SBI指令可用于切换端口中的一个位。