2016-11-16 43 views
0

我想爲Atmel ATMega32U4實現與Arduino的引腳號類似的東西。我看過Arduino的digitalWrite命令和相關的源文件,看看它們是如何做的,但我認爲這有點複雜,所以我想實現一個更基本的版本。在AVR微控制器中實現類似於Arduino的引腳號

這個想法是有整數1到n代表AVR芯片上的每個I/O引腳。我開始用指針數組的DDR/PORT寄存器,其中該指數將代表銷地址:

volatile uint8_t *pin_port_dir_regs[] = { 
    0,    // NOT USED 
    0,    // NOT USED 
    0,    // NOT USED 
    0,    // NOT USED 
    0,    // NOT USED 
    0,    // NOT USED 
    0,    // NOT USED 
    &DDRE,   // PIN_7 
    &DDRB,   // PIN_8 
    0,    // NOT USED 
    0,    // NOT USED 
    0,    // NOT USED 
    0,    // NOT USED 
    0,    // NOT USED 
    0,    // NOT USED 
    &DDRB,   // PIN_15 
    &DDRB    // PIN_16 
}; 

volatile uint8_t *pin_port_out_regs[] = { 
    0,     // NOT USED 
    0,     // NOT USED 
    0,     // NOT USED 
    0,     // NOT USED 
    0,     // NOT USED 
    0,     // NOT USED 
    0,     // NOT USED 
    &PORTE,   // PIN_7 
    &PORTB,   // PIN_8 
    0,     // NOT USED 
    0,     // NOT USED 
    0,     // NOT USED 
    0,     // NOT USED 
    0,     // NOT USED 
    0,     // NOT USED 
    &PORTB,   // PIN_15 
    &PORTB    // PIN_16 
}; 

我還需要在每一個的DDRx/PORTx寄存器的知道比特數,所以我創造了另一個數組:

const uint8_t pin_bits[] = { 
    _BV(0), // NOT USED 
    _BV(0), // NOT USED 
    _BV(0), // NOT USED 
    _BV(0), // NOT USED 
    _BV(0), // NOT USED 
    _BV(0), // NOT USED 
    _BV(0), // NOT USED 
    _BV(6), // PIN_7 
    _BV(4), // PIN_8 
    _BV(0), // NOT USED 
    _BV(0), // NOT USED 
    _BV(0), // NOT USED 
    _BV(0), // NOT USED 
    _BV(0), // NOT USED 
    _BV(0), // PIN_14 
    _BV(1), // PIN_15 
    _BV(3) // PIN_16 
}; 

要設置引腳模式,並寫入到腳,我創建了以下功能:

void pin_mode(uint8_t pin, uint8_t direction) { 
    // defeference the pointer to the direction register 
    uint8_t port_dir_register = *(pin_port_dir_regs[pin]); 

    // get pin mask 
    uint8_t mask = pin_bits[pin]; 

    // set its mode 
    if (direction == INPUT) { 
     port_dir_register &= ~mask; 
    } else { 
     port_dir_register |= mask; 
    } 
} 

void pin_write(uint8_t pin, uint8_t level) { 
    // defeference the pointer to the output register 
    uint8_t port_out_register = *(pin_port_out_regs[pin]); 

    // get pin mask 
    uint8_t mask = pin_bits[pin]; 

    // set output 
    if (level == LOW) { 
     port_out_register &= ~mask; 
    } else { 
     port_out_register |= mask; 
    } 
} 

什麼是應該發生的是,你會打電話如pin_mode(7, OUTPUT)將引腳7設置爲輸出,然後pin_write(7, HIGH)將輸出設置爲1(其中OUTPUT和HIGH是預定義的宏)。代碼編譯併成功上傳到AVR,但是當我測試輸出時,它不響應。我想我必須寫一些內存位置,但不是對應於預期的寄存器。有沒有人看到我試圖做到這一點的方式有問題?

+0

爲什麼你不使用gcc提供的標準文件avr?另外:如果你使用類似pin_write方法的方式爲引腳寫入一些初始化,則只會爲prog的開始階段浪費大量代碼。所有這些都可以在編譯時通過模板代碼完成,而不是單獨針對每個引腳進行操作。爲相同的作業設置一次不是8次的ddr和端口寄存器。 – Klaus

+0

@Klaus,你指的是什麼標準文件?我沒有意識到現有的代碼可以做我想做的事情。 此外,我並不關心現階段的啓動優化 - 但感謝您的建議。 – Sean

+0

這看起來很浪費寶貴的RAM和ROM空間給我。你的問題不在這裏討論。我們是noi討論網站,它太過於自負。編輯:對不起,我有最後一句話。請提供更詳細的信息。見[問]。 – Olaf

回答

1

的原因,爲什麼你的代碼不能工作這一步是:

uint8_t port_out_register = *(pin_port_out_regs[pin]); 

你要寫信給位於特定地址的硬件寄存器。要做到這一點,你需要:

*(pin_port_out_regs[pin]) = some_value; 

否則,你只會修改堆棧內存沒有收益。

嘗試改變這個代替:

void pin_write(uint8_t pin, uint8_t level) 
{ 
    uint8_t *port_out_register = pin_port_out_regs[pin]; 
    uint8_t mask = pin_bits[pin]; 

    if (level == LOW) { 
     *port_out_register &= ~mask; 
    } else { 
     *port_out_register |= mask; 
    } 
} 
+0

謝謝,這樣做! – Sean

2

至於答案的評論我給:

你指的是什麼標準的文件嗎?

從安裝了avrlibc的avr-gcc是每個可用控制器的標準文件集合。

如果你的代碼是一樣的東西:

#include <avr/io.h> // automatic include correct io from device like 
        // <avr/iom32u4.h> in your case. That file defines 
        // all registers and pin descriptions and also irq 
        // vectors! 

// So you can write: 
int main() 
{ 
    DDRA= 1 << PA4; // enable output Pin 4 on Port A 
    PORTA= 1 << PA4; // set output Pin4 on Port A high 

    // and normally on startup all needed output pins will be 
    // set with only one instruction like: 
    // To set Pin 2..4 as output 
    DDRA= (1 << PA4) | (1 << PA3) | (1 << PA2); 
} 

做一個簡單的PORTA= 1 << PA4的函數調用是一個很大的浪費。並且定義你自己的寄存器名稱和引腳名稱是沒用的。所有的引腳已經被定義,你可以看到。

你的想法只有一個邏輯端口號位於「某處」魔術定義的端口看起來不是很自然。如果您設計電路和軟件,則必須按照數據表中所述處理引腳。沒有「邏輯引腳號」。這個想法只對更大的代碼大小有幫助:-)

此外,你必須記住哪些引腳也有像uarts和所有其他硬件東西的多個功能。因此移動到其他設備將始終需要查看引腳/端口使用情況。這裏的邏輯端口號也是硬件和自然軟件之間的一個複雜層。

相關問題