原理圖
AVR Core
大多數ATmega設備的核心是AVR CPU,它被描述為RISC型CPU。然而,盡管是RISC CPU,AVR內核可以說非常強大,并且與競爭器件(例如Microchip PIC系列)相比具有許多優勢。
例如,AVR內核包含通用的8位寄存器可以配對為內存位置創建16位指針。此外,AVR內核有超過130條指令,其中許多是單周期的(由于一級管道),并且沒有方案。
然而,AVR設備特別容易發生磚塊化用戶開始使用保險絲(特定芯片選項),這就是為什么強烈建議您手頭有多個AVR設備。 AVR器件的另一個問題是如果沒有購買官方編程器,他們很難進行芯片編程(例如與PICKIT3相比)。
盡管如此,AVR已成為最流行的微控制器之一,謝謝Arduino的發明,其核心包含ATmega。事實上,Arduino只是一個AVR微控制器,帶有一些特殊的啟動加載代碼和一個USB轉串口轉換器。
以下是典型ATmega器件的內部架構(在我們的例子中,ATmega168) 。
I/O端口
了解微控制器的內部工作情況很好,但知道如何讓芯片與外界交流是很好的。大多數微控制器(如果不是全部)都包含引腳,允許器件讀取和寫入外部電路的數字值。例如,LED可以連接到I/O(帶有串聯電阻),這將允許微控制器打開和關閉LED。另一個例子是一個開關,它可以連接在引腳和電源之間,微控制器可以在檢測到開關被按下時執行動作。
當然,微控制器可以連接到幾乎任何電路,并以您可能想象的任何方式與它進行交互。但要做到這一點,我們需要了解I/O端口如何在AVR設備上工作以及如何正確使用它們!
I/O端口包含三個寄存器:
DDRx - 端口x的數據方向寄存器
PINx - 從端口x讀取
PORTx - 寫入端口x
數據方向寄存器
數據方向寄存器(DDR)很可能是您配置的第一個寄存器,因為DDR寄存器確定特定端口上的引腳是輸入還是輸出。 DDR寄存器長8位,每個位對應I/O端口的引腳。
例如,DDRB的第一位(位0)將決定PB0是輸入還是輸出,最后一位(第7位)將確定PB7是輸入還是輸出。
在PIC器件中,值1用于輸入,值0用于輸出,但對于AVR器件則反之亦然; 1表示輸出,0表示輸入。因此,假設我們想要將PORT B上的所有引腳配置為輸出,我們只需使用以下代碼:
DDRB = 0xFF;
或
DDRB = 0b11111111;
第一個示例使用十六進制,而第二個示例使用二進制。雖然通常的做法是使用十六進制,但二進制版本可以更清楚地將端口中的哪些位用作輸入或輸出。如果我們想將PORT B上的所有引腳轉換為輸入引腳,那么我們可以使用。。.。。.
DDRB = 0x00;
或
DDRB = 0b00000000;
更復雜的事情怎么樣?假設您希望前兩個引腳為輸出(PB0和PB1),其余引腳為輸入。以下代碼可以解決這個問題:
DDRB = 0x03;
或
DDRB = 0b00000011;
PINx寄存器
我們的DDR寄存器排序out,是時候學習如何從現實世界中將數字值讀入微控制器。這是使用寄存器PINx完成的,其中x是要讀取的寄存器。從端口讀取相當容易,如下面的代碼示例所示:
dataValue = PINB;
執行此操作時,PORT B上的所有引腳都被讀入dataValue,并且dataValue中的每個位現在將對應于讀取時每個引腳上的數字電平。雖然這可能很有用,但我們有時可能希望同時測試單個位而不是所有位。在PIC中,.bits成員可用于訪問各個位,但AVR設備不是這種情況。相反,訪問單個位涉及一些操作(原諒雙關語),包括使用邏輯AND,OR和XOR。
要測試一個位是否打開(邏輯1),以下兩個可以使用語句。這些函數對PIN寄存器和位執行邏輯AND(表示為8位數)。如果結果為零,則不會執行if語句,因為if語句僅在條件為非零時執行。第一個語句使用二進制值來表示要測試的位,而第二個語句使用邏輯移位指令來創建位掩碼,該掩碼表示要測試的位。邏輯移位版本可以說更具可讀性,因此更容易理解。但是,執行該指令可能需要比第一次更長的時間(取決于優化)。
if(PINB&(0b00000001))
或
if(PINB&(1 《
在主要測試(!)
if(!(PINB&(0b00000001)))
或《之前使用否定運算符可以輕松地測試邏輯0 br》 if(!(PINB&(1 《
PORTx寄存器
現在我們可以讀取整個端口和各個引腳,我們如何寫入端口和單個引腳?這是PORTx寄存器的用武之地。寫入該寄存器(其中x表示要寫入的端口)將導致輸出引腳打開或關閉。請記住,物理輸出引腳只有與PORTx寄存器IF對應的數字電平,只有相應的DDR位被設置為輸出!
將值寫入端口非常容易:
PORTB = 0xFF;
或
PORTB = 0b11111111;
但個別位怎么樣?這再次使用按位運算符完成,并且設置/清除位稍微復雜一些。這是因為我們需要保留PORT寄存器中其他位的值,否則它們可能會被更改,如果它們連接到外部設備(如LED,顯示器,IC等),可能會導致意外行為。
要打開特定位,我們可以使用OR邏輯運算符:
PORTB = PORTB | (0b00000001);打開位0
或
PORTB = PORTB | (1 《
要關閉特定位,我們使用AND運算符和NOT運算符(?):
PORTB = PORTB& ?(0b00000001);關閉位0
或
PORTB = PORTB& ?(1 《
要切換一點(以便它與以前相反)我們可以使用XOR運算符:
PORTB = PORTB ^(0b00000001);切換位0
o r
PORTB = PORTB ^(1 《
引腳名稱
使用數字來表示引腳可能會導致某些不可讀代碼,這就是為什么WinAVR足夠好,可以包含一些我們可以使用的定義。請參閱以下示例:
PORTB = PORTB& ?(1 《
如果(PINC&(1 《
一個簡單的例子
在我們的例子中,我們將制作一個電路當按下連接到PD1的開關時,切換連接到PD0的LED。
/*
* AVR IO.c
*
* Created: 03/01/2018 11:25:21
* Author : RobinLaptop
*/
#define F_CPU 1000000UL
#include
#include
int main(void)
{
// Configure PORT D bit 0 to an output and bit 1 to an input
DDRD = 0b00000001;
// Main program loop
while (1)
{
// Wait until the switch found on PIND1 (bit 1)
if(PIND & (1 《《 PIND1))
{
// Toggle the LED found on PIND0
PORTD = PORTD ^ (1 《《 PIND0);
// Force a delay to prevent de-bounce!
_delay_ms(100);
// Wait until the button is released
while(PIND & (1 《《 PIND1));
}
}
}
結論
現在我們可以控制I/O引腳了,沒有理由不能在復雜控制器可以使用的項目中開始使用AVR。使用本文中的知識,您可以創建一個鍵盤輸入系統,一個復雜的7段顯示控制器,一個音樂系統,甚至是一個基本的80年代風格的計算機。
-
ATmega
+關注
關注
2文章
79瀏覽量
42858
發布評論請先 登錄
相關推薦
評論