Trong bài này mình sẽ hướng dẫn các bạn làm việc với nhiều led ma trận hơn để hiển thị chữ cái mình muốn lên màn hình led ma trận.Cụ thể, chúng ta sẽ làm việc với 4 tấm matrix led 8×8, tức là led ma trận 8×32
Giới thiệu IC mở rộng ngõ ra 74hc595
Do dùng tới 4 tấm nên 32 chân của 89s52 không thể đủ để điều khiển. Mình sẽ cần tới sự hỗ trợ của ic mở rộng ngõ ra 74hc595, hay còn gọi là thanh ghi dịch 8 bit
Còn ic này cũng thuộc vào dòng kinh điển rồi, trên mạng cũng rất nhiều bài viết nói về ic này nên mình không nói lại nữa. Các bạn chưa biết có thể tham khảo tại đây:
- https://codientu.org/threads/74hc595-su-thong-dung-va-cach-dung.196/
- http://arduino.vn/bai-viet/113-dieu-khien-8-den-led-sang-nhap-nhay-theo-y-muon-cua-ban-de-hay-kho
- http://www.payitforward.edu.vn/forum/threads/1406/
Với ic mở rộng ngõ ra 74hc595. Chỉ với 3 chân của vi điều khiển, chúng ta có thể mở rộng ra vô cực chân theo ý thích. Nhưng nhược điểm của nó là làm chậm tốc độ của vi điều khiển đi do dữ liệu được chuyển tự dạng song song sang nối tiếp. Hãy tượng tượng như kiểu dữ liệu của bạn phải xếp hàng để đẩy đi lần lượt từng bit một thay vì tất cả đi cùng nhau đến đích vậy.
Do vậy, hãy tính toán số lượng chân mở rộng cho hợp lí với tốc độ của MCU, nếu không bạn sẽ phải giảm tần số quét xuống dẫn tới hình ảnh hiển thị không được đẹp. Nếu cố tình tăng tần số quét lên thì MCU dành hết tài nguyên cho việc quét led, sẽ không thể làm được việc khác.
Project này. Mình sẽ sử dụng 1 Port của 89s52 để quét led và 4 con 74hc595 mắc nối tiếp để mở rộng ngõ ra. Như vậy, tổng số chân cần dùng chỉ là 11 chân.
Sơ đồ nguyên lí
3 chân mở rộng ngõ ra sẽ được nối vào IC74hc595 và 32 đầu ra nối vào 32 cột LED
8 chân âm quét hàng sẽ được nối vào PORT P2 để quét hàng. Do vậy phương pháp quét vẫn là 1/8
Thạch anh mình sử dụng sẽ là 24Mhz để đảm bảo tốc độ nhanh nhất có thể
Xây dựng bộ font ASCII
Mình sẽ lại dùng phần mềm LCD font maker để tạo font
Các bạn để ý sẽ thấy các chân có trọng số cao ( Q7 -> Q0 ) nối với các led từ trái sang phải. Do vậy led bên trái sẽ có trọng số cao hơn bên phải. Hãy setup ở phần mềm LCD font maker sao cho pixel bên trái là bit cao hơn
Giờ hãy tạo bộ font theo đúng thứ tự của mã ASCII, bắt đầu từ kí tự Space. Đây là bộ font mình đã lấy sẵn
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 |
unsigned char code font[][8]= { 0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 32 0x10,0x38,0x38,0x10,0x10,0x00,0x10, //! 33 0x6C,0x6C,0x48,0x00,0x00,0x00,0x00, //" 34 0x00,0x28,0x7C,0x28,0x28,0x7C,0x28, //# 35 0x20,0x38,0x40,0x30,0x08,0x70,0x10, //$ 36 0x64,0x64,0x08,0x10,0x20,0x4C,0x4C, //% 37 0x20,0x50,0x50,0x20,0x54,0x48,0x34, //& 38 0x30,0x30,0x20,0x00,0x00,0x00,0x00, //' 39 0x10,0x20,0x20,0x20,0x20,0x20,0x10, //( 40 0x20,0x10,0x10,0x10,0x10,0x10,0x20, //) 41 0x00,0x28,0x38,0x7C,0x38,0x28,0x00, //* 42 0x00,0x10,0x10,0x7C,0x10,0x10,0x00, //+ 43 0x00,0x00,0x00,0x00,0x00,0x30,0x30, //, 44 0x00,0x00,0x00,0x7C,0x00,0x00,0x00, //- 45 0x00,0x00,0x00,0x00,0x00,0x30,0x30, //. 46 0x00,0x04,0x08,0x10,0x20,0x40,0x00, /// 47 0x38,0x44,0x4C,0x54,0x64,0x44,0x38, //0 48 0x00,0x04,0x08,0x10,0x20,0x40,0x00, //1 49 0x38,0x44,0x04,0x18,0x20,0x40,0x7C, //2 50 0x38,0x44,0x04,0x38,0x04,0x44,0x38, //3 51 0x08,0x18,0x28,0x48,0x7C,0x08,0x08, //4 52 0x7C,0x40,0x40,0x78,0x04,0x44,0x38, //5 53 0x18,0x20,0x40,0x78,0x44,0x44,0x38, //6 54 0x7C,0x04,0x08,0x10,0x20,0x20,0x20, //7 55 0x38,0x44,0x44,0x38,0x44,0x44,0x38, //8 56 0x38,0x44,0x44,0x3C,0x04,0x08,0x30, //9 57 0x00,0x00,0x30,0x30,0x00,0x30,0x30, //: 58 0x00,0x00,0x30,0x30,0x00,0x30,0x30, //; 59 0x08,0x10,0x20,0x40,0x20,0x10,0x08, //< 60 0x00,0x00,0x7C,0x00,0x00,0x7C,0x00, //= 61 0x20,0x10,0x08,0x04,0x08,0x10,0x20, //> 62 0x38,0x44,0x04,0x18,0x10,0x00,0x10, //? 63 0x38,0x44,0x5C,0x54,0x5C,0x40,0x38, //@ 64 0x38,0x44,0x44,0x44,0x7C,0x44,0x44, //A 65 0x78,0x44,0x44,0x78,0x44,0x44,0x78, //B 66 0x38,0x44,0x40,0x40,0x40,0x44,0x38, //C 67 0x78,0x44,0x44,0x44,0x44,0x44,0x78, //D 68 0x7C,0x40,0x40,0x78,0x40,0x40,0x7C, //E 69 0x7C,0x40,0x40,0x78,0x40,0x40,0x40, //F 70 0x38,0x44,0x40,0x5C,0x44,0x44,0x3C, //G 71 0x44,0x44,0x44,0x7C,0x44,0x44,0x44, //H 72 0x38,0x10,0x10,0x10,0x10,0x10,0x38, //I 73 0x04,0x04,0x04,0x04,0x44,0x44,0x38, //J 74 0x44,0x48,0x50,0x60,0x50,0x48,0x44, //K 75 0x40,0x40,0x40,0x40,0x40,0x40,0x7C, //L 76 0x44,0x6C,0x54,0x44,0x44,0x44,0x44, //M 77 0x44,0x64,0x54,0x4C,0x44,0x44,0x44, //N 78 0x38,0x44,0x44,0x44,0x44,0x44,0x38, //O 79 0x78,0x44,0x44,0x78,0x40,0x40,0x40, //P 80 0x38,0x44,0x44,0x44,0x54,0x48,0x34, //Q 81 0x78,0x44,0x44,0x78,0x48,0x44,0x44, //R 82 0x38,0x44,0x40,0x38,0x04,0x44,0x38, //S 83 0x7C,0x10,0x10,0x10,0x10,0x10,0x10, //T 84 0x44,0x44,0x44,0x44,0x44,0x44,0x38, //U 85 0x44,0x44,0x44,0x44,0x44,0x28,0x10, //V 86 0x44,0x44,0x54,0x54,0x54,0x54,0x28, //W 87 0x44,0x44,0x28,0x10,0x28,0x44,0x44, //X 88 0x44,0x44,0x44,0x28,0x10,0x10,0x10, //Y 89 0x78,0x08,0x10,0x20,0x40,0x40,0x78, //Z 90 0x38,0x20,0x20,0x20,0x20,0x20,0x38, //[ 91 0x00,0x40,0x20,0x10,0x08,0x04,0x00, //\ 92 0x38,0x08,0x08,0x08,0x08,0x08,0x38, //] 93 0x10,0x28,0x44,0x00,0x00,0x00,0x00, //^ 94 0x00,0x00,0x00,0x00,0x00,0x00,0x7C, //_ 95 0x30,0x30,0x10,0x00,0x00,0x00,0x00, //` 96 0x00,0x00,0x38,0x04,0x3C,0x44,0x3C, //a 97 0x40,0x40,0x78,0x44,0x44,0x44,0x78, //b 98 0x00,0x00,0x38,0x44,0x40,0x44,0x38, //c 99 0x04,0x04,0x3C,0x44,0x44,0x44,0x3C, //d 100 0x00,0x00,0x38,0x44,0x78,0x40,0x38, //e 101 0x18,0x20,0x20,0x78,0x20,0x20,0x20, //f 102 0x00,0x3C,0x44,0x44,0x3C,0x04,0x38, //g 103 0x40,0x40,0x70,0x48,0x48,0x48,0x48, //h 104 0x10,0x00,0x10,0x10,0x10,0x10,0x18, //i 105 0x08,0x00,0x18,0x08,0x08,0x48,0x30, //j 106 0x40,0x40,0x48,0x50,0x60,0x50,0x48, //k 107 0x20,0x20,0x20,0x20,0x20,0x20,0x38, //l 108 0x00,0x00,0x68,0x54,0x54,0x44,0x44, //m 109 0x00,0x00,0x70,0x48,0x48,0x48,0x48, //n 110 0x00,0x00,0x38,0x44,0x44,0x44,0x38, //o 111 0x00,0x78,0x44,0x44,0x44,0x78,0x40, //p 112 0x00,0x3C,0x44,0x44,0x44,0x3C,0x04, //q 113 0x00,0x00,0x58,0x24,0x20,0x20,0x70, //r 114 0x00,0x00,0x38,0x40,0x38,0x04,0x38, //s 115 0x00,0x20,0x78,0x20,0x20,0x28,0x10, //t 116 0x00,0x00,0x48,0x48,0x48,0x58,0x28, //u 117 0x00,0x00,0x44,0x44,0x44,0x28,0x10, //v 118 0x00,0x00,0x44,0x44,0x54,0x7C,0x28, //w 119 0x00,0x00,0x48,0x48,0x30,0x48,0x48, //x 120 0x00,0x48,0x48,0x48,0x38,0x10,0x60, //y 121 0x00,0x00,0x78,0x08,0x30,0x40,0x78, //z 122 0x18,0x20,0x20,0x60,0x20,0x20,0x18, //{ 123 0x10,0x10,0x10,0x10,0x10,0x10,0x10, //| 124 0x30,0x08,0x08,0x0C,0x08,0x08,0x30, //} 125 0x00,0x00,0x28,0x50,0x00,0x00,0x00, //~ 126 }; |
Xây dựng module ngắt hiện thị dữ liệu từ bộ đệm
Do có 8×32 con LED nên sẽ cần 8×32 bit dữ liệu cho bộ đệm. Mà cứ 8 bit là 1 byte nên ta cần 32byte cho bộ đệm. Có 2 cách để thiết lập bộ đệm như sau:
- unsigned char Buffer_display[32];
- unsigned char Buffer_display[8][4];
Với cách 1: bộ đệm sẽ là mảng 1 chiều, còn cách 2 thì là mảng 2 chiều. Mình sẽ khởi tạo mảng với 2 chiều để việc thao tác với mảng dễ dàng thuận tiện hơn
Bây giờ xây dựng hàm ngắt để đẩy data ra. Có thể nói hàm ngắt y chang như ở bài 3, chỉ khác 1 chút ở chỗ đẩy dữ liệu ra IO thôi. Mà IO ở đây là 4 con ic74hc595 nối tiếp nên trước tiên dựng 1 hàm đẩy dữ liệu ra HC595 nhé
1 2 3 4 5 6 7 8 9 10 11 12 |
#define DAT P2_1 #define LAT P2_2 #define SCK P2_3 void hc595_out(unsigned char byte) { int i; for(i=0;i<8;i++) { DAT = byte & (0x80>>i); SCK=0;SCK=1; } } |
Hàm ngắt Timer1 bắn dự liệu trong bộ đệm ra
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
void T1_ISR() interrupt 3 // Dung timer 1 de quet led matrix { static unsigned char z ; // Bien dem P3=0xFF; //tat het LED hc595_out(Buffer_display[z][0]); //lay du lieu trong bo dem hien thi ra man hinh matrix 1 hc595_out(Buffer_display[z][1]); //lay du lieu trong bo dem hien thi ra man hinh matrix 2 hc595_out(Buffer_display[z][2]); //lay du lieu trong bo dem hien thi ra man hinh matrix 3 hc595_out(Buffer_display[z][3]); //lay du lieu trong bo dem hien thi ra man hinh matrix 4 LAT=0;LAT=1; //chot du lieu P3=maquet[z]; //cho phep LED sang z++;if(z==8)z=0; TH1=0xFC; // Nap gia tri cho TH1 TL1=0x17; // Nap gia tri cho TL1 } |
Vậy là xong, công việc hiển thị đã có ngắt lo. Bây giờ chúng ta chỉ việc xây dựng các hàm để bắn dữ liệu vào bộ đệm.
1 2 3 4 5 6 7 8 |
void Matrix_guikitu(unsigned char txt) { int i; for(i=0;i<7;i++) { Buffer_display[i][0] = font[txt-32][i]; } } |
Hãy thử gọi hàm này trong main để in ra chữ ‘A’ nhé !
Matrix_guikitu(‘A’);
Giải thích
Hàm này yêu cầu nạp vào biến txt chính là kí tự mà ta muốn in ra.
Vòng lặp for tới 7 vì mỗi kí tự được tạo với font gồm 7 byte data.
Chúng ta phải trừ txt đi 32 vì mảng font của ta bắt đầu từ 0 nhưng mã ascii lại bắt đầu từ 32. Do vậy phải trừ đi để 2 font này trùng khớp nhau.
Giờ hãy để ý số 0 trong bộ đệm Buffer_display, nó đại diện cho tấm matrix thứ 1 ngoài cùng bên trái. Nếu ta điền vô đó là 1 thì nó sẽ in ra tấm matrix thứ 2. Tương tự …
Do vậy, mình sẽ chỉnh thêm 1 chút đó là thêm 1 biến vị trí được nạp vào hàm để chọn tấm matrix ta sẽ in ra
1 2 3 4 5 6 7 8 |
void Matrix_guikitu(int vitri,unsigned char txt) { int i; for(i=0;i<7;i++) { Buffer_display[i][vitri] = font[txt-32][i]; } } |
Gọi lệnh Matrix_guikitu(2,’A’);
Giờ thi chữ ‘A’ đã được in ở tấm thứ 3
Tiếp tục, mình sẽ xây dựng 1 hàm gửi chuỗi kí tự
1 2 3 4 5 6 7 8 9 10 |
void Matrix_guichuoi(unsigned char *s) { int vitri=0; while(*s) { Matrix_guikitu(vitri++,*s); if(vitri==4)return; s++; } } |
Hàm này thực chất chỉ là gọi lại hàm Matrix_guikitu nhiều lần. Vòng lặp while sẽ lặp cho tới khi gặp NULL để thoát. Mỗi lần in sẽ tăng biến vitri lên 1 tấm. Do chỉ có 4 tấm matrix lên mình chỉ in đc có 4 kí tự. Vậy nên mình để thêm 1 dòng lệnh kiểm tra nếu đã in đủ 4 kí tự thì thoát
Giờ test thử hàm này nhé
Matrix_guichuoi(“ABCD”);
FULL code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 |
#include <REGX52.H> #define DAT P2_0 #define LAT P2_1 #define SCK P2_2 unsigned char code maquet[8]={0xFE,0xFD,0xFB,0xF7,0xEF,0xDF,0xBF,0x7F}; unsigned char code font[][7]= { 0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 32 0x10,0x38,0x38,0x10,0x10,0x00,0x10, //! 33 0x6C,0x6C,0x48,0x00,0x00,0x00,0x00, //" 34 0x00,0x28,0x7C,0x28,0x28,0x7C,0x28, //# 35 0x20,0x38,0x40,0x30,0x08,0x70,0x10, //$ 36 0x64,0x64,0x08,0x10,0x20,0x4C,0x4C, //% 37 0x20,0x50,0x50,0x20,0x54,0x48,0x34, //& 38 0x30,0x30,0x20,0x00,0x00,0x00,0x00, //' 39 0x10,0x20,0x20,0x20,0x20,0x20,0x10, //( 40 0x20,0x10,0x10,0x10,0x10,0x10,0x20, //) 41 0x00,0x28,0x38,0x7C,0x38,0x28,0x00, //* 42 0x00,0x10,0x10,0x7C,0x10,0x10,0x00, //+ 43 0x00,0x00,0x00,0x00,0x00,0x30,0x30, //, 44 0x00,0x00,0x00,0x7C,0x00,0x00,0x00, //- 45 0x00,0x00,0x00,0x00,0x00,0x30,0x30, //. 46 0x00,0x04,0x08,0x10,0x20,0x40,0x00, /// 47 0x38,0x44,0x4C,0x54,0x64,0x44,0x38, //0 48 0x00,0x04,0x08,0x10,0x20,0x40,0x00, //1 49 0x38,0x44,0x04,0x18,0x20,0x40,0x7C, //2 50 0x38,0x44,0x04,0x38,0x04,0x44,0x38, //3 51 0x08,0x18,0x28,0x48,0x7C,0x08,0x08, //4 52 0x7C,0x40,0x40,0x78,0x04,0x44,0x38, //5 53 0x18,0x20,0x40,0x78,0x44,0x44,0x38, //6 54 0x7C,0x04,0x08,0x10,0x20,0x20,0x20, //7 55 0x38,0x44,0x44,0x38,0x44,0x44,0x38, //8 56 0x38,0x44,0x44,0x3C,0x04,0x08,0x30, //9 57 0x00,0x00,0x30,0x30,0x00,0x30,0x30, //: 58 0x00,0x00,0x30,0x30,0x00,0x30,0x30, //; 59 0x08,0x10,0x20,0x40,0x20,0x10,0x08, //< 60 0x00,0x00,0x7C,0x00,0x00,0x7C,0x00, //= 61 0x20,0x10,0x08,0x04,0x08,0x10,0x20, //> 62 0x38,0x44,0x04,0x18,0x10,0x00,0x10, //? 63 0x38,0x44,0x5C,0x54,0x5C,0x40,0x38, //@ 64 0x38,0x44,0x44,0x44,0x7C,0x44,0x44, //A 65 0x78,0x44,0x44,0x78,0x44,0x44,0x78, //B 66 0x38,0x44,0x40,0x40,0x40,0x44,0x38, //C 67 0x78,0x44,0x44,0x44,0x44,0x44,0x78, //D 68 0x7C,0x40,0x40,0x78,0x40,0x40,0x7C, //E 69 0x7C,0x40,0x40,0x78,0x40,0x40,0x40, //F 70 0x38,0x44,0x40,0x5C,0x44,0x44,0x3C, //G 71 0x44,0x44,0x44,0x7C,0x44,0x44,0x44, //H 72 0x38,0x10,0x10,0x10,0x10,0x10,0x38, //I 73 0x04,0x04,0x04,0x04,0x44,0x44,0x38, //J 74 0x44,0x48,0x50,0x60,0x50,0x48,0x44, //K 75 0x40,0x40,0x40,0x40,0x40,0x40,0x7C, //L 76 0x44,0x6C,0x54,0x44,0x44,0x44,0x44, //M 77 0x44,0x64,0x54,0x4C,0x44,0x44,0x44, //N 78 0x38,0x44,0x44,0x44,0x44,0x44,0x38, //O 79 0x78,0x44,0x44,0x78,0x40,0x40,0x40, //P 80 0x38,0x44,0x44,0x44,0x54,0x48,0x34, //Q 81 0x78,0x44,0x44,0x78,0x48,0x44,0x44, //R 82 0x38,0x44,0x40,0x38,0x04,0x44,0x38, //S 83 0x7C,0x10,0x10,0x10,0x10,0x10,0x10, //T 84 0x44,0x44,0x44,0x44,0x44,0x44,0x38, //U 85 0x44,0x44,0x44,0x44,0x44,0x28,0x10, //V 86 0x44,0x44,0x54,0x54,0x54,0x54,0x28, //W 87 0x44,0x44,0x28,0x10,0x28,0x44,0x44, //X 88 0x44,0x44,0x44,0x28,0x10,0x10,0x10, //Y 89 0x78,0x08,0x10,0x20,0x40,0x40,0x78, //Z 90 0x38,0x20,0x20,0x20,0x20,0x20,0x38, //[ 91 0x00,0x40,0x20,0x10,0x08,0x04,0x00, //\ 92 0x38,0x08,0x08,0x08,0x08,0x08,0x38, //] 93 0x10,0x28,0x44,0x00,0x00,0x00,0x00, //^ 94 0x00,0x00,0x00,0x00,0x00,0x00,0x7C, //_ 95 0x30,0x30,0x10,0x00,0x00,0x00,0x00, //` 96 0x00,0x00,0x38,0x04,0x3C,0x44,0x3C, //a 97 0x40,0x40,0x78,0x44,0x44,0x44,0x78, //b 98 0x00,0x00,0x38,0x44,0x40,0x44,0x38, //c 99 0x04,0x04,0x3C,0x44,0x44,0x44,0x3C, //d 100 0x00,0x00,0x38,0x44,0x78,0x40,0x38, //e 101 0x18,0x20,0x20,0x78,0x20,0x20,0x20, //f 102 0x00,0x3C,0x44,0x44,0x3C,0x04,0x38, //g 103 0x40,0x40,0x70,0x48,0x48,0x48,0x48, //h 104 0x10,0x00,0x10,0x10,0x10,0x10,0x18, //i 105 0x08,0x00,0x18,0x08,0x08,0x48,0x30, //j 106 0x40,0x40,0x48,0x50,0x60,0x50,0x48, //k 107 0x20,0x20,0x20,0x20,0x20,0x20,0x38, //l 108 0x00,0x00,0x68,0x54,0x54,0x44,0x44, //m 109 0x00,0x00,0x70,0x48,0x48,0x48,0x48, //n 110 0x00,0x00,0x38,0x44,0x44,0x44,0x38, //o 111 0x00,0x78,0x44,0x44,0x44,0x78,0x40, //p 112 0x00,0x3C,0x44,0x44,0x44,0x3C,0x04, //q 113 0x00,0x00,0x58,0x24,0x20,0x20,0x70, //r 114 0x00,0x00,0x38,0x40,0x38,0x04,0x38, //s 115 0x00,0x20,0x78,0x20,0x20,0x28,0x10, //t 116 0x00,0x00,0x48,0x48,0x48,0x58,0x28, //u 117 0x00,0x00,0x44,0x44,0x44,0x28,0x10, //v 118 0x00,0x00,0x44,0x44,0x54,0x7C,0x28, //w 119 0x00,0x00,0x48,0x48,0x30,0x48,0x48, //x 120 0x00,0x48,0x48,0x48,0x38,0x10,0x60, //y 121 0x00,0x00,0x78,0x08,0x30,0x40,0x78, //z 122 0x18,0x20,0x20,0x60,0x20,0x20,0x18, //{ 123 0x10,0x10,0x10,0x10,0x10,0x10,0x10, //| 124 0x30,0x08,0x08,0x0C,0x08,0x08,0x30, //} 125 0x00,0x00,0x28,0x50,0x00,0x00,0x00, //~ 126 }; unsigned char Buffer_display[8][4]; void delay(unsigned int t) //hàm delay { unsigned int x,y; for(x=0;x<t;x++) { for(y=0;y<123;y++); } } void hc595_out(unsigned char byte) { int i; for(i=0;i<8;i++) { DAT = byte & (0x80>>i); SCK=0;SCK=1; } } void T1_ISR() interrupt 3 // Dung timer 1 de quet led matrix { static unsigned char z ; // Bien dem P3=0xFF; //tat het LED hc595_out(Buffer_display[z][0]); //lay du lieu trong bo dem hien thi ra man hinh matrix 1 hc595_out(Buffer_display[z][1]); //lay du lieu trong bo dem hien thi ra man hinh matrix 2 hc595_out(Buffer_display[z][2]); //lay du lieu trong bo dem hien thi ra man hinh matrix 3 hc595_out(Buffer_display[z][3]); //lay du lieu trong bo dem hien thi ra man hinh matrix 4 LAT=0;LAT=1; //chot du lieu P3=maquet[z]; //cho phep LED sang z++;if(z==8)z=0; TH1=0xFC; // Nap gia tri cho TH1 TL1=0x17; // Nap gia tri cho TL1 } void Matrix_guikitu(int vitri,unsigned char txt) { int i; for(i=0;i<7;i++) { Buffer_display[i][vitri] = font[txt-32][i]; } } void Matrix_guichuoi(unsigned char *s) { int vitri=0; while(*s) { Matrix_guikitu(vitri++,*s); if(vitri==4)return; s++; } } void main() { TMOD=0x10; // khoi tao ngat T1, 16bit ET1=1; // cho phep ngat T1 TF1=0; // xoa co ngat T1 TR1=1; // khoi dong T1 EA = 1; // cho phep ngat toan cuc Matrix_guichuoi("ABCD"); while(1) { } } |
Đến đây cũng có thể nói là xong rồi. Nhưng hãy để ý các chữ của chúng ta cách nhau khá xa. Hãy tùy biến hàm gửi kí tự lại 1 chút để nhìn chữ đẹp hơn và có thêm không gian để hiện đc nhiều kí tự hơn nhé ! Chúng ta cũng thể hiện thị chữ thoải mái ở bất kì vị trí nào trên màn hình
Các bạn nên hiểu kĩ code bên trên trước khi đọc tiếp
Điều khiển matrix bằng tọa độ pixel
Đầu tiên mình khai báo hai biến toàn cục
MatrixX, MatrixY
1 |
int MatrixX,MatrixY; |
Viết 1 hàm để set vị trí con trỏ màn hình
1 2 3 4 5 |
void Matrix_chonvitri(int x,int y) { MatrixX=x; MatrixY=y; } |
Hàm Set pixel, hàm này có nhiệm vụ làm sáng hoặc tắt 1 con LED ở tọa độ nào đó trên màn hình
1 2 3 4 5 6 |
void Matrix_setpx(int x,int y,char color) { if(x>31 || y>7 || x<0 || y < 0)return; if(color)Buffer_display[y][x/8] |= (0x80 >> (x%8)); //sáng led else Buffer_display[y][x/8] &= ~(0x80 >> (x%8)); //tắt led } |
Tham số đầu tiền là tọa độ x, tiếp theo là tọa độ y, cuối cùng là trạng thái bật hay tắt
color = 0 là tắt
color = 1 là bật
Mình có thêm 1 lệnh kiểm tra if(x>31 || y>7 || x<0 || y < 0)return; có nghĩa là nếu tọa độ cần set vọt lố ra ngoài chiều dài tối đa và chiều rộng tối của tấm LED thì sẽ thoát luôn !
Nhắc tới tọa độ lại phải nhắc tới hệ tọa độ và gốc tọa độ. Mình đã chọn gốc tọa độ ở trên cùng phía bên trái của màn hình LED
Matrix_setpx(0,0,1);
Khi chạy hàm này thì con led ở tọa độ 0,0 đã sáng
Giờ thì viết lại hàm Matrix_guikitu nhé !
1 2 3 4 5 6 7 8 9 10 11 |
void Matrix_guikitu(unsigned char txt) { int x,y; for(y=MatrixY;y<7+MatrixY;y++) { for(x=MatrixX;x<6+MatrixX;x++) { Matrix_setpx(x,y,1); } } } |
Thử test hàm này nào
Matrix_chonvitri(0,0);
Matrix_guikitu(‘A’);
Các bạn có thể thấy vùng không gian mà chữ ‘A’ chiếm chỗ bắt đầu từ tọa độ (0,0) do mình set vị trí con trỏ hiên tại là (0,0). Các bạn hãy thử test vị trí chỗ khác xem nhé !
Nhưng tại sao chữ A chưa hiện. Vì code trên mình chỉ gọi hàm Matrix_setpx(x,y,1); làm cho led sáng hết. Giờ phải quyết định xem led nào sáng , led nào tắt bằng cách đọc từ bộ font ra
1 2 3 4 5 6 7 8 9 10 11 12 13 |
void Matrix_guikitu(unsigned char txt) { int x,y; for(y=MatrixY;y<7+MatrixY;y++) { for(x=MatrixX;x<6+MatrixX;x++) { if ( (font[txt-32][y-MatrixY] & (0x80>>(x-MatrixX))) != 0)Matrix_setpx(x,y,1); else Matrix_setpx(x,y,0); } } MatrixX+=6; //sau khi in xong thi tang con tro vi tri len } |
Matrix_chonvitri(0,0);
Matrix_guikitu(‘A’);
Nếu thấy đoạn code trên khó hiểu, hãy thử thay giá trị của các biến, xóa biến này biến kia đi và quan sát sự thay đổi. Các bạn sẽ tự hiểu ngay thôi !
Matrix_chonvitri(-3,0);
Matrix_guikitu(‘A’);
Các bạn có thể chọn ví trí âm thoải mái nhé ! Lúc đó chữ sẽ bị cắt bớt đi 1 phần và lọt ra ngoài không gian hiển thị
OK, giờ viết lại hàm gửi chuỗi kí tự nào
1 2 3 4 5 6 7 8 |
void Matrix_guichuoi(unsigned char *s) { while(*s) { Matrix_guikitu(*s); s++; } } |
Hàm này thực chất cũng chỉ là gọi lại hàm Matrix_guikitu nhiều lần
Matrix_chonvitri(0,1);
Matrix_guichuoi(“IoT47”);
FULL CODE
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 |
#include <REGX52.H> #define DAT P2_0 #define LAT P2_1 #define SCK P2_2 int MatrixX,MatrixY; unsigned char code maquet[8]={0xFE,0xFD,0xFB,0xF7,0xEF,0xDF,0xBF,0x7F}; unsigned char code font[][7]= { 0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 32 0x10,0x38,0x38,0x10,0x10,0x00,0x10, //! 33 0x6C,0x6C,0x48,0x00,0x00,0x00,0x00, //" 34 0x00,0x28,0x7C,0x28,0x28,0x7C,0x28, //# 35 0x20,0x38,0x40,0x30,0x08,0x70,0x10, //$ 36 0x64,0x64,0x08,0x10,0x20,0x4C,0x4C, //% 37 0x20,0x50,0x50,0x20,0x54,0x48,0x34, //& 38 0x30,0x30,0x20,0x00,0x00,0x00,0x00, //' 39 0x10,0x20,0x20,0x20,0x20,0x20,0x10, //( 40 0x20,0x10,0x10,0x10,0x10,0x10,0x20, //) 41 0x00,0x28,0x38,0x7C,0x38,0x28,0x00, //* 42 0x00,0x10,0x10,0x7C,0x10,0x10,0x00, //+ 43 0x00,0x00,0x00,0x00,0x00,0x30,0x30, //, 44 0x00,0x00,0x00,0x7C,0x00,0x00,0x00, //- 45 0x00,0x00,0x00,0x00,0x00,0x30,0x30, //. 46 0x00,0x04,0x08,0x10,0x20,0x40,0x00, /// 47 0x38,0x44,0x4C,0x54,0x64,0x44,0x38, //0 48 0x00,0x04,0x08,0x10,0x20,0x40,0x00, //1 49 0x38,0x44,0x04,0x18,0x20,0x40,0x7C, //2 50 0x38,0x44,0x04,0x38,0x04,0x44,0x38, //3 51 0x08,0x18,0x28,0x48,0x7C,0x08,0x08, //4 52 0x7C,0x40,0x40,0x78,0x04,0x44,0x38, //5 53 0x18,0x20,0x40,0x78,0x44,0x44,0x38, //6 54 0x7C,0x04,0x08,0x10,0x20,0x20,0x20, //7 55 0x38,0x44,0x44,0x38,0x44,0x44,0x38, //8 56 0x38,0x44,0x44,0x3C,0x04,0x08,0x30, //9 57 0x00,0x00,0x30,0x30,0x00,0x30,0x30, //: 58 0x00,0x00,0x30,0x30,0x00,0x30,0x30, //; 59 0x08,0x10,0x20,0x40,0x20,0x10,0x08, //< 60 0x00,0x00,0x7C,0x00,0x00,0x7C,0x00, //= 61 0x20,0x10,0x08,0x04,0x08,0x10,0x20, //> 62 0x38,0x44,0x04,0x18,0x10,0x00,0x10, //? 63 0x38,0x44,0x5C,0x54,0x5C,0x40,0x38, //@ 64 0x38,0x44,0x44,0x44,0x7C,0x44,0x44, //A 65 0x78,0x44,0x44,0x78,0x44,0x44,0x78, //B 66 0x38,0x44,0x40,0x40,0x40,0x44,0x38, //C 67 0x78,0x44,0x44,0x44,0x44,0x44,0x78, //D 68 0x7C,0x40,0x40,0x78,0x40,0x40,0x7C, //E 69 0x7C,0x40,0x40,0x78,0x40,0x40,0x40, //F 70 0x38,0x44,0x40,0x5C,0x44,0x44,0x3C, //G 71 0x44,0x44,0x44,0x7C,0x44,0x44,0x44, //H 72 0x38,0x10,0x10,0x10,0x10,0x10,0x38, //I 73 0x04,0x04,0x04,0x04,0x44,0x44,0x38, //J 74 0x44,0x48,0x50,0x60,0x50,0x48,0x44, //K 75 0x40,0x40,0x40,0x40,0x40,0x40,0x7C, //L 76 0x44,0x6C,0x54,0x44,0x44,0x44,0x44, //M 77 0x44,0x64,0x54,0x4C,0x44,0x44,0x44, //N 78 0x38,0x44,0x44,0x44,0x44,0x44,0x38, //O 79 0x78,0x44,0x44,0x78,0x40,0x40,0x40, //P 80 0x38,0x44,0x44,0x44,0x54,0x48,0x34, //Q 81 0x78,0x44,0x44,0x78,0x48,0x44,0x44, //R 82 0x38,0x44,0x40,0x38,0x04,0x44,0x38, //S 83 0x7C,0x10,0x10,0x10,0x10,0x10,0x10, //T 84 0x44,0x44,0x44,0x44,0x44,0x44,0x38, //U 85 0x44,0x44,0x44,0x44,0x44,0x28,0x10, //V 86 0x44,0x44,0x54,0x54,0x54,0x54,0x28, //W 87 0x44,0x44,0x28,0x10,0x28,0x44,0x44, //X 88 0x44,0x44,0x44,0x28,0x10,0x10,0x10, //Y 89 0x78,0x08,0x10,0x20,0x40,0x40,0x78, //Z 90 0x38,0x20,0x20,0x20,0x20,0x20,0x38, //[ 91 0x00,0x40,0x20,0x10,0x08,0x04,0x00, //\ 92 0x38,0x08,0x08,0x08,0x08,0x08,0x38, //] 93 0x10,0x28,0x44,0x00,0x00,0x00,0x00, //^ 94 0x00,0x00,0x00,0x00,0x00,0x00,0x7C, //_ 95 0x30,0x30,0x10,0x00,0x00,0x00,0x00, //` 96 0x00,0x00,0x38,0x04,0x3C,0x44,0x3C, //a 97 0x40,0x40,0x78,0x44,0x44,0x44,0x78, //b 98 0x00,0x00,0x38,0x44,0x40,0x44,0x38, //c 99 0x04,0x04,0x3C,0x44,0x44,0x44,0x3C, //d 100 0x00,0x00,0x38,0x44,0x78,0x40,0x38, //e 101 0x18,0x20,0x20,0x78,0x20,0x20,0x20, //f 102 0x00,0x3C,0x44,0x44,0x3C,0x04,0x38, //g 103 0x40,0x40,0x70,0x48,0x48,0x48,0x48, //h 104 0x10,0x00,0x10,0x10,0x10,0x10,0x18, //i 105 0x08,0x00,0x18,0x08,0x08,0x48,0x30, //j 106 0x40,0x40,0x48,0x50,0x60,0x50,0x48, //k 107 0x20,0x20,0x20,0x20,0x20,0x20,0x38, //l 108 0x00,0x00,0x68,0x54,0x54,0x44,0x44, //m 109 0x00,0x00,0x70,0x48,0x48,0x48,0x48, //n 110 0x00,0x00,0x38,0x44,0x44,0x44,0x38, //o 111 0x00,0x78,0x44,0x44,0x44,0x78,0x40, //p 112 0x00,0x3C,0x44,0x44,0x44,0x3C,0x04, //q 113 0x00,0x00,0x58,0x24,0x20,0x20,0x70, //r 114 0x00,0x00,0x38,0x40,0x38,0x04,0x38, //s 115 0x00,0x20,0x78,0x20,0x20,0x28,0x10, //t 116 0x00,0x00,0x48,0x48,0x48,0x58,0x28, //u 117 0x00,0x00,0x44,0x44,0x44,0x28,0x10, //v 118 0x00,0x00,0x44,0x44,0x54,0x7C,0x28, //w 119 0x00,0x00,0x48,0x48,0x30,0x48,0x48, //x 120 0x00,0x48,0x48,0x48,0x38,0x10,0x60, //y 121 0x00,0x00,0x78,0x08,0x30,0x40,0x78, //z 122 0x18,0x20,0x20,0x60,0x20,0x20,0x18, //{ 123 0x10,0x10,0x10,0x10,0x10,0x10,0x10, //| 124 0x30,0x08,0x08,0x0C,0x08,0x08,0x30, //} 125 0x00,0x00,0x28,0x50,0x00,0x00,0x00, //~ 126 }; unsigned char Buffer_display[8][4]; void delay(unsigned int t) //hàm delay { unsigned int x,y; for(x=0;x<t;x++) { for(y=0;y<123;y++); } } void hc595_out(unsigned char byte) { int i; for(i=0;i<8;i++) { DAT = byte & (0x80>>i); SCK=0;SCK=1; } } void T1_ISR() interrupt 3 // Dung timer 1 de quet led matrix { static unsigned char z ; // Bien dem P3=0xFF; //tat het LED hc595_out(Buffer_display[z][0]); //lay du lieu trong bo dem hien thi ra man hinh matrix 1 hc595_out(Buffer_display[z][1]); //lay du lieu trong bo dem hien thi ra man hinh matrix 2 hc595_out(Buffer_display[z][2]); //lay du lieu trong bo dem hien thi ra man hinh matrix 3 hc595_out(Buffer_display[z][3]); //lay du lieu trong bo dem hien thi ra man hinh matrix 4 LAT=0;LAT=1; //chot du lieu P3=maquet[z]; //cho phep LED sang z++;if(z==8)z=0; TH1=0xFC; // Nap gia tri cho TH1 TL1=0x17; // Nap gia tri cho TL1 } void Matrix_chonvitri(int x,int y) { MatrixX=x; MatrixY=y; } void Matrix_setpx(int x,int y,char color) { if(x>31 || y>7 || x<0 || y < 0)return; if(color)Buffer_display[y][x/8] |= (0x80 >> (x%8)); else Buffer_display[y][x/8] &= ~(0x80 >> (x%8)); } void Matrix_guikitu(unsigned char txt) { int x,y; for(y=MatrixY;y<7+MatrixY;y++) { for(x=MatrixX;x<6+MatrixX;x++) { if ( (font[txt-32][y-MatrixY] & (0x80>>(x-MatrixX))) != 0)Matrix_setpx(x,y,1); else Matrix_setpx(x,y,0); } } MatrixX+=6; //sau khi in xong thi tang con tro vi tri len } void Matrix_guichuoi(unsigned char *s) { while(*s) { Matrix_guikitu(*s); s++; } } void main() { TMOD=0x10; // khoi tao ngat T1, 16bit ET1=1; // cho phep ngat T1 TF1=0; // xoa co ngat T1 TR1=1; // khoi dong T1 EA = 1; // cho phep ngat toan cuc Matrix_chonvitri(0,1); Matrix_guichuoi("IoT47"); while(1) { } } |
Tổng kết
Các bạn có thể tải về toàn bộ file cho bài này Tại đây
Nếu chưa hiểu code, cách tốt nhất là tải project của mình về, thử thay đổi các giá trị data, biến, cắt bớt vòng lặp, tưởng tượng cách thực thi của các vòng lặp để nhận thấy sự khác biệt là sẽ hiểu được cách hoạt động của code thôi
Các bạn nên đọc các bài viết của mình từ bài 1 sẽ dễ hiểu hơn là đọc tắt, nhảy bài. Vì các bài đều có sự liên quan và có lộ trình !
Trong bài tiếp theo mình sẽ hướng dẫn về các hiệu ứng chạy chữ, lật chữ …
You have touched some nice points here. Any way keep up wrinting.
unsigned char Buffer_display[8][4]; mình chưa hiểu cái này từ đâu ra? Giải thích giúp mình vs.
đây là khai báo mảng lưu dữ liệu bật tắt của các con led
Cái mảng đó giống mảng tam để chứa các giá trị của cột của 1 con led ma trận đó ạ
Ad ơi.
Cho em hỏi cái điều kiện này là sao vậy ạ.
(font[txt-32][y-MatrixY] & (0x80>>(x-MatrixX))
Ví dụ font có byte data là 0xA5 = 10100101 nằm ở tọa độ n m
txt phải -32 vì mã ascii bắt đầu từ 32 ( trong khi font bắt đầu từ 0 )
y-MatrixY và (x-MatrixX : Do x,y là tọa độ trên màn led, trong khi tọa độ của font bắt đầu từ 0 nên mình – đi để căn chỉnh lại đúng tọa độ font về vị trí n m => chính là byte 0xA5 ví dụ bên trên
Sau khi lấy được mã font chính xác là 0xA5 mình sẽ cần lấy chính xác bit của nó bằng cách cho & với 0x80 dịch trái 1 lượng
hc595_out(Buffer_display[z][0]);
hc595_out(Buffer_display[z][1]);
hc595_out(Buffer_display[z][2]);
hc595_out(Buffer_display[z][3]);
chỉ với 1 hàm hc595_out làm sao để ic biết mà xuất ra lần lượt 4 con hc595 ạ, e không thấy phần nào là chỉ định con hc595 nào nhận dat để xuất.
dữ liệu đẩy ra hc595 là nối tiếp mà bạn, cứ xếp hàng đẩy lần lượt ra thôi. byte nào đẩy trước thì là cho con cuối
Mình thấy mạch test cùng OK, nhưng vẫn đề lên mạch thực điện áp cấp sao hả bạn. Giả sử mình muốn mở thêm 1;2 tấm nữa thì áp cấp ra sao.
m không giỏi về mảng điện tử lắm đâu. bạn có thể dùng transistor để kích cho led sáng đều đẹp
có thể dùng timer của pic để quét matrix đc ko a
cho em xin code assembly dc ko anh, em còn 1 tuần nữa nộp bài r ạ
anh còn đó k ạ
Bạn cho mính hỏi txt – 32 là sao nhỉ, mình chưa hiểu lắm
void Matrix_setpx(int x,int y,char color)
{
if(x>31 || y>7 || x<0 || y > (x%8)); //sáng led
else Buffer_display[y][x/8] &= ~(0x80 >> (x%8)); //tắt led
}
Mình không hiểu ý nghĩa của [y][x/8] . Ban có thể giải thích cho mình 1 chút về nó được không?
Bài viết rất hay và tâm huyết!