1. Trang chủ
  2. » Kỹ Thuật - Công Nghệ

Cách lưu trữ các biến số, mảng, chuỗi trong Arduino

6 3 0

Đang tải... (xem toàn văn)

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 6
Dung lượng 62,94 KB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

Bạn có bao giờ tự hỏi những biến số, biến chuỗi hay biến mảng của mình được lâu ở đâu trên Arduino chưa? Trước kia, mình từng nghĩ rằng, nó được lưu ở vùng nhớ flash, nơi lưu trữ code mà chúng ta tải lên. Nhưng không, bình thường nó được lưu ở RAM Vậy RAM (viết tắt từ Random Access Memory) là gì? Nó là chữ viết tắt của một loại bộ nhớ chính của máy tính (Arduino cũng có thể xem là một máy tính). Như vậy nếu hết RAM, chương trình của bạn sẽ crash (hư – đỗ vỡ,…) một cách bất ngờ mà bạn không tài nào debug được (nếu bạn chưa đọc về bài này – hoặc những nội dung tương đương). Vậy, thiết nghĩ, chúng ta cần nắm rõ hơn bản chất của vấn đề này. Nó thật thú vị phải không nào?

Trang 1

Cách lưu trữ các biến số, mảng, chuỗi trong Arduino

Tại sao bạn cần đọc bài viết này?

Bạn có bao giờ tự hỏi những biến số, biến chuỗi hay biến mảng của mình được lâu ở đâu trên Arduino chưa? Trước kia, mình từng nghĩ rằng, nó được lưu ở vùng nhớ flash, nơi lưu trữ code

mà chúng ta tải lên Nhưng không, bình thường nó được lưu ở RAM!

Vậy RAM (viết tắt từ Random Access Memory) là gì? Nó là chữ viết tắt của một loại bộ nhớ chính của máy tính (Arduino cũng có thể xem là một máy tính) Như vậy nếu hết RAM, chương trình của bạn sẽ crash (hư – đỗ vỡ,…) một cách bất ngờ mà bạn không tài nào debug được (nếu bạn chưa đọc về bài này – hoặc những nội dung tương đương)

Vậy, thiết nghĩ, chúng ta cần nắm rõ hơn bản chất của vấn đề này Nó thật thú vị phải không nào?

Nội dung cần nắm

Biết được các biến mà bạn khai báo được lưu trữ ở đâu?

Các vùng nhớ trong RAM

o Vùng heap, stack

o Vùng tĩnh (static)

Chuỗi được lưu trữ như thế nào trong RAM của Atmega328?

Lưu ý: Tác giả sử dụng chương trình Arduino IDE phiên bản 1.0.4 nên khi các bạn thực hành

trên các bản IDE khác số lượng RAM còn trống có thể bị chênh lệch vài chục KB Điều đó

Trang 2

không sao cả, vì càng về sau, thư viện Serial Software của Arduino ngày càng được nâng cấp và được gọt tỉa dung lượng rất tỉ mỉ

Các loại bộ nhớ thông dụng trong Arduino

Thứ nhất, khi nói đến Arduino thì hầu hết chúng ta nghĩ đến vi điều khiển Atmega328 (vđk), con vđk này có đến 32KB flash (đã bao gồm bootloader), là một nơi rất lý tưởng cho việc lập trình ứng dụng nhúng trên môi trường lập trình Arduino Để sử dụng hết 32KB này thì đòi hỏi code của bạn phải cực kỳ cực kỳ nặng (tính theo số dòng code) Mình đã từng thử sử dụng hết

32KB flash này bằng một file sketch nặng đến cả MB! Bạn có muốn thử không nào?

Một điều khá may mắn cho chúng ta là Arduino IDE cho ta biết đúng chính xác đến từng byte bộ nhớ flash mà sketch của bạn sử dụng (giống như chính xác đến từng nano mét trong việc thiết kế

vi xử lý vậy ^_^)

Thứ hai, thiết nghĩ, có lẻ, đó là bộ nhớ EEPROM, và việc sử dụng hết dung lượng nhớ EEPROM của Atmega328 (lên đến 512 byte) cũng là một điều khó có thể xảy ra! Có chữ ROM

nên bạn có thể tạm xem nó như là bộ nhớ ROM (Read Only Memory) trên Arduino, nhưng cái

hay của nó là bạn có thể chỉnh được giá trị trong từng ô nhớ của EEPROM Bạn nên tham khảo thư viện EEPROM để có thể thông tin về phần này

Cuối cùng, đó là bộ nhớ RAM Từ trước giờ, khi mua một chiếc máy vi tính, thông số về RAM,

tốc độ xử lý, core i5, i7,… luôn được chúng ta quan tâm hàng đầu Nhưng khi nhảy qua một loại

