BÀI 2 - Sử dụng nhiều ic eeprom 24Cxx cùng lúc

Mô tả dự án: 

Qua bài đầu, mình đã giúp các bạn giải quyết được một vấn đề khá quan trọng trong việc sử dụng EEPROM. Bài này sẽ giúp bạn biết cách ghép nhiều module eeprom để tạo ra Super eeprom như đã hứa.

Bây giờ chúng ta bàn về địa chỉ

Trên 1 Bus i2c  (2 dây) có thể có tới 128 thiết bị khác nhau cùng dùng chung đường dây.

Lúc này, địa chỉ của mỗi thiết bị sẽ giúp arduino (master) tìm đến và giao tiếp truyền nhận với thiết bị đó (slave). Tất nhiên địa chỉ phải của mỗi thiết bị phải khác nhau.

Dùng chung đường dây có nghĩa là các thiết bị (module) sẽ nối song song với nhau trên đường bus chung, điều này làm tiết kiệm đáng kể lượng dây kết nối với arduino/mcu.

Địa chỉ của ic eeprom trên bus do người dùng thiết lập bằng cách đấu nối các chân A0, A1, A2 với mức điện áp 0v/5v .

Địa chỉ xác định bởi 7 bit

1
0
1
0
A2
A1
A0

3 bit đầu là trạng thái của 3 pin

  • Bằng 1: Nối pin đó lên điện áp High (5v)
  • Bằng 0: Nối pin đó xuống điện áp Low (0v)

Nhà sản xuất đã giới hạn khả năng thiết lập địa chỉ với từng ic:

Bảng 1.1. Các trường hợp cụ thể theo từng dòng IC

Tên ic
A2
A1
A0
24c01
X
X
X
24c02
X
X
X
24c04
V
V
X
24c08
V
X
X
24c16
X
X
X
24c32
V
V
V
24c64
V
V
V
24c128
V
V
V
24c256
V
V
V

Với trường hợp X:

Pin không có khả năng thay đổi địa chỉ của ic

Khi đó giá trị tại địa chỉ này mặc định bằng Low(0) bạn được phép để hở chân này, hoặc nối xuống nguồn 0V. Và không được nối chân này lên High(5v).

Với trường hợp V:

Pin khả dụng để thay đổi địa chỉ eeprom bằng cách nối dây.

  • Bằng 1: Nối pin đó lên điện áp High (5v)
  • Bằng 0: :Nối pin đó xuống điện áp Low (0v)

Trường hợp chung để suy ra địa chỉ: 1010A2A1A0 rồi đổi sang hex.

Bảng 2.1. Ánh xạ giá trị của cặp A0,A1,A2 ra mã hex

A2
A1
A0
Address (hex)=
0
0
0
0x50
0
0
1
0x51
0
1
0
0x52
0
1
1
0x53
1
0
0
0x54
1
0
1
0x55
1
1
0
0x56
1
1
1
0x57

Ví dụ

Tất cả các ic đều có địa chỉ : 0x50, địa chỉ này thường dùng như một địa chỉ mặc định khi chỉ muốn dùng 1 ic trên bus giống như ở bài 1.

XÉT IC 24C04, 24C08, 24C16.

Như ta đã biết mỗi thiết bị trên đường bus chỉ được phép mang một và chỉ một địa chỉ duy nhất.

Chạy code  i2c_scanner  Kiểm tra địa chỉ của các ic ta được kết quả sau.

Bảng 3.1. Kết quả chạy chương trình i2c_scanner

 
A2
A1
A0
Địa chỉ thu được hiện lên trên cửa sổ Serial.
24c04
0
0
0
0x50 và 0x51
0
1
0
0x52 và 0x53
1
0
0
0x54 và 0x55
1
1
0
0X56 và 0x57
24c08
0
0
0
0x50,0x51, 0x52, 0x53
 
1
0
0
0x54, 0x55, 0x56, 0x57
24c16
0
0
0
Từ 0x50 đến 0x57

Thật ngạc nhiên khi trên một ic lại có thể có tới nhiều hơn 1 địa chỉ.   Vậy ta nên chọn địa chỉ nào để giao tiếp arduino với ic eeprom. ???

  • Màu đỏ với hàm ý : Bắt buộc . 
  • Màu đen : Tùy chọn (1/0)

 

Giải thích nguyên nhân

Do sự nâng cấp về dung lượng, ic được phân ra làm các trang ô nhớ (Page), mỗi trang có dung lượng 256 ô nhớ. 24c04 có 2 Page, 24c08 có 4 Page, 24c16 có 8 Page.

Do đó chỉ với 1 byte địa chỉ ô nhớ sẽ không thể truy cập đến dung lượng lớn hơn. Người ta giải quyết bằng cách sử dụng chân A0 (hoặc A1, A2) làm chân chọn Page.

Ví dụ ic24c04

