SAM3X8E(Arduino Due)引脚IO寄存器


9

Arduino Due的IO寄存器如何工作?在Arduino的乌诺刚刚成立DDRx,那么PINx读,PORTx写,我想这样做同样的事情用一个Arduino到期,但它有更多的寄存器,如PIO_OWERPIO_OSERPIO_CODRPIO_SODR等我发现的Arduino UNO和之间没有对应Arduino Due寄存器。

也有一些有用的功能,如pio_clearpio_setpio_get,等人,都在这里解释:

http://asf.atmel.com/docs/3.19.0/sam3x/html/group__sam__drivers__pio__group.html

现在,我想我已经理解了所提到的三个函数的功能,但其他的函数却无法理解,例如:

pio_configure (Pio *p_pio, const pio_type_t ul_type, const uint32_t ul_mask, const uint32_t ul_attribute)

我想不出有什么ul_attributeul_type是。


这是为AVR和SAM实现的GPIO类。可能会给如何使用寄存器一个提示:github.com/mikaelpatel/Arduino-GPIO/blob/master/src/Hardware/...
的Mikael帕特尔

Answers:


7

如果您已阅读数据表第31节(可从此处获得),则可能对您而言更清楚了。

以下是我所知道的摘要:

PIO代表并行输入/输出,并提供一次读取和写入多个寄存器端口的功能。数据表中提到了一个寄存器,例如PIO_OWER,Arduino库具有用于以REG_PIO?_OWER格式访问它们的宏。对于不同的可用端口,是A,B,C或D。

我倾向于仍然使用缓慢的Arduino pinMode()函数来设置引脚上的输入/输出,因为它使代码比诸如REG_PIOC_OWER = 0xdeadbeef之类的基于首字母缩写的寄存器调用更具可读性,但是随后使用直接寄存器来设置引脚性能/同步。到目前为止,我还没有对输入进行任何操作,因此我的示例全部基于输出。

对于基本用法,可以使用REG_PIO?_SODR将输出线设置为高电平,而使用REG_PIO?_CODR将其设置为低电平。例如,REG_PIOC_SODR = 0x00000002会将PORTC(这是Due数字引脚33)上的位1(从零开始编号)设置为高。PORTC上的所有其他引脚保持不变。REG_POIC_CODR = 0x00000002会将PORTC的位1设置为低电平。同样,所有其他引脚将保持不变。

由于这仍然不是最佳选择,或者如果您正在处理并行数据,则不是同步的,因此有一个寄存器允许您通过一次调用写入端口的所有32位。这些是REG_PIO?_ODSR,因此REG_PIOC_ODSR = 0x00000002现在将在单个CPU指令中立即将PORTC上的位1设置为高,而将PORTC上的所有其他位立即设置为低。

由于您不太可能需要同时设置端口的所有32位,因此您需要存储引脚的当前值,执行AND操作以掩盖您的引脚要进行更改,请执行“或”操作将您要设置的值设置为高,然后再次执行写入操作,这不是最佳选择。为了克服这个问题,CPU本身将为您执行屏蔽。有一个称为OWSR(输出写状​​态寄存器)的寄存器,它将屏蔽您写入ODSR的所有与OWSR中设置的位都不匹配的位。

因此,现在,如果我们调用REG_PIOC_OWER = 0x00000002(这将OWSR的位1设置为高)并且REG_PIOC_OWDR = 0xfffffffd(这将清除OWSR的位1除外),然后再次调用REG_PIOC_ODSR = 0x00000002,这一次它只会更改位PORTC的1和其他所有位保持不变。要注意一个事实,即OWER使任何位被设置为1在你写的价值和OWDR禁止任何位被设置为1在你写的值。即使我在阅读时理解了这一点,但在编写第一个测试代码时仍然认为OWDR禁用了在我编写的值中未设置为1的位,因此仍然犯了一个代码错误。

我希望这至少可以让您开始了解Due CPU的PIO。阅读并玩耍,如果您还有其他问题,我会尽力回答。

编辑:还有一件事...

您如何知道PORT的哪些位与Due的哪些数字线相对应?检查一下:Due Pinout


3

基本的直接引脚访问相当简单。以下是一些示例代码,显示了如何将数字引脚设置为高电平然后再设置为低电平。第一个用于Arduino Due,第二个用于Arduino Uno / Mega / etc。

const unsigned int imThePin = 10; //e.g. digital Pin 10

#ifdef _LIB_SAM_

    //First lets get the pin and bit mask - this can be done once at the start and then used later in the code (as long as the variables are in scope
    Pio* imThePort = g_APinDescription[imThePin].pPort; 
    unsigned int imTheMask = g_APinDescription[imThePin].ulPin; 

    //Lets set the pin high
    imThePort->PIO_SODR = imTheMask;
    //And then low
    imThePort->PIO_CODR = imTheMask;

#else

    //First lets get the pin and bit mask - this can be done once at the start and then used later in the code (as long as the variables are in scope
    volatile unsigned char* imThePort = portOutputRegister(digitalPinToPort(imThePin)); 
    unsigned char imTheMask = digitalPinToBitMask(imThePin);

    //Lets set the pin high
    *imThePort |= imTheMask;
    //Now low
    *imThePort &= ~imTheMask;

#endif

缺省情况下,应该包括执行此操作所需的所有操作-如果不#include <Arduino.h>足够,则应包含在其中。

实际上,一旦您有Pio指针进行设置/清除/上拉电阻/等操作,便可以调用这些功能。使用外观更简洁的函数调用。完整列表可以在 头文件。


0

这是一个代码示例,其引脚33上的LED闪烁。快速访问端口。我认为我的代码正确-特别是将引脚设置为低电平的线。LED指示灯愉快地闪烁。

void setup() 
{
  pinMode(33, OUTPUT); 
  REG_PIOC_OWER = 0x00000002; 
  REG_PIOC_OWDR = 0xfffffffd; 
}

void loop() 
{
  REG_PIOC_ODSR = 0x00000002; 
  delay(1000);             
  REG_PIOC_ODSR = 0x00000000;    
  delay(1000);   
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.