无法使用 PINxn 从 Arduino Mega 读取引脚值
Not able to read the pin value from Arduino Mega using PINxn
使用 Arduino Mega 2560 的寄存器,我试图获取 PORTA 的信息。我已经参考了 datasheet(第 69-72 页)并了解我必须为此使用 PINxn (PINA)。但我得到的只是 0 作为输出。我已将引脚连接到 LED。
下面提到了代码和输出。
代码
#define F_CPU 16000000
#include <avr/io.h>
int main(void) {
DDRA = (1 << DDA0); // sets the pin OUTPUT
__asm__("nop\n\t");
PORTA = 0x01; // Sets it HIGH
unsigned int i = PINA;
Serial.println(i);
}
输出
0
提前感谢您抽出宝贵时间 - 如果我遗漏了什么,过分强调或低估了某个特定点,请在评论中告诉我。
如果你想读回之前写入输出的值,我建议从你写入的寄存器中读取它,即PORTA
。
但是根据提供的文档(我加粗):
13.2.4 Independent of the setting of Data Direction bit DDxn, the port pin can be read through the PINxn Register bit.
在写入不同值后立即读回旧值的可能解释可能是同一章中紧随其后的部分:
PINxn Register bit and the preceding latch constitute a synchronizer. This is
needed to avoid metastability if the physical pin changes value near the edge of the internal clock, but it also introduces
a delay.
因此您将不得不考虑该延迟。
查看提供的计时功能,例如通过可用的库和可用的定时器硬件。
但作为概念证明,我建议通过
来证明
- 打印
PINA
的值在写入反转值 之前
- 将反转后的值写入
PORTA
(当然只反转相关位)
- 读取并打印
PINA
之后的值(希望你的header在这里使用volatile
)多次(比如1000)
我希望您会看到几个旧值,然后是新值。
取决于打印的完成方式(忙着等待?),一次可能就足够了。
您的 NOP
(__asm__("nop\n\t");
) 可能旨在进行适当的等待。但我认为它放错了地方(应该在写入新值之后)并且它可能太短了。如果它来自示例代码,它应该足够了。移动它,也许做两次,以确保第一次尝试。那可能会有效。
您应该将 "nop" 放在 "PORTA = " 赋值和 "PINA" 读取之间。因为写入 PORTx 寄存器的指令恰好在时钟发生器上升沿的系统时钟周期结束时更新输出引脚的状态,但是从 PINx 寄存器读取 returns 锁存的信息一个中间缓冲区。缓冲器在前一个时钟周期的中间(即时钟发生器的下降沿)锁存。
因此,从 PINx 读取总是延迟 0.5 到 1.5 个时钟周期。
如果某个系统时钟的逻辑电平在其中间之前(即在时钟发生器的下降沿之前)发生变化,则该值将立即被锁存,并可在下一个系统时钟周期通过读取 PINx 寄存器进行读取。因此,延迟为 0.5 个周期
如果逻辑电平刚好在那个latch moment之后发生变化,那么,它只会在下一个cycle被latch,在之后的下一个cycle才可以读取,这样就引入了1.5个cycles
的延迟
写入PORTx寄存器会在时钟周期结束时更新输出值,因此,它仅在下一个周期锁存,并且在之后的下一个周期只能读取。
C 编译器非常适合优化,因此,PORTA 赋值和 PINA 读取的两个后续行被编译为两个后续 out PORTA,rxx 和 在 ryy 中,PINA 指令,导致这种效果
使用 Arduino Mega 2560 的寄存器,我试图获取 PORTA 的信息。我已经参考了 datasheet(第 69-72 页)并了解我必须为此使用 PINxn (PINA)。但我得到的只是 0 作为输出。我已将引脚连接到 LED。
下面提到了代码和输出。
代码
#define F_CPU 16000000
#include <avr/io.h>
int main(void) {
DDRA = (1 << DDA0); // sets the pin OUTPUT
__asm__("nop\n\t");
PORTA = 0x01; // Sets it HIGH
unsigned int i = PINA;
Serial.println(i);
}
输出
0
提前感谢您抽出宝贵时间 - 如果我遗漏了什么,过分强调或低估了某个特定点,请在评论中告诉我。
如果你想读回之前写入输出的值,我建议从你写入的寄存器中读取它,即PORTA
。
但是根据提供的文档(我加粗):
13.2.4 Independent of the setting of Data Direction bit DDxn, the port pin can be read through the PINxn Register bit.
在写入不同值后立即读回旧值的可能解释可能是同一章中紧随其后的部分:
PINxn Register bit and the preceding latch constitute a synchronizer. This is needed to avoid metastability if the physical pin changes value near the edge of the internal clock, but it also introduces a delay.
因此您将不得不考虑该延迟。
查看提供的计时功能,例如通过可用的库和可用的定时器硬件。
但作为概念证明,我建议通过
- 打印
PINA
的值在写入反转值 之前
- 将反转后的值写入
PORTA
(当然只反转相关位) - 读取并打印
PINA
之后的值(希望你的header在这里使用volatile
)多次(比如1000)
我希望您会看到几个旧值,然后是新值。
取决于打印的完成方式(忙着等待?),一次可能就足够了。
您的 NOP
(__asm__("nop\n\t");
) 可能旨在进行适当的等待。但我认为它放错了地方(应该在写入新值之后)并且它可能太短了。如果它来自示例代码,它应该足够了。移动它,也许做两次,以确保第一次尝试。那可能会有效。
您应该将 "nop" 放在 "PORTA = " 赋值和 "PINA" 读取之间。因为写入 PORTx 寄存器的指令恰好在时钟发生器上升沿的系统时钟周期结束时更新输出引脚的状态,但是从 PINx 寄存器读取 returns 锁存的信息一个中间缓冲区。缓冲器在前一个时钟周期的中间(即时钟发生器的下降沿)锁存。
因此,从 PINx 读取总是延迟 0.5 到 1.5 个时钟周期。 如果某个系统时钟的逻辑电平在其中间之前(即在时钟发生器的下降沿之前)发生变化,则该值将立即被锁存,并可在下一个系统时钟周期通过读取 PINx 寄存器进行读取。因此,延迟为 0.5 个周期 如果逻辑电平刚好在那个latch moment之后发生变化,那么,它只会在下一个cycle被latch,在之后的下一个cycle才可以读取,这样就引入了1.5个cycles
的延迟写入PORTx寄存器会在时钟周期结束时更新输出值,因此,它仅在下一个周期锁存,并且在之后的下一个周期只能读取。
C 编译器非常适合优化,因此,PORTA 赋值和 PINA 读取的两个后续行被编译为两个后续 out PORTA,rxx 和 在 ryy 中,PINA 指令,导致这种效果