Bộ nhớ flash lưu dữ liệu trong avr là gì năm 2024

Uploaded by

Thế Vĩ

0% found this document useful (0 votes)

245 views

98 pages

Copyright

© © All Rights Reserved

Available Formats

PDF, TXT or read online from Scribd

Share this document

Did you find this document useful?

Is this content inappropriate?

0% found this document useful (0 votes)

245 views98 pages

VXL CHG 2 3

Uploaded by

Thế Vĩ

Jump to Page

You are on page 1of 98

Search inside document

Reward Your Curiosity

Everything you want to read.

Anytime. Anywhere. Any device.

No Commitment. Cancel anytime.

Bộ nhớ flash lưu dữ liệu trong avr là gì năm 2024

Bộ nhớ EEPROM song song: Các thiết bị EEPROM song song thường có bus rộng 8 bit. Sử dụng một bus song song cho phép nó bao phủ hoàn chỉnh bộ nhớ của nhiều ứng dụng vi xử lý nhỏ hơn. Thông thường, các thiết bị có các chân bảo vệ ghi và chọn chip và một số vi điều khiển được sử dụng có một EEPROM song song tích hợp để lưu trữ phần mềm. Tốc độ của EEPROM song song nhanh hơn nhiều so với tốc độ của EEPROM nối tiếp, và hoạt động cũng đơn giản hơn so với EEPROM nối tiếp. Nhược điểm là các EEPROM song song lớn hơn do số lượng chân nhiều hơn. Ngoài ra, loại này đang giảm dần mức độ phổ biến so với EEPROM nối tiếp hoặc bộ nhớ flash do sự tiện lợi và chi phí.

Hãy nhớ rằng EEPROM thường chỉ được sử dụng để thực hiện các tác vụ ngắn gọn, thường là trong quá trình khởi động thiết bị. Nó chạy ở tốc độ khiêm tốn và ít khi bị sử dụng cho thao tác ghi dài dòng nào. Khi tính đến những cân nhắt này, người dùng có thể đặt câu hỏi về giá trị của việc lựa chọn bộ nhớ EEPROM song song thay vì bộ nhớ EEPROM nối tiếp Đọc và lập trình EEPROM Bộ lập trình EEPROM là một thiết bị được sử dụng để ghi dữ liệu hay chương trình vào module bộ nhớ thích hợp cho phép nó thực hiện các hoạt động cần thiết. Tùy thuộc vào kiểu máy và thương hiệu, các nhà lập trình EEPROM có thể cho phép người dùng định cấu hình chip bằng cách cắm nó vào trên chính thiết bị hoặc bằng cách gắn thiết bị với PCB (bảng mạch in) đã được cài đặt EEPROM. Tương tự, đầu đọc EEPROM là thiết bị được sử dụng để đọc dữ liệu đã được lập trình trên mô-đun bộ nhớ và thường được kết nối thông qua cùng một phạm vi giao diện.

Bộ nhớ flash lưu dữ liệu trong avr là gì năm 2024

Trong bài Tiết kiệm RAM trong Arduino?, chúng ta đã biết cách lưu chuỗi hằng vào bộ nhớ FLASH thay cho việc lưu hết bọn chúng vào RAM. Như vậy, một hằng chuỗi có thể được lưu vào bộ nhớ FLASH thay vì lưu vào RAM. Vậy, câu hỏi đặt ra là, những biến hằng khác (hằng số, hẳng mảng, hẳng số thực) có thể được lưu vào FLASH thay vì vào RAM hay không?

Trong thực tế, các biến hằng (trừ hằng chuỗi) hầu hết chỉ tốn vài chục byte để lưu trữ nên RAM, nên chúng ta cũng chưa gặp vấn đề gì trong việc lưu trữ hằng số hay hằng mảng cả. Nhưng thỉnh thoảng, có những lúc, ta phải tìm cách lưu trữ chúng ở một nơi khác, ví dụ Bài 12: Phát nhạc bằng Arduino với một cái loa hoặc buzzer.

Chần chừ gì nữa, biết muốn phám khá khả năng của Arduino - hay không?

Những điều bạn sẽ rút ra được từ bài này

  1. Hiểu vì sao vùng nhớ dữ liệu trong bộ nhớ FLASH chỉ có thể lưu biến hằng
  2. Lưu trữ hằng số, hằng mảng vào RAM

