Arduino Ports and Register
心血來潮看了一下Arduino底層對pin腳的控制,整理了一下並且分為兩部分:第一部分:Arduino內部pin腳的port以及register的編號,並且如何使用這些register對腳位進行控制
第二部分:使用最底層的avr-libc進行pinMode、digitalWrite函數的改寫練習,發現使用avr-libc可以有效降低script的大小
Arduino UNO R3版子所用的Atmega328晶片有三個8-bit的PORTs,分別為:
- B (digital pin 8 to 13)
- C (analog input pins)
- D (digital pin 0 to 7)
所以位於PortB的Digital Pin 8可以說是PB0,位於PortC的Analog Pin 2也可以說是PC2,而在之後要介紹的AVR-GCC中使用的便是PB0、PC2這種腳位編號方式。
另外在晶片內是透過暫存器(register)來對腳位進行設定,對於Arduino這種AVR晶片來說,每個Port都受三個暫存器控制,分別是(x可以用B, C, D代替):
- DDRx register:決定腳位是INPUT或是OUTPUT,似pinMode()
- PORTx register:控制腳位輸出訊號為HIGH或為LOW,似digitalWrite()
- PINx register:存有腳位輸入的訊號,似analogRead()
表1. Port Register bit所控制的腳位對應表
PORTx、PINx與腳位的對應都可以參考表1。關於Arduino UNO Ports and Registers,在官網上也有一些說明[2]。
Getting Started with AVR-GCC
接下來要實作將Arduino原本的程式碼改以AVR-GCC函數撰寫,下列程式碼為Arduino自帶的blink範例程式,讓位於Pin 13上的LED兩秒一次的頻率閃爍:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// the setup function runs once when you press reset or power the board | |
void setup() { | |
// initialize digital pin 13 as an output. | |
pinMode(13, OUTPUT); | |
} | |
// the loop function runs over and over again forever | |
void loop() { | |
digitalWrite(13, HIGH); // turn the LED on (HIGH is the voltage level) | |
delay(1000); // wait for a second | |
digitalWrite(13, LOW); // turn the LED off by making the voltage LOW | |
delay(1000); // wait for a second | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Rework original sample with AVR-GCC. | |
*/ | |
// the setup function runs once when you press reset or power the board | |
void setup() { | |
// initialize digital pin 13 as an output. | |
DDRB |= (1 << 5); // pinMode(13, OUTPUT); | |
} | |
// the loop function runs over and over again forever | |
void loop() { | |
PORTB |= (1 << 5); //digitalWrite(13, HIGH); | |
delay(1000); | |
PORTB &= ~(1 << 5); //digitalWrite(13, LOW); | |
delay(1000); | |
} |
使用_BV()巨集修改程式
在C語言中,我們可以使用位元運算子(bit operators)處理位元的運算(bitwise operation),範例如下:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
PORTC |= (1 << 0); // Set bit 0 only | |
PORTC &= ~(1 << 1); // Clear bit 1 only | |
PORTC ^= (1 << 4); // Toggle bit 4 only. | |
PORTC |= (1 << 7); // Set bit 7 only. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#define _BV(x) (1 << x) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <avr/io.h> | |
PORC |= _BV(0); //PORTC |= (1 << 0); // Set bit 0 only | |
PORCT &= ~_BV(1); //PORTC &= ~(1 << 1); // Clear bit 1 only | |
PORTC ^= _BV(4); //PORTC ^= (1 << 4); // Toggle bit 4 only. | |
PORTC |= _BV(7); //PORTC |= (1 << 7); // Set bit 7 only. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <avr/io.h> | |
PORTC |= (_BV(0) | _BV(1) | _BV(2)); // Set bits 0, 1, 2 | |
PORTC &= ~(_BV(3) | _BV(4) | _BV(5)); // Clear bits 3, 4, 5 | |
PORTC ^= (_BV(6) | _BV(7)); // Toggle bits 6, 7 | |
//without using MACRO _BV() would looks like this | |
PORTC |= ((1 << 0) | (1 << 1) | (1 << 2)); // Set bits 0, 1, 2 | |
PORTC &= ((1 << 3) | (1 << 4) | (1 << 5)); // Clear bits 3, 4, 5 | |
PORTC ^= ((1 << 6) | (1 << 7)); // Toggle bits 6, 7 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Rework original sample with AVR-libc. | |
*/ | |
#include <avr/io.h> | |
#include <util/delay.h> | |
// the setup function runs once when you press reset or power the board | |
void setup() { | |
// initialize digital pin 13 as an output. | |
DDRB |= _BV(5); // pinMode(13, OUTPUT); | |
} | |
// the loop function runs over and over again forever | |
void loop() { | |
PORTB |= _BV(5); //digitalWrite(13, HIGH); | |
_delay_ms(1000); | |
PORTB &= ~_BV(5); //digitalWrite(13, LOW); | |
_delay_ms(1000); | |
} |
參考資料:
[1] Pighixxx. Arduino UNI Pinout Diagram.
Available from: http://forum.arduino.cc/index.php/topic,146315.0.html
[2] Arduino.cc. Port Registers.
Available from: http://www.arduino.cc/en/Reference/PortManipulation
Available from: http://www.arduino.cc/en/Reference/PortManipulation
[3] Cooper Maa. 2.1) Blink part 1.
Available from: http://coopermaa2nd.blogspot.tw/2011/04/21-blink-part-1.html
Available from: http://coopermaa2nd.blogspot.tw/2011/04/21-blink-part-1.html
[4] arduino吧. Arduino 下使用 avr gcc.
Available from: http://tieba.baidu.com/p/1292575395
Available from: http://tieba.baidu.com/p/1292575395
[5] Cooper Maa. _BV() 巨集介紹.
Available from: http://coopermaa2nd.blogspot.tw/2011/04/bv.html
Available from: http://coopermaa2nd.blogspot.tw/2011/04/bv.html
[6] Atmel. Macro _BV.
Available from: http://www.atmel.com/webdoc/AVRLibcReferenceManual/group__avr__sfr_1ga11643f271076024c395a93800b3d9546.html
Available from: http://www.atmel.com/webdoc/AVRLibcReferenceManual/group__avr__sfr_1ga11643f271076024c395a93800b3d9546.html
[7] Garretlab. pinMode. Available from: http://garretlab.web.fc2.com/en/arduino/inside/arduino/wiring_digital.c/pinMode.html
Comments
Post a Comment