2017-09-17 57 views
0

使用Arduino的IDE的一個Arduino宇野口......AVR彙編了從可變

我可以成功發送到端口使用宏如PORTB但我無法弄清楚如何將數據發送到一個端口在一個變量的定義,像這樣:

uint8_t pin = 0; // any value... 
uint8_t port = digitalPinToPort(pin); 
uint8_t *portreg = portModeRegister(port); 
uint8_t portsfr = _SFR_IO_ADDR(port); 

asm volatile 
(
    // other asm instructions... 

    "out %[port], %[masklo] \n\t" 
    :: 
    [port]  "I" (_SFR_IO_ADDR(PORTB)) // works 

    // [port] "I" (_SFR_IO_ADDR(port)) // doesn't compile 
    // [port] "I" (portreg) // doesn't compile 
    // [port] "I" (portsfr) // doesn't compile 
); 

我發現下面的文章,其接縫相關但不顯示的例子如何:avr gcc inline asm variable input operand

+0

作爲任何指令集引用將告訴你,'out'不採取一個變量。看看你是否可以使用內存映射地址來訪問你的端口。 – Jester

回答

0

AVR的指令集不支持非即時參數到IN和OUT指令。所以,根本沒有機器指令來完成你想要的。

因此,如果沒有提到自行修改代碼,這些代碼自然會禁止從閃存運行系統,那麼您無法實現您想要的功能。

上的AVR可能端口的數量,但是有限的,一般爲3 - 因此,它很容易和相對廉價的使用開關情況以及一些枚舉來實現:

typedef enum {PortA, PortB, PortC} portNo; 

void out (portNo, value) { 
    switch (portNo) { 
     case PortA: 
     out (PORTA, value); 
     break; 
     ... 
0

的AVR的inout,sbicbi指令只需要文字I/O地址,因此它們正在訪問的寄存器在編譯時必須已知。 pololu-led-strip-arduino庫是一個庫的例子,它使用模板來解決這個問題:一個模板參數指定一個Arduino引腳號,編譯器在編譯時查找適當的I/O地址並將其燒寫到函數的彙編代碼中。

如果方法不爲你工作,一個更簡單的方法是使用switch語句轉換的引腳數(或用什麼針其他一些規範)從某事某物在編譯時未知的是:

switch (pin_number) 
{ 
case 1: 
    // some assembly using pin "1" 
    break; 
case 2 
    // some assembly using pin "2" 
    break; 
// ... 
} 

第三種方法:AVR的指令集確實有指針的支持,我相信你可以設置一個指針在I/O寄存器,然後讀取並通過指針寄存器寫入點。所以,你應該嘗試編譯像這樣的代碼,看看你的工具鏈提供的反彙編列表,看看它是如何在裝配完成的:

void write_to_reg_through_pointer(uint16_t value) { 
    volatile unsigned char * volatile ptr = &PORTB; 
    *ptr = value; 
} 
+0

它不會是您在'switch ... case'結構中尋址的「引腳」,而是端口(PORTA,PORTB,...)。引腳將通過您放入寄存器的位值進行尋址。 – tofro

+0

這只是一種方法,它取決於開發人員。 –

0

注意,任何I/O寄存器可以得到解決通它的內存位置。所以,你需要的只是利用指針指向那個內存位置。 portModeRegister(port)返回一個指向寄存器或指定端口的指針DDRx。還有portOutputRegister(port)女巫返回指針PORTx寄存器和portInputRegister()PINx

volatile uint8_t * p_port = portOutputRegister(port); 

*p_port = xxx; // writing to the PORTx by a pointer 
uint8_t yyy = *p_port; // reading the PORTx value 

也,可以直接指針寄存器分配,使用的PORTx宏:

volatile uint8_t * p_port = &PORTB; 

實用生活

由於ATMEGA328P(這是在Arduino的),以及在許多其他AVR,端口寄存器都以相同順序放置在相應位置,通常位於:PIXx,DDRx,PORTx。 因此,代替存儲三個指針時,可以只利用較低的一個(即PINX),然後訪問指針數組:

volatile uint8_t * p_base = portInputRegister(port); // obtaining pointer to PINx 

p_base[1] = ddr_val; // writing the DDRx value: offset + 1 
p_base[2] = port_val; // writing the PORTx value: offset + 2 
uint8_t pin_val pin_val = p_base[0]; // reading the PINx value: offset 0