Với A0=0, địa chỉ truy cập ô nhớ chạy từ 0->255 thì ô nhớ trên ic là từ 0->255 của Page 1.

Với A0=1, địa chỉ truy cập ô nhớ chạy từ 256->511 thì ô nhớ trên ic là từ 0->255 của Page 2.

Cứ như thế người ta sử dụng nốt các chân A1, A2 làm các chân chọn Page để tăng dung lượng mà vẫn đảm bảo tốc độ giao thức.

Có nghĩa bảng địa chỉ ic eeprom sẽ được hiểu như sau:

Điều này cũng đã được nói rõ trong datasheet .

Đây cũng là lời giải thích cho vấn đề đã nêu: Một ic có thể mang nhiều địa chỉ.

Vậy thì ta sẽ chọn địa chỉ bằng cách cho P=0, như sau:

Bảng 4.1. Ví dụ chọn địa chỉ

 
A2
A1
A0
Địa chỉ thật của ic
24c04
0
0
0
0x50
0
1
0
0x52
1
0
0
0x54
1
1
0
0X56
24c08
0
0
0
0x50
 
1
0
0
0x54
24c16
0
0
0
0x50
  • Màu đỏ với hàm ý : Bắt buộc . 
  • Màu đen : Tùy chọn (1/0)
  • Bạn nên nhớ, mỗi Slave chỉ có một và chỉ một địa chỉ để truy cập mà thôi.
  • Không nên để cho các Slave có địa chỉ giống nhau trên cùng một bus.

Về cách thức truy cập của các ic trên cũng khác nhau, bạn có thể theo dõi trong thư viện, mình đã chú thích rất rõ.

Ic 24c32, 24c64, 24c128, 24c256.

Dung lượng ic ngày càng tăng, chân A2,A1,A0 cũng đã dùng hết.  Người ta lại tiến hành tăng độ dài chuỗi ô địa chỉ nhớ lên 2 byte.

Lúc này dung lượng có thể lên tới tới 256*256 ô nhớ.

Còn các chân A2, A1, A0 được quay về chức năng nguyên thủy của nó là cài địa chỉ cho ic.

Không còn chân chọn Page, mỗi ic (32,64,128,256) có thể có tới 8 địa khác nhau bằng cách thiết lập như  thông thường.

Bảng 5.1. Ánh xạ mã hex của các IC 24c32, 24c64, 24c128, 24c256

IC 24c32, 24c64, 24c128, 24c256
A2
A1
A0
Address (hex)=
0
0
0
0x50
0
0
1
0x51
0
1
0
0x52
0
1
1
0x53
1
0
0
0x54
1
0
1
0x55
1
1
0
0x56
1
1
1
0x57

Ok, chúng ta đi vào ví dụ sử dụng

Gỉa sử, bạn muốn sử dụng 3 ic 24c04 trên cùng một đường bus:

Nhìn vào bảng 4.1, bạn sẽ nhặt ra 3 địa chỉ hợp lệ là  0x50 (cho ic1), 0x52 (cho ic2), 0x54 (ic3).

Kiểm tra bằng i2c_scanner:

Cái mình đóng khung đỏ chính là địa chỉ ta đã thiết lập bằng phần cứng của 3 ic, (địa chỉ ảo 0x51, 0x53, 0x55, là của Page 2 có trên mỗi ic. Chúng ta không quan tâm đến nó).

Kiểm tra xong, bây giờ tiến hành đọc/ghi trên bus:

#include <Wire.h>
#include <Eeprom24Cxx.h>
static Eeprom24C ic1(4, 0x50);
static Eeprom24C ic2(4, 0x52);
static Eeprom24C ic3(4, 0x54);
void setup()
{
    Serial.begin(9600);
    //ghi
    const int address = 200; // lưu vào ô 200
    ic1.write_1_byte(address, 10);
    delay(5);
    ic2.write_1_byte(address, 20);
    delay(5);
    ic3.write_1_byte(address, 30);
    delay(5);
    //đọc
    Serial.println("Read byte from EEPROM memory...");
    byte d1, d2, d3;
    d1 = ic1.read_1_byte(address);
    d2 = ic2.read_1_byte(address);
    d3 = ic3.read_1_byte(address);
    //in ra
    Serial.println(d1);
    Serial.println(d2);
    Serial.println(d3);
}
void loop()
{
}

Vẫn giữ nguyên 3 ic, mình muốn dùng thêm ic 24c02, 24c08, 24c16, 24c256, 24c64, 24c128

Vì chỉ có tối đa 8 ic eeprom trên 1 bus nên mình sẽ lập 1 bảng để phân bố sao cho các địa chỉ thuộc địa chỉ cho phép và khác các địa chỉ còn lại.

B1: Bỏ ic 24c02 vì đã quá số lượng cho phép.

B2: Nhìn vào bảng 4.1 và 5.1 , mình cần chọn ra các địa chỉ phù hợp nhất