Lưu ý, các bạn nên đọc chuỗi bài Cách lưu trữ các biến số, mảng, chuỗi trong Arduino và Tiết kiệm RAM trong Arduino? để có một số kiến thức nền tảng và xây dựng sự hứng thú "tột đỉnh" khi đọc bài viết này!

Đặt vấn đề

Trong 2 bài viết trước (Cách lưu trữ các biến số, mảng, chuỗi trong Arduino và Tiết kiệm RAM trong Arduino?), chúng ta đã biết được có thể di chuyển việc lưu trữ biến và hàm; biết được làm thế nào để giảm thiểu sự tiêu thụ RAM trong khai báo chuỗi. Và từ những nhận xét, kết luận rút ra được, chắc hẳn, bạn cũng muốn xem bộ nhớ FLASH còn những gì hay ho nữa, đúng không nào?

Từ bài viết Tiết kiệm RAM trong Arduino?, chúng ta biết được rằng, chúng ta có thể lưu trữ các hằng chuỗi trong bộ nhớ FLASH nhằm tiết kiệm một lượng lớn RAM, mà chưa đề cập đến việc "có thể lưu trữ được những biến số khác hay không". Vậy rốt cuộc là nó có thể hay không? Đó là câu hỏi mà bạn và tôi có lẻ đang đau đáu muốn trả lời, bởi vì, chúng ta có một điểm chung đó là muốn khám phá những điều mới mẻ mà từ trước đây chúng ta chưa biết.

Vì sao chỉ có thể lưu BIẾN HẰNG trong FLASH

Như đã nói ở bài trước, bộ nhớ FLASH có một phần nào đó giống như bộ nhớ ROM của máy tính. Nó chính là nơi lưu giữ liệu sketch của bạn. Và nó chỉ bị thay đổi khi bạn upload một sketch mới lên mà thôi. Như vậy, khi một sketch đã được bạn upload lên vđk thì nó không thể bị thay đổi hoặc mất. Tương tự, vì các biến của bạn đã được lưu lên flash thì ta chỉ có thể truy cập đến nó mà không thể sửa chữa (trừ phi bạn upload sketch mới với những biến hằng mới)

Cách lưu trữ

Cũng giống như lưu trữ string trong RAM, đầu tiên bạn phải include thư viện avr/pgmspace.h vào sketch của bạn.

include

Sau đó, bạn chỉ cần thêm từ khóa PROGMEM vào sau tên biến, hoặc tên mảng là bạn đã có một biến hằng được lưu vào FLASH mà chẳng tốn một ô nhớ nào trong RAM rồi!

PROGMEM = ; [] PROGMEM = ; //Ví dụ: int HOURS_PER_DAY PROGMEM = 123; int array[] PROGMEM = {0, 1, 2}; unsigned long TIME_IN_DAY PROGMEM = 86400;

Lưu ý

Chỉ có các kiểu số nguyên (int, long, long long, ...), kiểu char và các kiểu mảng một chiều của các dữ liệu nói trên mới được lưu trữ trong bộ nhớ FLASH.

Ví dụ thử nghiệm

include

