Professional Documents
Culture Documents
THUẬT MẬT MÃ
KHOA ĐIỆN TỬ- VIỄN THÔNG
Đề tài: “Thiết kế đồng hồ thời gian thực có LED nháy theo nhạc sử
dụng hệ điều hành FREERTOS”
1
LỜI NÓI ĐẦU
Ngày nay khoa học công nghệ ngày càng phát triển, vi điều khiển AVR và
vi điều khiển PIC ngày càng thông dụng và hoàn thiện hơn, nhưng có thể nói sự
xuất hiện của Arduino vào năm 2005 tại Italia đã mở ra một hướng đi mới cho vi
điều khiển. Sự xuất hiện của Arduino đã hỗ trợ cho con người rất nhiều trong lập
trình và thiết kế, nhất là đối với những người bắt đầu tìm tòi về vi điều khiển mà
không có quá nhiều kiến thức, hiểu biết sâu sắc về vật lý và điện tử . Phần cứng
của thiết bị đã được tích hợp nhiều chức năng cơ bản và là mã nguồn mở. Ngôn
ngữ lập trình trên nền Java lại vô cùng dễ sử dụng tương thích với ngôn ngữ C
và hệ thư viện rất phong phú và được chia sẻ miễn phí. Chính vì những lý do
như vậy nên Arduino hiện đang dần phổ biến và được phát triển ngày càng
mạnh mẽ trên toàn thế giới.
Trên cơ sở kiến thức đã học trong môn học: Tin học đại cương, Điện tử
tương tự và số, Hệ điều hành nhúng thời gian thực… cùng với những hiểu biết
về các thiết bị điện tử, chúng em đã quyết định thực hiện đề tài “Thiết kế đồng
hồ thời gian thực có LED nháy theo nhạc sử dụng hệ điều hành thời gian thực
FreeRTOS”. Do kiến thức còn hạn hẹp nên chắc chắn không tránh khỏi những
thiếu sót, hạn chế vì thế chúng em rất mong có được sự góp ý và nhắc nhờ từ cô
giáo để có thể hoàn thiện đề tài của mình. Chúng em xin chân thành cảm ơn cô
Lê Thị Hồng Vân đã giúp đỡ chúng em rất nhiều trong quá trình tìm hiểu, thiết
kế và hoàn thành đề tài đồ án môn học này.
2
Mục lục
LỜI NÓI ĐẦU...............................................................................................................2
Mục lục...........................................................................................................................3
Danh mục hình ảnh.......................................................................................................4
CHƯƠNG I: TỔNG QUAN VỀ HỆ THỐNG............................................................5
1.1. Đặt vấn đề..........................................................................................................5
1.2. Lý do chọn đề tài...............................................................................................5
1.3. Mục đích nghiên cứu đề tài...............................................................................5
1.4. Giải pháp thiết kế..............................................................................................5
CHƯƠNG II: CƠ SỞ LÝ THUYẾT...........................................................................7
2.1. Tìm hiểu về hệ điều hành nhúng thời gian thực FreeRTOS.................................7
2.1.1 Lịch sử phát triển của hệ điều hành nhúng thời gian thực FreeRTOS...........7
2.1.2. Cách thức hoạt động của FreeRTOS.............................................................8
2.1.3. Các chức năng của FreeRTOS.......................................................................9
2.2. Giới thiệu các thiết bị phần cứng sử dụng..........................................................10
2.2.1. Kit Arduino UNO R3..................................................................................10
2.2.2. Module thời gian thực Module Tiny RTC I2C............................................17
2.2.3. Module LED P10.........................................................................................18
2.2.4. Module cảm biến âm thanh.........................................................................20
CHƯƠNG III: THIẾT KẾ VÀ THI CÔNG SẢN PHẨM......................................22
3.1. Thiết kế và thi công phần cứng..........................................................................22
3.2. Thiết kế và thi công phần mềm..........................................................................24
3.2.1. Chương trình hiển thị lên LED P10.............................................................24
3.2.2. Thiết kế chương trình chính........................................................................25
3.2.3. Chương trình điều khiển sản phẩm..............................................................27
CHƯƠNG IV: TỔNG KẾT.......................................................................................29
4.1. Nhận xét, đánh giá..............................................................................................29
4.2. Hướng phát triển................................................................................................29
4.3. Kết luận..............................................................................................................29
TÀI LIỆU THAM KHẢO..........................................................................................30
3
PHỤ LỤC.....................................................................................................................31
4
5
CHƯƠNG I: TỔNG QUAN VỀ HỆ THỐNG.
1.1. Đặt vấn đề.
Khoa học kỹ thuật ngày càng phát triển kéo theo việc ra đời các loại đồng
hồ nhằm xác định thời gian rõ ràng và chính xác hơn, tiêu biểu là đồng hồ cơ và
đồng hồ số. Đồng hồ số ra đời mang những tính năng vượt bậc so với đồng hồ
cơ hay những loại đồng hồ xưa về những mặt: kinh phí, độ chính xác và nhiều
tính năng khác.
6
Hình 1: Sơ đồ khối
Chức năng của các khối:
- Khối nguồn: cung cấp nguồn hoạt động cho hệ thống vi điều
khiển.
- Khối xử lý trung tâm: Đóng vai trò đầu não của hệ thống. Xử lý
tín hiệu nhận được từ khối thời gian thực và khối cảm biến âm
thanh từ đó hiển thị thông tin lên khối hiển thị. Nhận tín hiệu điều
khiển để thay đổi trạng thái hoạt động.
- Khối hiển thị: Hiển thị các thông số thời gian như giờ, phút, giây
và
- Khối RTC: Khối này thực chất là một chíp thời gian thực (Real
Time Clock), được sử dụng với ý nghĩa thời gian tuyệt đối mà
con người đang sử dụng. Trong sơ đồ này nó sẽ đảm nhiệm chức
năng cấp time chính xác cho vi điều khiển xử lý.
- Khối điều khiển: Sử dụng nút bấm. Thực hiện chức năng nhập
các dữ liệu đưa đến vi điều khiển và bao gồm thao tác thay đổi
hiển thị.
- Khối cảm biến âm thanh: Cảm biến âm thanh có chức nặng nhận
biết được âm thanh giúp LED nháy theo điệu nhạc.
7
CHƯƠNG II: CƠ SỞ LÝ THUYẾT.
2.1. Tìm hiểu về hệ điều hành nhúng thời gian thực FreeRTOS.
Hệ điều hành thời gian thực – Real Time Operating Systems (RTOS) là
một hệ điều hành cho các hệ thống nhúng. Loại hệ điều hành này thường được
thiết kế để tiết kiệm tài nguyên và đáng tin cậy. Phần cứng chạy hệ điều hành
nhúng có thể rất hạn chế về tài nguyên như RAM và ROM, do đó thiết kế nhúng
của các hệ điều hành này có thể có phạm vi hẹp phù hợp với ứng dụng cụ thể để
đạt được hoạt động mong muốn theo các ràng buộc này. Để tận dụng tốt hơn sức
mạnh xử lý của CPU, các nhà phát triển phần mềm có thể viết mã quan trọng
trực tiếp bằng ngôn ngữ máy (tốc độ, chi phí, khả năng bảo trì), hoặc ngôn ngữ
khả chuyển (portable language) như C.
Một số hệ điều hành nhúng phổ biến như: QNX, PDOS, pSOS, VxWorks,
Nulceus, ERCOS, EMERALDS, Windows CE….Nhưng trong đồ án môn học
này chúng em sử dụng hệ điều hành nhúng thời gian thực FreeRTOS. Vì
FreeRTOS phù hợp cho nghiên cứu, học tập về các kỹ thuật, công nghệ trong
viết hệ điều hành nói chung và hệ điều hành nhúng thời gian thực nói riêng,
cũng như việc phát triển mở rộng tiếp các thành phần cho hệ điều hành (bổ sung
mô-đun, trình điều khiển, chuyển đổi môi trường thực hiện).
2.1.1 Lịch sử phát triển của hệ điều hành nhúng thời gian thực
FreeRTOS
FreeRTOS là lõi của hệ điều hành thời gian thực miễn phí. Hệ điều hành
này được Richard Barry công bố rộng rãi từ năm 2003, phát triển mạnh đến nay
và được cộng đồng mạng mã nguồn mở ủng hộ. FreeRTOS có tính khả chuyển,
mã nguồn mở, lõi có thể down miễn phí và nó có thể dùng cho các ứng dụng
thương mại. Nó phù hợp với những hệ nhúng thời gian thực nhỏ. Hầu hết các
8
code được viết bằng ngôn ngữ C nên nó có tính phù hợp cao với nhiều nền khác
nhau.
Ưu điểm của nó là dung lượng nhỏ và có thể chạy trên những nền mà
nhiều hệ không chạy được. Có thể port cho nhiều kiến trúc vi điều khiển và
những công cụ phát triển khác nhau. Mỗi port chính thức bao gồm những ứng
dụng ví dụ tiền cấu hình biểu hiện sự riêng biệt của lõi, kiến thức mới và hướng
phát triển. Những hỗ trợ miễn phí được cung cấp bởi cộng đồng mạng. Hỗ trợ
thương mại với những dịch vụ phát triển đầy đủ cũng được cung cấp
FreeRTOS được cấp giấy phép bởi bản đã được chỉnh sửa bởi GPL
(GeneralPublic License và có thể sử dụng trong ứng dụng thương mại với giấy
phép này. Ngoài ra liên quan đến FreeRTOS có OpenRTOS và SafeRTOS.
OpenRTOS là bản thương mại của FreeRTOS.org và không liên quan gì đến
GPL. SafeRTOS là về cơ bản dựa trên FreeRTOS nhưng được phân tích, chứng
minh bằng tài liệu và kiểm tra nghiêm ngặt với chuẩn IEC61508. Và chuẩn
IEC61508 SIL3 đã được tạo ra và phát triển độc lập để hoàn thiện tài liệu cho
SafeRTOS.
9
state= 2;
case 2: //Code for Task 2;
state= 3;
case 3: //Code for Task 3;
state= 4;
case 4: //Code for Task 4;
state=1;
}
}
Chương trình sẽ thực thi từ states 1 tới states 4 sau đó quay vòng lại. Bất
kì khi nào states thay đổi, chương trình sẽ nhảy qua phục vụ task đó.
Nhược điểm của phương pháp này đó là tài nguyên sử dụng chung, tốc độ
chuyển chậm khi thay đổi states bởi nó phải hoàn thành mỗi Task trước khi
chuyển sang Task khác, khó kiểm soát khi nhiều tác vụ (Task)
10
Sự chuyển dịch giữa các Task rất linh động, độ trễ thấp mang lại độ tin
cậy cao cho chương trình.
11
Quản lý I / O thiết bị: Quản lý I / O thiết bị giúp cung cấp khung thống
nhất (API - Giao diện lập trình viên ứng dụng). Nó cũng giúp truy cập trình điều
khiển thiết bị phần cứng cụ thể, tức là nó định vị thiết bị phù hợp cho yêu cầu I /
O.
12
- Cổng USB: đây là loại cổng giao tiếp để ta upload code từ PC lên vi
điều khiển. Đồng thời nó cũng là giao tiếp serial để truyền dữ liệu giữa vi điều
khiển và máy tính.
- Jack nguồn: để chạy Arduino thỉ có thể lấy nguồn từ cổng USB ở trên,
nhưng không phải lúc nào cũng có thể cắm với máy tính được . Lúc đó ta cần
một nguồn từ 9V đến 12V.
- Có 14 chân vào/ra số đánh số thứ tự từ 0 đến 13, ngoài ra có một chân
nối đất (GND) và một chân điện áp tham chiếu (AREF).
- Vi điều khiển AVR: đây là bộ xử lí trung tâm của toàn bo mạch. Với
mỗi mẫu Arduino khác nhau thì con chip là khác nhau. Ở con Arduino Uno này
thì sử dụng ATMega328.
THÔNG SỐ KỸ THUẬT
- Vi xử lý: Atmega328
- Điện áp hoạt động: 5V
- Điện áp đầu vào: 7-12V
- Điện áp đầu vào (Giới hạn): 6-20V
- Chân vào/ra (I/O) số: 14 ( 6 chân có thể cho đầu ra PWM)
- Chân vào tương tự: 6
- Dòng điện trong mỗi chân I/O: 40mA
- Dòng điện chân nguồn 3.3V: 50mA
- Bộ nhớ trong: 32 KB (ATmega328)
- SRAM: 2 KB (ATmega328)
- EEPROM: 1 KB (ATmega328)
- Xung nhịp: 16MHz
13
Hình 2. 3: Vi điều khiển của Arduino Uno
Arduino UNO có thể sử dụng 3 vi điều khiển họ 8bit AVR là ATmega8 ,
ATmega168 , ATmega328 . Bộ não này có thể xử lý những tác vụ đơn giản như
điều khiển đèn LED nhấp nháy , xử lý tín hiệu cho xe điều khiển từ xa , làm một
trạm đo nhiệt độ - độ ẩm và hiển thị lên màn hình LCD , ..
Thiết kế tiêu chuẩn của Arduino UNO sử dụng vi điều khiển ATmega328
với giá khoảng 90.000đ . Tuy nhiên nếu yêu cầu phần cứng của bạn không cao
hoặc túi tiền không cho phép , bạn có thể sử dụng các loại vi điều khiển khác có
chức năng tương đương nhưng rẻ hơn như ATmega8 ( bộ nhớ flash 8KB ) với
giá khoảng 45.000đ hoặc ATmega168 ( bộ nhớ flash 16KB ) với giá khoảng
65.000đ
Điện áp
Arduino UNO có thể được cấp nguồn 5V thông qua cổng USB hoặc cấp
nguồn ngoài với điện áp khuyên dùng là 7-12V DC và giới hạn là 6-20v,
Thường thi cấp nguồn bằng pin vuông 9V là hợp lí nhất nếu bạn không có sẵn
nguồn từ cổng USB . Nếu cấp nguồn vượt quá ngưỡng giới hạn trên, bạn sẽ làm
hỏng Arduino UNO.
Các chân năng lượng
14
- GND ( Ground ) : cực âm của nguồn điện cấp cho Arduino UNO Khi bạn
dùng các thiết bị sử dụng những nguồn điện riêng biệt thì những chân này
phải được nối với nhau .
- 5V ; cấp điện áp 5V đầu ra . Dòng tối đa cho phép ở chân này là 500mA .
- 3.3V : cấp điện áp 3.3V đầu ra . Dòng tối đa cho phép ở chân này là
50mA .
- Vin ( Voltage Input ) : để cấp nguồn ngoài cho Arduino UNO , bạn nối
cực dương của nguồn với chân này và cực âm của nguồn với chân GND .
- IOREF : điện áp hoạt động của vi điều khiển trên Arduino UNO có thể
được đo ở chân này . Và dĩ nhiên nó luôn là 5V . Mặc dù vậy bạn không
được lấy nguồn 5V từ chân này để sử dụng bởi chức năng của nó không
phải là cấp nguồn .
- RESET : việc nhấn nút Reset trên board để reset vi điều khiển tương
đương với việc chân RESET được nối với GND qua 1 điện trở 10K .
Bộ nhớ
Vi điều khiển Atmega328 tiêu chuẩn cung cấp cho người dùng :
32KB bộ nhớ Flash ; những đoạn lệnh bạn lập trình sẽ được lưu trữ trong
bộ Flash của vi điều khiển . Thưởng thì sẽ có khoảng vài KB trong số này sẽ
được dùng cho bootloader nhưng đừng lo , bạn hiếm khi nào cần quả 20KB bộ
nhở này đâu .
2KB cho SRAM ( Stats Random Access Memory ) : giá trị các biến bạn
khai báo khi lập trình sẽ lưu ở đây . Bạn khai bảo càng nhiều biến thì càng cần
nhiều bộ nhớ RAM . Tuy vậy , thực sự thì cũng hiếm khi nào bộ nhớ RAM lại
trở thành thứ mà bạn phải bận tâm . Khi mất điện , dữ liệu trên SRAM sẽ bị
mất .
1KB cho EEPROM ( Electrically Eraseble Programmable Read Only
Memory ) : dây giống như một chiếc ổ cứng mini – nơi bạn có thể đọc và ghi dữ
15
liệu của mình vào đây mà không phải lo bị mất khi cúp điện giống như dữ liệu
trên SRAM .
Cổng vào ra
16
- Chân PWM ( - ) 3 , 5 , 6 , 9 , 10 , và 1l : cho phép bạn xuất ra
xung PWM với độ phân giải 8bit ( giá trị từ 0 – 28-1 tương ứng
với 0V – 5V ) bằng hàm analogWrite ( ) . Nói một cách đơn giản ,
bạn có thể điều chỉnh được điện áp ra ở chân này từ mức 0V đến
5V thay vì chỉ cố định ở mức 0V và 5V như những chân khác .
- Chân giao tiếp SPI : 10 ( SS ) , 11 ( MOSI ) , 12 ( MISO ) 13
( SGK ) . Ngoài các chức năng thông thường , 4 chân này còn
dùng để truyền phát dữ liệu bằng giao thức SPI với các thiết bị
khác ,
- LED 13 trên Arduino UNO có 1 đèn led màu cam ( kí hiệu chữ
L ) . Khi bấm nút Reset , bạn sẽ thấy đèn này nhấp nháy để bảo
hiệu . Nó được nối với chân số 13. Khi chân này được người
dùng sử dụng , LED sẽ sảng .
- Arduino UNO có 6 chân analog ( A0 A5 ) cung cấp độ phân giải
tín hiệu 10bit ( 0 – 210-1 ) để đọc giá trị điện áp trong khoảng 0v
- 5v . Với chân AREF trên board , bạn có thể để đưa vào điện áp
tham chiếu khi sử dụng các chân analog . Tức là nếu bạn cấp điện
áp 2.5V vào chân này thì bạn có thể dùng các chân analog để đo
điện áp trong khoảng từ 0V – 2.5V với độ phân giải vẫn là 10bit .
- Đặc biệt , Arduino UNO có 2 chân A4 ( SDA ) và A5 ( SCL ) hỗ
trợ giao tiếp I2C / TWI với các thiết bị khác.
Ngắt trong Arduino
Ngắt (interrupt) là quá trình dừng chương trình chính đang chạy để ưu
tiên thực hiện một chương trình khác, chương trình này được gọi là chương trình
phục vụ ngắt (ISR – Interrupt Service Routine). Sau khi thực hiện xong chương
trình phục vụ ngắt thì vi điều khiển quay lại thực hiện tiếp công việc trước đó.
Trong các quá trình ngắt, ta phân biệt thành 2 loại: ngắt cứng và ngắt mềm. Ngắt
mềm là ngắt được gọi bằng một lệnh trong chương trình ngôn ngữ máy. Khác
17
với ngắt mềm, ngắt cứng không được khởi động bên trong máy tính mà do các
linh kiện điện tử tác đông lên hệ thống.
Đối với Arduino, ngắt Timer chủ yếu được dùng để định các khoảng thời
gian nhất định, xuất xung tần số tùy chỉnh ra chân đầu ra số hay định thời gian
kiểm tra dự liệu truyền nối tiếp. Tùy theo Board Arduino mà số lượng Timer
cũng khác nhau
Arduino UNO có 3 Timer, Timer 0, 1 và 2. Các timer này sẽ tăng giá trị
của nó dựa vào xung nhịp của Arduino. Khi bạn đặt giá trị ngắt, Timer sẽ tăng
dần giá trị khi xảy ra xung nhịp và so sánh với giá trị đặt trước, khi bằng nhau
nó sẽ xảy ra một ngắt.
Timer 0, 2 là 2 timer 8 bit, hay nói cách khác nó chỉ có thể đếm từ 0 đến
255 và với Timer1 là timer 16 bit, nó có thể đếm từ 0 đến 65535 mà thôi.
Arduino UNO có xung nhịp là 16MHz, tương đương 1/16000000s, 63ns. Nếu
các Timer đếm các xung nhịp này thì với Timer 0,2 chỉ có thể đếm
256*63ns 16us và với Timer 1 là 4 ms.
18
2.2.2. Module thời gian thực Module Tiny RTC I2C.
Module Thời Gian Thực Tiny RTC I2C là IC thời gian thực giá rẻ, rất
chính xác với thạch anh tích hợp sẵn có khả năng điều chỉnh nhiệt. Sử dụng
chuẩn giao tiếp I2C giúp giao tiếp dễ dang với các dòng vi điều khiển hiện có.
Module có đầu vào cho pin riêng, tách biệt khỏi nguồn chính đảm bảo cho việc
giữ thời gian chính xác. Thạch anh tích hợp sẵn giúp tăng độ chính xác trong
thời gian dài hoạt động và giảm số lượng linh kiện cần thiết khi làm board.
Thời gian trong Module được giữ ở dạng: giờ, phút, giây, ngày, thứ,
tháng, năm. Các tháng có ít hơn 31 ngày sẽ tự động được điều chỉnh, các năm
Nhuận cũng được chỉnh đúng số ngày. Thời gian có thể hoạt động ở chế độ 24h
hoặc 12h AmPM.
19
- Pin CMOS 2032/2025
- Kích thước : 27x28x8.4mm
20
Chức năng của các chân
R1: Chân data cho màu đỏ của 8 hàng led bên trên
R2: Chân data cho màu đỏ của 8 hàng led phía dưới
G1: Chân data cho màu xanh lá của 8 hàng led bên trên
G2: Chân data cho màu xanh lá của 8 hàng led phía dưới
B1: Chân data cho màu xanh dương của 8 hàng led bên trên
B2: Chân data cho màu xanh dương của 8 hàng led phía dưới
CLK: Chân đẩy data vào ic ghi dịch
LAT: Chân chốt data ( đẩy data lưu trong ic ghi dịch ra ngoài led)
OE: Chân cho phép bảng led sáng ( OE=0 thì bảng led được phép sáng, OE=1
thì bảng led auto tắt)
A,B,C: 3 chân của ic vào 3 ra 8, tức 3 chân dùng để quét led, cho phép hàng nào
sáng. Với 3 chân ABC ta điều khiển đc 8 hàng độc lập, nhưng module P10 có
tới 16 hàng => trong 1 thời điểm có 2 hàng cùng sáng => module này quét kiểu
2/16 = 1/8
=> Trong 1 thời điểm số led RGB ta có thể điều khiển là 512 x 1/8 = 64 LED
RGB
Chiều đi của data
Với P10 1 màu, data đi theo chiều zigzac, thì P10 FULL, data đi theo đường
thẳng
Các bạn có thể thấy, module này chia ra làm 2 nửa theo chiều ngang, với dữ liệu
của 8 hàng trên do RGB1 quyết định, còn 8 hàng dưới do RGB2 quyết định.
Chân ABC sẽ quyết định hàng nào trong 8 hàng của cả 2 nửa được sáng.
21
T
rong 1 thời điểm sẽ có 2 hàng được phép sáng ( do ABC quyết định)
22
Hình 2. 8: Module cảm biến âm thanh
THÔNG SỐ KỸ THUẬT
- Microphone có dải tần từ 50Hz – 13kHz
- Đầu ra là dạng sóng tương tự có thể điều chỉnh được
- Điện áp hoạt động: 5V 1x3
- Header: OUT = đầu ra tương tự, kết nối với đầu vào tương tự trên
MCU VCC = 4~12VDC (5V thông thường) GND = đất
- Kích thước: 36mm x 20mm
ỨNG DỤNG
- Sử dụng chip xử lý âm thanh chất lượng cao
- Có thể điều chỉnh biên độ của tín hiệu âm thanh đầu ra để phát
hiện kích thước của âm thanh
- Hệ thống dây nối đất một điểm được sử dụng để giảm, tăng vòng
lặp và cải thiện chất lượng tín hiệu âm thanh
23
- Giao diện Arduino tiêu chuẩn, có thể kết nối trực tiếp với Arduino
- Độ nhạy tốt, mạch khuếch đại tích hợp, có thể điều chỉnh, tín hiệu
điện áp cường độ âm thanh có thể thu được thông qua chuyển đổi
AD
24
CHƯƠNG III: THIẾT KẾ VÀ THI CÔNG SẢN PHẨM.
3.1. Thiết kế và thi công phần cứng.
Kết nối Arduino và các thiết bị.
25
Hình 3. 1: Mô phỏng mạch trên proteus
Trong thực tế chúng em sử dụng cáp 7 màu đề kết nối các module vời
nhau. Việc này giúp các module thiết bị kết nối với nhau ổn định, dễ dàng trong
việc nâng cấp và sửa chữa thiết bị.
Sơ đồ kết nối các thiết bị thực tế:
26
Hình 3. 2: Thiết kế và thi công vỏ hộp để chứa và bảo vệ các thiết bị
27
chương trình khác gây khó chịu cho người sử dụng và ảnh hưởng đến chất lượng
hiển thị. Khắc phục tình trạng đó chúng em đã sử dụng phương pháp ngắt timer
đề thực hiện thuật toán quét led. Nó giống như 1 module tự động quét led và làm
công việc hiển thị ra màn hình.
Tuy nhiên giữa chương trình và hàm ngắt phải có 1 mối liên hệ nhất định
để hàm main muốn hiển thị gì thì ngắt phải nghe theo. Do vậy phương pháp này
cần tới 1 Buffer( bộ đệm hiển thị) – nó là 1 mảng dữ liệu chứa dữ liệu cần hiển
thị. Khi hàm main muốn hiển thị gì thì chỉ cần ghi dữ liệu vào bộ đệm. Còn hàm
ngắt sẽ tự động lấy dữ liệu trong bộ đệm ra để hiển thị 1 cách định kì và tự động.
Hình 3. 4: Phương pháp ngắt timer thực hiện thuật toán quét led
Đồi với LED P10 (32X16) tương đương với 512 LED đồng nghĩa với việc
cần 512 bit để quản lý ma trận LED. Mà mỗi LED là sự kết hợp của 3 màu RGB
nên cần thêm một chiều để quản lý màu.
Khai bảo một mảng 3 chiều: char Buffer_display[3][16][4] để quản lý
ma trận LED và làm bộ đệm cho chương trình ngắt Timer.
Xấy dựng chương trình ngắt quét LED dựa trên bộ Timer1 của Arduino.
Để không gây ảnh hưởng đến mắt và não bộ thì tối thiểu là 24-30fps. Ở đây
chúng em sử dụng quét với 33 khung hình trên 1 giây. Đối với Led P10 cứ 8 lần
quét sẽ hoàn thành một khung hình (mối lần ngắt chỉ có thể sáng 1 hàng). Thời
gian cho mỗi lần ngắt là: 1 / (8 x 33) = 0.0037s.
Giá trị nạp vào thanh ghi TCNT1 = 2^16 – 0.0037*(16 *10^6)/256.
28
3.2.2. Thiết kế chương trình chính.
Lưu đồ thuật toán của chương trình chính.
29
Hình 3. 6: Lưu đồ thuật toán tác vụ taskRealTime
Lưu đồ thuật toán tác vụ “animation”:
30
Hình 3. 7: Lưu đồ thuật toán tác vụ “animation”
3.2.3. Chương trình điều khiển sản phẩm.
Sơ đồ điều khiển sản phẩm
31
Chương trình điều khiển nhận dữ liệu trực tiếp từ người dùng thông qua nút
nhấn. Để quá trình tương tác này điễn ra và đáp ứng thời gian thực chúng em sử
dụng tính năng ngắt cứng trên arduino uno.
Lưu đồ thuật toán chương trình điều khiển:
32
CHƯƠNG IV: TỔNG KẾT
4.1. Nhận xét, đánh giá
Sản phẩm hoạt động ổn định, đạt yêu cầu đã đặt ra, tuy nhiên vẫn còn một
số hạn chế như sau:
- Chưa điều chỉnh được ngày, tháng, năm.
- Sản phẩm chưa có tính thẩm mỹ cao.
33
TÀI LIỆU THAM KHẢO
Trong báo cáo này, chúng em đã sử dụng các tài liệu tham khảo:
[1]. “Giáo Trình Vi Điều Khiển” Của GV Phạm Hùng Kim Khánh
[2]. Từ các trang web: www.dientuvietnam.net, codientu.org
[3]. Vi điều khiển với lập trình C_Ngô Diên Tập
Trang Web tham khảo
http://arduino.vn/bai-viet/369-giao-tiep-i2c-va-su-dung-module-realtime-
clock-ds1307
34
PHỤ LỤC
#include
<avr/inte
rrupt.h>
#include <Arduino_FreeRTOS.h>
#include <queue.h>
#include <Wire.h>
#include <stdlib.h>
#define R1 4
#define G1 5
#define B1 6
#define R2 7
#define G2 8
#define B2 9
#define CLK 10
#define OE 11
#define STB 12
#define A A0
#define B A1
#define C A2
#define M A3
unsigned char Buffer_display[3][16][4];
TaskHandle_t animationHandle = NULL;
TaskHandle_t danceOfMusicHandle = NULL;
TaskHandle_t realTimeHandle = NULL;
char col[32];
int wday, day, month, year;
char color_row[4] = {0x01, 0x03, 0x06, 0x02};
const char font [][7] ={
0x38,0x44,0x4C,0x54,0x64,0x44,0x38, //0 48
0x10,0x30,0x10,0x10,0x10,0x10,0x38, //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,0x00,0x00,0x00,0x00,0x00,
};
const char dayOfTheWeek[7][3][7]= {
35
0x38,0x44,0x40,0x38,0x04,0x44,0x38,0x00,0x00,0x48,0x48,0x4
8,0x58,0x28,0x00,0x00,0x68,0x54,0x54,0x44,0x44,// Su
0x44,0x6C,0x54,0x44,0x44,0x44,0x44,0x00,0x00,0x38,0x44,0x4
4,0x44,0x38,0x00,0x00,0x70,0x48,0x48,0x48,0x48,// Mo
0x7C,0x10,0x10,0x10,0x10,0x10,0x10,0x00,0x00,0x48,0x48,0x4
8,0x58,0x28,0x00,0x00,0x38,0x40,0x38,0x04,0x38,// Tu
0x44,0x44,0x54,0x54,0x54,0x54,0x28,0x00,0x00,0x38,0x44,0x7
8,0x40,0x38,0x00,0x00,0x70,0x48,0x48,0x48,0x48,// We
0x7C,0x10,0x10,0x10,0x10,0x10,0x10,0x40,0x40,0x70,0x48,0x4
8,0x48,0x48,0x00,0x00,0x48,0x48,0x48,0x58,0x28,// Th
0x7C,0x40,0x40,0x78,0x40,0x40,0x40,0x00,0x00,0x58,0x24,0x2
0,0x20,0x70,0x10,0x00,0x10,0x10,0x10,0x10,0x18,// Fr
0x38,0x44,0x40,0x38,0x04,0x44,0x38,0x00,0x00,0x38,0x04,0x3
C,0x44,0x3C,0x00,0x20,0x78,0x20,0x20,0x28,0x10,// Sa
};
const char miniFont [][3] = {
0xf8, 0x88, 0xf8,// 0
0x40, 0xf8, 0x00,// 1
0xb8, 0xa8, 0xe8,// 2
0xa8, 0xa8, 0xf8,// 3
0xe0, 0x20, 0xf8,// 4
0xe8, 0xa8, 0xb8,// 5
0xf8, 0xa8, 0xb8,// 6
0x80, 0x80, 0xf8,// 7
0xf8, 0xa8, 0xf8,// 8
0xe8, 0xa8, 0xf8 // 9
};
QueueHandle_t mode = NULL;
ISR (TIMER1_OVF_vect) //Chương trình ngắt Timer1
{
static unsigned char z = 0;// biến đếm hàng;
unsigned char i;
digitalWrite (OE, HIGH); // tắt hết LED
for (i = 0; i < 4; i++){
data_transfet (Buffer_display[0][z][i], Buffer_display[1][z][i],
Buffer_display[2][z][i], Buffer_display[0][z+8][i],
Buffer_display[1][z+8][i], Buffer_display[2][z+8]
[i]);
}
rows(z);
digitalWrite (STB, LOW); digitalWrite (STB, HIGH);
digitalWrite (OE, LOW);// bật LED
z++;
36
if (z == 8) z = 0;
delay(1);
TCNT1= 65300;
}
void setup() {
Serial.begin (9600);
Wire.begin();
pinMode (G1, OUTPUT);// cài đặt chế độ hoạt động của các
chân
pinMode (R1, OUTPUT);
pinMode (B1, OUTPUT);
pinMode (R2, OUTPUT);
pinMode (G2, OUTPUT);
pinMode (B2, OUTPUT);
pinMode (A, OUTPUT);
pinMode (B, OUTPUT);
pinMode (C, OUTPUT);
pinMode (CLK, OUTPUT);
pinMode (OE, OUTPUT);
pinMode (STB, OUTPUT);
pinMode (M, INPUT);
pinMode (2, INPUT_PULLUP);
pinMode (3, INPUT_PULLUP);
mode = xQueueCreate (1, sizeof (int));
int status = 0;
xQueueSend(mode, &status, 0);
attachInterrupt(digitalPinToInterrupt(3),changeOnMode ,
RISING);
//attachInterrupt(digitalPinToInterrupt(2),changeMode ,
RISING);
getDate();
cli(); //Tắt ngắt toàn cục
TCCR1A = 0; //Reset Timer1
TCCR1B = 0;
TIMSK1 = 0;
TCCR1B |= (1 << CS11);
TCNT1= 65500;
TIMSK1 |= (1 << TOIE1);
sei();
//xTaskCreate (taskDanceMusic,"1", 128, NULL, 2,
&danceOfMusicHandle);
xTaskCreate (taskRealTime,"2", 128, NULL, 2, &
realTimeHandle);
37
xTaskCreate (animation,"3", 128, NULL, 2, &
animationHandle);
}
void loop(){}
void changeOnMode () {
static int moe = 0 ;
moe = (++ moe)%3;
xQueueOverwriteFromISR (mode, &moe, 0);
vTaskResume(realTimeHandle);
}
void animation (void *pv){
int x, y = 0,b;
while (1){
xQueuePeek(mode, &b,0);
if (b == 1) {
for (x = 0 ; x < 16; x++){
draw_icon(x * 4,0,(y+x) % 3 +1 );
draw_icon1(32 - x * 4,15,(y+x) % 3 +1);
}
y++;
delay(100);
}else if (b == 0 ){
for (y = 0; y <7; y++){
for (x = 0 ; x < 5; x++) {
if ((dayOfTheWeek[wday-1][0][y] & (0x40 >> x) ) !=
0) set_pixel (x + 0, y +9, 0x05);
else set_pixel (x + 0, y +9 ,0x00);
}
}
vTaskDelay(20);
for (y = 0; y <7; y++){
for (x = 0 ; x < 5; x++) {
if ((dayOfTheWeek[wday-1][1][y] & (0x40 >> x) ) !=
0) set_pixel (x + 5, y +9, 0x05);
else set_pixel (x + 5, y +9 ,0x00);
}
}
vTaskDelay(20);
for (y = 0; y <7; y++){
38
for (x = 0 ; x < 5; x++) {
if ((dayOfTheWeek[wday - 1][2][y] & (0x40 >> x) ) !=
0) set_pixel (x + 10, y +9, 0x05);
else set_pixel (x + 10, y +9,0x00);
}
}
vTaskDelay(20);
put_mini_number (16,11,day/10,0x04);
put_mini_number (20,11,day%10,0x04);
vTaskDelay(20);
put_mini_number (25,11,month/10,0x07);
put_mini_number (29,11,month%10,0x07);
delay (5000);
for (x =31; x >=0; x -- ){
for ( y =9; y < 16;y++){
set_pixel(x,y,0x00);
}
vTaskDelay(5);
}
put_char (4,9,2,0x03);
vTaskDelay(20);
put_char (10,9,0,0x03);
vTaskDelay(20);
put_char (16,9,year /10,0x03);
vTaskDelay(20);
put_char (22,9,year %10,0x03);
delay (5000);
for (x =31; x >=0; x -- ){
for ( y =8; y < 16;y++){
set_pixel(x,y,0x00);
}
vTaskDelay(5);
}
}else{
for (x =0; x<31;x++){
y = analogRead(M);
if (y > 507) y = y -508;
else y = 506- y;
drawRow (x,y/3);
}
}
}
}
39
void taskRealTime (void *pv){
int nowStatus, nextStatus;
xQueuePeek(mode,&nowStatus, 0);
while (1){
xQueuePeek(mode,&nextStatus, 0);
if (nowStatus != nextStatus) {
nowStatus = nextStatus;
vTaskDelete(animationHandle);
clear_display();
xTaskCreate (animation,"3", 128, NULL, 2, &
animationHandle);
}
if (nowStatus == 0){
getTime();
}else if (nowStatus == 1) {
getTime1();
}else {
vTaskSuspend(realTimeHandle);
}
}
}
void taskDanceMusic (void *pv){
int i, sensor, sensor2;
while (1){
for (i =1; i<31;i++){
sensor = analogRead(M);
if (sensor > 507) sensor = sensor -508;
else sensor = 506- sensor;
drawRow (i,sensor/3);
}
}
}
void data_transfet (char byte_r1, char byte_g1, char byte_b1, char
byte_r2, char byte_g2, char byte_b2 ){ // chyển dữ liệu vào màn
hình
unsigned char i, mask;
for (i = 0; i < 8; i++){
mask = 0x80 >> i;
digitalWrite (R1, byte_r1 & mask);
digitalWrite (G1, byte_g1 & mask);
digitalWrite (B1, byte_b1 & mask);
digitalWrite (R2, byte_r2 & mask);
digitalWrite (G2, byte_g2 & mask);
40
digitalWrite (B2, byte_b2 & mask);
digitalWrite (CLK, LOW); digitalWrite (CLK, HIGH); // tạo
xung clk cho phép chuyển dữ liệu
}
}
void rows (unsigned char row_number){ // chọn hàng được sáng
switch (row_number){
case 0:{ digitalWrite(A, LOW);digitalWrite (B, LOW);
digitalWrite (C, LOW);break;}
case 1:{ digitalWrite(A, HIGH);digitalWrite (B, LOW);
digitalWrite (C, LOW);break;}
case 2:{ digitalWrite(A, LOW);digitalWrite (B, HIGH);
digitalWrite (C, LOW);break;}
case 3:{ digitalWrite(A, HIGH);digitalWrite (B, HIGH);
digitalWrite (C, LOW);break;}
case 4:{ digitalWrite(A, LOW);digitalWrite (B, LOW);
digitalWrite (C, HIGH);break;}
case 5:{ digitalWrite(A, HIGH);digitalWrite (B, LOW);
digitalWrite (C, HIGH);break;}
case 6:{ digitalWrite(A, LOW);digitalWrite (B, HIGH);
digitalWrite (C, HIGH);break;}
case 7:{ digitalWrite(A, HIGH);digitalWrite (B, HIGH);
digitalWrite (C, HIGH);break;}
}
}
void set_pixel (unsigned char x, unsigned char y, unsigned char
color) {
if (x >31 || x <0 || y >15|| y <0) return;
if ((color & 0x01) != 0) Buffer_display [0][y][x/8] =
Buffer_display[0][y][x/8] | (0x80 >> (x %8));
else Buffer_display[0][y][x/8] = Buffer_display[0][y][x/8] &
(~(0x80 >> (x %8)));
}
void getTime1(){
Wire.beginTransmission(0x68);
Wire.write ((byte)0x00);
Wire.endTransmission ();
Wire.requestFrom (0x68, 7);
int x;
x = bcd2dec (Wire.read() & 0x7f);
if (x %2 == 0){
draw_point(15,5,0x02);
draw_point(15,9,0x02);
}else {
draw_point(15,5,0x00);
draw_point(15,9,0x00);
43
}
x = bcd2dec (Wire.read());
put_mini_number_2(18,3,x/10,0x01);
put_mini_number_2(25,3,x%10,0x01);
x = bcd2dec (Wire.read());
put_mini_number_2(1,3,x/10,0x01);
put_mini_number_2(8,3,x%10,0x01);
if (x == 0){
getDate();
}
}
void draw_point (int x, int y, char color){
set_pixel (x ,y, color);
set_pixel (x+1,y, color);
set_pixel (x+1,y+1, color);
set_pixel (x,y+1, color);
}
void put_mini_number(int i, int j, char txt, char color){
char x, y;
for (y = 0; y <3; y++){
for (x = 0 ; x < 5; x++) {
if ((miniFont[txt][y] & (0x80 >> x)) != 0) set_pixel(y+i,
x+j, color);
else set_pixel(y+i, x+j, 0x00);
}
}
}
void put_mini_number_2(int i, int j, char txt, char color){
char x, y;
for (y = 0; y <3; y++){
for (x = 0 ; x < 5; x++) {
if ((miniFont[txt][y] & (0x80 >> x)) != 0) draw_point(2*y
+i, x*2 +j, color);
else draw_point(2*y +i, x*2 +j, 0x00);
}
}
}
void draw_icon(int x, int y, char color){
set_pixel (x , y, color);
set_pixel (x+1 , y+1, color);
set_pixel (x+1 , y, color);
set_pixel (x+2 , y, color);
}
44
void draw_icon1(int x, int y, char color){
set_pixel (x , y, color);
set_pixel (x+1 , y-1, color);
set_pixel (x+1 , y, color);
set_pixel (x+2 , y, color);
}
void clear_display (){
unsigned char i, j;
for (i = 0;i < 16; i++)
for (j =0; j < 32; j++){
set_pixel(j,i,0x00);
}
}
45