24c16
0x50. Đây cũng là địa chỉ duy nhất  của ic nên phải ưu tiên chọn trước

Next

24c08
0x54.  (0x50 đã bị dùng)

Next

24c04 (ic1)
0x52.(50,54 đã bị dùng)
24c04 (ic2)
0x56.( 50,52,54, đã bị dùng)

Còn 4 địa chỉ chưa dùng: 0x51,0x53, 0x55, 0x57

24c064
0x51
24c128
0x53
24c256
0x57

Chúng ta còn dư 1 ic 24c04(ic3) do không  còn địa chỉ phù hợp.

B3: ráp mạch, tùy vào địa chỉ mà các bạn nối chân A cho phù hợp.

Do biết được đặc điểm là chỉ có thể có tối đa  8 ic nên mình đã làm một Shield như thế này,

Có 8 đế ic, mỗi đế có sãn địa chỉ khác nhau (0x50->0x57).

#include <Wire.h>
#include <Eeprom24Cxx.h>
static Eeprom24C ic_16(16, 0x50);
static Eeprom24C ic_64(64, 0x51);
static Eeprom24C ic_4_1(4, 0x52);
static Eeprom24C ic_128(128, 0x53);
static Eeprom24C ic_8(8, 0x54);
static Eeprom24C ic_4_2(4, 0x56);
static Eeprom24C ic_256(256, 0x57);
// quản lí các đối tượng bằng mảng.
static Eeprom24C ic[7] = { ic_16, ic_64, ic_4_1, ic_128, ic_8, ic_4_2, ic_256 };

void setup()
{
    Serial.begin(9600);
    //ghi
    const int address = 100; // lưu vào ô 100

    for (byte i = 0; i < 7; i++) {
        ic[i].write_1_byte(address, (i + 1) * 10);
        delay(5);
    }
    //đọc
    Serial.println("Read byte from EEPROM memory...");

    for (byte i = 0; i < 7; i++) {
        byte d;
        d = ic[i].read_1_byte(address);
        //in ra
        Serial.println(d);
    }
}

void loop()
{
}

Kết quả

Nhìn vào kết quả, ta có thể khẳng định, arduino đã tìm đến đúng ic mong muốn. Không cái nào trùng cái nào.

Lời khuyên

Nếu bạn là beginner,  bạn cảm thấy việc tìm địa chỉ gây khó khăn, mình khuyên bạn chỉ nên sử dụng ic 24c32, 24c64, 24c128, 24c256 (giá mua của nó chỉ cao hơn một chút xíu thôi, bạn hãy đầu tư nhé).  Việc cài đặt địa chỉ rất dễ dàng. Bạn cũng chưa cần cố gắng hiểu đến những gì mình đã viết về ic khác (24c16 trở xuống).

Đó là bước làm quen tốt nhất.

Xong rồi đó.

HEHE, từ mục tiêu tìm hiểu cái eeprom trong  tivi vứt xó đến khi mình viết được bài viết này là cả một quãng đường đầy thú vị. Ở nước ta, việc sử dụng ic này đã phổ biến rồi. Tuy vậy, tài liệu hướng dẫn vẫn rất hạn chế. Thậm chí là không ai muốn đả động đến phần sử dụng cùng lúc nhiều ic trên bus do có một chút nhập nhằng về cách thiết lập địa chỉ, các bài nước ngoài cũng chỉ nói đến  8 con ic 256 giống nhau, chứ chưa đề cập 8 con khác nhau như bài của mình.

Vấn đề về ic 24cxx cũng đã hết.

Tạm kết tại đây, rất mong sự ủng hộ của các bạn .laughdevilcheekyyes

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

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

Bộ điều khiển PID - ứng dụng phần 2 - xe dò line dùng thuật toán PID

Tiép nối bài viết về xe dò line cảm ơn Đỗ Hữu Toàn đã viết hộ mình phần 4. hôm nay mình sẽ làm cho chiếc xe dò line đi mượt và có hồn hơn 

lên
34 thành viên đã đánh giá bài viết này hữu ích.
Các bài viết cùng tác giả

Các hàm số học exp(), Idexp(), modf, ln(), log10(), ceil(), floor(), atoi(chuyển chữ thành số).

Bài này bổ xung các tập lệnh về các phép tính : exp(ex), Idexp(x*2exponent),  modf, ln(x), log10(x), floor(), ceil(), atoi()…

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

Truyền các số kiểu long, int, float trong giao tiếp Serial (UART)

Rất dễ dàng để gửi một số hoặc chuỗi kí tự để hiển thị lên màn hình qua cổng Serial. Nhưng mọi chuyện không đơn giản như vậy khi ta muốn truyền số kiểu int, long, double, ..v.v giữa 2 board arduino với nhau bằng Serial. Đừng lo, sau đây mình sẽ giúp bạn giải quyết vấn đề nan giải đó.

 

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