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?
Cách lưu trữ biến số, mảng, chuỗi Arduino Tại bạn cần đọc viết này? Bạn có tự hỏi biến số, biến chuỗi hay biến mảng lâu đâu Arduino chưa? Trước kia, nghĩ rằng, lưu vùng nhớ flash, nơi lưu trữ code mà tải lên Nhưng khơng, bình thường lưu RAM! Vậy RAM (viết tắt từ Random Access Memory) gì? Nó chữ viết tắt loại nhớ máy tính (Arduino xem máy tính) Như hết RAM, chương trình bạn crash (hư – đỗ vỡ,…) cách bất ngờ mà bạn không tài debug (nếu bạn chưa đọc – nội dung tương đương) Vậy, thiết nghĩ, cần nắm rõ chất vấn đề Nó thật thú vị phải khơng nào? Nội dung cần nắm • Biết biến mà bạn khai báo lưu trữ đâu? • Các vùng nhớ RAM • o Vùng heap, stack o Vùng tĩnh (static) Chuỗi lưu trữ RAM Atmega328? Lưu ý: Tác giả sử dụng chương trình Arduino IDE phiên 1.0.4 nên bạn thực hành IDE khác số lượng RAM trống bị chênh lệch vài chục KB Điều khơng cả, sau, thư viện Serial Software Arduino ngày nâng cấp gọt tỉa dung lượng tỉ mỉ Các loại nhớ thơng dụng Arduino Thứ nhất, nói đến Arduino hầu hết nghĩ đến vi điều khiển Atmega328 (vđk), vđk có đến 32KB flash (đã bao gồm bootloader), nơi lý tưởng cho việc lập trình ứng dụng nhúng mơi trường lập trình Arduino Để sử dụng hết 32KB đòi hỏi code bạn phải cực kỳ nặng (tính theo số dịng code) Mình thử sử dụng hết 32KB flash file sketch nặng đến MB! Bạn có muốn thử khơng nào? Một điều may mắn cho Arduino IDE cho ta biết xác đến byte nhớ flash mà sketch bạn sử dụng (giống xác đến nano mét việc thiết kế vi xử lý ^_^) Thứ hai, thiết nghĩ, có lẻ, nhớ EEPROM, việc sử dụng hết dung lượng nhớ EEPROM Atmega328 (lên đến 512 byte) điều khó xảy ra! Có chữ ROM nên bạn tạm xem nhớ ROM (Read Only Memory) Arduino, hay bạn chỉnh giá trị ô nhớ EEPROM Bạn nên tham khảo thư viện EEPROM để thơng tin phần Cuối cùng, nhớ RAM Từ trước giờ, mua máy vi tính, thơng số RAM, tốc độ xử lý, core i5, i7,… quan tâm hàng đầu Nhưng nhảy qua loại “super mini computer” Arduino, lại không trọng nhiều đến thông số tương tự RAM, tốc độ xử lý,… mà quan tâm đến dung lượng nhớ flash Đồng ý với bạn dung lượng nhớ flash quan trọng nhất, khơng lưu code nói đến việc sử dụng RAM Nhưng RAM khơng cạnh gì, thiết nghĩ so sánh mức độ quan trọng Arduino RAM đứng sau nhớ flash, ROM Ram nơi lưu giữ biến, trỏ, trình thực thi hàm,… dung lượng hạn chế Trên Atmega328, dung lượng RAM / 16 so với dung lượng flash Khác với hai loại nhớ trên, nhớ RAM dễ bị thiếu hụt, điều hay xảy ra! Và xảy … bạn biết đấy, sketch bạn Arduino bị “dừng” cách đột ngột mà bạn debug code đến cỡ khơng lỗi, bạn nắm vững Bộ nhớ RAM Arduino, phân chia nào? Có ba vùng nhớ RAM vi điều khiển họ AVR (trong có dịng Atmel, cụ thể viết Atmega328 – gắn sẵn bé Arduino UNO R3): Static data, vùng nhớ tĩnh, bao gồm biến toàn cục, mảng kiểu chuỗi (string) 2 Vùng “heap”, vùng dùng để lưu biến trỏ, dùng xóa bạn gọi hàm malloc() free() Vùng “stack”, vùng dùng để lưu trữ biến, giá trị hàm gọi hàm khác (Đó lý người ta có khái niệm “khử đệ quy” mục đích tiết kiệm RAM) Vùng “heap” tăng lên sử dụng cách thức “ép không chắn đều” Nghĩa là, bạn giải phóng vùng nhớ, sau vđk trỏ vùng nhớ “vừa giải phóng” đó, vùng nhớ sử dụng có hàm malloc() gọi đòi cấp vùng nhớ “vừa khít” (bằng nhỏ hơn) với kích thước “vùng nhớ” giải phóng Ví dụ: xem số vùng nhớ trống heap, số vùng nhớ sử dụng heap Giả sử vùng heap chưa dùng có dạng 0000000000000000… sau thời gian dùng giải phóng có dạng 0001111000011111…, ta giải phóng (free) vùng nhớ thứ - ô nhớ sử dụng heap, trỏ heap trỏ vệ vị trí byte thứ (bắt đầu từ byte thứ tính từ trái qua phải) Bây giờ, ta yêu cầu byte hàm malloc() cấp ta vùng nhớ vừa bị xóa byte thừa có “trở nên dư thừa” khơng dùng đến Cịn ta u cầu lớn byte, trỏ heap trỏ vùng nhớ đáp ứng yêu cầu bạn gần (phần chưa rõ) Các vùng nhớ dư thừa bị bỏ gọi “unused memory” Lưu ý: bạn nên xem hình sau để ý vào vùng heap stack để biết cách vđk AVR lưu trữ chúng Một điểm hay vđk AVR cung cấp nhiều biến hệ thống mà từ bạn biết thông tin vùng nhớ RAM Trong đó, có biến biến trỏ brkval Nó cho bạn biệt “độ phình” vùng heap, tức vị trí cực đại vùng heap Vùng nhớ stack xác định cuối RAM, mở rộng 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 rõ Vùng nhớ stack sử dụng giải phóng (nếu cần) trình hàm gọi hàm khác Đây nơi biến cục (local variable) lưu trữ Làm để tiết kiệm RAM Arduino? Việc quan trọng nhà thiết kế tài ba họ không để chương trình sử dụng ram cách “ngấu nghiến” “vô vội vạ” Và coder Arduino nghệ nhân thực thụ (RAM Arduino có 2KB) Dưới hàm nho nhỏ để biết RAM free int getMemoryFree() { // Trong trường hợp này, ta hiểu extern khai báo biến toàn cục chương trình (nếu chưa có) include biến tồn cục extern trước extern int heap_start; extern int * brkval; //Dấu & phía trước tên biến / tên trỏ cho ta biết vị trí nhớ mà đứng //Lưu ý: viết không dành cho beginner bạn cần tưởng tượng chút để mườn tượng vấn đề return (int) SP - ( brkval == ? (int) & heap_start : (int) brkval); } Bây bạn thêm đoạn code sau bật Serial Monitor lên để xem số lương RAM chương trình sử dụng void setup () { Serial.begin(9600); Serial.println("Free Mem: "); Serial.println(getMemoryFree()); } void loop () {/*do nothing*/} Như vậy, khoảng 1,8 KB RAM trống đoạn chương trình ngắn “chút chỉn” Mà sketch chẳng có làm nhiệm vụ hết ăn chúng hết 2048 – 1832 = 216 byte RAM (trong 128 byte cho phần đệm serial, bạn xem thêm datasheet Atemega328 muốn tìm hiểu thêm nhé) Và hàm trả giá trị 0, chương trình bạn “đứng cứng ngắt”, thử xem! Gợi ý: bạn xay dựng vịng lặp vơ tận, chạy lệnh tính tốn phức tạp (số thực,…) Hoặc đơn giản vòng đệ quy liên tục! Nào làm số thay đổi nhỏ đoạn code trên: Serial.println("Free Mem(test 2): "); Kết quả, ta được: Free Mem(test 2): 1824 Có thể thấy lượng nhớ cho RAM giảm! Như vậy, bạn yêu cầu thêm RAM thay đổi đoạn text để in Serial Monitor Nhận xét: Tất chuỗi C lưu RAM Điều giải thích thêm ký tự đơn vào chuỗi ăn bớt lượng RAM khơng nhỏ Chuỗi lưu vào nhớ flash Bạn thử xóa chữ test thay vào test2 (tức xóa ký tự khoảnh trống) Nhưng dung lượng flash sau tải code lên vđk Atmega328 không đổi, thử tiếp lần xóa ký tự số 2, ta thấy dung lượng flash bị giảm byte Điều cho thấy nhớ flash lưu trữ theo kiểu 2-byte (word), tức ô nhớ byte! Kết luận Hãy cẩn thận “thả” message thông báo cho dịng code, điều dẫn đến việc sử dụng RAM cách lãng phí Ngồi ra, cịn gây nhiều vấn đề bạn nghĩ Vì vậy, nghệ sĩ thơng minh! Vậy để chương trình bạn khơng cịn tốn nhiều RAM nữa! Hãy đợi viết sau nhé, bật mí cho bạn cách làm điều đó! ... (phần chưa rõ) Các vùng nhớ dư thừa bị bỏ gọi “unused memory” Lưu ý: bạn nên xem hình sau để ý vào vùng heap stack để biết cách vđk AVR lưu trữ chúng Một điểm hay vđk AVR cung cấp nhiều biến hệ thống... Đây nơi biến cục (local variable) lưu trữ Làm để tiết kiệm RAM Arduino? Việc quan trọng nhà thiết kế tài ba họ không để chương trình sử dụng ram cách “ngấu nghiến” “vô vội vạ” Và coder Arduino. .. free() Vùng “stack”, vùng dùng để lưu trữ biến, giá trị hàm gọi hàm khác (Đó lý người ta có khái niệm “khử đệ quy” mục đích tiết kiệm RAM) Vùng “heap” tăng lên sử dụng cách thức “ép không chắn đều”