“super mini computer” như Arduino, chúng ta lại không chú trọng nhiều đến những thông số tương tự như RAM, tốc độ xử lý,… mà chỉ còn quan tâm đến dung lượng bộ nhớ flash Đồng ý với bạn là dung lượng bộ nhớ flash cực kỳ quan trọng nhất, vì không lưu được code thì nói gì đến việc sử dụng RAM Nhưng RAM cũng không kém cạnh gì, và thiết nghĩ nếu so sánh về mức

độ quan trọng trên Arduino thì RAM chỉ đứng sau bộ nhớ flash, kế đến là ROM

Ram là nơi lưu giữ các biến, con trỏ, quá trình thực thi hàm,… và dung lượng của nó cũng khá là hạn chế Trên Atmega328, dung lượng của RAM chỉ bằng 1 / 16 so với dung lượng flash

Khác với hai loại bộ nhớ trên, bộ nhớ RAM rất dễ bị thiếu hụt, và điều này rất hay xảy ra! Và một khi nó xảy ra thì … bạn biết đấy, sketch của bạn trên Arduino sẽ bị “dừng” một cách đột ngột mà bạn debug code đến cỡ nào nó cũng không ra lỗi, cho đến khi bạn nắm vững bài này

Bộ nhớ RAM trong Arduino, nó phân chia như thế nào?

Có ba vùng nhớ trên RAM của mọi vi điều khiển họ AVR (trong đó có các dòng Atmel, cụ thể trong bài viết này là Atmega328 – được gắn sẵn trên các bé Arduino UNO R3):

1. Static data, vùng nhớ tĩnh, bao gồm các biến toàn cục, mảng và cả kiểu chuỗi nữa (string)

Trang 3

2. Vùng “heap”, vùng này dùng để lưu các biến con trỏ, nó được dùng và xóa khi bạn gọi

hàm malloc() và free().

3. Vùng “stack”, vùng này dùng để lưu trữ các biến, giá trị khi một hàm này gọi một hàm

khác (Đó là lý do vì sao người ta có khái niệm “khử đệ quy” vì mục đích tiết kiệm RAM) Vùng “heap” sẽ tăng lên và được sử dụng trong một cách thức “ép không chắc chắn đều” Nghĩa

là, khi bạn giải phóng một vùng nhớ, sau đó vđk sẽ trỏ về vùng nhớ “vừa được giải phóng” đó,

và vùng nhớ này sẽ được sử dụng nếu có một hàm malloc() gọi và đòi được cấp một vùng nhớ

“vừa hoặc khít” (bằng hoặc nhỏ hơn) với những kích thước “vùng nhớ” được giải phóng Ví dụ:

chúng ta sẽ xem những con số 0 là vùng nhớ trống trong heap, và số 1 là vùng nhớ đã sử dụng

trong heap Giả sử vùng heap chưa được dùng và có dạng 0000000000000000… và sau một thời

gian nó được dùng và giải phóng nó có dạng 0001111000011111…, bây giờ ta giải phóng (free)

vùng nhớ thứ nhất - 4 ô nhớ đã sử dụng đầu tiên trong heap, thì con trỏ heap sẽ trỏ vệ vị trí byte thứ 3 (bắt đầu từ byte thứ 0 tính từ trái qua phải) Bây giờ, nếu ta yêu cầu ít hơn hoặc bằng 4 byte

bởi hàm malloc() thì nó sẽ cấp ta đúng vùng nhớ vừa bị xóa và những byte thừa nếu có sẽ “trở

nên dư thừa” và không được dùng đến nữa Còn khi ta yêu cầu lớn hơn 4 byte, thì con trỏ heap sẽ được trỏ về vùng nhớ nào đáp ứng được yêu cầu của bạn gần nhất có thể được (phần này mình cũng chưa rõ) Các vùng nhớ dư thừa bị bỏ ra gọi là “unused memory”

Lưu ý: bạn nên xem hình sau và để ý vào vùng heap và stack để biết cách các vđk AVR lưu trữ chúng.

Một điểm hay của vđk AVR đó là cung cấp rất nhiều biến hệ thống mà từ đó bạn có thể biết được các thông tin về các vùng nhớ của RAM Trong đó, có một biến khá hay đó là biến con trỏ

brkval Nó sẽ chỉ cho bạn biệt “độ phình” của vùng heap, tức là vị trí cực đại của vùng heap.

Vùng nhớ stack được xác định ở cuối RAM, nó được mở rộng và rút ngắn ngược hướng với cách

mà heap làm! Bạn nhìn hình mũi tên ở hình trên là rõ ngay Vùng nhớ stack được sử dụng và được giải phóng (nếu cần) trong quá trình hàm này gọi một hàm khác Đây cũng là nơi các biến cục bộ (local variable) được lưu trữ

