Mục lục
Lời nói đầu 1
Tóm tắt đồ án 2
Danh sách các hình vẽ 5
Danh sách các bảng 6
Danh sách các công thức 7
Phần mở đầu 8
Chương 1 : Giới thiệu chung 10
1.1) Quảng cáo 10
1.2) Bảng led quảng báo 11
1.2.1) Một số đặc trưng 11
1.1.2) Quảng cáo bằng led 12
1.3) Giới thiệu chung về hệ thống 16
Chương 2 : Giới thiệu về vi điều khiển AVR Atmega16 19
2.1) Giới thiệu về vi điều khiển họ AVR 19
2.1.1) Một số đặc trưng 19
2.1.2) Một số đặc trưng 20
2.1.3) Một số đặc trưng 22
2.1.4) Một số họ vi diều khiển AVR 23
2.2) Sơ bộ về vi điều khiển Atmega16 23
2.2.1) Đặc trưng 25
2.2.2) CPU 27
2.2.3) Bộ nhớ 34
Chương 3 : Nguyên tắc điều khiển led ma trận 39
3.1) Cấu trúc và nguyên lý cấp nguồn cho led ma trận 39
3.2) Nguyên tắc tạo font chữ hiển thị 40
3.3) Điều khiển hiển thị led ma trận 41
Chương 4: Điều khiển cấp nguồn cho led ma trận 44
4.1) Điều khiển cấp nguồn cho cột dùng 74HC138 44
4.1.1) Chức năng của 74HC138 44
4.1.2) Sử dụng 74HC138 để cấp nguồn cho các cột ma trận 45
4.2) Điều khiển cấp nguồn cho hàng dùng 74HC595 47
4.2.1) Chức năng của 74HC595 47
4.2.2) Sử dụng 74HC595để cấp nguồn cho các hàng của ma trận 49
4.3) Truyền dữ liệu cấp nguồn cho hàng sử dụng SPI 51
4.3.1) Atmega16 SPI 51
4.3.2) Thiết lập SPI truyền dữ liệu cho 74HC595 55
4.3) Kết luận 56
Chương5: Tạo tần số quét cho ma trận 57
5.1) Timer1 Atmega16 57
5.1.1) Một số chế độ hoạt động 57
5.1.2) Các thanh ghi 62
5.2) Tạo tần số quét ma trận 67
5.3) Kết luận 68
Chương 6: Hiệu ứng hiển thị bảng led 69
6.1) Bảng led hiển thị 69
6.2) Dịch trái, phải 71
6.3) Dịch lên xuống 74
6.4) Hiển thị từng kí tự 77
6.5) Kết luận 79
Kết luận 80
Tài liệu tham khảo 81
Phụ lục A: Sơ đồ ghép nối hệ thống điều khiển led ma trận 82
Phụ lục B: Mã chương trình nạp cho vi điều khiển 86
Tóm tắt đồ án
Nội dung chính của đồ án là việc điều khiển hiển thị led ma trận. Khi điều khiển hiển thị led ma trận có 2 phương pháp cấp nguồn theo từng hàng hay từng cột. Đồ án sẽ tập trung trình bày về phương pháp cấp nguồn theo từng cột . Việc cấp nguồn cho các cột được thực hiện bằng cách sử dụng IC giải mã 74HC138 , cấp nguồn cho các hàng trong cột được thực hiện bằng cách sử dụng bộ ghi dịch 74HC595. Dữ liệu mã hóa cấp nguồn cho các hàng trong cột được gửi ra bộ ghi dịch thông qua việc sử dụng SPI của vi điều khiển. Việc điều khiển thời gian cấp nguồn cho ma trận tạo tốc độ quét được thực hiện bằng cách sử dụng bộ định thời. Phần cuối của đồ án sẽ trình bày về cách tạo một số hiệu ứng cho ma trận led khi sử dụng phương pháp cấp nguồn theo cột
102 trang |
Chia sẻ: lvcdongnoi | Lượt xem: 4880 | Lượt tải: 5
Bạn đang xem trước 20 trang tài liệu Đồ án Thiết kế bảng quảng cáo led sử dụng vi điều khiển atmega16 module điều khiển hiển thị, để xem tài liệu hoàn chỉnh bạn click vào nút DOWNLOAD ở trên
nhỏ thì ta có thể dùng trực tiếp các chân của vi điều khiển để điều khiển việc cấp nguồn cho led ma trận. Nếu ma trận lớn hơn thì ta phải dùng các bộ ghi dịch để cấp nguồn cho led ma trận.
Để hình ảnh trên led ma trận hiển thị rõ ràng không bị nháy ta cần phải điều khiển tần số quét led ma trận. Có thể dùng các bộ định thời của vi điều khiển để điều khiển thời điểm cấp nguồn cho led ma trận tạo tần số quét.
Tóm lại để điều khiển led ma trận ta đầu tiên ta cần phải xác định được phương pháp cấp nguồn cho ma trận ( cấp nguồn theo từng cột hay từng hàng ). Sau khi đã xác định được phương pháp cấp nguồn ta cần phải xây dựng font chữ cho phù hợp với cách cấp nguồn. Từ đây ta có thể tiến hành điều khiển việc cấp nguồn cho ma trận để dòng chữ trên ma trận hiển thị như mong muốn.
Chương 4: Điều khiển cấp nguồn cho led ma trận
Chương này sẽ trình bày về cách điều khiển cấp nguồn cho ma trận sử dụng phương pháp cấp nguồn theo từng cột. Việc điều khiển cấp nguồn cho các cột được thực hiện bằng cách sử dụng IC 74HC138. Các hàng của ma trận sẽ được cập nguồn bằng cách sử dụng bộ ghi dịch 74HC595. Các dữ liệu mã hóa font được truyền nối tiếp từ vi điều khiển tới bộ ghi dịch bằng cách sử dụng SPI .
4.1) Điều khiển cấp nguồn cho cột dùng 74HC138
4.1.1) Chức năng của 74HC138
Sơ đồ chân của 74HC138 [4] :
Hình 4 - 1 Sơ đồ chân 74HC138
IC 74HC138 là bộ giả mã 3 đầu vào ( A0,A1,A2) 8 đầu ra phủ định (Y0 đến Y7 ). Nó có 3 đầu vào cho phép : 2 đầu vào tích cực thấp (,) và một đầu vào tích cực mức cao (E3). Tất cả các đầu ra của 74HC138 sẽ ở mức cao trừ khi , ở mức thấp và E3 ở mức cao. Khi các đầu vào , ở mức thấp và E3 ở mức cao thì đầu ra của 74HC138 sẽ được quyết định bởi đầu vào .
Bảng 4 - 1 Chức nămg hoạt động của 74HC138
Đầu vào
Đầu ra
E3
A0
A1
A2
Y0
Y1
Y2
Y3
Y4
Y5
Y6
Y7
H
X
X
X
H
X
X
X
X
X
X
X
X
X
X
X
X
X
H
H
H
H
H
H
H
H
H
H
H
H
H
H
H
H
H
H
H
H
H
H
H
H
L
L
L
L
L
L
L
L
L
L
L
L
L
L
L
L
H
H
H
H
H
H
H
H
L
L
L
L
H
H
H
H
L
L
H
H
L
L
H
H
L
H
L
H
L
H
L
H
L
H
H
H
H
H
H
H
H
L
H
H
H
H
H
H
H H
L
H
H
H
H
H
H H
H
L
H
H
H
H
H H
H
H
L
H
H
H
H H
H
H
H
L
H
H
H H
H
H
H
H
L
H
H H
H
H
H
H
H
L
4.1.2) Sử dụng 74HC138 để cấp nguồn cho các cột ma trận
Theo nguyên tắc quét ma trận led thì tại mỗi thời điểm ta chỉ cấp nguồn cho một cột của ma trận do đó có thể dung 74HC138 để cấp nguồn cho các cột của ma trận . Các đầu vào ( A0,A1,A2) của 74HC138 sẽ được nối với các chân của vi điều khiển, các đầu ra của 74HC138 được nối với các cột của ma trận led thông qua một cổng phủ định ( hoặc các bộ đệm dòng cấp nguồn cho cột ), còn các chân , được nối đất, E3 nối dương nguồn .Thông qua việc gửi tín hiệu từ vi điều khiển tới các chân đầu vào của 74HC138 ta có thể chọn được cột cần cấp nguồn .
Hình 4 - 2 Ghép nối 74HC138 với vi diều khiển dể cấp nguồn cho cột của ma trận
Khi mở rộng ma trận ta tăng thêm số lượng IC để cấp nguồn cho tất cả các cột, các IC này có thể cùng nối chung hoặc riêng chân điều khiển. Hoặc chỉ sử dụng một IC nhưng cấp nguồn đồng thời cho tất cả các ma trận, khi đó một chân của IC sẽ được nối với các cột của các ma trận khác nhau .
4.2) Điều khiển cấp nguồn cho hàng dùng 74HC595
4.2.1) Chức năng của 74HC595
74HC595 [5] là bộ ghi dịch 8 bít gồm có :
1 đầu vào cho phép ()
1 đầu vào chọn thanh ghi dịch ()
1 đầu vào dữ liệu nối tiếp (DS)
1 đầu vào cấp xung cho thanh ghi dịch (SH_CP)
1 đầu vào cấp xung cho thanh ghi chứa (ST_CP)
8 đầu ra 3 trạng thái ( Q1 đến Q7 và Q7’)
Hình 4 - 3 Sơ đồ chân 74HC595
Bảng 4 - 2 Chức năng hoạt động của 74HC595
Đầu vào
Đầu ra
Chức năng
SH_CP
ST_CP
DS
Q7’
Qn
X
X
L
L
X
L
kđ
MR mức thấp dữ liệu chỉ dịch trong thanh ghi dịch đầu ra không đổi trạng thái
X
L
L
X
L
L
Xóa thanh ghi dich nạp dữ liệu vào thanh ghi chứa
X
X
H
L
X
L
Z
Xóa thanh ghi dịch đầu ra ở trạng thái trở kháng cao
X
L
H
H
Q6’
kđ
Dịch chuyển trạng thái cao vào thanh ghi dịch, giá trị trước đó của bít thứ 6 trong thanh ghi dịch được chuyển sang đầu ra Q7’
X
L
H
X
kđ
Qn’
Nội dụng của thanh ghi dịch được chuyển sang thanh ghi chứa và chuyển sang đầu ra
L
H
X
Q6’
Qn’
Dịch chuyển nội dung của thanh ghi dịch đồng thời nội dung của thanh ghi dịch cũ được chuyển vào thanh ghi chứa và các đầu ra song song
4.2.2) Sử dụng 74HC595để cấp nguồn cho các hàng của ma trận
Khi dùng 74HC595 để cấp nguồn cho ma trận led ta nối các đầu ra song song của 74HC595 với các chân cấp nguồn cho hàng của ma trận. Đồng thời phải sử dụng 3 chân của vi điều khiển để nối với các chân DS,SH_CP,ST_CP của 74HC595. Các bit dữ liệu mã hóa mức logic cần cấp cho các hàng của 1 cột ma trận sẽ được truyền liên tiếp DS của 74HC595. Để đồng bộ bit thì vi điều khiển mỗi khi xuất 1 bit tới chân DS sẽ phát một xung có sườn dương vào chân SH_CP. Sau khi truyền xong hết dữ liệu, để các led trên cột sáng thì ta phải chuyển dữ liệu trong thanh ghi dịch vào các đầu ra của 74HC595 bằng cách cấp 1 xung sườn dương vào chân ST_TP. Chú ý để IC có thể hoạt động và đẩy dữ liệu ra các chân đầu ra thì chân phải nối đất, chân nối dương nguồn.
Hình 4 - 4 Ghép nối 74HC595 với vi điều khiển để cấp nguồn cho hàng của ma trận
Khi mở rộng ma trận led ta ghép nhiều 74HC595 nối tiếp nhau: các chân SH_CP được nối chung với 1 nguồn cấp xung, các chân ST_CP cũng được nối chung với nhau, đầu ra Q7’ của IC phía trước được nối với đầu vào DS của IC tiếp theo. Khi đó dữ liệu sẽ được dịch đồng bộ từ IC này sang IC khác và đầu ra của các IC cũng được chốt đồng bộ.
Hình 4 - 5 Ghép nối tiếp các IC 74HC595
4.3) Truyền dữ liệu cấp nguồn cho hàng sử dụng SPI
4.3.1) Atmega16 SPI
Để truyền dữ liệu từ vi điều khiển vào bộ ghi dịch ta có thể dùng một đoạn chương trình phần mềm lập trình cho vi điều khiển truyền từng bit của dữ liệu. Tuy nhiên Atmega16 có phần cứng hỗ trợ việc truyền dữ liệu nối tiếp với các thiết bị ngoại vi (SPI).
a) Sơ đồ khối và các chế độ SPI [3] :
Hình 4 - 6 Sơ đồ khối của SPI
Ta có thể thiết lập SPI ở 2 chế độ Master và Slave :
Ở chế độ Slave, chân Slave Select ( SS ) phải đặt là đầu vào .Khi chân này bị kéo xuống mức thấp thì SPI sẽ hoạt động, chân MISO có thể đặt làm đầu ra, các chân khác là đầu vào. Khi chân SS được kéo lên mức cao ở mức cao SPI ngừng nhận dữ liệu từ bên ngoài vào. Chân SS có tác dụng đồng bộ byte, gói giúp cho bộ đếm bit của slave đồng bộ với bộ phát xung của master. Khi SS bị kéo lên mức cao thì SPI slave sẽ tái lập lại mức logic truyền và nhận, đồng thời xóa dữ liệu đã nhận trong thanh ghi dịch.
Ở chế độ Master, ta có thể đặt SS làm đầu ra hay vào tùy ý :
Nếu SS được đặt làm đầu ra thì nó không làm ảnh hưởng tói SPI , nó chỉ có tác dụng điều khiển mức logic cho chân SS của SPI slave.
Nếu SS được đặt làm đầu vào thì nó phải được giữ ở mức cao để đảm bảo các hoạt động của SPI master. Nếu SPI bị kéo xuống mức thấp bởi thiết bị ngoại vi thì nó sẽ hiểu đó là một Master khác nên sẽ đặt lại SPI ở chế độ Slave và bắt đầu truyền dữ liệu. Để tránh xung đột trong quá trình này SPI tiến hành các thủ tục sau:
- Xóa bit MSTR trong thanh ghi SPCR để SPI ở chế độ Slave. Do đó các chân MOSI và SCK trở thành đầu vào.
- Thiết lập mức cao cho cờ SPIF trong thanh ghi SPCR. Nếu ngắt SPI và ngắt toàn cục được cho phép thì quá trình ngắt sẽ được thực hiện.
b) Các thanh ghi SPI:
* Thanh ghi diều khiển - SPCR :
Bit 7 6 5 4 3 2 1 0
SPIE
SPE
DORD
MSTR
CPOL
CPHA
SPR1
SPR0
Read/Write R/W R/W R/W R/W R/W R/W R/W R/W
Khởi tạo 0 0 0 0 0 0 0 0
Bit 7 - SPIE : SPI Interupt Enable
Ngắt SPI sẽ được thực hiện nếu cờ SPIF trong SPSR được thiết lập và ngắt toàn cục được cho phép.
Bit 6 - SPE : SPI Enable
Bit này phải được đặt ở mức cao để SPI có thể hoạt động
Bit 5 - DORD : Data Order
Khi DORD ở mức cao thì bit LSB được truyền trước
Khi DORD ở mức thấp thì bit MSB được truyền trước
Bit 4 - MSTR : Master/Slave Select
Bit có tác dụng chọn chế độ cho SPI : Master nếu ở mức cao, Slave nếu ở mức thấp. Nếu chân SS được đặt làm đầu vào thì khi chân này bị kéo xuống mức thấp thì MSTR sẽ bị xóa và SPIF được thiết lập mức cao. Do dó người dùng sẽ phải đặt MSTR trở lại mức cao nếu muốn tiếp tục sử dụng chế độ Master.
Bit 3 – CPOL :Clock Polarity:
Khi bit này được ghi 1 thì SCK ở mức cao khi rỗi, ngược lại thì SCK ở mức thấp khi rỗi.
Bảng 4 - 3 Chức năng của bit CPOL
CPOL
Leading Edge
Trailing Edge
0
Rising
Failing
1
Failing
Rising
Bit 2 – CPHA : Clock Phase
Xác định việc lấy mẫu dữ liệu trên sườn trước hay sau của SCK :
Bảng 4 - 4 Chức năng của bit CPHA
CPHA
Leading Edge
Trailing Edge
0
Sample
Setup
1
Setup
Sample
Bit1,0 – SPR1,SPR0 :SPI Clock Rate Select 1 and 0
Điều khiển tốc độ của SCK ở chế độ Master . Quan hệ giữa SCK
và tần số giao động (fosc) được thể hiện như sau:
Bảng 4 - 5 Quan hệ giữa tần số SCK và tần số giao động
SPI2X
SPR1
SPR0
Tần số SCK
0
0
0
fosc/4
0
0
1
fosc/16
0
1
0
fosc/64
0
1
1
fosc/128
1
0
0
fosc/2
1
0
1
fosc/8
1
1
0
fosc/32
1
1
1
fosc/64
* Thanh ghi trạng thái – SPSR :
Bit 7 6 5 4 3 2 1 0
SPIF
WCOL
-
-
-
-
-
SPI2X
Read/Write R R R R R R R R/W
Khởi tạo 0 0 0 0 0 0 0 0
Bit 7 – SPIF: SPI Interrupt Flag
Sau khi kết thúc việc dữ liệu, cờ SPIF được thiết lập. Ngắt sẽ xảy ra nếu ngắt SPI và ngắt toàn cục được cho phép.
Bit 6 – WCOL: Write COLision flag
Được thiết lập nếu SPDR được ghi dữ liệu khi đang truyền dữ liệu. Sẽ được xóa sau khi thanh ghi trạng thái được kiểm tra.
Bit 5..1 : Không được dùng trong Atmega16
Bit 0: SPI2X: Double SPI Speed Bit
Sử dụng kèm với SPR1, SPR0 để xác định tần số của SCK
* Thanh ghi dữ liệu – SPDR :
Bit 7 6 5 4 3 2 1 0
MSB
LSB
Read/Write R/W R/W R/W R/W R/W R/W R/W R/W
Khởi tạo X X X X X X X X
Chứa dữ liệu cần truyền và nhận .
4.3.2) Thiết lập SPI truyền dữ liệu cho 74HC595
Để kết nối SPI giữa Atmega16 và 74HC595 ta cần nối chân SCK của vi điều khiển với chân SH_CP của 74HC595, nối chân MOSI của vi điều khiển với chân DS của 74HC595. Ngoài ra còn phải dùng 1 chân của vi điều khiển nối với chân ST_CP của 74HC595 để chốt dữ liệu tại đầu ra của 74HC595.
Hình 4 - 7 Ghép nối vi điều khiển với 74HC595 sử dụng SPI
Do việc giao tiếp giữa vi điều khiển và 74HC595 chỉ là quá trình truyền dữ liệu từ vi điều khiển đến 74HC595 nên ta có thể thiết lập cho SPI ở chế độ master với cách sắp xếp dữ liệu theo trật tự bit có trọng số cao thì mã hóa cho hàng ở trên và các đầu ra của 74HC595 cũng được nối với các chân của ma trận led theo trật tự trên thì ta đặt bit DORD=0 .
Các giá trị cần nạp cho thanh ghi :
SPCR=0x50
SPSR=0x00
Sau đó trong chương trình mỗi khi muốn gửi 1 byte nào đó ra ta có thể dùng lệnh trong CodeVisionAVR :
spi(byte) ;
Lệnh này cho phép gửi 1 byte từ vi điều khiển qua chân MOSI tới thiết bị ngoại vi.Sau đó nếu muốn chốt dữ liệu ta cần phải sử dụng 1 thủ tục để gửi 1 sườn dương tới chân ST_CP của 74HC595 thông :
void latchdata( ) {
PORTB.3=0;
PORTB.3=1;
}
4.3) Kết luận
Khi cấp nguồn cho ma trận tùy theo kích thước của ma trận mà ta có thể sử dụng nhiều phương pháp khác nhau. Với các ma trận đủ nhỏ ta có thể sử dụng các chân của vi điều khiển để trực tiếp điều khiển việc cấp nguồn cho ma trận. Với ma trận lớn thì cần phải dùng các IC hỗ trợ cho việc điều khiển cấp nguồn cho ma trận. Khi cấp nguồn cho ma trận theo từng cột thì ta có thể sử dụng các IC có tác dụng chọn kênh để cấp nguồn cho ma trận, tại mỗi thời điểm mỗi IC này chỉ cấp nguồn cho 1 cột của ma trận . Đối với các hàng trong cột thì ta có thể dùng các bộ ghi dịch để cấp nguồn. Khi cấp nguồn thì ta cần chú ý việc cấp phát dữ liệu của các hàng phải tương ứng với cột được cấp nguồn.
Chương5: Tạo tần số quét cho ma trận
Để đảm bảo cho hình ảnh hiển thị rõ nét thì ta cần phải điều chỉnh tần số hiển thị cho phù hợp . Tần số hiển thị càng cao thì hình ảnh càng rõ nét . Dùng bộ định thời của vi điều khiển giúp ta có thể điều khiển tần số hiển thị của ma trận led. Mỗi khi ngắt định thời được thực hiện thì ta sẽ cho một cột của ma trận sáng . Qua đó ta có thể tính được tần số hiển thị của ma trận bằng 1/8 tần số ngắt. Chương sẽ giới thiệu về một số chế độ của Timer1 và các thanh ghi dùng để thiết lập chế độ , sau đó sẽ trình bày về cách thiết lập thanh ghi dùng cho việc điều khiển tần số quét led ma trận.
5.1) Timer1 Atmega16
5.1.1) Một số chế độ hoạt động
Trước tiên ta cần chú ý các định nghĩa sau:
BOTTOM : Counter tới BOTTOM khi nó có dạng 0x0000.
MAX : Counter tới MAX khi nó có dạng 0xFFFF.
TOP : khi Counter tới TOP khi giá trị của nó bằng giá trị cao nhất trong hàng đếm. Giá trị TOP có thể được gán là 1 trong các giá trị cố định khác sau : 0x00FF, 0x01FF, 0x03FF hoặc là giá trị lưu trong OCR1A hoặc thanh ghi ICR1. Việc gán giá trị TOP phụ thuộc vào chế độ hoạt động.
a) Chế độ thông thường :
Chế độ hoạt động đơn giản nhất của Timer là chế độ thường (WGM13:0 = 0). Trong chế độ này bộ đếm luôn đếm lên và không được xóa. Bộ đếm tràn khi đếm qua giá trị max (MAX= 0xFFF) và trở lại BOTTOM (0x0000). Trong chế độ này Timer/Counter Overflow Flag (TOV1) sẽ được thiết lập ngay khi TCNT1 trở về 0. Trong trường hợp này cờ TOV1 hoạt dộng như bit thứ 17 của bộ đếm nên nó không tự xóa. Tuy nhiên khi kết hợp với ngắt tràn Timer cờ này có thể tự động xóa, độ phân giải của Timer có thể tăng lên bởi phần mềm.
Khối bắt tín hiệu đầu vào khá dễ sử dụng ở chế độ thường nhưng cần phải chú ý tới khoảng thời gian lớn nhất giữa các sự kiện ngoài, khoảng thời gian này phải không vượt quá độ phân giải của bộ đếm. Nếu khoảng thời gian giữa các sự kiện quá dài ta có thể dùng ngắt tràn hay tăng độ rộng xung đếm để có thể mở rộng độ phân giải cho khối này .
b) Chế độ CTC ( clear timer on compare) :
Trong chế độ CTC (WGM13:0 = 4 hoặc 12), thanh ghi ICR1 hoặc OCR1A được sử dụng tạo độ phân giải cho bộ đếm. Trong chế độ CTC bộ đếm bị xóa về 0 khi giá trị bộ đếm (TCTN1) trùng với giá trị của thanh ghi OCR1A (WGM13:0 = 4) hoặc ICR1 (WGM13:0 = 12). Thanh ghi OCR1A hoặc ICR1 định nghĩa giá trị đỉnh cho bộ đếm.
Hình 5 - 1 Giản đồ thời gian chế độ CTC
Một ngắt có thể phát ra khi giá trị bộ đếm đạt tới giá trị TOP bởi cùng sử dụng cờ OCF1A hoặc ICF1. Nếu ngắt được cho phép, thủ tục điều khiển ngắt có thể được sử dụng để cập nhập lại giá trị TOP. Thay đổi TOP bằng giá trị gần với BOTTOM khi bộ đếm đang chạy với độ rộng xung lớn phải thực hiện cẩn thận . Nếu giá trị mới ghi cho OCR1A hoặc ICR1 thấp hơn so với giá trị của TCNT, bộ đếm sẽ không bắt được thời điểm đạt giá trị TOP. Do đó nó sẽ đếm tới giá trị MAX (0xFFF) rồi quay về 0x0000 trước khi có thể có thể gặp đượcgiá trị TOP. Để có thể tạo sóng đầu ra trong chế độ CTC, đầu ra OC1A có thể lật mức logic của nó mỗi khi bắt gặp giá trị top bằng cách thiết lập các bit chọn chế độ so sánh đầu ra COM1A1:0 = 01. Giá trị của chân OC1A sẽ không được cập nhật nếu ta không thiết lập nó là đầu ra (DDR_OC1A=1). Sóng phát ra từ chân OCA1 sẽ có tần số cực đại của = khi OCR1A được lập về 0x0000. Tần số của sóng được tính như sau:
Công thức 5 - 1 Quan hệ giữa tần số đầu ra với tần số timer ở chế dộ CTC
N thể hiện độ chia tần ,có thể là các giá trị sau : 1, 8, 64, 256, 1024
c) Chế độ fast PWM :
Fast Pulse Width Modulation hoặc chế độ fast PWM ( WGM13:0 = 5,6,7,14,15) có chức năng tạo ra nhiều dạng sóng tần số cao. Fast PWM khác với chức năng PWM bởi nó chế độ hoạt động sườn đơn. Bộ đếm đếm từ BOTTOM tới TOP sau đó lập tức quay về BOTTOM. Trong chế độ so sánh không đảo đầu ra thì đầu ra OC1x được thiết lập khi TCNT1 và OCR1x bằng nhau, và xóa khi đạt giá trị TOP. Trong chế độ so sánh đảo đầu ra thì chân OC1x được xóa khi ICNT1 và OCR1x bằng nhau, và được thiết lập khi đạt giá trị TOP. Do chỉ dùng sườn đơn nên tần số hoạt động của fast PWM cao gấp 2 lần so với các chế độ Phase correct và Phase and Frequency corect PWM ( các chế độ này khi hoạt động dùng 2 sườn). Tần số cao làm chế độ fast PWM phù hợp với điều chỉnh công suất, chỉnh lưu và ứng dụng DAC. Độ phân giải cho fast PWM có thể cố định 8, 9 hoặc 10 bit, hoặc định nghĩa bởi ICR1 hoặc OCR1A. Độ phân giải nhỏ nhất cho phép là 2 bit (ICR1, OCR1A lập lên 0x0003), lớn nhất là 16 bit (ICR1 hoặc OCR1A khi được gán giá trị MAX). Độ phân giải PWM trong các bit có thể tính theo hàm :
Công thức 5 - 2 Độ phân giải PWM
Hình 5 - 2 Giản đồ thời gian chế độ Fast PWM
Cờ tràn Timer/Counter (TOV1) được lập mỗi khi Counter tới giá trị TOP. Ngoài ra chân OC1A hoặc ICF1 được thiết lập trong cùng một chu kỳ xung với thời điểm TOV1 được thiết lập. Nếu ngắt được cho phép, thủ tục điều khiển ngắt có thể được sử dụng để cập nhập lại TOP và các giá trị so sánh. Khi thay đổi các giá trị TOP ta phải chắc chắn giá trị TOP mới lớn hơn hoặc bằng giá trị của tất cả các thanh ghi so sánh nếu không sẽ không có sự gặp nhau giữa TCNT1 và OCR1x .
Thủ tục cập để nhập lại ICR1 khác với 0CR1A khi sử dụng để định nghĩa giá trị TOP. Thanh ghi ICR1 không có 2 bộ đệm. Nếu ICR1 thay đổi tới 1 giá trị thấp hơn TCNT1 khi bộ đếm đang chạy thì nó sẽ đếm tớ giá trị MAX (0xFFFF) và quay lại giá trị 0x0000 . OCR1A có bộ đẹm kép nên có thể ghi lên nó bất kỳ lúc nào. Khi OCR1A I/O được ghi, giá trị ghi sẽ được đưa vào trong thanh ghi đệm OCR1A. Thanh ghi so sánh OCR1A sẽ cập nhập lại ghía trị trong thanh ghi đệm tại chu kỳ sau khi TCNT1 đạt giá trị TOP.
Trong chế độ fast PWM, khối so sánh cho phép tạo ra 1 dạng sóng tại chân OC1x. Thiết lập các bit COM1x1:0 tới 2 có thể tạo ra một dạng PWM không đảo và một PWM đảo bằng cách thiết lập COM1x1:0 lên 3. Giá trị tại chân OC1x chỉ quan sát được nếu chân này được thiết lập là đầu ra (DDR_OC1x). Dạng sóng PWM được sinh ra khi thiết lập (xóa) chân OC1x tại thời điểm OCR1x = TCNT1 và xóa (thiết lập) OC1x tại thời điểm bộ đếm bị xóa ( từ TOP về BOTTOM).
Tần số PWM tại đầu ra có thể được tính theo hàm:
Công thức 5 - 3 Quan hệ giữa tần số đầu ra với tần số timer ở chế độ Fast PWM
N thể hiện độ chia tần ,có thể là các giá trị sau : 1, 8, 64, 256, 1024
d) Chế độ Phase Correct PWM
Chế độ này hoạt động dựa trên hai sườn lên xuống.Bộ đếm sẽ đếm liên tục từ giá trị BOTTOM đến giá trị MAX và sau đó từ giá trị MAX đến giá trị BOTTOM.Trong chế độ so sánh không đảo chân so sánh (OCx) sẽ bị xóa khi giá trị TCNTx bằng giá trị OCRx trong quá trình đếm lên và sẽ được thiết lập bằng 1 khi giá trị so sánh xuất hiện trong quá trình đếm xuống.Chế độ so sánh đảo thì các giá trị là ngược lại.Với hoạt động hai sườn xung này thì chế độ này không tạo ra được tần số nhỏ như chế độ một sườn xung. Nhưng do tính cân đối của hai sườn xung thì nó tốt hơn cho điều khiển động cơ .
Chế độ phase correct PWM hoạt động cố định là 8 bít.Trong chế độ này bộ đếm sẽ tăng cho đến khi đạt giá trị MAX, khi đó nó sẽ đổi chiều đếm. Biểu đồ thời gian sau đây mô tả hoạt động của hoạt động quá trình:
Hình 5 - 3 Giản đồ thời gian chế độ Phase Corect PWM
Từ biểu đồ thời gian ta nhận thấy việc thay đổi tần số trong hoạt động của phase correct PWM có thể thay thế bằng hai giá trị là MAX và BOTTOM. Nó linh hoạt hơn so với chế độ Fast PWM.
5.1.2) Các thanh ghi
1.TCCR1A:
Bit 7 6 5 4 3 2 1 0
COM1A1
COM1A0
COM1B1
COM1B0
FOC1A
FOC1B
WGM11
WGM10
Read/Write R/W R/W R/W R/W W W R/W R/W
Khởi tạo 0 0 0 0 0 0 0 0
Bit7,6 COM1A1,2 : chọn chế độ đầu ra cho kênh A
Bit5,4 COM1B1,2 : chọn chế độ đầu ra cho kênh B
Nếu cả 2 bit đều được ghi 0 thì các chân OC1A và OC1B coi như không được kết nối với bộ dịnh thời và hoạt động như các chân bình thường khác của vi điều khiển. Khi có ít nhất 1 trong 2 bit được ghi mức cao thì các chân này sẽ được điều khiển bởi bô định thời tùy theo chế độ hoạt động được chọn:
Bảng 5 - 1 Thiết lập chế độ đầu ra cho timer
COM1A1/ COM1B1
COM1A0/ COM1B0
Mô tả
0
0
Port hoạt động thông thường.Không kết nối OC1A/OC1B.
0
1
Lật trạng thái OC1A/OC1B
1
0
Xóa OC1A/OC1B
1
1
Thiết lập OC1A/OC1B
Bit3,2 : cưỡng chế so sánh ở các chế độ không điều chế xung.
Bit1,0 : Được sử dụng kết hợp với các bít WGM12 và WGM13 để xác định chế độ của bộ định thời :
Bảng 5 - 2 Các chế độ điều chế xung
Chế độ
WGM13
WGM12
WGM11
WGM10
Chế độ hoạt động của timer
TOP
Cập nhật OCR1X
Thiết lập cờ TOV1
0
0
0
0
0
Thường
0xFFFF
Lập tức
MAX
1
0
0
0
1
PWM, Phase Correct, 8-bit
0x00FF
TOP
BOTTOM
2
0
0
1
0
PWM, Phase Correct, 9-bit
0x01FF
TOP
BOTTOM
3
0
0
1
1
PWM, Phase Correct, 10-bit
0x03FF
TOP
BOTTOM
4
0
1
0
0
CTC
OCR1A
Lập tức
MAX
5
0
1
0
1
Fast PWM, 8-bit
0x00FF
TOP
TOP
6
0
1
1
0
Fast PWM, 9-bit
0x01FF
TOP
TOP
7
0
1
1
1
Fast PWM, 10-bit
0x03FF
TOP
TOP
8
1
0
0
0
PWM, Phase and Frequency Correct
ICR1
BOTTOM
BOTTOM
9
1
0
0
1
PWM, Phase and Frequency Correct
OCR1A
BOTTOM
BOTTOM
10
1
0
1
0
PWM, Phase Correct
ICR1
TOP
BOTTOM
11
1
0
1
1
PWM, Phase Correct
OCR1A
TOP
BOTTOM
12
1
1
0
0
CTC
ICR1
Lập tức
MAX
13
1
1
0
1
Reserved
-
-
-
14
1
1
1
0
Fast PWM
ICR1
TOP
TOP
15
1
1
1
1
Fast PWM
OCR1A
TOP
TOP
2.TCCR1B:
Bit 7 6 5 4 3 2 1 0
ICNC11
ICES1
-
WGM13
WGM12
CS12
CS11
CS10
Read/Write R/W R/W R R/W R/W R/W R/W R/W
Khởi tạo 0 0 0 0 0 0 0 0
Bit 7 ICNC1: Khi bit này được ghi1 thì các tín hiệu vào từ chân ICP1 sẽ được lọc nhiễu. Bộ lọc nhiễu cần 4 lần lấy mẫu liên tiếp có giá trị bằng nhau ở chân ICP1. Do đó tín hiệu vào bị trễ 4 chu kỳ giao động so với khi không lọc nhiễu.
Bit 6 ICES1 : Bit này lựa chọn sườn kích hoạt sự kiện tại chân ICP1. Khi bit này được ghi 0 thì sườn âm được sử dụng để kích hoạt Khi bit này được ghi 1 thì sườn dương được sử dụng.
Bit 5 : không dùng trong Atmega16
Bit 4,3 WGM13,2 : Cùng với WGM11,0 để để xác định chế độ của bộ định thời
Bit 2,1,0 CS12,1,0 : Dùng để lựa chọn tần số cho Timer
Bảng 5 - 3 Lựa chọn tần số cho bộ đếm
CS12
CS11
CS10
Mô tả
0
0
0
Timer không hoạt động
0
0
1
/1 ( không chia tần )
0
1
0
/8 ( từ bộ chia tần )
0
1
1
/64 ( từ bộ chia tần )
1
0
0
/256 ( từ bộ chia tần )
1
0
1
/1024( từ bộ chia tần )
1
1
0
Nguồn ngoài từ chân T1 , sườn lên
1
1
1
Nguồn ngoài từ chân T1 , sườn xuống
3.TCNT1H/L:
Bit 7 6 5 4 3 2 1 0
TCNT1[15:8]
TCNT1[7:0]
Read/Write R/W R/W R/W R/W R/W R/W R/W R/W
Khởi tạo 0 0 0 0 0 0 0 0
Lưu giá trị của bộ đếm. Có khả năng truy nhập trực tiếp để ghi và đọc thông qua việc sử dụng thanh ghi tạm thời. Việc thay đổi thanh ghi này trong khi bộ đếm đang hoạt động có thể bỏ qua một lần gặp nhau giữa TCNT1 và các thanh ghi OCR1x .
4.OCR1AH/L:
Bit 7 6 5 4 3 2 1 0
OCR1A[15:8]
OCR1A[7:0]
Read/Write R/W R/W R/W R/W R/W R/W R/W R/W
Khởi tạo 0 0 0 0 0 0 0 0
5.OCR1BH/L:
Bit 7 6 5 4 3 2 1 0
OCR1B[15:8]
OCR1B[7:0]
Read/Write R/W R/W R/W R/W R/W R/W R/W R/W
Khởi tạo 0 0 0 0 0 0 0 0
Các thanh ghi OCR1x được liên tục so sánh với thanh ghi TCNT1 . Mỗi khi bằng nhau có thể tạo ra 1 ngắt so sánh đầu ra hay để thay đổi dạng sóng tại các chân đầu ra OC1x .
6.TIMSK:
Bit 7 6 5 4 3 2 1 0
OCIE2
TOIE2
TICE1
OCIE1A
OCIE1B
TOIE1
OCIE0
TOIE0
Read/Write R/W R/W R R/W R/W R/W R/W R/W
Khởi tạo 0 0 0 0 0 0 0 0
Các bit 7,6,1,0 dùng cho các timer khác của Atmega16.
Bit 5 - TICIE1 : Khi bit này được thiết lập thành 1 và ngắt toàn cục (global interrupt) được cho phép thì ngắt bộ đếm đầu vào Timer/couter1 (Timer/Counter1 Input Capture interrupt) được cho phép. Vector ngắt tương ứng sẽ được thực thi khi cờ ICF1 trong thanh ghi TIFR được thiết lập.
Bit4 - OCIE1A : Khi bit này được thiết lập thành 1 và ngắt toàn cục (global interrupt) được cho phép thì ngắt so sánh đầu ra 1A (Timer/Counter1 Output Compare A Match Interrupt) được cho phép. Vector ngắt tương ứng sẽ được thực hiện khi cờ OCF1A trong thanh ghi TIFR được thiết lập.
Bit3 - OCIE1B : Khi bit này được set thành 1 và ngắt toàn cục (global interrupt) được cho phép thì ngắt so sánh đầu ra 1B (Timer/Counter1 Output Compare B Match Interrupt) được cho phép. Vector ngắt tương ứng sẽ được thực thi khi cờ OCF1B trong thanh ghi TIFR được thiết lập .
Bit2 – TOIE1 : Khi bit này đượcset thành 1 và ngắt toàn cục (global interrupt) được cho phép thì ngắt cờ tràn bộ định thời 1 (Timer/Counter1 overflow interrupt) được cho phép. Vector ngắt tương ứng sẽ được thực thi khi cờ TOV1 trong thanh ghi TIFR được thiết lập .
7.TIFR:
Bit 7 6 5 4 3 2 1 0
OCF2
TOV2
ICF1
OCF1A
OCF1B
TOV1
OCF0
TOF0
Read/Write R/W R/W R R/W R/W R/W R/W R/W
Khởi tạo 0 0 0 0 0 0 0 0
Các bit 7,6,1,0 dùng cho các timer khác của Atmega16.
Bit5 - ICF1 : Cờ này được thiết lập khi xảy ra sự kiện tại ngõ vào (Input Capture) của chân ICP1. Khi thanh ghi ICR1 (InputCapture Register) được thiết lập bởi các bit WGMn3:0 để sử dụng như một giá trị đỉnh thìcờ ICF1 sẽ được thiết lập khi bộ đếm đạt tới giá trị đỉnh. Cờ ICF1 sẽ tự động xóa khi ngắt tương ứng được thực thi, hoặc có thể xóa hay thiết lập bằng cách ghi một giá trị logic vào vị trí của nó.
Bit4 - OCF1A : Cờ này được thiết lập ngay sau khi giá trị bộ đếm (TCNT1) bằng với giá trị thanh ghi OCR1A (Output Compare Register A). Chú ý là một so sánh cưỡng bức (FOC1A) sẽ không thiết lập cờ này. Cờ OCF1A sẽ tự động xóa khi ngắt tương ứng được thực thi, hoặc có thể xóa hay thiết lập bằng cách ghi một giá trị logic vào vị trí của nó.
Bit 3 - OCF1B : Cờ này được thiết lập ngay sau khi giá trị bộ đếm (TCNT1) bằng với giá trị thanh ghi OCR1B (Output Compare Register B). Chú ý là một so sánh cưỡng bức (FOC1B) sẽ không thiết lập cờ này. Cờ OCF1B sẽ tự động xóa khi ngắt tương ứng được thực thi, hoặc có thể xóa hay thiết lập bằng cách ghi một giá trị logic vào vị trí của nó.
Bit 2 - TOV1 : Việc thiết lập cờ này phụ thuộc vào thiết lập của các bit WGMn3:0, trong chế độ bình thường và CTC cờ TOV1 được thiết lập khi bộ định thời tràn.
5.2) Tạo tần số quét ma trận
Để đảm bảo mắt người có thể cảm nhận được hình ảnh dễ dàng không bị rung thì ta cần tạo tần số quét khoảng 60Hz .
Do ma trận led có 8 cột sáng luân phiên nên số lần cấp nguồn cho led là :
60 x 8= 480 lần/s .
Khi đó khoảng cách giữa 2 lần cấp nguồn liên tiếp khoảng :
1000:480= 2,083 ms
Tần số của thạch anh là 11.0592MHz do đó số chu kì dao động trong khoảng thời gian trên là :
11.0592 x 2083= 23040lần
Đây cũng là số chu kì mà timer phải đếm để cấp nguồn cho led các cột của ma trận.
Để đơn giản trong việc điều khiển cấp nguồn cho led ma trận ta dùng ngắt Timer1 chế độ CTC ngắt khi bộ đếm đạt giá trị TOP=OCR1A . Do không cần lấy sóng đầu ra nên ta có thể gán 0x10 cho thanh ghi TIMSK , gán 0x00 cho thanh ghi TCCR1A , gán 0x0M cho TCCR1B với M là một trong các giá trị sau :9,A,B,C,D.
Do đó khi dùng ngắt chế độ CTC thì ta cần nạp giá trị 23115 cho thanh ghi OCR1A nếu không chia tần số dao động ( các bit CS12:0 của TCCR1B dược gán 001). Với các độ chia tần khác của Timer ta có thể nạp các giá trị sau:
Bảng 5 - 4 Tạo tốc độ quét 60 Hz cho ma trận
CS12
CS11
CS10
OCR1A
TCCR1B
0
0
1
23040
0x09
0
1
0
2880
0x0A
0
1
1
360
0x0B
1
0
0
90
0x0C
1
0
1
22
0x0D
Để thay đổi tốc độc quét cho ma trận ta có thể thay đổi các giá trị của các thanh ghi OCR1A và TCCR1B ( các bit CS12,11,10 của TCCR1B) .
5.3) Kết luận
Tốc độ quét ma trận ảnh hưởng hình ảnh quan sát được trên ma trận. Do đó việc tạo tốc độ quét hợp lý có vai trò quan trọng trong việc điều khiển hiển thị led ma trận. Dùng bộ định thời là phương pháp đơn giản nhất để điều khiển tốc độ quét một cách chính xác. Việc thiết lập các thông số cho bộ định thời một cách linh hoạt sẽ giúp ta dễ dàng hơn trong việc điều khiển tốc độ quét cho ma trận.
Chương 6: Hiệu ứng hiển thị bảng led
Để tạo các hiệu ứng thì ta phải quét ma trận led sao cho hình ảnh hiển thị trên ma trận đạt được như mong muốn. Do đó ta chỉ cần điều khiển việc đưa dữ liệu vào các chân của ma trận một cách hơp lý là có thể tạo ra được hiệu ứng mong muốn . Để thực hiện điều này ta có thể dùng 2 mảng dữ liệu, 1 mảng để lưu dữ liệu của hình ảnh ( chưa có hiệu ứng ), 1 mảng lưu dữ liệu của hình ảnh tức thời để đưa ra hiển thị. Mảng thứ 2 được xây dựng bằng cách xử lí lại dữ liệu của mảng thứ nhất. Nguyên tắc chung cho việc điều khiển led ma trận tạo hiệu ứng là sau khi 1 hình ảnh được hiển thị thì ta lấy mẫu cho hình ảnh tiếp theo rồi cho hiển thị hình ảnh đó ( dữ liệu mã hóa các hình ảnh này được lưu ở mảng thứ 2 ).
6.1) Bảng led hiển thị
Trước khi xây dựng các hiệu ứng hiển thị ta cần xác định xem bảng led cần điều khiển có kích thước như thế nào và phải xác định được bảng led được xây dựng như thế nào. Khi hiểu rõ cách xây dựng bảng led ta mới có thể điều khiển cấp nguồn cho bảng led. Trong đồ án này chúng em xây dựng một bảng led gồm 6 ma trận led 8x8 hai màu ( xanh, đỏ) anot chung được bố tí thành hai hàng mỗi hàng 3 ma trận :
Hình 6 - 1 Bảng led hiển thị
Các ma trận được xoay sao cho các anot của led được nối chung theo từng cột. Mỗi cột có 8 led 2 màu, các catot của led xanh được nối với đầu ra của IC 74HC595 thứ nhất thông qua bộ dệm dòng ULN2803, còn các catot của led đỏ được nối với IC 74HC595 thứ hai. Hai IC 74HC595 được mắc nối tiếp nhau, đầu ra nối tiếp Q7’ của IC thứ nhất được nối với đầu vào của IC thứ 2. Đầu ra Q7’ của IC thứ 2 sẽ được nối với giắc cắm để mở rộng sang các led ma trận tiếp theo. Với cách bố trí như trên, đế của ma trận led mỗi ma trận led sẽ có 8 chân đầu vào cấp nguồn ( cho từng cột ), 2 chân đầu vào cấp nguồn cho các IC, 3 chân đầu vào nối với 74HC595 ( DS, SH_CP, ST_CP), và 5 chân đầu ra để nối với các ma trận led khác gồm 2 chân nguồn và 3 chân nối với 74HC595.
Với cách tổ chức ma trận như trên phải cấp nguồn cho ma trận led theo từng cột. Dữ liệu cấp nguồn cho các hàng khi gửi nối tiếp thông qua SPI cần phải gửi theo thứ tự: dữ liệu cho ma trận led phía sau được gửi ra trước và sau khi đã gửi hết dữ liệu cho tất cả các ma trận thì mới chốt dữ liệu tại đầu ra của các IC 74HC595. Mỗi ma trận cần dữ liệu của 2 màu, IC chứa dữ liệu màu xanh ở phía trước nên ta sẽ phải truyền dữ liệu cho màu đỏ trước rồi mới đến màu xanh.
Các phần tiếp theo của chương này sẽ tình bày về cách tạo các hiệu ứng hiển thị cho bảng led gồm 3 ma trận led có cấu tạo như trên. Tuy nhiên ta có thể sử dụng các thuật toán này khi mở rộng ma trận với kích thước lớn hơn.
6.2) Dịch trái, phải
Với cách tổ chức dữ liệu mã hóa kí tự theo từng cột thì việc điều khiển hiển thị cho các ký tự dịch trái , phải trên led ma trận là khá đơn giản .
Giả sử ta muốn hình ảnh dịch sang trái thì ta chỉ việc đưa dữ liệu của cột bên phải của hình ảnh trước ra để hiển thị cho cột hiện tại của hình ảnh sau (cột 1 của hình ảnh mới là cột 2 của hình ảnh cũ … ) .
Cụ thể với ma trận 8 hàng 24 cột ta có thể làm như sau :
- Dùng một mảng để lưu dữ liệu của toàn bộ hình ảnh khi không dịch chuyển. Mảng này cần có kích thước 24 bytes ( lưu dữ liệu của 24 cột ).
- Dùng một mảng khác để lưu dữ liệu của các hình ảnh tức thời , hình ảnh này có kích thước bằng với hình ảnh trên (24 bytes).
- Tại thời điểm đầu tiên thì hình ảnh tức thời sẽ lưu giá trị 0 cho tất cả các cột ( ma trận tắt ). Tại thời điểm thứ 2 ta gán giá trị của cột 1 của mảng thứ nhất và cột 24 của mảng thứ 2 . Tại thời điểm tiếp theo ta gán giá trị của cột 1,2 của mảng thứ nhất vào cột 23,24 của mảng thứ 2... Cứ như thế khi lần lượt hiển thị và lấy mẫu lại hình ảnh ta sẽ thấy hình ảnh trên ma trận led dịch từ trái sang phải.
Hình 6 - 2 Mô phỏng hiệu ứng dịch trái
Hình 6 - 3 Lưu đồ thuật toán hiệu ứng dịch trái
Khi mở rộng kích thước của ma trận hay số lượng các ký tự làm vượt quá kích thước của ma trận thì ta vẫn có thể sử dụng phương pháp trên nhưng với giá trị giới hạn không phải là 23 mà là số cột của ma trận hay số cột cần để hiển thị hết toàn bộ các ký tự.
Ngoài ra ta cũng có thể xếp 2 mảng thành một, mảng ở sau, mảng 2 ở trước rồi cứ mỗi lần hiển thị ta là phép gán dịch trái các dữ liệu trong mảng M[i]=M[i+1], bắt đầu với i=0, gán M[2n-1]=0 với n là số cột hiển thị. Dữ liệu đưa ra hiển thị là n giá trị đầu của mảng.
Hiệu ứng dịch phải cũng tương tự như dịch trái nhưng phải thay phép gán trong vòng lặp j thành M2[j]=M1[n-j]. Ta cũng có thể gom 2 mang làm một, mảng 1 ở trước mảng 2 ở sau, cứ mỗi lần hiển thị ta gán M[i] = M[i-1] nhưng bắt đầu với i = 2n-1và gán M[0]=0 ; dữ liệu đưa ra hiển thị là n giá trị sau của mảng.
6.3) Dịch lên xuống
Với cách tổ chức dữ liệu mã hóa kí tự theo từng cột thì việc điều khiển hiển thị cho các ký tự dịch lên xuống có thể thực hiện bằng cách dịch bit các dữ liệu mã hóa hình ảnh của từng cột .
Cụ thể với ma trận 8 hàng 24 cột cho hình ảnh dịch lên ta có thể làm như sau:
- Dùng một mảng để lưu dữ liệu của toàn bộ hình ảnh khi không dịch chuyển. Mảng này cần có kích thước 24 bytes ( lưu dữ liệu của 24 cột ).
- Dùng một mảng khác để lưu dữ liệu của các hình ảnh tức thời , hình ảnh này có kích thước bằng với hình ảnh trên (24 bytes).
- Tại thời điểm đầu tiên thì hình ảnh tức thời sẽ lưu giá trị 0 cho tất cả các cột ( ma trận tắt ). Tại thời điểm thứ 2 ta cần gán bit mã hóa hàng trên cùng của mảng 1 ( MSB ) vào hàng dưới cùng của mảng 2 ( LSB ). Do đó ta cần phải dịch phải các bit trong từng byte dữ liệu của mảng 1 đi 7 bit rồi gán vào mảng 2. Tại thời điểm tiếp theo ta dịch phải 6 bit . Cứ như vậy hình ảnh sẽ dịch dần lên. Tuy nhiên nếu chi dịch như vậy thì thình ảnh chỉ dịch đến khi ra giữa ma trận. Để hình có thể tiếp tục dịch lên thì ta phải dịch trái dữ liệu đi từ 1 bit cho đến 7 bit . Sau khi dịch trái hết thì lại gán 0 cho tất cả các bit của ma trận .
Hình 6 - 4 Mô phỏng hiệu ứng dịch lên
Hình 6 - 5 Lưu đồ thuật toán hiệu ứng dịch lên
Khi mở rộng ma trận chu trình gán giá trị hiển thị sẽ phứa tạp hơn do kích thước dữ liệu cần gán cho một cột của ma trận tăng lên. Khi đó ta có thể chia dữ liệu đem ra hiển thị thành nhiều mảng với mỗi mảng đại diện cho 1 “ dòng ” của ma trận. Phần tử đầu tiên của mỗi mảng sẽ chứa dữ liệu cho cột đầu tiên của mỗi dòng. Cứ mỗi lần dịch ta có thể gán Mt[i] = ( Mt[i]>(8-j) ). Với Mt là dòng trên, Md là dòng dưới .
Hiệu ứng dịch xuống cũng tương tự như dịch lên nhưng khác ở chiều của phép dịch bit và số lần dịch bit ta có thể thay chiều của phép dịch và số bit dịch đổi từ (8-i) thành i .
6.4) Hiển thị từng kí tự
Với cách tổ chức dữ liệu mã hóa kí tự theo từng cột thì việc điều khiển cho các ký tự lần lượt hiện trên bảng led có thể thực hiện bằng cách lấy mẫu lần lượt thêm từng ý tự một .
Cụ thể với ma trận 8 hàng 24 cột cho hiển thị tưng ký tự một ta có thể làm như sau :
- Dùng một mảng để lưu dữ liệu của toàn bộ hình ảnh khi không dịch chuyển. Mảng này cần có kích thước 24 bytes ( lưu dữ liệu của 24 cột ).
- Dùng một mảng khác để lưu dữ liệu của các hình ảnh tức thời, hình ảnh này có kích thước bằng với hình ảnh trên (24 bytes).
- Tại thời điểm đầu tiên thì mảng lưu hình ảnh tức thời được gán 0 để tắt tất cả các led. Sau đó tại các thời điểm tiếp theo ta lần lượt gán từng 6 bytes của mảng 1 vào mảng 2 để đưa ra hiển thị ( do cứ 6 bytes thì mã hóa 1 ký tự).
Hình 6 - 6 Mô phỏng hiệu ứng hiển thị từng chữ
Hình 6 - 7 Lưu đồ thuật toán hiệu ứng hiển thị tưng ký tự
6.5) Kết luận
Việc sử dụng 2 mảng dữ liệu một mảng lưu toàn bộ khung hình, một mảng lưu hình ảnh tức thời sẽ giúp việc tạo các hiệu ứng đơn giản hơn. Xử lý các dữ liệu trên mảng thứ nhất rồi lưu vào mảng thứ 2 để đưa ra hiển thị sẽ cần một lượng bộ nhớ lớn khi số lượng ký tự và kích thước của font chữ tăng. Do đó khi tạo các hiệu ứng và điều khiển hiển thị cần phải chú ý đến kích thước bộ nhớ. Nếu cần có thể dùng thêm các bộ nhớ ngoài hoặc chọn các vi điều khiển có bộ nhớ đủ lớn để có thể tạo hiệu ứng cần thiết. Các bảng điện tử thông dụng thường chỉ hiển thị một nội dung cố định nên ta có thể sử dụng bộ nhớ flash (có kích thước khá lớn ) để lưu giá trị của mảng thứ nhất, thậm chí có thể lưu toàn bộ các khung cần hiển thị. Khi đó ta chỉ cần điều khiển việc xuất dữ liệu theo địa chỉ để hiển thị.
Đối với phương pháp cấp nguồn theo từng cột thì việc tạo các hiệu ứng dịch trái, dịch phải khá đơn giản và việc mở rộng ma trận không ảnh hưởng nhiều đến việc gán dữ liệu nhưng với các hiệu ứng dịch lên xuống khá phức tạp khi mở rộng ma trận. Tuy nhiên nếu chỉ sử dụng một hiệu ứng cho ma trận thì với hiệu ứng dịch lên, xuống ta có thể chọn phương pháp cấp nguồn theo từng hàng. Khi đó cần phải xây dựng font chữ theo tưng hàng và phải xắp xếp lại các ma trận led ( xoay 90 độ so với khi cấp nguồn theo cột ).
Kết luận
Module điều khiển hiển thị đã hoàn thành , và đạt được những kết quả sau:
- Có khả năng điều khiển hiển thị 2 chuỗi ký tự trên hai hàng ma trận, có khả năng điều khiển hiển thị ma trận có đọ rộng lớn hơn.
- Có khả năng hiển thị các dòng ký tự với ba màu xanh, đỏ và cam.
- Có khả năng điều khiển hiển thị các ký tự với một số hiệu ứng cơ bản. Thuật toán điều khiển hiển thị hiệu ứng có thể sử dụng khi mở rộng ma trận và có thể làm cơ sở để tạo các hiệu ứng phức tạp hơn.
- Có khả năng thay đổi tần số quét ma trận .
Tuy nhiên module vẫn còn một số giới hạn :
- Có thể hiển thị các ký tự trên hai dòng nhưng lại độc lập với nhau. Do đó khi gặp phải một số yêu cầu về việc hiển thị 2 dòng chữ có độ tương quan nhất định thì cần phải thay đổi về việc điều khiển xuất dữ liệu.
- Tuy có thể thay đổi màu của dòng chữ hiển thị nhưng lại chưa điều khiển được màu sắc của từng ký tự. Vấn đề này có thể dễ dàng khắc phục khi hiển thị các ký tự tĩnh, nhưng khi cần điều khiển các ký tự động thì sẽ khó khăn trong việc điều khiển màu sắc.
- Do quá trình điều khiển hiển thị cần có giai đoạn lấy mẫu lại dữ liệu nên khi điều khiển hiển thị ma trận có kích thước lớn có thể gây ảnh hưởng đến việc điều khiển tần số quét .
Trong đề tài có thể có một số vấn đề hợp lý hay chưa tối ưu về các thuật toán điều khiển hiển thị và sử dụng bộ nhớ của vi điều khiển. Do đó em rất mong có sự góp ý của các thầy cô và các bạn để đồ án có thể hoàn thiện hơn.
Tài liệu tham khảo
[1] Steven F. Barrett and Daniel J. Pack, Atmel AVR Microcontroller Primer: Programming and Interfacing, Morgan & Claypool, 2008
[2] Joe Pardue, C Programming for Microcontrollers, Smiley Micros, 2005
[3] Atmega16 datasheet, www.alldatasheet.com, truy nhập cuối cùng ngày 26/5/2009
[4] 74HC595 datasheet, www.alldatasheet.com, truy nhập cuối cùng ngày 26/5/2009
[5] 74HC138 datasheet, www.alldatasheet.com, truy nhập cuối cùng ngày 26/5/2009
[6] truy nhập cuối cùng ngày 26/5/2009
[7] truy nhập cuối cùng ngày 26/5/2009
[8] truy nhập cuối cùng ngày 26/5/2009
[9] truy nhập cuối cùng ngày 26/5/2009
Phụ lục A: Sơ đồ ghép nối hệ thống điều khiển led ma trận
Hình A - 1 Sơ đồ ghép nối hệ thống
KHỐI CẤP NGUỒN:
Hình A - 2 Khối cấp nguồn
KHỐI CHỐT DỮ LIỆU CÁC HÀNG
Hình A - 3 Khối chốt dữ liệu các hàng
KHỐI GIAO TIẾP VỚI MÁY TÍNH:
Hình A - 4 Khối giao tiếp máy tính
KHỐI KHUẾCH ĐẠI DÒNG CHO CỘT:
Hình A - 5 Khối khuếch đại dòng cho cột
KHỐI ĐIỀU KHIỂN TRUNG TÂM VÀ QUÉT CỘT:
Hình A - 6 Khối xử lý trung tâm và quét cột
Phụ lục B: Mã chương trình nạp cho vi điều khiển
#include
#include
#include
#include
#define SCL PORTB.3
unsigned char flash FONT []={0,
62,65,65,65,62,0, //0 1
17,33,127,1,1,0, //1 2
35,69,73,73,49,0, //2 3
34,65,73,73,54,0, //3 4
12,20,36,79,4,0, //4 5
114,73,73,73,70,0, //5 6
62,73,73,73,38,0, //6 7
65,66,68,72,112,0, //7 8
54,73,73,73,54,0, //8 9
50,73,73,73,62,0, //9 10
63,68,68,68,63,0, //A 11
127,73,73,73,54,0, //B 12
62,65,65,65,34,0, //C 13
127,65,65,65,62,0, //D 14
127,73,73,73,65,0, //E 15
127,72,72,72,64,0, //F 16
62,65,73,73,46,0, //G 17
127,8,8,8,127,0, //H 18
65,65,127,65,65,0, //I 19
70,65,65,126,64,0, //J 20
127,8,20,34,65,0, //K 21
127,1,1,1,1,0, //L 22
127,32,24,32,127,0, //M 23
127,32,16,8,127,0, //N 24
62,65,65,65,62,0, //O 25
127,68,68,68,56,0, //P 26
62,65,69,66,61,0, //Q 27
127,68,68,74,49,0, //R 28
50,73,73,73,38,0, //S 29
64,64,127,64,64,0, //T 30
126,1,1,1,126,0, //U 31
124,2,1,2,124,0, //V 31
127,2,12,2,127,0, //W 33
65,34,28,34,65,0, //X 34
96,16,15,16,96,0, //Y 35
67,69,73,81,97,0, //Z 36
4,42,42,42,28,0, //a 37
126,18,18,18,12,0, //b 38
28,34,34,34,20,0, //c 39
12,18,18,20,126,0, //d 40
28,42,42,16,0,0, //e 41
4,62,72,64,32,0, //f 42
24,37,37,37,30,0, //g 43
126,16,16,16,14,0, //h 44
0,92,2,2,4,0, //i 45
4,2,2,92,0,0, //j 46
126,8,20,34,0,0, //k 47
124,2,2,2,0,0, //l 48
30,32,30,32,30,0, //m 49
62,8,16,62,0,0, //n 50
28,34,34,34,28,0, //o 51
31,36,36,36,24,0, //p 52
24,36,36,36,31,0, //q 53
0,30,32,32,24,0, //r 54
18,42,42,42,36,0, //s 55
0,32,124,34,4,0, //t 56
60,2,2,2,60,0, //u 57
56,4,2,4,56,0, //v 58
56,2,12,2,56,0, //w 59
34,20,8,20,34,0, //x 60
48,8,14,8,48,0, //y 61
34,38,42,50,34,0, //z 62
0,0,0,0,0,0, //
255};
unsigned char dong1[192],dong2[192];
unsigned char tocdo_quet=50,tocdo_chay=3,c,col=2,eff=1,sc=0,sp=0;
unsigned char tg,m=0,t=0,k=0,i,j,sokt=4,sokt1=4,sokt2=4;
unsigned char chuoi1[16]={8,8,8,8,8,8,8,8};
unsigned char chuoi2[16]={6,6,6,6,6,6,6,6};
void LatchData(){
SCL=0;
SCL=1;
}
void lm1() {
for (i=0;i<=sokt1-1;i++){
for (j=0;j<=5;j++) {
dong1[i*6+j]=~FONT[chuoi1[i]*6+j+1];
}
}
for (i=0;i<=sokt2-1;i++){
for (j=0;j<=5;j++) {
dong2[i*6+j]=~FONT[chuoi2[i]*6+j+1];
}
}
}
void lm2(){
for (i=0;i<=sokt1*6-1;i++){
dong1[i+sokt1*6]=dong1[i];
//dong1[i]=0;
dong1[i]=255;
}
for (i=0;i<=sokt2*6-1;i++){
dong2[i+sokt2*6]=dong2[i];
//dong2[i]=0;
dong2[i]=255;
}
}
void xulychuoi(){
for (i=0;i<sokt1;i++) {
if ((chuoi1[i]>47)&&(chuoi1[i]<58)) chuoi1[i]=chuoi1[i]-48;
else if ((chuoi1[i]>64)&&(chuoi1[i]<91)) chuoi1[i]=chuoi1[i]-55;
else if ((chuoi1[i]>96)&&(chuoi1[i]<123)) chuoi1[i]=chuoi1[i]-60;
else chuoi1[i]=62;
}
for (i=0;i<sokt2;i++) {
if ((chuoi2[i]>47)&&(chuoi2[i]<58)) chuoi2[i]=chuoi2[i]-48;
else if ((chuoi2[i]>64)&&(chuoi2[i]<91)) chuoi2[i]=chuoi2[i]-55;
else if ((chuoi2[i]>96)&&(chuoi2[i]<123)) chuoi2[i]=chuoi2[i]-60;
else chuoi2[i]=62;
}
}
void shiftleft(){
for (i=0;i<sokt1*12-1;i++){
dong1[i]=dong1[i+1];
}
//dong1[sokt1*12-1]=0;
dong1[sokt1*12-1]=255;
for (i=0;i<sokt2*12-1;i++){
dong2[i]=dong2[i+1];
}
//dong2[sokt2*12-1]=0;
dong2[sokt2*12-1]=255;
}
void shiftright(){
tg= dong1[sokt*12-1];
for (i=sokt1*12-1;i>0;i--){
dong1[i]=dong1[i-1];}
dong1[0]=tg;
tg= dong2[sokt*12-1];
for (i=sokt2*12-1;i>0;i--){
dong2[i]=dong2[i-1];}
dong2[0]=tg;
}
void UP(int k){
sokt=((sokt1>sokt2)?sokt1:sokt2);
if (k<8)
for (i=0;i<=sokt*6-1;i++){
dong1[i]=0xFF;
dong2[i]=(dong1[i+sokt*6]>>(8-k))|(0xFF<<k);
}
else if ((k>7)&&(k<16)) {
m=k-8 ;
for (i=0;i<=sokt*6-1;i++){
dong1[i]=(dong1[i+sokt*6]>>(8-m))|(0xFF<<m);
dong2[i]=(dong1[i+sokt*6]>(8-m));
} }
else if ((k>15)&&(k<24)) {
m=k-16 ;
for (i=0;i<=sokt*6-1;i++){
dong1[i]=(dong1[i+sokt*6]>(8-m));
dong2[i]=(dong2[i+sokt*6]>(8-m));
} }
else {
m=k-24 ;
for (i=0;i<=sokt*6-1;i++){
dong1[i]=(dong2[i+sokt*6]>(8-m));
dong2[i]=0xFF;
} }
/*
if ( k>=8) {
for (i=0;i<=sokt*6-1;i++){
m=k-8;
dong1[i]=(dong1[i+sokt*6]>(8-m));
dong2[i]=(dong2[i+sokt*6]>(8-m));
} }
if (k<8) {
for (i=0;i<=sokt*6-1;i++){
dong1[i]=(dong1[i+sokt*6]>>(8-k))|(0x7F<<k);
dong2[i]=(dong2[i+sokt*6]>>(8-k))|(0x7F<<k);
} }
*/
}
void down(int k){
sokt=((sokt1>sokt2)?sokt1:sokt2);
if (k>23) {
m=k-24;
for (i=0;i<=sokt*6-1;i++){
dong1[i]=0xFF;
dong2[i]=(dong1[i+sokt*6]>>m)|(0x7F<<m);
} }
if ((k>15)&&(k<=23)) {
m=k-16;
for (i=0;i<=sokt*6-1;i++){
dong1[i]=(dong1[i+sokt*6]>>m)|(0xFF<<(8-m));
dong2[i]=(dong1[i+sokt*6]>m);
} }
if ((k>7)&&(k<16)) {
m=k-8;
for (i=0;i<=sokt*6-1;i++){
dong1[i]=(dong1[i+sokt*6]>m);
dong2[i]=(dong2[i+sokt*6]<<m)|(0xFF<<(8-m));
} }
if (k<8){
m=8-k ;
for (i=0;i<=sokt*6-1;i++){
dong1[i]=(dong2[i+sokt*6]>(8-m));
dong2[i]=0xFF;
} }
/*
if ( k>8) {
for (i=0;i<sokt*6;i++){
m=k-8;
dong2[i]=(dong2[i+sokt*6]>>m)|(0x7F<<(8-m));
dong1[i]=(dong1[i+sokt*6]>>m)|(0x7F<<(8-m));
} }
if (k<=8) {
for (i=0;i<sokt*6;i++){
dong2[i]=(dong2[i+sokt*6]>k);
dong1[i]=(dong1[i+sokt*6]>k);
} }
*/
}
void tungchu () {
for (i=0;i<k*6;i++){
dong1[i]=dong1[sokt*6+i];
dong2[i]=dong2[sokt*6+i];
}
}
void hienthi() {
switch (col){
// 2do1do
case 0 :
spi(0x00);
spi(dong2[c+16]);
spi(0x00);
spi(dong2[c+8]);
spi(0x00);
spi(dong2[c]);
spi(0x00);
spi(dong1[c+16]);
spi(0x00);
spi(dong1[c+8]);
spi(0x00);
spi(dong1[c]);
break;
// 2xanh1do
case 1 :
spi(dong2[c+16]);
spi(0x00);
spi(dong2[c+8]);
spi(0x00);
spi(dong2[c]);
spi(0x00);
spi(0x00);
spi(dong1[c+16]);
spi(0x00);
spi(dong1[c+8]);
spi(0x00);
spi(dong1[c]);
break;
// 2cam1do
case 2 :
spi(dong2[c+16]);
spi(dong2[c+16]);
spi(dong2[c+8]);
spi(dong2[c+8]);
spi(dong2[c]);
spi(dong2[c]);
spi(0x00);
spi(dong1[c+16]);
spi(0x00);
spi(dong1[c+8]);
spi(0x00);
spi(dong1[c]);
break;
// 2do1xanh
case 3 :
spi(0x00);
spi(dong2[c+16]);
spi(0x00);
spi(dong2[c+8]);
spi(0x00);
spi(dong2[c]);
spi(dong1[c+16]);
spi(0x00);
spi(dong1[c+8]);
spi(0x00);
spi(dong1[c]);
spi(0x00);
break;
// 2xanh1xanh
case 4 :
spi(dong2[c+16]);
spi(0x00);
spi(dong2[c+8]);
spi(0x00);
spi(dong2[c]);
spi(0x00);
spi(dong1[c+16]);
spi(0x00);
spi(dong1[c+8]);
spi(0x00);
spi(dong1[c]);
spi(0x00);
break;
// 2cam1xanh
case 5 :
spi(dong2[c+16]);
spi(dong2[c+16]);
spi(dong2[c+8]);
spi(dong2[c+8]);
spi(dong2[c]);
spi(dong2[c]);
spi(dong1[c+16]);
spi(0x00);
spi(dong1[c+8]);
spi(0x00);
spi(dong1[c]);
spi(0x00);
break;
// 2do1cam
case 6 :
spi(0x00);
spi(dong2[c+16]);
spi(0x00);
spi(dong2[c+8]);
spi(0x00);
spi(dong2[c]);
spi(dong1[c+16]);
spi(dong1[c+16]);
spi(dong1[c+8]);
spi(dong1[c+8]);
spi(dong1[c]);
spi(dong1[c]);
// 2xanh1cam
case 7 :
spi(dong2[c+16]);
spi(0x00);
spi(dong2[c+8]);
spi(0x00);
spi(dong2[c]);
spi(0x00);
spi(dong1[c+16]);
spi(dong1[c+16]);
spi(dong1[c+8]);
spi(dong1[c+8]);
spi(dong1[c]);
spi(dong1[c]);
break;
// 2cam1cam
case 8 :
spi(dong2[c+16]);
spi(dong2[c+16]);
spi(dong2[c+8]);
spi(dong2[c+8]);
spi(dong2[c]);
spi(dong2[c]);
spi(dong1[c+16]);
spi(dong1[c+16]);
spi(dong1[c+8]);
spi(dong1[c+8]);
spi(dong1[c]);
spi(dong1[c]);
break;
default: break;
}
}
void hieuung() {
switch (eff){
// hienbt
case 0 :
lm1();
break;
// dichtrai
case 1 :
if (t==48){
t=0;
sp++;
}
if (sp==tocdo_chay){
sp=0;
k++ ;
shiftleft();
}
if (k==sokt*12) {
lm1();
lm2();
k=0;
}
break;
// dichphai
case 2 :
if (t==48){
t=0;
sp++;
}
if (sp==tocdo_chay){
sp=0;
k++ ;
shiftright();
}
if (k==sokt*12) {
lm1();
lm2();
k=0;
}
break;
// dichlen
case 3 :
if (t==48){
t=0;
sp++;
}
if (sp==tocdo_chay){
sp=0;
k++ ;
UP(k);
}
if (k>=32) {
lm1();
lm2();
k=0;
/* if (t==sokt*8){
k++;
UP(k);
}
if (k==16) {
lm1();
lm2();
k=0;
}
*/
}
break;
// dichxuong
case 4 :
if (t==48){
t=0;
sp++;
}
if (sp==tocdo_chay){
sp=0;
k++ ;
down(k);
}
if (k>=32) {
lm1();
lm2();
k=0;
}
break;
// tungchu
case 5 :
if (t==200){
t=0;
sp++;
}
if (sp==tocdo_chay){
sp=0;
k++ ;
tungchu();
}
if (k>sokt) {
lm1();
lm2();
k=0;
}
break;
default: break;
}
}
// Timer 1 output compare A interrupt service routine
interrupt [TIM1_COMPA] void timer1_compa_isr(void) {
hienthi();
LatchData();
PORTC=c+8;
PORTA=c+8;
c++;
t++;
if (c==8) c=0;
hieuung();
}
void main(void){
lm1();
lm2();
// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: clk/256 kHz
// Mode: CTC top=OCR1A
// OC1A output: Discon.
// OC1B output: Discon.
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer 1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: On
// Compare B Match Interrupt: Off
TCCR1A=0x00;
TCCR1B=0x0C;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=tocdo_quet;
OCR1BH=0x00;
OCR1BL=0x00;
/*UCSRA=0x00;
UCSRB=0x18;
UCSRC=0x86;
UBRRH=0x00;
UBRRL=0x19;*/
UCSRB=0x18;
UCSRC=0x86;
UBRRH=0x00;
UBRRL=0x47;
DDRB=0xFF;
DDRC=0xFF;
DDRA=0xFF;
SCL=1;
// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK=0x10;
// Global enable interrupts
#asm("sei")
// SPI initialization
// SPI Type: Master
// SPI Clock Rate: clk
// SPI Clock Phase: Cycle Half
// SPI Clock Polarity: Low
// SPI Data Order: MSB First
SPCR=0x50;
SPSR=0x00;
while (1){
unsigned char temp1,temp2,length;
int i;
temp1 = getchar();
if (temp1=='A')
{
TIMSK=0x00;
//Nhan chuoi ky tu hang 1
//tinh do dai chuoi
temp1 = getchar()-48;
temp2 = getchar()-48;
length = temp1*10 + temp2;
sokt1=length;
//Nhan chuoi ky tu
if (length >=1){
for( i=0;i<length;i++)
{
chuoi1[i] = getchar();
}
//Nhan chuoi ky tu hang 2
//tinh do dai chuoi
temp1 = getchar()-48;
temp2 = getchar()-48;
length = temp1*10 + temp2;
sokt2=length;
//Nhan chuoi ky tu
if (length >=1){
for( i=0;i<length;i++)
{
chuoi2[i] = getchar();
}
//Nhan mau
col = getchar() - 48;
//Nhan hieu ung
eff = getchar() - 48;
//Nhan Toc do quet
temp1 = getchar()-48;
temp2 = getchar()-48;
tocdo_quet = temp1*10 + temp2;
//Nhan toc do chay
temp1 = getchar()-48;
temp2 = getchar()-48;
tocdo_chay = temp1*10 + temp2;
xulychuoi();
lm1();
lm2();
t=0;
c=0;
TIMSK=0x10;
}
}
}
}
}
Các file đính kèm theo tài liệu này:
- Thiết kế bảng quảng cáo LED sử dụng vi điều khiển ATMEGA16 Module điều khiển hiển thị (ĐH BK HN).doc