Professional Documents
Culture Documents
Thiết Bị Đo Thông Số Sức Khỏe Tự Động
Thiết Bị Đo Thông Số Sức Khỏe Tự Động
ĐỒ ÁN TỐT NGHIỆP
2
NHẬN XÉT CỦA GIẢNG VIÊN HƯỚNG DẪN
• Thái độ, tác phong và nhận thúc trong quá trình thực hiện
...........................................................................................................................
...........................................................................................................................
...........................................................................................................................
• Kiến thức chuyên môn
.........................................................................................................................
.........................................................................................................................
.........................................................................................................................
• Hình thức, bố cục trình bày
.........................................................................................................................
.........................................................................................................................
.........................................................................................................................
• Nội dung, kết quả
.........................................................................................................................
.........................................................................................................................
.........................................................................................................................
• Nhận xét khác
.........................................................................................................................
.........................................................................................................................
.........................................................................................................................
Bà Rịa – Vũng Tàu, ngày … tháng … năm 2021
Giảng viên hướng dẫn
(Ký và ghi rõ họ tên)
3
NHẬN XÉT CỦA GIẢNG VIÊN PHẢN BIỆN
• Thái độ, tác phong và nhận thúc trong quá trình thực hiện
...........................................................................................................................
...........................................................................................................................
...........................................................................................................................
• Kiến thức chuyên môn
.........................................................................................................................
.........................................................................................................................
.........................................................................................................................
• Hình thức, bố cục trình bày
.........................................................................................................................
.........................................................................................................................
.........................................................................................................................
• Nội dung, kết quả
.........................................................................................................................
.........................................................................................................................
.........................................................................................................................
• Nhận xét khác
.........................................................................................................................
.........................................................................................................................
.........................................................................................................................
Bà Rịa – Vũng Tàu, ngày … tháng … năm 2021
Giảng viên phản biện
(Ký và ghi rõ họ tên)
4
LỜI CẢM ƠN
Đầu tiên nhóm em xin gởi lời cảm ơn sâu sắc đến Thầy Lưu Hoàng - Giảng viên
bộ môn Điện - Điện Tử, đã tận tình giúp đỡ, hướng dẫn, giảng giải cho chúng em
trong lựa chọn đề tài cũng như trong quá trình thực hiện đề tài. Trong quá trình
thực hiện đồ án cũng đã xảy ra nhiều khó khăn, thiếu sót nhưng được sự hỗ trợ và
góp ý của Thầy nên em đã hoàn thành tốt đồ án.
Trong suốt thời gian được theo học tại trường Đại học Bà Rịa Vũng Tàu, Tp.
Vũng Tàu, em đã nhận được nhiều sự quan tâm và giúp đỡ từ Thầy Cô và bạn bè.
Cảm ơn Hiệu Trưởng, cùng các quý thầy cô trường Đại học Bà Rịa – Vũng Tàu đã
hỗ trợ tận tình về trang thiết bị, phần mềm, cơ sở vật chất tạo điều kiện hoàn thành
đồ án. Với lòng biết ơn sâu sắc, em xin gửi lời cảm ơn tới quý Thầy Cô, những
người đã truyền lại cho em rất nhiều kinh nghiệm và kiến thức quý báu, những sự
giúp đỡ ấy đã tiếp thêm động lực cho em vững bước trên con đường mình đã chọn.
Và đặc biệt là Thầy, Cô khoa Điện - Điện tử đã truyền đạt kiến thức, kinh nghiệm
cũng như tạo những điều kiện tốt nhất để nhóm em hoàn thành đề tài.
Xin cảm ơn các bạn cùng khóa, cùng khoa đã động viên, khích lệ, ủng hộ về
nhiều mặt góp phần làm nên thành công của đồ án này.
5
LỜI MỞ ĐẦU
Hiện nay, khoa học Công nghệ ngày càng đạt được những thành tựu to lớn,
kéo theo đó là sự phát triển vượt bậc trong các ngành nghề có ứng dụng khoa học
kỹ thuật thì việc ứng dụng khoa học Công nghệ vào mọi mặt đời sống là điều cấp
thiết và cần được mở rộng
Theo dõi, cập nhật thông tin sức khỏe là vấn đề được quan tâm bởi đại đa số
người hiện nay. Nhưng thiết bị thu thập thông số sức khỏe thì chưa đủ toàn diện
và được phổ biến. Với khí hậu, tình hình môi trường cũng như các vấn đề về
thực phẩm, dịch bệnh trong thời gian gần thì đây là một đề tài mang tính thực tế.
Để góp phần làm sáng tỏ hiệu quả của những ứng dụng trong thực tế của ngành
điện - điện tử, sau một thời gian học tập, em đã nghiên cứu thực hiện đề tài “Thiết
kế thiết bị đo thông số sức khỏe tự động”.
6
MỤC LỤC
4. Đối tượng, phạm vi nghiên cứu và phương pháp nghiên cứu ............................ 10
6. Bố cục ................................................................................................................. 11
1.7. Cảm Biến Nhiệt Hồng Ngoại Không Tiếp Xúc MLX90614 ................ 20
7
CHƯƠNG III. THIẾT KẾ THIẾT BỊ........................................................................ 27
8
DANH MỤC HÌNH
9
CHƯƠNG I. TỔNG QUAN
1. Đặt vấn đề
Theo dõi, cập nhật thông tin sức khỏe là vấn đề được quan tâm bởi đại đa số
người hiện nay. Nhưng thiết bị thu thập thông số sức khỏe thì chưa đủ toàn diện
và được phổ biến. Với khí hậu, tình hình môi trường dang ngày càng trở nên xấu
đi cũng như các vấn đề về an toàn vệ sinh thực phẩm, dịch bệnh trong thời gian
gần mang tới những ảnh hưởng mạnh mẽ tới sức khỏe con người. Vì vậy cần có
một thiết bị đơn giản có thể thu thập những thông số sức khỏe cơn bản là điều vô
cùng cần thiết. Em đã nghiên cứu thực hiện đề tài “Thiết kế thiết bị đo thông số
sức khỏe tự động” đây là đề tài nghiên cứu mang tính thực tế cao.
6. Bố cục
• Chương I: Tổng quan
Trình bày, đặt vấn đề dẫn nhập lí do chọn đề tài, mục tiêu, nội dung nghiên cứu,
các giới hạn thông số và bố cục đồ án.
Trình bày tổng quan các yêu cầu của để tài về thiết kế. Trình bày kết quả thi
công phần cứng và kết quả hình ảnh trên màn hình hay mô phỏng tín hiệu, kết
quả thống kê.
11
• Chương IV: Kết luận và phương hướng phát triển
Trình bày kết quả đạt được so với mục tiêu đề ra ban đầu, nhận xét và đánh giá
kết quả đạt được của đề tài nghiên cứu. Hướng phát triển của đề tài sau này trong
quá trình nghiên cứu.
12
CHƯƠNG II. CƠ SỞ LÝ THUYẾT
Mạch Arduino Mega 2560 Atmega là một board vi điều khiển dựa trên ATmega2560.
Board này có 54 chân I/O (14 chân PWM ), 16 analog đầu hàng vào, 4 UARTs (phần
cứng cổng tuần tự), sử dụng thạch anh 16 MHz, kết nối cổng USB, một Jack cắm điện,
chân ICSP, và một nút reset. Board có tất cả mọi thứ cần thiết để hỗ trợ vi điều khiển
Thông số kỹ thuật:
• Vi điều khiển chính: ATmega2560
• IC nạp và giao tiếp UART: ATmega16U2.
13
• Nguồn nuôi mạch: 5VDC từ cổng USB hoặc nguồn ngoài cắm từ giắc
tròn DC (khuyên dùng 7-9VDC để đảm bảo mạch hoạt động tốt. Nếu bạn cắm
12V thì IC ổn áp rất dễ chết và gây hư hỏng mạch).
• Số chân Digital: 54 (15 chân PWM)
• Số chân Analog: 16
• Giao tiếp UART : 4 bộ UART
• Giao tiếp SPI : 1 bộ ( chân 50 -> 53 ) dùng với thư viện SPI của Arduino
• Giao tiếp I2C : 1 bộ
• Ngắt ngoài : 6 chân
• Bộ nhớ Flash: 256 KB, 8KB sử dụng cho Bootloader
• SRAM: 8 KB
• EEPROM: 4 KB
• Xung clock: 16 MHz
Nguồn tổ ong 5V 20A là bộ nguồn được thiết kế để chuyển đổi điện áp xoay chiều thành
điện áp một chiều. Nguồn tổ ong 5V 20A có thiết kế gọn nhẹ, vỏ ngoài bằng kim loại
14
với những lỗ rổng giống như hình tổ ong nhằm mục đích nâng cao khả năng tản nhiệt,
cũng vì có thiết kế bề ngoài độc đáo này mà người ta thường gọi nó là Nguồn tổ ong.
Thông số kỹ thuật:
• Điện áp đầu vào: 110 – 220 VAC chỉnh bằng công tắc gạt
• Công suất: 100W
• Dòng đầu ra tối đa: 20A
• Nhiệt độ làm việc: -10 ~ 60 độ C
• Kích thước: 198 x 48 x 42mm
Cảm biến Loadcell 50Kg sử dụng để đo khối lượng của vật thể tối đa 50Kg, cảm biến
bằng kim loại với thiết kế rất dễ lắp đặt, phù hợp với các ứng dụng cân điện tử, cảm
biến khối lượng,..., lưu ý để sử dụng với Vi điều khiển cần gắn thêm Mạch chuyển
đổi ADC HX711 chuyên dụng dành cho Loadcell.
Thông số kỹ thuật:
• Tải trọng: 50 kg
• Dộ nhạy 1 ±1.5% mv/V
• Độ lệch tuyến tính 0.05%F.S
• Zero Output -0.3 mv/V
• Creep( 1 min) 0.1%F.S
• Ảnh hưởng của nhiệt độ đến điểm 0: 0.3%F.S/10
• Ảnh hưởng của nhiệt độ đến đầu ra: 0.1%F.S/10
15
• Điện trở: 1000 ± 10 Ω
• Trở kháng cách ly: >= 2000 M
• Điện áp hoạt động: 5~8V
• Nhiệt độ hoạt động: -20~65 0C
• Cáp: φ0.8×460 mm
16
1.4. Mạch chuyển đổi ADC 24bit Loadcell HX711
Mạch chuyển đổi ADC 24bit Loadcell HX711: module chuyển đổi analog sang
digital 24-bit. HX711 được thiết kế để chuyển đối tín hiệu và ứng dụng điều khiển
công nghiệp để giao tiếp trực tiếp với một cảm biến cầu.
Mạch chuyển đổi ADC HX711 không chỉ có một vài chức năng cơ bản, cũng có tích
hợp cao, phản ứng nhanh, khả năng chống nhiễu, và độ tin cậy cao.
Đây là mạch đọc giá trị cảm biến loadcell với độ phân giải 24bit và chuyển sang giao
tiếp 2 dây ( clock và data ) để gửi dữ liệu cho vi điều khiển / arduino.
Thông số kỹ thuật:
• Điện áp hoạt động : 2.7 – 5V
• Dòng tiêu thụ : < 1.5 mA
• Tốc độ lấy mẫu : 10 – 80 SPS ( tùy chỉnh )
• Độ phân giải : 24 bit ADC
• Độ phân giải điện áp : 40mV
• Kích thước : 38 x 21 x 10 mm
17
1.5. HCSR04
Cảm biến siêu âm HC-SR04 (Ultrasonic Sensor) được sử dụng rất phổ biến để xác
định khoảng cách vì RẺ và CHÍNH XÁC. Cảm biến HC-SR04 sử dụng sóng siêu âm
và có thể đo khoảng cách trong khoảng từ 2 -> 300cm, với độ chính xác gần như chỉ
phụ thuộc vào cách lập trình.
Cảm biến siêu âm HC-SR04 sử dụng nguyên lý phản xạ sóng siêu âm. Cảm biến gồm
2 module.1 module phát ra sóng siêu âm và 1 module thu sóng siêu âm phản xạ
về. Đầu tiên cảm biến sẽ phát ra 1 sóng siêu âm với tần số 40khz. Nếu có chướng
ngại vật trên đường đi, sóng siêu âm sẽ phản xạ lại và tác động lên module nhận
sóng. Bằng cách đo thời gian từ lúc phát đến lúc nhận sóng ta sẽ tính được khoảng
cách từ cảm biến đến chướng ngại vật với công thức:
Thông số kỹ thuật:
• Điện áp: 5V DC
• Dòng hoạt động: < 2mA
• Mức cao: 5V
18
• Mức thấp: 0V
• Góc tối đa: 15 độ
• Khoảng cách: 2cm – 450cm (4.5m)
• Độ chính xác: 3mm
Cảm biến nhịp tim Pulse Sensor sử dụng nguyên lý đo nhịp tim bằng ánh sáng với kích
thước nhỏ gọn và giao tiếp Analog rất dễ sử dụng, cảm biến nhịp tim phù hợp cho các
ứng dụng điện tử y sinh.
Thông số kỹ thuật:
• Nguồn: 3~5VDC
• Dòng tiêu thụ: < 4mA
• Ngõ ra: Analog.
• Độ dài dây: 61cm ( 24 inch).
• Đường kính cảm biến: 1.6 cm ( 0.625 inch).
19
1.7. Cảm biến nhiệt hồng ngoại không tiếp xúc MLX90614
Hình 8. Cảm biến nhiệt hồng ngoại không tiếp xúc MLX90614
Cảm biến nhiệt hồng ngoại không tiếp xúc MLX90614 là loại cảm biến đo nhiệt
độ hồng ngoại không tiếp xúc dùng chip MXL90614 sử dụng giao tiếp I2C có thể
dễ dàng kết nối với bất cứ vi điều khiển nào.
20
Ứng dụng cảm biến nhiệt hồng ngoại không tiếp xúc:
Ví dụ ứng dụng
21
• Phát hiện chuyển động
• Điều khiển nhiệt độ nhiều vùng – lên đến 127 bộ cảm biến có thể được đọc
thông qua 2 dây phổ biến
• Relay / cảnh báo nhiệt
• Đo nhiệt độ cơ thể
Module led ma trận P10 Full color 32×16 gồm 32 led hàng ngang và 16 led hàng
dọc, bản thân mỗi led bên trong có 3 led với 3 màu RGB, mỗi pixel cách nhau 1cm.
Tổng số led RGB là 32×16=512 LED RGB.
22
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
Với P10 1 màu, data đi theo chiều zigzac, thì P10 FULL, data đi theo đường thẳng
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
23
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.
Vì Arduino IDE được viết trên Java nên bạn cần phải cài đặt JRE trước Arduino
IDE.
Chú ý:
Nhiều bạn do không cài JRE trên máy nên thường hay gặp phải tình trạng không
chạy được Arduino IDE.
2 bản JRE phổ biến nhất là bản dành cho Windows 32bit (x86) và Windows 64bit
(x64) mình đã đánh dấu trong hình. Nhớ chọn "Accept License Agreement".
Bước 1: Truy cập địa chỉ http://arduino.cc/en/Main/Software/... Đây là nơi lưu trữ
cũng như cập nhật các bản IDE của Arduino. Bấm vào mục “Windows ZIP file for
non admin install”.
24
Bạn sẽ được chuyển đến một trang mời quyền góp tiền để phát triển phần mềm cho
Arduino, tiếp tục bấm JUST DOWNLOAD để bắt đầu tải.
Bước 2: Sau khi download xong, các bạn bấm chuột phải vào file vừa download
arduino-1.8.12-windows.zip và chọn “Extract here” để giải nén.
Bước 3: Copy thư mục arduino-1.8.12 vừa giải nén đến nơi lưu trữ.
Bước 4: Chạy file trong thư mục arduino-1.8.12 để khởi động Arduino IDE
25
- Cài đặt Driver
Để máy tính của bạn và board Arduino giao tiếp được với nhau, chúng ta cần phải
cài đặt driver trước tiên.
Nếu bạn dùng Windows 8, trong một số trường hợp Windows không cho phép bạn
cài Arduino driver (do driver không được kí bằng chữ kí số hợp lệ). Do vậy bạn
cần vào Windows ở chế độ Disable driver signature enforcement thì mới cài được
driver.
- Khi có yêu cầu xác nhận cài đặt driver, chọn “Install”
- Đợi khoảng 10 giây trong lúc quá trình cài đặt diễn ra …
26
CHƯƠNG III. THIẾT KẾ THIẾT BỊ
1. Giới thiệu và yêu cầu của thiết bị
Khối điều khiển trung tâm: khối điều khiển trung tâm sử dụng Arduino MEGA
2560 có hiệu năng cao, dùng để điều khiển các thiết bị khác trong hệ thống:
- Truyền dữ liệu qua màn hình hiển thị của thiết bị.
Khối cảm biến: bao gồm cảm biến siêu âm, cảm biến nhiêt độ, cảm biến nhịp tim,
loadcell dùng để thu thập dữ liệu về cân nặng, chiều cao, nhiệt độ, nhịp tim đối
tượng, từ đó đưa tín hiệu về khối điều khiển trung tâm.
Khối hiển thị: Khối hiển thị sử dụng màn hình Led matrix RGB P10 16x32 dùng
để hiển thị số liệu đọc được từ khối cảm biến.
Khối nguồn : Khối nguồn là khối quan trọng giúp cung cấp điện cho toàn bộ hệ
thống. Vì vậy cần tính toán hợp lý để khối nguồn có thể cung cấp đủ dòng và áp để
mạch có thể hoạt động tốt và ổn định.
27
3. Các thành phần của thiết bị
Cảm biến siêu âm HC-SR04 sử dụng nguyên lý phản xạ sóng siêu âm. Cảm
biến gồm 2 module.1 module phát ra sóng siêu âm và 1 module thu sóng siêu âm
phản xạ về. Đầu tiên cảm biến sẽ phát ra 1 sóng siêu âm với tần số 40khz. Sau khi
gặp đối tượng thì phản xạ về module thu và tính ra khoảng cách.
S = V*t/2 (cm)
Trong đó:
- t: Thời gian đo
28
Sau đó chiều cao đối tượng dược tính bằng:
H = hcb – S (cm)
Trong đó:
Bộ phận này bao gồm: 4 Loadcell 50kg, mạch chuyển dổi 24bit HX711 và một
số phụ kiện khác được kết nối như hình sau:
29
Hình 18. Sơ đồ kết nối các loadcell với HX711
Các loadcell đọc và gửi tín hiệu về bộ xử lý trung tâm thông qua HX711.
Cảm biến nhịp tim Pulse Sensor sử dụng nguyên lý đo nhịp tim bằng ánh sáng.
Cảm biến thi thập tín hiệu từ đối tượng rồi gửi về bộ xử lý trung tâm.
30
3.4. Bộ phận đo nhiệt độ
Cảm biến này đo nhiệt độ đối tượng thông qua bức xạ hông ngoại mà đối tượng
phát ra. Từ tín hiệu thu thập được qua kết nối I2C tới bộ xử ký trung tâm
Tấm Led matrix RGB 16x32 hiển thị các thông số sức khỏa thu thập được từ các
cảm biến thông qua chuẩn truyền SPI kết nối với bộ xử lý trung tâm. Các thông số
hiẻn thị lần lượt theo chương tringf đặt sẵn: Chiều cao, cân nặng, nhiệt độ, nhịp tim.
31
3.6. Bộ phận nguồn cung cấp
Nguồn tổ ong 5V-20A cung câp năng lượng hoạt động cho toàn bộ thiết bị vận
hành bình thường.
32
Hình 24. Thiết bị lắp ráp hoàn chỉnh
33
CHƯƠNG IV. KẾT LUẬN VÀ PHƯƠNG HƯỚNG PHÁT TRIỂN
1. Kết luận
Sau một thời gian nghiên cứu và hoàn thành đề tài, nhóm đã nhận thấy mô hình
đã hiệu quả được 85%, trong thời gian nghiên cứu và thực hiện đề tài, nhóm đã học
hỏi và tìm hiểu thêm được nhiều kiến thức mới cũng như củng cố lại kiến thức đã
học giúp hoàn thành đề tài này. Vì đây là đề tài hướng đến việc giúp thu thập thông
tin sức khỏe con người nên phải chú trọng độ ổn định và chính xác dẫn đến nhiều
khó khăn trong quá trình lập trình. Nhưng nhờ sự hướng dẫn của giảng viên hướng
dẫn và các tài liệu tham khảo thì nhóm đã giải quyết được tương đối yêu cầu của
đề tài.
Trong quá trình thực hiện đề tài về phần cứng, nhóm đã tìm hiểu được chức năng
của các chân IO của board Ardruino, kết hợp với các cảm biến để đọc giá trị, sử
dụng các kiểu truyền dữ liệu để giao tiếp và module Led matrix RGB. Việc kết hợp
các module này lại với nhau để làm việc ổn định mất nhiều thời gian nhưng cũng
học hỏi được rất nhiều trong quá trình làm.
Tuy rằng sản phẩm đã được hoàn thành nhưng nhóm vẫn nhận thấy sản phẩm còn
nhiều thiếu sót, cần được chỉnh sửa và cải tiến hơn. Xây dựng hoàn thành mô hình
có khả năng cập nhật dữ liệu từ đối tượng đến thiết bị khác để xử lý theo nhiều yêu
cầu mà người dùng cần.
34
TÀI LIỆU THAM KHẢO
[1] Trần Thu Hà, Trương Thị Bích Ngà, “Giáo trình Điện tử cơ bản”, Nhà xuất
bản ĐH Quốc Gia TP Vũng Tàu, 2013.
[2] Nguyễn Việt Hùng, Nguyễn Ngô Lâm, Nguyễn Văn Phúc, Đặng Phước Hải
Trang, Giáo trình kỹ thuật truyền số liệu, NXB ĐH Quốc Gia TP. HCM, 2012.
[3] Phan Quang Phô, Nguyễn Đức Chiến, “Giáo trình cảm biến”. Nhà xuất bản
Khoa Học Kỹ Thuật, 2000.
[4] Dương Minh Trí, “Cảm biến và ứng dụng”, Nhà xuất bản Khoa học và Kỹ
thuật, 2001.
[5] http://arduino.vn/bai-viet/68-cai-dat-driver-va-arduino-ide
[6] http://alldatasheet.com/
[7] http://arduino.vn/
[8] http://codientu.org/
[9] http://webdien.com/
[10] http://www.tailieu.vn/
[11] https://hshop.vn/
35
PHỤ LỤC
36
0x0000C38A, // Ê
0x00E1BB80, // Ề
0x00E1BABE, // Ế
0x00E1BB82, // Ể
0x00E1BB84, // Ễ
0x00E1BB86, // Ệ
0x0000C38C, // Ì
0x0000C38D, // Í
0x00E1BB88, // Ỉ
0x0000C4A8, // Ĩ
0x00E1BB8A, // Ị
0x0000C392, // Ò
0x0000C393, // Ó
0x00E1BB8E, // Ỏ
0x0000C395, // Õ
0x00E1BB8C, // Ọ
0x0000C394, // Ô
0x00E1BB92, // Ồ
0x00E1BB90, // Ố
0x00E1BB94, // Ổ
0x00E1BB96, // Ỗ
0x00E1BB98, // Ộ
0x0000C6A0, // Ơ
0x00E1BB9C, // Ờ
0x00E1BB9A, // Ớ
0x00E1BB9E, // Ở
0x00E1BBA0, // Ỡ
0x00E1BBA2, // Ợ
0x0000C399, // Ù
0x0000C39A, // Ú
0x00E1BBA6, // Ủ
37
0x0000C5A8, // Ũ
0x00E1BBA4, // Ụ
0x0000C6AF, // Ư
0x00E1BBAA, // Ừ
0x00E1BBA8, // Ứ
0x00E1BBAC, // Ử
0x00E1BBAE, // Ữ
0x00E1BBB0, // Ự
0x00E1BBB2, // Ỳ
0x0000C39D, // Ý
0x00E1BBB6, // Ỷ
0x00E1BBB8, // Ỹ
0x00E1BBB4, // Ỵ
0x0000C3A0, // à
0x0000C3A1, // á
0x00E1BAA3, // ả
0x0000C3A3, // ã
0x00E1BAA1, // ạ
0x0000C483, // ă
0x00E1BAB1, // ằ
0x00E1BAAF, // ắ
0x00E1BAB3, // ẳ
0x00E1BAB5, // ẵ
0x00E1BAB7, // ặ
0x0000C3A2, // â
0x00E1BAA7, // ầ
0x00E1BAA5, // ấ
0x00E1BAA9, // ẩ
0x00E1BAAB, // ẫ
0x00E1BAAD, // ậ
0x0000C491, // đ
38
0x0000C3A8, // è
0x0000C3A9, // é
0x00E1BABB, // ẻ
0x00E1BABD, // ẽ
0x00E1BAB9, // ẹ
0x0000C3AA, // ê
0x00E1BB81, // ế
0x00E1BABF, // ề
0x00E1BB83, // ể
0x00E1BB85, // ễ
0x00E1BB87, // ệ
0x0000C3AC, // ì
0x0000C3AD, // í
0x00E1BB89, // ỉ
0x0000C4A9, // ĩ
0x00E1BB8B, // ị
0x0000C3B2, // ò
0x0000C3B3, // ó
0x00E1BB8F, // ỏ
0x0000C3B5, // õ
0x00E1BB8D, // ọ
0x0000C3B4, // ô
0x00E1BB93, // ố
0x00E1BB91, // ồ
0x00E1BB95, // ổ
0x00E1BB97, // ỗ
0x00E1BB99, // ộ
0x0000C6A1, // ơ
0x00E1BB9D, // ờ
0x00E1BB9B, // ớ
0x00E1BB9F, // ở
39
0x00E1BBA1, // ỡ
0x00E1BBA3, // ợ
0x0000C3B9, // ù
0x0000C3BA, // ú
0x00E1BBA7, // ủ
0x0000C5A9, // ũ
0x00E1BBA5, // ụ
0x0000C6B0, // ư
0x00E1BBAB, // ừ
0x00E1BBA9, // ứ
0x00E1BBAD, // ử
0x00E1BBAF, // ữ
0x00E1BBB1, // ự
0x00E1BBB3, // ỳ
0x0000C3BD, // ý
0x00E1BBB7, // ỷ
0x00E1BBB9, // ỹ
0x00E1BBB5 // ỵ
};
const uint8_t Sinclair_S[] ={//764
0x08,0x08,0x20,0x7E,0x01,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // <space>
0x08,0x08,0x08,0x08,0x08,0x00,0x08,0x00, // !
0x14,0x14,0x00,0x00,0x00,0x00,0x00,0x00, // "
0x00,0x24,0x7E,0x24,0x24,0x7E,0x24,0x00, // #
0x10,0x7C,0x50,0x7C,0x14,0x7C,0x10,0x00, // $
0x00,0x62,0x64,0x08,0x10,0x26,0x46,0x00, // %
0x00,0x10,0x28,0x10,0x2A,0x44,0x3A,0x00, // &
0x00,0x08,0x10,0x00,0x00,0x00,0x00,0x00, // '
0x00,0x08,0x10,0x10,0x10,0x10,0x08,0x00, // (
0x00,0x10,0x08,0x08,0x08,0x08,0x10,0x00, // )
40
0x00,0x00,0x28,0x10,0x7C,0x10,0x28,0x00, // *
0x00,0x00,0x10,0x10,0x7C,0x10,0x10,0x00, // +
0x00,0x00,0x00,0x00,0x00,0x08,0x08,0x10, // ,
0x00,0x00,0x00,0x00,0x7C,0x00,0x00,0x00, // -
0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00, // .
0x00,0x00,0x04,0x08,0x10,0x20,0x40,0x00, // /
0x00,0x78,0x8C,0x94,0xA4,0xC4,0x78,0x00, // 0
0x00,0x60,0xA0,0x20,0x20,0x20,0xF8,0x00, // 1
0x00,0x78,0x84,0x04,0x78,0x80,0xFC,0x00, // 2
0x00,0x78,0x84,0x18,0x04,0x84,0x78,0x00, // 3
0x00,0x10,0x30,0x50,0x90,0xFC,0x10,0x00, // 4
0x00,0xFC,0x80,0xF8,0x04,0x84,0x78,0x00, // 5
0x00,0x78,0x80,0xF8,0x84,0x84,0x78,0x00, // 6
0x00,0xFC,0x04,0x08,0x10,0x20,0x20,0x00, // 7
0x00,0x78,0x84,0x78,0x84,0x84,0x78,0x00, // 8
0x00,0x78,0x84,0x84,0x7C,0x04,0x78,0x00, // 9
0x00,0x00,0x00,0x10,0x00,0x00,0x10,0x00, // :
0x00,0x00,0x10,0x00,0x00,0x10,0x10,0x20, // ;
0x00,0x00,0x08,0x10,0x20,0x10,0x08,0x00, // <
0x00,0x00,0x00,0x7C,0x00,0x7C,0x00,0x00, // =
0x00,0x00,0x20,0x10,0x08,0x10,0x20,0x00, // >
0x00,0x3C,0x42,0x04,0x08,0x00,0x08,0x00, // ?
0x00,0x3C,0x4A,0x56,0x5E,0x40,0x3C,0x00, // @
0x00,0x78,0x84,0x84,0xFC,0x84,0x84,0x00, // A
0x00,0xF8,0x84,0xF8,0x84,0x84,0xF8,0x00, // B
0x00,0x78,0x84,0x80,0x80,0x84,0x78,0x00, // C
0x00,0xF0,0x88,0x84,0x84,0x88,0xF0,0x00, // D
0x00,0xFC,0x80,0xF8,0x80,0x80,0xFC,0x00, // E
0x00,0xFC,0x80,0xF8,0x80,0x80,0x80,0x00, // F
41
0x00,0x78,0x84,0x80,0x9C,0x84,0x78,0x00, // G
0x00,0x84,0x84,0xFC,0x84,0x84,0x84,0x00, // H
0x00,0x7C,0x10,0x10,0x10,0x10,0x7C,0x00, // I
0x00,0x04,0x04,0x04,0x84,0x84,0x78,0x00, // J
0x00,0x88,0x90,0xE0,0x90,0x88,0x84,0x00, // K
0x00,0x80,0x80,0x80,0x80,0x80,0xFC,0x00, // L
0x00,0x84,0xCC,0xB4,0x84,0x84,0x84,0x00, // M
0x00,0x84,0xC4,0xA4,0x94,0x8C,0x84,0x00, // N
0x00,0x78,0x84,0x84,0x84,0x84,0x78,0x00, // O
0x00,0xF8,0x84,0x84,0xF8,0x80,0x80,0x00, // P
0x00,0x78,0x84,0x84,0xA4,0x94,0x78,0x00, // Q
0x00,0xF8,0x84,0x84,0xF8,0x88,0x84,0x00, // R
0x00,0x78,0x80,0x78,0x04,0x84,0x78,0x00, // S
0x00,0xFE,0x10,0x10,0x10,0x10,0x10,0x00, // T
0x00,0x84,0x84,0x84,0x84,0x84,0x78,0x00, // U
0x00,0x84,0x84,0x84,0x84,0x48,0x30,0x00, // V
0x00,0x84,0x84,0x84,0x84,0xB4,0x48,0x00, // W
0x00,0x84,0x48,0x30,0x30,0x48,0x84,0x00, // X
0x00,0x82,0x44,0x28,0x10,0x10,0x10,0x00, // Y
0x00,0xFC,0x08,0x10,0x20,0x40,0xFC,0x00, // Z
0x00,0x38,0x20,0x20,0x20,0x20,0x38,0x00, // [
0x00,0x00,0x40,0x20,0x10,0x08,0x04,0x00, // <backslash>
0x00,0x38,0x08,0x08,0x08,0x08,0x38,0x00, // ]
0x00,0x10,0x38,0x54,0x10,0x10,0x10,0x00, // ^
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE, // _
0x3C,0x42,0x99,0xA1,0xA1,0x99,0x42,0x3C, // `
0x00,0x00,0x38,0x04,0x3C,0x44,0x3C,0x00, // a
0x00,0x40,0x40,0x78,0x44,0x44,0x78,0x00, // b
0x00,0x00,0x1C,0x20,0x20,0x20,0x1C,0x00, // c
42
0x00,0x04,0x04,0x3C,0x44,0x44,0x3C,0x00, // d
0x00,0x00,0x38,0x44,0x78,0x40,0x3C,0x00, // e
0x00,0x0C,0x10,0x18,0x10,0x10,0x10,0x00, // f
0x00,0x00,0x3E,0x42,0x42,0x3E,0x02,0x3C, // g
0x00,0x40,0x40,0x78,0x44,0x44,0x44,0x00, // h
0x00,0x08,0x00,0x18,0x08,0x08,0x1C,0x00, // i
0x00,0x04,0x00,0x04,0x04,0x04,0x24,0x18, // j
0x00,0x40,0x50,0x60,0x60,0x50,0x48,0x00, // k
0x00,0x10,0x10,0x10,0x10,0x10,0x0C,0x00, // l
0x00,0x00,0x68,0x54,0x54,0x54,0x54,0x00, // m
0x00,0x00,0x78,0x44,0x44,0x44,0x44,0x00, // n
0x00,0x00,0x38,0x44,0x44,0x44,0x38,0x00, // o
0x00,0x00,0x78,0x44,0x44,0x78,0x40,0x40, // p
0x00,0x00,0x3C,0x44,0x44,0x3C,0x04,0x06, // q
0x00,0x00,0x1C,0x20,0x20,0x20,0x20,0x00, // r
0x00,0x00,0x38,0x40,0x38,0x04,0x78,0x00, // s
0x00,0x10,0x38,0x10,0x10,0x10,0x0C,0x00, // t
0x00,0x00,0x44,0x44,0x44,0x44,0x38,0x00, // u
0x00,0x00,0x44,0x44,0x28,0x28,0x10,0x00, // v
0x00,0x00,0x44,0x54,0x54,0x54,0x28,0x00, // w
0x00,0x00,0x44,0x28,0x10,0x28,0x44,0x00, // x
0x00,0x00,0x44,0x44,0x44,0x3C,0x04,0x38, // y
0x00,0x00,0x7C,0x08,0x10,0x20,0x7C,0x00, // z
0x00,0x1C,0x10,0x60,0x10,0x10,0x1C,0x00, // {
0x00,0x10,0x10,0x10,0x10,0x10,0x10,0x00, // |
0x00,0x70,0x10,0x0C,0x10,0x10,0x70,0x00, // }
0x00,0x14,0x28,0x00,0x00,0x00,0x00,0x00, // ~
};
43
2. Khởi tạo thư viện MatrixDisp.h
#include <SPI.h>
#define A A0
#define B A1
#define C A2
#define OE 32
#define ST 33 //LAT
#define dispW 32
#define dispH 16
#define dispWB dispW/8
#define dispHB dispH/8
#define scanBuffLen (dispH*dispWB*3)/8
uint8_t dispBuff[3][dispH][dispWB];
uint8_t scanBuff[scanBuffLen];
volatile uint8_t scan=0;
uint8_t dispX,dispY,dataW=0,dataH;
uint8_t DELAY=1,textSpeed=15;
uint8_t *Font;
#define red 1
#define green 2
#define blue 4
#define yellow 3
#define purple 5
#define cyan 6
#define white 7
#define randc 8
void ShiftDispLeft(int8_t dispw,int8_t disph,int8_t dispx,int8_t dispy,uint8_t
color);
void setupMatrixDisp() {
44
SPI.begin();
SPI.setBitOrder(MSBFIRST);
SPI.setClockDivider(SPI_CLOCK_DIV2);
pinMode(53, OUTPUT); //HSPI SS
pinMode(A, OUTPUT);digitalWrite(A, 0);
pinMode(B, OUTPUT);digitalWrite(B, 0);
pinMode(C, OUTPUT);digitalWrite(C, 0);
pinMode(OE, OUTPUT);digitalWrite(OE, 0);
pinMode(ST, OUTPUT);digitalWrite(ST, 0);
Font=Sinclair_S;
}
void DispScan(){
uint8_t c,y,x,j,i;
uint16_t idx=0;
for(c=0;c<3;c++){
for(j=scan;j<16;j+=8){
y=j;
while(y<dispH){
for(x=0;x<dispWB;x++)scanBuff[idx++]=dispBuff[c][y][x];
y+=16;
}
}
}
for(i=0;i<scanBuffLen;i++)SPI.transfer(scanBuff[i]);
digitalWrite(OE, 1);
digitalWrite(A,(bool)(scan&0x01));
digitalWrite(B,(bool)(scan&0x02));
digitalWrite(C,(bool)(scan&0x04));
digitalWrite(ST, 1);digitalWrite(ST, 0);
45
digitalWrite(OE, 0);
if(++scan>7)scan=0;
}
//xoa het dispClrAll(0);
void dispClrAll(uint8_t type){
uint8_t i,j,k,x,y,s=10;
if(type==0xff)type=(rand()%6) + 1;
if(type==0){
for(y=0;y<dispH;y++){
for(x=0;x<dispWB;x++){
dispBuff[0][y][x]=0;
dispBuff[1][y][x]=0;
dispBuff[2][y][x]=0;
}
}
}
else if(type==1){ //xoa tren xuong cham
for(y=0;y<dispH;y++){
for(x=0;x<dispWB;x++){
dispBuff[0][y][x]=0;
dispBuff[1][y][x]=0;
dispBuff[2][y][x]=0;
}
delay(s);
}
}
else if(type==2){ //xoa duoi len cham
for(y=dispH;y>0;y--){
for(x=0;x<dispWB;x++){
46
dispBuff[0][y-1][x]=0;
dispBuff[1][y-1][x]=0;
dispBuff[2][y-1][x]=0;
}
delay(s);
}
}
else if(type==3){ //troi xuong cham
i=dispH;
while(i--){
for(y=dispH-1;y>0;y--){
for(x=0;x<dispWB;x++){
dispBuff[0][y][x]=dispBuff[0][y-1][x];
dispBuff[1][y][x]=dispBuff[1][y-1][x];
dispBuff[2][y][x]=dispBuff[2][y-1][x];
}
}
for(x=0;x<dispWB;x++){dispBuff[0][0][x]=0;dispBuff[1][0][x]=0;dispBuff[2][
0][x]=0;}
delay(s);
}
}
else if(type==4){ //troi len cham
i=dispH;
while(i--){
for(y=0;y<dispH;y++){
for(x=0;x<dispWB;x++){
dispBuff[0][y][x]=dispBuff[0][y+1][x];
47
dispBuff[1][y][x]=dispBuff[1][y+1][x];
dispBuff[2][y][x]=dispBuff[2][y+1][x];
}
}
for(x=0;x<dispWB;x++){dispBuff[0][dispH-1][x]=0;dispBuff[1][dispH-
1][x]=0;dispBuff[2][dispH-1][x]=0;}
delay(s);
}
}
else if(type==5){ //xoa sang trai cham
for(x=0;x<dispW;x++){ShiftDispLeft(dispW,dispH,0,0,7);delay(s/2);}
}
else if(type==6){ //troi len cham
i=dispH;
while(i--){
for(y=0,j=dispH-1;y<dispH;y++,j--){
for(x=0,k=1;x<dispWB;x+=2,k+=2){
dispBuff[0][y][x]=dispBuff[0][y+1][x];
dispBuff[1][y][x]=dispBuff[1][y+1][x];
dispBuff[2][y][x]=dispBuff[2][y+1][x];
dispBuff[0][j][k]=dispBuff[0][j-1][k];
dispBuff[1][j][k]=dispBuff[1][j-1][k];
dispBuff[2][j][k]=dispBuff[2][j-1][k];
}
}
for(x=0;x<dispWB;x+=2){dispBuff[0][dispH-1][x]=0;dispBuff[1][dispH-
1][x]=0;dispBuff[2][dispH-1][x]=0;}
48
for(x=1;x<dispWB;x+=2){dispBuff[0][0][x]=0;dispBuff[1][0][x]=0;dispBuff[2]
[0][x]=0;}
delay(s);
}
}
}
//Ham set con tro man hinh
void dispGotoXY(uint8_t dispx,uint8_t dispy){
if(dispx)dispx--;dispX=dispx;
if(dispY)dispy--;dispY=dispy;
}
//hiển thị 1 mảng dữ liệu lên màn hình ở vị trí X(1-dispW) và Y(1-dispH)
void dispImage(uint8_t PROGMEM *ptr,uint8_t color,int8_t dispx,int8_t
dispy){
uint8_t c,i,j,w,h,wb,x,shl,shr,temp,buff,del;
int8_t y;
uint8_t PROGMEM *ptrs;
shr=dispx%8;shl=8-shr;dispx/=8;
x=dispx;y=dispy;
if(dataW==0){w=*ptr++;h=*ptr++;}
else{w=dataW;h=dataH;}
wb=(w+7)/8;
del=DELAY;
for(c=0;c<3;c++){
if((color&(1<<c))==0)continue;
ptrs=ptr;y=dispy;
for(j=0;j<h;j++,y++){
if(y<0){ptrs+=wb;continue;}
if(y>=dispH)break;
49
x=dispx;
temp=dispBuff[c][y][x];
temp&=(0xff<<shl);
for(i=0;i<=wb;i++,x++){
if(x>=dispWB){ptrs+=(wb-i);break;}
if(i<wb){buff=*ptrs++;}
else{buff=(dispBuff[c][y][x]<<shr);}
temp|=(buff>>shr);
if(((i+1)*8)>(w+shr)){
i=(w+shr)%8;
temp&=(0xff<<(8-i));
temp|=(dispBuff[c][y][x]&(0xff>>i));
i=wb+1;
}
dispBuff[c][y][x]|=temp;
if(del)delay(del);
temp=(buff<<shl);
}
}
del=0;
}
dataW=0;
}
void insertImage(uint8_t PROGMEM *ptr,uint8_t color,int8_t dispx,int8_t
dispy){
uint8_t c,i,j,w,h,wb,x,shl,shr,temp,buff,mask,sh;
int8_t y,del;
uint8_t PROGMEM *ptrs;
shr=dispx%8;shl=8-shr;dispx/=8;
50
x=dispx;y=dispy;
if(dataW==0){w=*ptr++;h=*ptr++;}
else{w=dataW;h=dataH;}
wb=(w+7)/8;
for(c=0;c<3;c++){
ptrs=ptr;y=dispy;
for(j=0;j<h;j++,y++){
if(y<0){ptrs+=wb;continue;}
if(y>=dispH)break;
x=dispx;
temp=dispBuff[c][y][x];
temp&=(0xff<<shl);
mask=temp|(0xff>>shr);
for(i=0;i<=wb;i++,x++){
if(x>=dispWB){ptrs+=(wb-i);break;}
if(i<wb){buff=*ptrs++;mask&=~(buff>>shr);}
else{buff=(dispBuff[c][y][x]<<shr);mask|=(0xff>>shr);}
temp|=(buff>>shr);
if(((i+1)*8)>(w+shr)){
sh=(w+shr)%8;
temp&=(0xff<<(8-sh));
temp|=(dispBuff[c][y][x]&(0xff>>sh));
mask|=(0xff>>sh);
i=wb+1;
}
dispBuff[c][y][x]&=mask;
if(color&(1<<c)){dispBuff[c][y][x]|=temp;if(del)delay(del);}
temp=(buff<<shl);
mask=~temp;
51
}
del=0;
}
}
dataW=0;
}
uint8_t UTF8_GetAddr(char PROGMEM *utf8_char,uint8_t *offset){
*offset=1;
uint8_t i=0,temp = *utf8_char;
//Serial.println(String(temp));
if(temp<0x80)return (temp); //nếu đây là kí tự trong bản ascii
uint32_t utf8Value=0; //nếu đây là kí tự tiếng Việt có đấu
temp&=0xf0;
while(temp){
utf8Value<<=8;
utf8Value|=*utf8_char++;
temp<<=1;
i++;
}
*offset=i;
for(i = 0; i < UTF8_table_size; i++){
if(utf8Value == UTF8_table[i]){
if(i<UTF8_char_end1)return i+1;
else return i+UTF8_char_start2-UTF8_char_end1;
}
}
return '?';
}
52
uint8_t writeVietStr(char PROGMEM *ptr,uint8_t color,int8_t dispx,int8_t
dispy){
uint8_t PROGMEM *ptrch,*ptrf;
uint8_t fw,fh,fwb,offset,rootchar,space,ch,i,j,k,mask,next,count=0;
ptrf=Font;
fw=*ptrf++;
fh=*ptrf++;
offset=*ptrf++;
rootchar=*ptrf++;
space=*ptrf++;
fwb=(fw+7)/8;
while(*ptr){
ch=UTF8_GetAddr(ptr,&next);
ptr+=next;
if(ch<offset)continue;
if(ch>rootchar)continue;
dataW=fw;dataH=fh;
ptrch=ptrf+(ch-offset)*fh*fwb;
if(ch==0x20){mask=fw/2;k=fwb;}else k=0;
for(k;k<fwb;k++){
mask=0x01;
for(i=0;i<8;i++){
for(j=fwb-k-1;j<fh*fwb;j+=fwb){
ch=*(ptrch+j);
if(ch&mask)break;
}
if(j<(fh*fwb))break;
else mask<<=1;
}
53
if(i<8){mask=fwb*8-i-(k*8)+space;break;}
}
if(color==8){j=rand()%7;j+=1;}else j=color;
dispImage(ptrch,j,dispx,dispy);
dispx+=mask;
count+=mask;
if(dispx>dispW)return count;
}
return count;
}
void ShiftDispLeft(int8_t dispw,int8_t disph,int8_t dispx,int8_t dispy,uint8_t
color){
uint8_t c,x,y,i,j,temp,temp2,left,right;
dispw+=dispx;dispw--;if(dispw>=dispW)dispw=dispW-1;
disph+=dispy;disph--;if(disph>=dispH)disph=dispH-1;
left=dispx%8;right=dispw%8;
dispx/=8;dispw/=8;
for(y=dispy;y<=disph;y++){
for(x=dispx;x<=dispw;x++){
for(c=0;c<3;c++){
if((color&(1<<c))==0)continue;
temp=dispBuff[c][y][x];
temp<<=1;
if(x<dispw){if(dispBuff[c][y][x+1]&0x80)temp|=0x01;}
else{
temp2=(dispBuff[c][y][x]&(0xff>>(right+1)));
temp&=(0xff<<(8-right));
temp|=temp2;
}
54
if(x==dispx){
temp2=(dispBuff[c][y][x]&(0xff<<(8-left)));
temp&=(0xff>>left);
temp|=temp2;
}
dispBuff[c][y][x]=temp;
}
}
}
}
void StringScrollLeft(char PROGMEM *text,uint8_t speedms,uint8_t
color,int8_t dispw,int8_t disph,int8_t dispx,int8_t dispy){
uint8_t count,chr,next,i,x,d=DELAY;
char temp[5];
DELAY=0;
if(color>7){color=rand()%7;color++;}
x+=dispw;if(x>dispW)x=dispW;
while(*text){
if(*text==0x0A){
i=x;
while(i--){delay(speedms);ShiftDispLeft(dispw,disph,dispx,dispy,7);}
text++;
}
temp[0]=UTF8_GetAddr(text,&next);
for(i=0;i<next;i++)temp[i]=*(text+i);
temp[i]=0;
text+=next;
count= writeVietStr(temp,color,x,dispy);
for(i=1;i<=count;i++){
55
delay(speedms);
ShiftDispLeft(dispw,disph,dispx,dispy,7);
writeVietStr(temp,color,x-i,dispy);
}
}
while(x--){delay(speedms);ShiftDispLeft(dispw,disph,dispx,dispy,7);}
DELAY=d;
}
3. Code điều khiển chính
#include <Wire.h>
#include <TimerOne.h> // khai báo thư viện timer 1
#include "Data.h"
#include "MatrixDisp.h"
#include <HCSR04.h>
UltraSonicDistanceSensor Sensor1(8,9);
int DistanceCm = 0;
int KhoangCach = 0;
int oldDis = 0;
#include <HX711.h>
#define DT 2
#define CK 3
HX711 scale;
float calibration_factor = -7050; //-7050 worked for my 440lb max scale setup
float n=0.45359237;
float LBS; int KG;
#include <Adafruit_MLX90614.h>
Adafruit_MLX90614 mlx = Adafruit_MLX90614();
56
//Nhiptim
int pulsePin = A8; // Pulse Sensor purple wire connected to analog pin
A0
int blinkPin = 13; // pin to blink led at each beat
// Volatile Variables, used in the interrupt service routine!
volatile int BPM; // int that holds raw Analog in 0. updated every 2mS
volatile int Signal; // holds the incoming raw data
volatile int IBI = 600; // int that holds the time interval between beats!
Must be seeded!
volatile boolean Pulse = false; // "True" when User's live heartbeat is detected.
"False" when not a "live beat".
volatile boolean QS = false; // becomes true when Arduoino finds a beat.
static boolean serialVisual = true; // Set to 'false' by Default. Re-set to 'true' to
see Arduino Serial Monitor ASCII Visual Pulse
volatile int rate[10]; // array to hold last ten IBI values
volatile unsigned long sampleCounter = 0; // used to determine pulse timing
volatile unsigned long lastBeatTime = 0; // used to find IBI
volatile int P = 512; // used to find peak in pulse wave, seeded
volatile int T = 512; // used to find trough in pulse wave, seeded
volatile int thresh = 525; // used to find instant moment of heart beat,
seeded
volatile int amp = 100; // used to hold amplitude of pulse waveform,
seeded
volatile boolean firstBeat = true; // used to seed rate array so we startup with
reasonable BPM
volatile boolean secondBeat = false; // used to seed rate array so we startup
with reasonable BPM
void setup() {
// put your setup code here, to run once:
//MLX90614
57
mlx.begin();
//Loadcell
scale.begin(DT,CK);
scale.set_scale();
scale.tare(); //Reset the scale to 0
long zero_factor = scale.read_average(); //Get a baseline reading
//LedMatrix
setupMatrixDisp();
Timer1.initialize(2000); // khởi tạo timer 1 2ms
Timer1.attachInterrupt(DispScan); // khai báo ngắt timer 1
dispClrAll(0);
//PS
pinMode(blinkPin,OUTPUT); // pin that will blink to your heartbeat!
interruptSetup();
}
void loop() {
// put your main code here, to run repeatedly:
//SFR04
DistanceCm = Sensor1.measureDistanceCm();
KhoangCach = (200-DistanceCm);
if (KhoangCach < 0)
{
KhoangCach = oldDis;
}
oldDis = KhoangCach;
String str =String(KhoangCach) + "CM";
char buf[100];
str.toCharArray(buf,100);
Serial.println(str);
//Loadcell
scale.set_scale(calibration_factor);//Adjust to this calibration factor
58
LBS=scale.get_units();
KG=LBS*n;
String str1 =String((KG)) + "KG";
char buf1[100];
str1.toCharArray(buf1,100);
Serial.println(str1);
//MLX90614
String str2 =String(mlx.readObjectTempC()) + "C";
char buf2[100];
str2.toCharArray(buf2,100);
Serial.println(str2);
//BPM
serialOutput();
if (QS == true) // A Heartbeat Was Found
{
serialOutputWhenBeatHappens(); // A Beat Happened, Output that to serial.
QS = false; // reset the Quantified Self flag for next time
}
dispClrAll(0);
writeVietStr("CAO:",green,1,0);
writeVietStr(buf,green,0,8);
delay(1000);
dispClrAll(0);
writeVietStr("NANG:",blue,1,0);
writeVietStr(buf1,blue,0,8);
delay(1000);
dispClrAll(0);
writeVietStr("TEMP:",purple,1,0);
writeVietStr(buf2,purple,0,8);
delay(1000);
59
void interruptSetup()
{
// Initializes Timer2 to throw an interrupt every 2mS.
TCCR2A = 0x02; // disable PWM on digital pins 3 and 11, and go into ctc mode
TCCR2B = 0x06; // don't force compare, 256 prescaler
OCR2A = 0X7C; // set the top of the count to 124 for 500hz sample rate
TIMSK2 = 0x02; // enable interrupt on match between timer2 and ocr2a
sei(); // make sure global interrupts are enabled
}
void serialOutput()
{ // Decide How To Output Serial.
if (serialVisual == true)
{
arduinoSerialMonitorVisual('-', Signal); // goes to function that makes Serial
Monitor Visualizer
}
else
{
sendDataToSerial('S', Signal); // goes to sendDataToSerial function
}
}
void serialOutputWhenBeatHappens()
{
if (serialVisual == true) // Code to Make the Serial Monitor Visualizer Work
{
String str3 = String(BPM);
char buf3[100];
str3.toCharArray(buf3,100);
dispClrAll(0);
writeVietStr("BPM:",cyan,1,0);
writeVietStr(buf3,cyan,0,8);
60
delay(1000);
Serial.println(str3);
}
else
{
sendDataToSerial('B',BPM); // send heart rate with a 'B' prefix
sendDataToSerial('Q',IBI); // send time between beats with a 'Q' prefix
}
}
void arduinoSerialMonitorVisual(char symbol, int data )
{
const int sensorMin = 0; // sensor minimum, discovered through experiment
const int sensorMax = 1024; // sensor maximum, discovered through
experiment
int sensorReading = data; // map the sensor range to a range of 12 options:
int range = map(sensorReading, sensorMin, sensorMax, 0, 11);
// do something different depending on the
// range value:
}
void sendDataToSerial(char symbol, int data )
{
Serial.print(symbol);
Serial.println(data);
}
ISR(TIMER2_COMPA_vect) //triggered when Timer2 counts to 124
{
cli(); // disable interrupts while we do this
Signal = analogRead(pulsePin); // read the Pulse Sensor
sampleCounter += 2; // keep track of the time in mS with this
variable
61
int N = sampleCounter - lastBeatTime; // monitor the time since the last beat
to avoid noise
// find the peak and trough of the pulse wave
if(Signal < thresh && N > (IBI/5)*3) // avoid dichrotic noise by waiting 3/5 of
last IBI
{
if (Signal < T) // T is the trough
{
T = Signal; // keep track of lowest point in pulse wave
}
}
if(Signal > thresh && Signal > P)
{ // thresh condition helps avoid noise
P = Signal; // P is the peak
} // keep track of highest point in pulse wave
// NOW IT'S TIME TO LOOK FOR THE HEART BEAT
// signal surges up in value every time there is a pulse
if (N > 250)
{ // avoid high frequency noise
if ( (Signal > thresh) && (Pulse == false) && (N > (IBI/5)*3) )
{
Pulse = true; // set the Pulse flag when we think there is a
pulse
digitalWrite(blinkPin,HIGH); // turn on pin 13 LED
IBI = sampleCounter - lastBeatTime; // measure time between beats in
mS
lastBeatTime = sampleCounter; // keep track of time for next pulse
if(secondBeat)
{ // if this is the second beat, if secondBeat == TRUE
secondBeat = false; // clear secondBeat flag
62
for(int i=0; i<=9; i++) // seed the running total to get a realisitic BPM at
startup
{
rate[i] = IBI;
}
}
if(firstBeat) // if it's the first time we found a beat, if firstBeat == TRUE
{
firstBeat = false; // clear firstBeat flag
secondBeat = true; // set the second beat flag
sei(); // enable interrupts again
return; // IBI value is unreliable so discard it
}
// keep a running total of the last 10 IBI values
word runningTotal = 0; // clear the runningTotal variable
for(int i=0; i<=8; i++)
{ // shift data in the rate array
rate[i] = rate[i+1]; // and drop the oldest IBI value
runningTotal += rate[i]; // add up the 9 oldest IBI values
}
rate[9] = IBI; // add the latest IBI to the rate array
runningTotal += rate[9]; // add the latest IBI to runningTotal
runningTotal /= 10; // average the last 10 IBI values
BPM = 60000/runningTotal; // how many beats can fit into a minute?
that's BPM!
QS = true; // set Quantified Self flag
// QS FLAG IS NOT CLEARED INSIDE THIS ISR
}
}
if (Signal < thresh && Pulse == true)
{ // when the values are going down, the beat is over
63
digitalWrite(blinkPin,LOW); // turn off pin 13 LED
Pulse = false; // reset the Pulse flag so we can do it again
amp = P - T; // get amplitude of the pulse wave
thresh = amp/2 + T; // set thresh at 50% of the amplitude
P = thresh; // reset these for next time
T = thresh;
}
if (N > 2500)
{ // if 2.5 seconds go by without a beat
thresh = 512; // set thresh default
P = 512; // set P default
T = 512; // set T default
lastBeatTime = sampleCounter; // bring the lastBeatTime up to date
firstBeat = true; // set these to avoid noise
secondBeat = false; // when we get the heartbeat back
}
sei(); // enable interrupts when youre done!
}
64