int HOURS_PER_DAY PROGMEM = 123; int array[] PROGMEM = {0, 1, 2}; int ch[] PROGMEM = {'a', 'b'}; unsigned long TIME_IN_DAY PROGMEM = 86400; int getMemoryFree() { // 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 đó extern int __heap_start; extern int *__brkval; //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 //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 đề return (int) SP - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); } void setup () { Serial.begin(9600);// Khởi động Serial ở mức baudrate 9600 Serial.println(getMemoryFree()); Serial.println(TIME_IN_DAY); Serial.println(HOURS_PER_DAY); Serial.println(array[0]); Serial.println(array[1]); Serial.println(array[2]); Serial.println(char(ch[0])); } void loop () {}

Tuy nhiên, nếu bạn dùng một biến đếm để in giá trị như trong ví dụ sau:

include

const int array1[] PROGMEM = {1, 10, 100}; const int array2[] PROGMEM = {1, 11, 111, 1111}; void setup () { Serial.begin(9600);// Khởi động Serial ở mức baudrate 9600 / In tung gia tri / Serial.println("Ko dung vong lap"); Serial.println(array1[0]); Serial.println(array1[1]); Serial.println(array1[2]); Serial.println(array2[0]); Serial.println(array2[1]); Serial.println(array2[2]); Serial.println(array2[3]); / In dung vong lap / Serial.println("Dung vong lap"); for (int i = 0; i < 3; i++)

Serial.println(array1[i]);
for (int j = 0; j < 4; j++)
Serial.println(array2[j]);
} void loop () {}

thì sẽ bị lỗi lúc In dùng vòng lặp. Lý do thì mình không rõ, tuy nhiên khi bạn truy xuất bằng chỉ số như lúc In từng giá trị thì lại bình thường. Như vậy, chẳng lẻ, chúng ta không có giải pháp nào khác để print nó ra hay sao? Câu trả lời cho bạn là có, chúng ta có giải pháp.

Như ở bài trước Tiết kiệm RAM trong Arduino?, chúng ta đã biết được cách in một chuỗi được lưu trong bộ nhớ Flash ra Serial. Tương tự, ta cũng sẽ dùng cách đó với những biến PROGMEM.

include

const int array1[] PROGMEM = {1, 10, 100}; const int array2[] PROGMEM = {1, 11, 111, 1111}; void setup () { Serial.begin(9600);// Khởi động Serial ở mức baudrate 9600 / In tung gia tri / Serial.println("Ko dung vong lap"); Serial.println(array1[0]); Serial.println(array1[1]); Serial.println(array1[2]); Serial.println(array2[0]); Serial.println(array2[1]); Serial.println(array2[2]); Serial.println(array2[3]); / In dung vong lap / Serial.println("Dung vong lap"); for (int i = 0; i < 3; i++)

Serial.println(pgm_read_word(array1 + i)); // array1 + i Con trỏ tới vị trí thứ i của mảng array1
for (int j = 0; j < 4; j++)
Serial.println(pgm_read_word(array2+j));
} void loop () {}

Hàm pgm_read_word có nhiệm vụ gì?

Trong bài viết tiết kiệm RAM, chúng ta đã dùng hàm pgm_read_byte để đọc được từng byte (từng char) từ con trỏ chuỗi và trả về byte đó. Vậy pgm_read_word sẽ có nhiệm vụ đọc từng word (2 byte) từ một con trỏ và trả về một word. Vậy tại sao không dùng pgm_read_byte mà lại dùng pgm_read_word? Bởi vì, kiểu int trong Arduino UNO sử dụng 2 byte để lưu trữ, vì vậy ta dùng hàm pgm_read_word để đọc được 2 byte đó. Nhưng, từ từ, 2 byte đó sẽ là một kiểu word... như vậy thì khi biểu diễn số âm thì sao, nó sẽ bị tràn số. Như vậy, ta phải ép kiểu trả về pgm_read_word là int như code sau để tránh bị lỗi tràn số.

include

const int array1[] PROGMEM = {1, 10, 100}; const int array2[] PROGMEM = {1, 11, 111, 1111}; void setup () { Serial.begin(9600);// Khởi động Serial ở mức baudrate 9600 / In tung gia tri / Serial.println("Ko dung vong lap"); Serial.println(array1[0]); Serial.println(array1[1]); Serial.println(array1[2]); Serial.println(array2[0]); Serial.println(array2[1]); Serial.println(array2[2]); Serial.println(array2[3]); / In dung vong lap / Serial.println("Dung vong lap"); for (int i = 0; i < 3; i++)

Serial.println(int(pgm_read_word(array1 + i))); // array1 + i Con trỏ tới vị trí thứ i của mảng array1
for (int j = 0; j < 4; j++)
Serial.println(int(pgm_read_word(array2+j))); // hot fix
} void loop () {}

Yeah, rất cảm ơn anh NTP_PRO đã giúp em tìm ra "con bọ" này và hoàn thiện hơn nữa bài viết của mình.

Mở rộng, để đọc được các biến hằng kiểu long thì bạn dùng hàm pgm_read_dword nhé. Vậy còng long long

Bộ nhớ flash lưu dữ liệu trong avr là gì năm 2024
. Bạn hãy thử nghĩ và tìm hiểu thêm xem.

Kết luận

FLASH và RAM đều có những ưu và nhược điểm riêng, và là một người nghệ sĩ, bạn sẽ phải là người uyển chuyển dung hòa ưu nhược của chúng nhằm tạo một kiệt tác hoàn hảo. Mong rằng, qua một trick nhỏ như vầy, sẽ giúp bạn xây dựng một hệ thống lớn trong tương lai!