“Lối xưa xe ngựa hồn thu thảo
Hồn cũ, lâu đài bóng tịch dương”
– Bà Huyện Thanh Quan –
Chúng ta đã làm gì? Đã làm như thế nào? Tìm ra câu giải đáp: “Có thể làm tốt hơn không?”
Phần trên, tôi đưa ra khái niệm computer đơn giản và cho là phần cứng có MCU chính là một computer đơn giản được sự thỏa hiệp của người dùng. Ta có thể dùng một khái niệm ‘sang trọng’ hơn để nói về nó: “Embedded computer”.
Theo định nghĩa: embedded computer là thiết bị gồm có vi điều khiển, firmware (thường là EPROM), và/hoặc FPGA, FPLD nhằm thực hiện một chức năng chuyên biệt nào đó. Nó là một thiết bị không thể tách rời khỏi hệ thống, khác hẳn với các thiết bị được điều khiển bởi một máy tính chủ.
Nói một cách đơn giản, hệ thống nhúng là hệ thống có thể tự vận hành chức năng chuyên biệt nào đấy nhờ ít nhất một đơn vị có thể điều khiển độc lập! Khái niệm này khác hẳn với PC, được chế tạo với mục đích đa dạng của người dùng.
Trong các ứng dụng hiện nay ở nước ta, ít khi thấy khái niệm hệ thống nhúng xuất hiện một cách ngạo nghễ (trong cuộc thi Trí tuệ Việt Nam năm nay, cụm từ này xuất hiện ở phần mềm Hệ thống thông tin bác sĩ), một phần vì ta thường dùng PC để điều khiển, phần khác, các hệ thống ta thiết kế chưa đến mức độ tích hợp và chuyên dụng cần thiết, vả lại, tâm lý sợ dùng từ lạ cũng gây khó khăn với người dùng!
Phần dưới đây, ta xét quy trình phát triển phần mềm (firmware) một hệ thống nhúng, hay đơn giản hơn chỉ là quy trình để tạo chương trình hoạt động cho CPU-MCU. Và cũng trong giới hạn phân tích cho một MCU. Khi có dịp, ta sẽ nói về cách làm việc với chương trình gồm nhiều vi điều khiển. Tuy nhiên, theo tôi nghĩ, cách làm việc khi ta mở rộng ra hệ thống lớn sẽ đi từ nền cơ bản với một CPU.
Quy trình phát triển firmware gồm các bước sau:
-
Soạn thảo chương trình
-
Dịch code
-
Kiểm tra lỗi
-
Đổ chương trình điều khiển cho CPU
-
Kiểm tra thực tế
1) Soạn thảo chương trình (viết code)
Thông thường, ta viết code cho MCU bằng hợp ngữ (Assembler) hoặc một ngôn ngữ cấp cao như C (hoặc C++, Java, Visual Basic…). Mã nguồn được viết bằng hợp ngữ thì cấu trúc lệnh sẽ chuẩn tắc và thực thi nhanh hơn khi viết bằng C (vì khi viết bằng C thì kích thước chương trình thường sẽ lớn hơn 20%-40% do cần phải có thêm một chương trình biên dịch – compiler – trung gian).
Tuy nhiên, nếu phát triển chương trình bằng hợp ngữ thì các giá lệnh hợp ngữ có thể thay đổi tùy theo họ điều khiển, khi thực thi các cấu trúc chương trình phức tạp gây khó khăn rất nhiều cho người lập trình: để viết ASM tốt, người lập trình phải có suy nghĩ ở cấp ngôn ngữ máy, nó rất khó thân thiện với chúng ta – người bình thường vốn thích nghe chim hót buổi sáng, ngắm ánh mặt trời mọc, nghe lời thánh thót bên tai…!
Tuy nhiên, thực tế, đa phần hiện nay dân lập trình thường sử dụng hợp ngữ, vì trường đại học chỉ dạy Assembler để lập trình cho họ MCU 8051. Điều ấy có hạn chế rất nhiều khi ta khai thác các chức năng phức tạp, cao cấp của vi điều khiển.
Những phong trào phát động gần đây của các nhóm phát triển vi điều khiển đã mang lại một sắc thái mới, người ta bắt đầu chuộng cách viết bằng C, VB, vì tính linh hoạt, rõ ràng, có kế thừa của nó. Những mong một ngày gần đây, trường đại học đi kèm với việc giảng dạy Assembler sẽ chú ý tới Compiler – chiếc cầu bắt nhịp những nhịp vui!
Điều đáng lo ngại là thói quen lập trình
Ta đặt cho mình một nhiệm vụ nào đó rồi ngồi ngay vào máy viết chương trình mà thường bỏ qua giai đoạn vẽ sơ đồ giải thuật và ghi các chú thích cần thiết. Bạn chưa thấy những bất tiện nếu chỉ làm với những chương trình nhỏ! Tuy nhiên, khi làm việc với những chương trình lớn, lên tới vài trăm, vài ngàn dòng lệnh, khi cần tìm lỗi, bạn sẽ không biết nên bắt đầu từ đâu!
Hay vài tuần, vài tháng sau, đọc lại chương trình, bạn chẳng biết mình viết gì, và “thà rằng viết lại một chương trình mới”! Hoặc đơn giản hơn, khi đang viết chương trình bạn lại thấy chỗ này cần sửa, chỗ khác cần bổ sung cho đúng hơn, nhanh hơn… chẳng hạn, nếu không có sơ đồ giải thuật ngay từ đầu, bạn phải khổ sở truy tìm nơi đặt các dòng lệnh cần bổ sung, chỉnh sửa.
Như vậy là, vô hình chung, ta đã đi từ tiểu tiết lên, điều này có lẽ cũng chẳng sao nếu bạn có óc tổ chức sẵn trong đầu, và bộ nhớ cực tốt! Còn tôi, do số neural tích cực cho công việc này là có giới hạn nên thật khó khăn khi cố gắng chứng tỏ 🙂
Một câu chuyện tôi cho là thích hợp để nói về vấn đề đang đề cập, được lấy từ phim: “390 yêu – độ yêu”:
Khung cảnh lớp học đang trong giờ Tâm lý, đồ dùng dạy học trên bàn là những lọ và các vật liệu: cát, đá, sỏi… Thầy bỏ các viên đá cuội đầy vào một cái lọ thủy tinh lớn trên bàn và hỏi cả lớp:
-
“Các anh chị thấy đầy chưa?”
-
“Dạ rồi!” – Cả lớp đáp.
Thầy lại bỏ các viên sỏi vào đến khi không thể bỏ thêm và lại hỏi cả lớp:
-
“Các anh chị thấy đầy chưa?”
-
“Dạ rồi!” – Cả lớp đồng thanh. Tiếng lao xao bàn tán.
Thầy không nói gì, tiếp tục bỏ cát vào đến khi không thể bỏ được nữa, và lại hỏi cả lớp:
-
“Đầy chưa?”
-
“Dạ rồi!” – Cả lớp lại ngoan ngoãn đáp.
Thầy mỉm cười đầy ẩn ý, sau đó lại lấy ca nước đổ vào lọ thủy tinh, nước tràn, thầy rút ra kết luận:
“Các anh chị thấy đấy, nếu ta làm ngược lại, thì không thể nào bỏ được các viên sỏi, đá vào bình, phải không nào?
Những viên đá, sỏi tượng trưng cho những kế hoạch lớn, những dự định quan trọng trong cuộc đời ta – ta phải luôn ưu tiên cho nó!
Cát, nước – tô điểm thêm cho cuộc sống sinh động, muôn màu tươi đẹp của chúng ta. Nếu ưu tiên cho những điều này thì cuộc sống chúng ta không làm được nhiều điều ý nghĩa cho mình – cho người xung quanh – cho xã hội.”
-
“Các anh chị thấy đầy chưa?”
-
“Dạ rồi!” – Cả lớp đáp.
Thầy lại bỏ các viên sỏi vào đến khi không thể bỏ thêm, và lại hỏi cả lớp:
-
“Các anh chị thấy đầy chưa?”
-
“Dạ rồi!” – Cả lớp đồng thanh. Tiếng lao xao bàn tán.
Thầy không nói gì, tiếp tục bỏ cát vào đến khi không thể bỏ được nữa, và lại hỏi cả lớp:
-
“Đầy chưa?”
-
“Dạ rồi!” – Cả lớp lại ngoan ngoãn đáp.
Thầy mỉm cười đầy ẩn ý, sau đó lại lấy ca nước đổ vào lọ thủy tinh, nước tràn ra, thầy rút ra kết luận:
“Các anh chị thấy đấy, nếu ta làm ngược lại thì không thể nào bỏ được các viên sỏi, đá vào bình, phải không nào?” – Thầy hỏi cả lớp – “Những viên đá, sỏi tượng trưng cho những kế hoạch lớn, những dự định quan trọng trong cuộc đời ta – ta phải luôn ưu tiên cho nó! Cát, nước – là những phần tô điểm cho cuộc sống sinh động, muôn màu tươi đẹp của chúng ta. Nếu ưu tiên cho những điều này trước, thì cuộc sống chúng ta không thể làm được nhiều điều ý nghĩa – cho mình, cho người xung quanh, cho xã hội.”
Trở lại với vấn đề đang đề cập:
Nếu ta có thói quen tổ chức tốt, có thói quen viết dàn bài trước khi viết code, thì hẳn bài văn của ta sẽ rõ nghĩa và không rơi vào tình trạng viết lan man, dàn trải!
(Tôi không có ý nói kiềm hãm sự sáng tạo bất chợt trong khi đang viết – những nguyên tắc bất biến và những khuôn mẫu cứng nhắc hủy diệt cả thiên tài và nghệ thuật – W. Hazlitt.)
Như vậy, việc viết code chương trình cũng cần phải có những quy tắc khung để dễ dàng quản lý! Theo những gì được thấy, tôi cho rằng cách giải quyết vấn đề theo hướng diễn dịch (top-down design) có lẽ thích hợp cho chúng ta hơn trong những ứng dụng trước mắt.
Còn bottom-up design thích hợp cho những chương trình cần nhiều sự sáng tạo, và người tổ chức, quản lý phải có óc khái quát hóa cao độ.
2) Dịch code sang mã máy
Các chỉ lệnh vi điều khiển là các mã máy dưới dạng chuỗi ‘0’, ‘1’. Tức là, để vi điều khiển có thể thực thi lệnh, ta phải chuyển đổi từ ngôn ngữ mà con người có thể đọc được sang mã máy.
Hiện nay, để viết những chương trình lớn, ta viết sẵn nhiều hàm con, tạo các thư viện, các liên kết để rút ngắn khoảng thời gian thiết kế một hệ thống mới, thỏa mãn các yêu cầu về thời gian, độ linh hoạt,… Nghĩa là, bằng các khai báo include
, define
,… ta có thể lấy thư viện các hàm sẵn có để đưa chúng vào chương trình đang thực hiện!
Một số công cụ biên dịch hex file nạp cho vi điều khiển:
Có 2 tool thường dùng: a51 và c51.
-
a51 phục vụ cho người viết chương trình bằng hợp ngữ.
-
c51 phục vụ cho người viết chương trình bằng ngôn ngữ C.
Các tool này có trong hầu hết các chương trình phần mềm phục vụ soạn thảo, biên dịch MCU:
-
ASM51: viết ASM bằng một trình soạn thảo như Notepad, sau đó dùng ASM51 dịch sang mã máy. Hoạt động trong môi trường DOS, hiện nay vẫn còn sử dụng ở phòng thí nghiệm bộ môn Điện tử – ĐHBK TP HCM.
-
WIN8051IDE: hoạt động trong môi trường Windows, có chức năng mô phỏng tương đối tốt.
-
AVR Edit: phục vụ cho họ AVR của Atmel.
-
Batronix: tích hợp C và ASM.
-
MPLAB/CCSC: cho PIC, tích hợp C và ASM.
-
Keil uV3: một phần mềm chuyên dụng cho các họ vi điều khiển 8/16/32 bit (ngoại trừ PIC). Theo đánh giá của tôi, đây là phần mềm tốt nhất cho đến thời điểm này – hội tụ được nhiều ưu điểm và thân thiện với người sử dụng. Có thể kết hợp viết inline, ANSI C hoặc chỉ ASM. Đặc biệt có chương trình chạy mô phỏng rất tốt và được hướng dẫn chi tiết, luôn được cập nhật.
Ngoài ra có thể kể đến PonyProg, Signum… nhưng không được nhiều người sử dụng, có thể do chưa quen.
2) Dịch code sang mã máy.
Các chỉ lệnh vi điều khiển là các mã máy dưới dạng chuỗi ‘0’, ‘1’. Tức là, để vi điều khiển có thể thực thi lệnh, ta phải chuyển đổi từ ngôn ngữ mà con người có thể đọc được sang mã máy.
Hiện nay, để viết những chương trình lớn, ta viết sẵn nhiều hàm con, tạo các thư viện, các liên kết để rút ngắn khoảng thời gian thiết kế một hệ thống mới, thỏa mãn các yêu cầu về thời gian, độ linh hoạt, … Nghĩa là, bằng các khai báo include
, define
,… ta có thể lấy thư viện các hàm sẵn có để đưa chúng vào chương trình đang thực hiện!
Nhân tiện, ta cũng thử xem qua các phần mềm chuyên dụng để biên dịch hex file nạp cho vi điều khiển.
Có 2 tool thường dùng: a51 và c51.
-
Tool a51 phục vụ cho người viết chương trình bằng hợp ngữ,
-
Tool c51 phục vụ cho người viết chương trình bằng ngôn ngữ C.
Các tool này có trong hầu hết các chương trình phần mềm phục vụ soạn thảo, biên dịch MCU.
Một số phần mềm thường dùng:
-
ASM51: Viết ASM bằng một trình soạn thảo như Notepad, sau đó dùng ASM51 dịch sang mã máy, hoạt động trong môi trường DOS. Hiện nay vẫn còn sử dụng ở phòng thí nghiệm Bộ môn Điện tử – ĐHBK TP. HCM.
-
WIN8051IDE: Hoạt động trong môi trường Windows, có chức năng mô phỏng tương đối tốt.
-
AVR Edit: Phục vụ cho họ AVR của Atmel.
-
Batronix: Tích hợp C và ASM.
-
MPLAB/CCSC: Dành cho PIC, tích hợp C và ASM.
-
Keil uV3: Một phần mềm chuyên dụng cho các họ vi điều khiển 8/16/32 bit (ngoại trừ PIC). Theo đánh giá của tôi, đây là phần mềm tốt nhất cho đến thời điểm này, hội tụ được nhiều ưu điểm và thân thiện với người sử dụng. Có thể kết hợp viết
inline
,Ansi C
hoặc chỉASM
.
Điều quan trọng là có chương trình chạy mô phỏng rất tốt và phần mềm được hướng dẫn chi tiết, luôn được cập nhật.
Ngoài ra, có thể kể đến PonyProg, Signum,… nhưng không được nhiều người sử dụng – có thể do chưa quen.
3) Kiểm tra lỗi, phát hiện lỗi nhờ các công cụ Debug:
Nếu bạn chỉ sử dụng các công cụ để biên dịch (như a51, c51…) mà không nhờ vào một chương trình Debug chuyên dụng, thì cũng thật khó khăn để kiểm tra và chỉnh sửa các lỗi. Theo tôi nhận thấy, sử dụng một chương trình chuyên nghiệp như Keil uV3, bạn sẽ rất thuận tiện để viết code và kiểm tra/chỉnh sửa lỗi, cả bằng ASM và C!
Phần mềm này còn cung cấp cho ta công cụ chạy mô phỏng rất tốt. Bạn sẽ dễ dàng kiểm tra việc thực thi từng dòng, từng đoạn lệnh và xem sự thay đổi ở các cổng (port) xuất/nhập, các chân (pin) chức năng chuyên dụng như counter, timer, ngắt ảo, v.v.
Kể ra thì cũng có 2 trường phái:
-
Một bên chỉ thích chạy thẳng chương trình trên ứng dụng để kiểm tra các lỗi chương trình (sau khi đúng tất cả cú pháp lệnh).
-
Một bên cẩn thận hơn, chạy mô phỏng trước khi đổ chương trình.
Theo tôi nghĩ, tiện ích các nhà sản xuất phần mềm phải đau đầu nghĩ ra, ta không sử dụng cũng uổng phí! Nó tỏ ra rất tiện ích khi ta dùng cách này kiểm tra phân đoạn những chương trình lớn.
4) Đổ chương trình điều khiển cho CPU vào ROM/FLASH:
Hiện nay, các nhà sản xuất đều sử dụng bộ nhớ Flash để tiện trong việc lập trình ISP/IAP.
ISP tỏ ra công hiệu đối với những người sử dụng MCU như chúng ta trong giai đoạn các ứng dụng đơn lẻ. Chỉ cần 5 chân:Vcc
, Vdd
, RST
, TxD
, RxD
.
Và tốt nhất, trên mạch ứng dụng, ta nên thiết kế để sao cho 5 chân này có thể sử dụng cho mục đích IAP.
5) Kiểm tra lại việc thực thi các yêu cầu đề ra có đúng như dự định hay không?
Với mạch thử nghiệm, ta có thể kiểm tra việc này bằng nhiều cách:
-
Giao tiếp với PC
-
Hiển thị kết quả bằng một dấu hiệu định trước
Giai đoạn này cũng rất quan trọng khi muốn sản phẩm mình tạo ra có sự chính xác, ổn định…
Chúng ta đã xem qua 5 bước cơ bản để hoàn thành một chương trình cho vi điều khiển.
Bạn làm tốt hơn tôi, điều ấy rất đáng mừng. Bạn trách tôi:
“Thằng cha này nói xàm”,
…cũng chẳng sao, vì tôi cũng chỉ là người chập chững vào địa hạt này, những thú vị, hoài nghi và bất trắc!
Chút mạo hiểm hay vẫn hoài cổ nhìn lại quá khứ đã qua mà buông lời thở dài?
Hy vọng phần này đem đến cho bạn một cách nhìn khác về cách lập trình, nếu lâu nay bạn chưa có điều kiện sử dụng những công cụ hỗ trợ tích cực cho công việc của chúng ta!
[1] Xin lỗi tác giả kịch bản vì tôi không nhớ hết lời thoại, tuy nhiên, tôi nghĩ là ý định của kịch bản được ghi lại không sai sót, và tôi xin phỏng lại ý của tác giả.
Các bài viết liên quan:
-
Bài 1: “Điểm mặt anh tài”
-
Bài 2: “Tính năng của từng dòng sản phẩm”
-
Bài 3: “Chúng ta cần gì ở các MCU?”
-
Bài 4: “Chúng ta đã làm gì với các MCU?”
-
Bài 5: “Nhìn lại quanh ta – Nhìn ra thế giới”