Làm thế nào để tiết kiệm RAM trên Arduino?

Trang 4

Việc quan trọng của một nhà thiết kế tài ba là họ không bao giờ để chương trình của mình sử dụng ram một cách “ngấu nghiến” và “vô vội vạ” Và những coder Arduino là những nghệ nhân thực thụ (RAM trên Arduino chỉ có 2KB)

Dưới đây là một hàm nho nhỏ để biết chúng ta còn bao nhiêu RAM free

1 int getMemoryFree() {

2 // Trong trường hợp này, ta có thể hiểu extern sẽ khai báo một biến toàn cục trong chương trình (nếu chưa có) hoặc include một biến toàn cục đã được extern trước đó

3 extern int heap_start;

4 extern int * brkval;

5

6 //Dấu & phía trước tên biến / tên con trỏ sẽ cho ta biết vị trí

ô nhớ mà nó đang đứng

7 //Lưu ý: bài viết này không dành cho beginner và bạn cần tưởng tượng một chút để có thể mườn tượng vấn đề

8 return (int) SP - ( brkval == 0 ? (int) & heap_start : (int) brkval);

9 }

Bây giờ bạn thêm đoạn code sau và bật Serial Monitor lên để xem số lương RAM chương trình chúng ta đã sử dụng

1 void setup () {

2 Serial.begin(9600);

3 Serial.println("Free Mem: ");

4 Serial.println(getMemoryFree());

5 }

6 void loop () {/*do nothing*/}

Trang 5

Như vậy, chúng ta còn khoảng 1,8 KB RAM còn trống trong một đoạn chương trình ngắn “chút chỉn” Mà cái sketch này chẳng có làm nhiệm vụ gì hết nhưng đã ăn mất của chúng hết 2048 –

1832 = 216 byte RAM (trong đó là 128 byte cho phần đệm serial, bạn xem thêm trong datasheet của Atemega328 nếu muốn tìm hiểu thêm nhé)

Và khi hàm kia trả về giá trị là 0, thì chương trình của bạn sẽ “đứng cứng ngắt”, thử xem! Gợi ý: bạn hãy xay dựng một vòng lặp vô tận, chạy những lệnh tính toán phức tạp (số thực,…) Hoặc đơn giản chỉ là một vòng đệ quy liên tục!

Nào chúng ta sẽ làm một số thay đổi nhỏ trong đoạn code trên:

1 Serial.println("Free Mem(test 2): ");

Kết quả, ta được:

Free Mem(test 2):

1824

Có thể thấy là lượng ô nhớ cho RAM đã giảm! Như vậy, bạn đã yêu cầu thêm RAM khi thay đổi đoạn text để in ra Serial Monitor

Nhận xét:

1. Tất cả các chuỗi trong C được lưu trong RAM Điều đó giải thích vì sao khi thêm các ký tự đơn vào chuỗi trên thì nó đã ăn bớt đi một lượng RAM không hề nhỏ

2. Chuỗi cũng được lưu vào bộ nhớ flash Bạn hãy thử xóa chữ test 2 và thay vào đó

là test2 (tức là xóa đi 1 ký tự khoảnh trống) Nhưng dung lượng flash sau khi tải

Trang 6

code lên vđk Atmega328 vẫn không đổi, thử tiếp một lần xóa đi ký tự số 2, ta thấy dung lượng flash bị giảm đi 2 byte Điều đó cho thấy bộ nhớ flash được lưu trữ theo kiểu 2-byte (word), tức là mỗi ô nhớ là 2 byte!

Kết luận

Hãy cẩn thận khi “thả” những message thông báo cho từng dòng code, vì điều đó sẽ dẫn đến việc sử dụng RAM một cách cực kì lãng phí Ngoài ra, nó còn gây ra nhiều vấn đề hơn những gì bạn nghĩ Vì vậy, hãy là một nghệ sĩ thông minh!

Vậy làm sao để chương trình của bạn không còn tốn nhiều RAM như thế nữa! Hãy đợi bài viết sau nhé, mình sẽ bật mí cho bạn cách làm điều đó!

Ngày đăng: 23/09/2022, 21:30

HÌNH ẢNH LIÊN QUAN

Lưu ý: bạn nên xem hình sau và để ý vào vùng heap và stack để biết cách các vđk AVR lưu trữ chúng. - Cách lưu trữ các biến số, mảng, chuỗi trong Arduino
u ý: bạn nên xem hình sau và để ý vào vùng heap và stack để biết cách các vđk AVR lưu trữ chúng (Trang 3)

TỪ KHÓA LIÊN QUAN

TÀI LIỆU CÙNG NGƯỜI DÙNG

TÀI LIỆU LIÊN QUAN

🧩 Sản phẩm bạn có thể quan tâm

w