Bài 2: Kiểm chứng tốc độ khi điều khiển các pin bằng ngôn ngữ AVR so với các lệnh trên Arduino

Mô tả dự án: 

Arduino dùng chip AVR, nếu điều khiển arduino bằng ngôn ngữ tiêu chuẩn của chip AVR thì tốc độ có thể nhanh hơn 12 lần so với cách dùng lệnh digitalWrite, nhanh hơn 4 lần so với lệnh digitalRead, nhanh 14 hơn lần so với analogRead, nhanh 10 hơn lần so với pinMode… thậm chí cách biệt còn xa hơn nữa. Điều này rất rất quan trọng. Cùng khám phá nào..

Bắt đầu nào...

Ở bài trước, ta đã biết cách điều khiển các chân port . Bây giờ hãy cùng mình  so sánh tốc độ của 2 phương pháp.

 

Tiêu chí đánh giá:

  • Bài viết sử dụng arduino uno r3 , tần số hệ thống 16mhz.
  • Mình dùng hàm micros() của hệ thống làm đồng hồ. Hàm này sẽ được đặt về 0 khi reset hoặc nạp code lần đầu. Qúa trình khảo sát diến ra rất nhanh ( < 500 micro giây) nên không lo hàm sẽ bị tràn số.
  • Công việc cần khảo sát:(đoạn code trong dấu ///) là đoạn code nằm giữa lúc bắt đầu tính thời gian và kết thúc tính thời gian (sát nhất). Các đoạn code khác (nằm trước và  sau ) chỉ mang tính chất điều kiện cần, và không liên quan đến khoảng thời gian khảo sát.
  • Khoảng thời gian khảo sát:  chỉ được bắt đầu tính từ khi đặt start lần đầu tiên, khi "công việc cần khảo sát" kết thúc, mình sẽ lấy hiệu của micros() với start. Hiệu đó sẽ mãi được giữ nguyên,đó chính là khoảng thời gian khảo sát. Cuối cùng nó được in ra bằng Print.  
  • Thống kê: mình sẽ nhấn nút  reset (giữ nguyên code), rồi lại xem kết quả để xem kết quả có bị lệch hay không giữa các lần .
  • Độ chính xác: Kết quả tìm HIỆU có thể không chính xác tuyệt đối (không có máy đo chính xác hơn), nhưng chúng ta KHÔNG thật sự cần đến nó, cái quan trọng là chúng ta sẽ so sánh  mức độ nhanh chậm gấp bao nhiêu lần của 2 loại code mà thôi(so sánh tương đối). Khi đó ở cùng một điều kiện phần cứng (không thay đổi)  thì kết quả được cho là đáng tin cậy.(Đây cũng là cách nhanh nhất và tiết kiệm nhất mà chúng ta có thể thực hiện.)
  • Điều kiện cuối: Nếu bạn chấp nhận các tiêu chí trên thì chúng ta sẽ tiếp tục laughlaugh hehe

Pin mode

Đặt pin digital 0 là output

unsigned long start;
void setup(){
    Serial.begin(9600);
    start=micros();
///
       pinMode(0,OUTPUT);
///
    start=micros()-start;
    Serial.println(start);
}
void loop(){
}
unsigned long start;
void setup(){
    Serial.begin(9600);
    start=micros();
///
       DDRD=B00000001;
///
    start=micros()-start;
    Serial.println(start);
}
void loop(){
}
Thời gian: 4 micro giây
4 micro giây

Đặt 14 pin digital là OUTPUT

unsigned long start;
void setup(){
    Serial.begin(9600);
    start=micros();
///
      for(byte pin=0; pin<14; pin++){
        pinMode(pin, OUTPUT);}
///
    start=micros()-start;
    Serial.println(start);
}
void loop(){
}
unsigned long start;
void setup(){
    Serial.begin(9600);
    start=micros();
///
       DDRB=B11111111;
       DDRD=B11111111;
///
    start=micros()-start;
    Serial.println(start);
}
void loop(){
}
Thời gian: 44 micro giây
4 micro giây
unsigned long start;
void setup(){
    Serial.begin(9600);
    start=micros();
   ///
        pinMode(0, OUTPUT);
        pinMode(1, OUTPUT);
        pinMode(2, OUTPUT);
        pinMode(3, OUTPUT);
        pinMode(4, OUTPUT);
        pinMode(5, OUTPUT);
        pinMode(6, OUTPUT);
        pinMode(7, OUTPUT);
        pinMode(8, OUTPUT);
        pinMode(9, OUTPUT);
        pinMode(10, OUTPUT);
        pinMode(11, OUTPUT);
        pinMode(12, OUTPUT);
        pinMode(13, OUTPUT);
    ///
    start=micros()-start;
    Serial.println(start);
}
void loop(){
}
 
Không dùng for,Thời gian: 48 micro giây  

 

 

digitalWrite();

Đặt 1 pin là HIGH

unsigned long start;
void setup(){
    Serial.begin(9600);
    pinMode(0,OUTPUT);
    start=micros();
///
       digitalWrite(0,HIGH);
///
    start=micros()-start;
    Serial.println(start);
}
void loop(){
}
unsigned long start;
void setup(){
    Serial.begin(9600);
    pinMode(0,OUTPUT);
    start=micros();
///
       PORTD=B00000001;
///
    start=micros()-start;
    Serial.println(start);
}
void loop(){
}
Thời gian: 8 micro giây
4 micro giây

Đặt 14 pin là HIGH

unsigned long start;
void setup(){
    Serial.begin(9600);
    for(byte pin=0; pin<14; pin++){
        pinMode(pin, OUTPUT);
    }
    start=micros();
///
     for(byte pin=0; pin<14; pin++){
          digitalWrite(pin,HIGH);}
///
    start=micros()-start;
    Serial.println(start);
}
void loop(){
}
unsigned long start;
void setup(){
    Serial.begin(9600);
    DDRB=B11111111;
    DDRD=B11111111;
    start=micros();
///
          PORTB=B11111111;
          PORTD=B11111111;
///
    start=micros()-start;
    Serial.println(start);
}
void loop(){
}

Thời gian: 52 micro giây

4 micro giây

unsigned long start;
void setup(){
    Serial.begin(9600);
    for(byte pin=0; pin<14; pin++){
        pinMode(pin, OUTPUT);
    }
    start=micros();
   ///
        digitalWrite(0,HIGH);
        digitalWrite(1,HIGH);
        digitalWrite(2,HIGH);
        digitalWrite(3,HIGH);
        digitalWrite(4,HIGH);
        digitalWrite(5,HIGH);
        digitalWrite(6,HIGH);
        digitalWrite(7,HIGH);
        digitalWrite(8,HIGH);
        digitalWrite(9,HIGH);
        digitalWrite(10,HIGH);
        digitalWrite(11,HIGH);
        digitalWrite(12,HIGH);
        digitalWrite(13,HIGH);
    ///
    start=micros()-start;
    Serial.println(start);
}
void loop(){
}

 

 
Không dùng for,Thời gian: 56 micro giây  

Khả năng điều khiển đồng bộ

pinMode/ digitalWrite
DDR/PORT
Lần lượt từng Pin (có thời gian trễ).
 Điều khiển cùng lúc 8 pin (tức thì)

 

digitalRead()

Đọc giá trị ở trạng thái digital của pin 7

unsigned long start;
void setup(){
    Serial.begin(9600);
    bool val;
    pinMode(7,INPUT);
    start=micros();
///
       val=digitalRead(7);
///
    start=micros()-start;
    Serial.println(start);
}
void loop(){
}
unsigned long start;
void setup(){
    Serial.begin(9600);
    bool val;
    pinMode(7,INPUT);
    start=micros();
///
        val=PIND&(1<<7);
///
    start=micros()-start;
    Serial.println(start);
}
void loop(){
}

Thời gian: 8 micro giây

4 micro giây

Đọc giá trị 4 nút ấn Game

unsigned long start;
void setup(){
    Serial.begin(9600);
    bool b[4];
    DDRB=B00000000;
    start=micros();
///
    for(byte i=0; i<4; i++){
        b[i]=digitalRead(8+i);
    }
///
    start=micros()-start;
    Serial.println(start);
}

void loop(){
}
unsigned long start;
void setup(){
    Serial.begin(9600);
    bool b[4];
    DDRB=B00000000;
    start=micros();
///
    for( byte i=0; i<4; i++){
        b[i]=PINB&( 1<<i);
    }
///
    start=micros()-start;
    Serial.println(start);
}
void loop(){
}

Thời gian: 16 micro giây

4  micro giây

unsigned long start;
void setup(){
    Serial.begin(9600);
    bool b[4];
    DDRB=B00000000;
    start=micros();
///
   b[0]=digitalRead(8);
   b[1]=digitalRead(9);
   b[2]=digitalRead(10);
   b[3]=digitalRead(11);
///
    start=micros()-start;
    Serial.println(start);
}
void loop(){
}

 

unsigned long start;
void setup(){
    Serial.begin(9600);
    bool b[4];
    DDRB=B00000000;
    start=micros();
///
    
        b[0]=PINB&B00000001;
        b[1]=PINB&B00000010;
        b[2]=PINB&B00000100;
        b[3]=PINB&B00001000;
    
///
    start=micros()-start;
    Serial.println(start);
}
void loop(){
}

 

Không dùng for,Thời gian: 16 micro s  Không dùng for,4 micro s

 

 

 

Đọc giá trị digital trên 16 pin.

unsigned long start;
void setup(){
    Serial.begin(9600);
    DDRD=255;// = B11111111
    PORTD=255;//INTPUT PULLUP
    DDRC=255;// 
    PORTC=255;//INTPUT PULLUP
  byte R1,R2;

    start=micros();
///
    
        R1=PIND;
        R2=PINC;
///
    start=micros()-start;
    Serial.println(start);
}
void loop(){
}

 

4 micro giây

 

analogRead();

Sử dụng 2 điện trở mắc nối tiếp làm cầu phân áp, đọc giá trị điện áp bằng chân A0

 

void setup(){
    pinMode(A0,INPUT);
    Serial.begin(9600);
}

unsigned long start;
unsigned int ana;
void loop(){
    start=micros();
///
    ana=analogRead(0);
///
    start=micros()-start;
    Serial.println(start);
    Serial.println(ana);
    delay(2000);
}

 

void setup(){
    pinMode(A0,INPUT);
    Serial.begin(9600);
    ADCSRA = ((ADCSRA&(B11111000)) | B00000010);
    // Cài tần số quét 4mhz
}
unsigned long start;
unsigned int ana;
void loop(){
    start=micros();
///
    ana=analogRead(0);
///
    start=micros()-start;
    Serial.println(start);
    Serial.println(ana);
    delay(2000);
}

Tần số của bộ đếm ADC mặc định: 125khz

Ana=506;

Thời gian: 116 micro giây

Tần số của bộ đếm ADC:  4mhz
  • Ana=507;
  • Thời gian :8 micro giây ( nhanh hơn 14 lần)
Tần số 1mhz:
  • Ana=506;
  • Thời gian: 16 micro giây

 

Tốc độ lấy mẫu rất nhanh, rất thích hợp với các dự án liên quan đến analogRead().

Sử dụng 2 điện trở khác, mình dùng cả 4 chân analog A->A3 để đo.

 

unsigned long start;
uint16_t val[4];
void setup(){  
DDRC=B00000000;//cho tiện ha
Serial.begin(9600);
//// ADCSRA = ((ADCSRA&(B11111000)) | B00000010);
}
void loop(){
start=micros();
///
for(byte i=0; i<4; i++){
val[i]=analogRead(i);
}
///
start=micros()-start;
Serial.println(start);
for(byte i=0; i<4; i++){
Serial.print(val[i]);
Serial.print("|");
}
delay(2000);
}

 

unsigned long start;
uint16_t val[4];
void setup(){  
DDRC=B00000000;//cho tiện ha
Serial.begin(9600);
ADCSRA = ((ADCSRA&(B11111000)) | B00000010);
// Cài tần số quét 4mhz
}
void loop(){
start=micros();
///
for(byte i=0; i<4; i++){
val[i]=analogRead(i);
}
///
start=micros()-start;
Serial.println(start);
for(byte i=0; i<4; i++){
Serial.print(val[i]);
Serial.print("|");
}
delay(2000);
}

 

Tần số của bộ đếm ADC mặc định: 125khz

 

Thời gian: 448 us.

val[0]=val[1]=val[2]=val[3]=178.

Tần số của bộ đếm ADC:  4mhz

 

Thời gian: 24 us. (nhanh hơn 18 lần)

val[0]=val[1]=val[2]=val[3]=177.

Tạm kết.

Dưới đây là test của anh John Boxall về tốc độ điều khiển chân port.

 

http://tronixstuff.com/2011/10/22/tutorial-arduino-port-manipulation/

Hẳn là có bạn vẫn còn nghi ngờ kết quảdevil. Hihi.Các bạn hãy test lại nhé.

Hãy tìm mọi cách để đảo ngược tình thế nhé, có thể đấy.enlightened

Các code trên còn là các ví dụ mẫu cho các bạn tham khảo.

Việc điều khiển các chân port là không khó. Nó đem lại cho ta nhiều lợi ích tuyệt vời, không những Full Speed mà còn tiết kiệm dung lượng code . Bạn hãy tìm hiểu cách điều khiển port tại đây:

link: Điều khiển pin bằng ngôn ngữ chính thống .

Tác giả:  Thái Sơn.

wink

lên
24 thành viên đã đánh giá bài viết này hữu ích.
Các dự án được truyền cảm hứng

Select any filter and click on Apply to see results

Các bài viết cùng tác giả

Bộ lọc Kalman – giải pháp chống nhiễu tuyệt vời cho mọi dự án sử dụng cảm biến

Rõ ràng khi ta sử dụng cảm biến, giá trị trả về từ  chúng luôn thay đổi quanh vị trí cân bằng dù là rất nhỏ, và bạn biết nguyên nhân của hiện tượng này  là do nhiễu, bạn luôn muốn loại bỏ nhiễu nhưng việc đó dường như ngoài tầm với của bạn.(-.-)… Đừng lo, chúng ta đã có giải pháp, bấm đọc bài viết này thôi nào!

lên
41 thành viên đã đánh giá bài viết này hữu ích.

AVR-Xuất xung với tần số và độ rộng theo ý muốn

Tiếp tục chuỗi bài: Điều khiển pin bằng ngôn ngữ chính thống. 

Bài viết này sẽ giúp bạn tạo một xung PWM có tần số và độ rộng xung theo ý muốn. 

lên
16 thành viên đã đánh giá bài viết này hữu ích.