You are on page 1of 52

Chương 1.

Hệ thống nhúng và phần mềm nhúng


1. Hệ thống nhúng
Hệ thống nhúng (Embedded system) là một thuật ngữ để chỉ một hệ thống có khả
năng tự trị được nhúng vào trong một môi trường hay một hệ thống mẹ. Đó là các hệ
thống tích hợp cả phần cứng và phần phềm phục vụ các bài toán chuyên dụng trong nhiều
lĩnh vực công nghiệp, tự động hoá điều khiển, quan trắc và truyền tin. Đặc điểm của các
hệ thống nhúng là hoạt động ổn định và có tính năng tự động hoá cao.[5]
Hệ thống nhúng thường được thiết kế để thực hiện một chức năng chuyên dụng,
thường nó có khả năng tự hành và được thiết kế tích hợp vào một hệ thống lớn hơn để
thực hiện một chức năng chuyên biệt nào đó. Khác với các máy tính đa chức năng, chẳng
hạn như máy tính cá nhân, một hệ thống nhúng chỉ thực hiện một hoặc một vài chức năng
nhất định, thường đi kèm với những yêu cầu cụ thể và bao gồm một số thiết bị máy móc
và phần cứng chuyên dụng mà ta không tìm thấy trong một máy tính đa năng nói chung
[5].
Vì hệ thống chỉ được xây dựng cho một số nhiệm vụ nhất định nên các nhà thiết kế
có thể tối ưu hóa nó nhằm giảm thiểu kích thước và chi phí sản xuất. Các hệ thống nhúng
thường được sản xuất hàng loạt với số lượng lớn. Hệ thống nhúng rất đa dạng, phong phú
về chủng loại. Đó có thể là những thiết bị cầm tay nhỏ gọn như đồng hồ kĩ thuật số và
máy chơi nhạc MP3, hoặc những sản phẩm lớn như đèn giao thông, bộ kiểm soát trong
nhà máy hoặc hệ thống kiểm soát các máy năng lượng hạt nhân. Xét về độ phức tạp, hệ
thống nhúng có thể rất đơn giản với một vi điều khiển hoặc rất phức tạp với nhiều đơn vị,
các thiết bị ngoại vi và mạng lưới được nằm gọn trong một lớp vỏ máy lớn. Các thiết bị
PDA hoặc máy tính cầm tay cũng có một số đặc điểm tương tự với hệ thống nhúng như
các hệ điều hành hoặc vi xử lý điều khiển chúng nhưng các thiết bị này không phải là hệ
thống nhúng thật sự bởi chúng là các thiết bị đa năng, cho phép sử dụng nhiều ứng dụng
và kết nối đến nhiều thiết bị ngoại vi [13].
Hệ thống nhúng bao gồm cả thiết bị phần cứng và phần mềm, hầu hết đều phải thỏa
mãn yêu cầu hoạt động theo thời gian thực (real-time). Tùy theo tính chất và yêu cầu,
mức độ đáp ứng của hệ thống có thể phải là rất nhanh (ví dụ như hệ thống thắng trong xe

1
hơi hoặc điều khiển thiết bị trong nhà máy), hoặc có thể chấp nhận một mức độ chậm trễ
tương đối (ví dụ như điện thoại di động, máy lạnh, ti-vi) [13].
Để có thể dễ hình dung, ta xem ví dụ sau đây: một chiếc xe hơi trung bình có
khoảng 70-80 chip vi xử lý (micro controller unit), mỗi bộ vi xử lý đảm nhiệm một nhiệm
vụ, chẳng hạn như đóng mở cửa, điều khiển đèn tín hiệu, đo nhiệt độ trong/ngoài xe, hiển
thị giao diện người dùng , điều khiển thắng (nếu dùng hệ thống thắng điện)…
Mỗi bộ phận như thế là một hệ thống nhúng, tất cả được thiết kế tích hợp vào một hệ
thống chung lớn hơn, chính là chiếc xe hơi. Một ví dụ khác gần gũi hơn với cuộc sống
hằng ngày, đó là những chiếc điện thoại di động. Các chức năng như điều khiển màn hình
hiển thị, máy nghe nhạc và radio, bộ cảm ứng chụp hình, kết nối với máy tính và thiết bị
ngoại vi, hoặc cao cấp hơn là kết nối với hệ thống định vị toàn cầu (GPS), tất cả đều là
những hệ thống nhúng được tích hợp chung vào chiếc điện thoại.
Các hệ thống nhúng có thể không có giao diện (đối với những hệ thống đơn nhiệm)
hoặc có đầy đủ giao diện giao tiếp với người dùng tương tự như các hệ điều hành trong
các thiết bị để bàn. Đối với các hệ thống đơn giản, thiết bị nhúng sử dụng nút bấm, đèn
LED và hiển thị chữ cỡ nhỏ hoặc chỉ hiển thị số, thường đi kèm với một hệ thống menu
đơn giản.
Còn trong một hệ thống phức tạp hơn, một màn hình đồ họa, cảm ứng hoặc có các
nút bấm ở lề màn hình cho phép thực hiện các thao tác phức tạp mà tối thiểu hóa được
khoảng không gian cần sử dụng; ý nghĩa của các nút bấm có thể thay đổi theo màn hình
và các lựa chọn. Các hệ thống nhúng thường có một màn hình với một nút bấm dạng cần
điểu khiển (joystick button). Sự phát triển mạnh mẽ của mạng toàn cầu đã mang đến cho
những nhà thiết kế hệ nhúng một lựa chọn mới là sử dụng một giao diện web thông qua
việc kết nối mạng. Điều này có thể giúp tránh được chi phí cho những màn hình phức tạp
nhưng đồng thời vẫn cung cấp khả năng hiển thị và nhập liệu phức tạp khi cần đến, thông
qua một máy tính khác. Điều này là hết sức hữu dụng đối với các thiết bị điều khiển từ xa,
cài đặt vĩnh viễn. Ví dụ, các router là các thiết bị đã ứng dụng tiện ích này.
Độ tin cậy của hệ thống nhúng
Các hệ thống nhúng thường nằm trong các cỗ máy được kỳ vọng là sẽ chạy hàng
năm trời liên tục mà không bị lỗi hoặc có thể khôi phục hệ thống khi gặp lỗi. Vì thế, các

2
phần mềm hệ thống nhúng được phát triển và kiểm thử một cách cẩn thận hơn là phần
mềm cho máy tính cá nhân.
Ngoài ra, các thiết bị rời không đáng tin cậy như ổ đĩa, công tắc hoặc nút bấm
thường bị hạn chế sử dụng. Việc khôi phục hệ thống khi gặp lỗi có thể được thực hiện
bằng cách sử dụng các kỹ thuật như watchdog timer – nếu phần mềm không đều đặn nhận
được các tín hiệu watchdog định kì thì hệ thống sẽ bị khởi động lại [5].
Một số vấn đề cụ thể về độ tin cậy như:
- Hệ thống không thể ngừng để sửa chữa một cách an toàn, ví dụ như ở các hệ thống
không gian, hệ thống dây cáp dưới đáy biển, các đèn hiệu dẫn đường,… Giải pháp đưa ra
là chuyển sang sử dụng các hệ thống con dự trữ hoặc các phần mềm cung cấp một phần
chức năng.
- Hệ thống phải được chạy liên tục vì tính an toàn, ví dụ như các thiết bị dẫn đường
máy bay, thiết bị kiểm soát độ an toàn trong các nhà máy hóa chất,… Giải pháp đưa ra là
lựa chọn backup hệ thống.
- Nếu hệ thống ngừng hoạt động sẽ gây tổn thất rất nhiều tiền của ví dụ như các
dịch vụ buôn bán tự động, hệ thống chuyển tiền, hệ thống kiểm soát trong các nhà máy
…[5]

2. Phần mềm nhúng


Là phần mềm trong các hệ thống nhúng. Phần mềm nhúng có thể là những chương
trình đơn giản chạy trực tiếp trên nền phần cứng hoặc là những chương trình, ứng dụng
chạy trên nền một hệ điều hành nhúng. Phần mềm nhúng thường chạy với số tài nguyên
phần cứng hạn chế: không có bàn phím, màn hình hoặc có nhưng với kích thước nhỏ, bộ
nhớ hạn chế.[5]
Phần mềm nhúng thường được lập trình trên máy tính cá nhân của lập trình viên,
được biên dịch với một trình biên dịch và một môi trường phát triển, máy tính dùng để lập
trình được gọi là host. Sau đó chương trình được nạp lên thiết bị và chạy, thiết bị mà
chương trình được nạp lên gọi la target.Với mỗi target khác nhau sẽ có cấu trúc vi điểu
khiển khác nhau, và sử dụng hệ điều hành nhúng khác nhau, do vậy tùy từng loại sẽ có
các cách thức lập trình tương ứng .

3
C là một trong những ngôn ngữ lập trình nhúng phổ biến nhất hiện nay. C có một số
ưu điểm nổi bật tiêu biểu như khá nhỏ và dễ dàng cho việc học, các chương trình biên
dịch C thường khá sẵn cho hầu hết các bộ xử lý đang sử dụng hiện nay, và có rất nhiều
người đã biết và làm chủ được ngôn ngữ này.

4
Chương 2. Kiểm thử phần mềm và kiểm thử phần mềm
nhúng
1 Kiểm thử phần mềm
+ Kiểm thử phần mềm là gì?
Kiểm thử phần mềm là hoạt động khảo sát sản phần mềm nhằm cung cấp cho người
có lợi ích liên quan đến phần mềm những thông tin về chất lượng của sản phẩm phần
mềm ấy. Mục đích của kiểm thử phần mềm là tìm ra các lỗi hay khiếm khuyết phần mềm
nhằm đảm bảo hiệu quả hoạt động tối ưu của phần mềm trong nhiều lĩnh vực khác
nhau.[6]
Theo nghĩa thông thường nhất, kiểm thử phần mềm bao gồm việc chạy thử phần
mềm hay một chức năng của phần mềm, xem nó chạy đúng như mong muốn hay không.
Việc kiểm thử này có thể thực hiện từng chặng, sau khi mỗi chức năng hoặc mô đun được
phát triển, hoặc thực hiện sau cùng, khi phần mềm đã được phát triển hoàn tất.
Các mức kiểm thử phần mềm thông thường là [6] :
- Unit Test – Kiểm thử mức đơn vị
- Integration Test – Kiểm thử tích hợp
- System Test - Kiểm thử mức hệ thống
- Acceptance Test - Kiểm thử chấp nhận sản phẩm
- Regression Test - Kiểm thử hồi quy

+ Kiểm thử đơn vị (unit test):

Một Unit là một thành phần phần mềm nhỏ nhất mà ta có thể kiểm thử được. Theo
định nghĩa này, các hàm (Function), thủ tục (Procedure), lớp (Class), hoặc các phương
thức (Method) đều có thể được xem là Unit.
Vì Unit được chọn để kiểm thử thường có kích thước nhỏ và chức năng hoạt động
đơn giản, chúng ta không khó khăn gì trong việc tổ chức, kiểm thử, ghi nhận và phân tích
kết quả kiểm thử. Nếu phát hiện lỗi, việc xác định nguyên nhân và khắc phục cũng tương
đối dễ dàng vì chỉ khoanh vùng trong một Unit đang kiểm thử. Một nguyên lý đúc kết từ

5
thực tiễn: thời gian tốn cho Unit Test sẽ được đền bù bằng việc tiết kiệm rất nhiều thời
gian và chi phí cho việc kiểm thử và sửa lỗi ở các mức kiểm thử sau đó.
Unit Test thường do lập trình viên thực hiện. Công đoạn này cần được thực hiện
càng sớm càng tốt trong giai đoạn viết code và xuyên suốt chu kỳ phát triển phần mềm.
Thông thường, Unit Test đòi hỏi kiểm thử viên (tester)có kiến thức về thiết kế và code
của chương trình. Mục đích của Unit Test là bảo đảm thông tin được xử lý và xuất ra
(khỏi Unit) là chính xác, trong mối tương quan với dữ liệu nhập và chức năng của Unit.
Điều này thường đòi hỏi tất cả các nhánh bên trong Unit đều phải được kiểm tra để phát
hiện nhánh phát sinh lỗi. Một nhánh thường là một chuỗi các lệnh được thực thi trong một
Unit, ví dụ: chuỗi các lệnh sau điều kiện If và nằm giữa then … else là một nhánh. Thực
tế việc chọn lựa các nhánh để đơn giản hóa việc kiểm thử và quét hết Unit đòi hỏi phải có
kỹ thuật, đôi khi phải dùng thuật toán để chọn lựa.
Cũng như các mức kiểm thử khác, Unit Test cũng đòi hỏi phải chuẩn bị trước các
tình huống (test case) hoặc kịch bản (script), trong đó chỉ định rõ dữ liệu vào, các bước
thực hiện và dữ liệu mong chờ sẽ xuất ra. Các test case và kịch bản này nên được giữ lại
để tái sử dụng.
Unit Test thường sử dụng các Unit Test Framework, đó là các khung chương trình
được viết sẵn để hộ trợ cho việc test các mô đun, các đơn vị phần mềm.
+ Integration Test – Kiểm thử tích hợp
Kiểm thử tích hợp kết hợp các thành phần của một ứng dụng và kiểm thử như một
ứng dụng đã hoàn thành. Trong khi Unit Test kiểm thử các thành phần và đơn vị phần
mềm riêng lẻ thì kiểm thử tích hợp kết hợp chúng lại với nhau và kiểm thử sự giao tiếp
giữa chúng.
Kiểm thử tích hợp có 2 mục tiêu chính:
- Phát hiện lỗi giao tiếp xảy ra giữa các Unit.
- Tích hợp các Unit đơn lẻ thành các hệ thống nhỏ (subsystem) và cuối cùng là
nguyên hệ thống hoàn chỉnh (system) chuẩn bị cho kiểm thử ở mức hệ thống.
+ System Test - Kiểm thử mức hệ thống

6
Mục đích Kiểm thử mức hệ thống là kiểm tra thiết kế và toàn bộ hệ thống (sau khi
tích hợp) có thỏa mãn yêu cầu đặt ra hay không.
Điểm khác nhau then chốt giữa kiểm thử tích hợp và kiểm thử hệ thống là kiểm thử
hệ thống chú trọng các hành vi và lỗi trên toàn hệ thống, còn kiểm thử tích hợp chú trọng
sự giao tiếp giữa các đơn vị hoặc đối tượng khi chúng làm việc cùng nhau. Thông thường
ta phải thực hiện kiểm thử đơn vị và kiểm thử tích hợp để bảo đảm mọi đơn vị phần mềm
và sự tương tác giữa chúng hoạt động chính xác trước khi thực hiện kiểm thử hệ thống
Kiểm thử hệ thống kiểm tra cả các hành vi chức năng của phần mềm lẫn các yêu cầu
về chất lượng như độ tin cậy, tính tiện lợi khi sử dụng, hiệu năng và bảo mật. Mức kiểm
thử này đặc biệt thích hợp cho việc phát hiện lỗi giao tiếp với phần mềm hoặc phần cứng
bên ngoài, chẳng hạn các lỗi “bế tắc” (deadlock) hoặc chiếm dụng bộ nhớ. Sau giai đoạn
kiểm thử hệ thống, phần mềm thường đã sẵn sàng cho khách hàng hoặc người dùng cuối
cùng kiểm thử để chấp nhận (Acceptance Test) hoặc dùng thử (Alpha/Beta Test).
+ Acceptance Test - Kiểm thử chấp nhận sản phẩm
Thông thường, sau giai đoạn kiểm thử hệ thống là kiểm thử chấp nhận, được khách
hàng thực hiện (hoặc ủy quyền cho một nhóm thứ ba thực hiện). Mục đích của kiểm thử
chấp nhận là để chứng minh phần mềm thỏa mãn tất cả yêu cầu của khách hàng và khách
hàng chấp nhận sản phẩm (và trả tiền thanh toán hợp đồng).
Kiểm thử chấp nhận có ý nghĩa hết sức quan trọng, mặc dù trong hầu hết mọi trường
hợp, các phép kiểm thử của kiểm thử hệ thống và kiểm thử chấp nhận gần như tương tự,
nhưng bản chất và cách thức thực hiện lại rất khác biệt.
+ Regression Test - Kiểm thử hồi quy
Kiểm thử hồi quy không phải là một mức kiểm thử, như các mức khác đã nói ở trên.
Nó đơn thuần kiểm tra lại phần mềm sau khi có một sự thay đổi xảy ra, để bảo đảm phiên
bản phần mềm mới thực hiện tốt các chức năng như phiên bản cũ và sự thay đổi không
gây ra lỗi mới trên những chức năng vốn đã làm việc tốt. Kiểm thử hồi quy có thể thực
hiện tại mọi mức kiểm thử.
Ví dụ: một phần mềm đang phát triển khi kiểm tra cho thấy nó chạy tốt các chức
năng A, B và C. Khi có thay đổi code của chức năng C, nếu chỉ kiểm tra chức năng C thì
chưa đủ, cần phải kiểm tra lại tất cả các chức năng khác liên quan đến chức năng C, trong

7
ví dụ này là A và B. Lý do là khi C thay đổi, nó có thể sẽ làm A và B không còn làm việc
đúng nữa.

2. Kiểm thử phần mềm nhúng


+ Tổng quan về kiểm thử phần mềm nhúng
Kiểm thử phần mềm nhúng cũng có các đặc điểm tương tự như kiểm thử phần mềm
nói chung, ngoài ra do đặc trưng của hệ thống nhúng rất đa dạng về môi trường phát triển,
đa dạng về kiến trúc phần cứng cũng như kiến trúc phần mềm nên kiểm thử cho phần
mềm nhúng có một số đặc trưng riêng.
Rõ ràng là kiểm thử phần mềm cho một chiếc điện thoại di động sẽ khác đáng kể so
với kiểm thử cho một chiếc máy giặt hay một hệ thống điểu khiển trong ô tô, mỗi hệ
thống đó yêu cầu một cách đánh giá riêng trong phương pháp kiểm thử của nó để có thể
kiểm thử được hết các phần của hệ thống.[12]
Mặc dù có nhiều lí do giải thích tại sao các hệ thống nhúng khác nhau phải được
kiểm thử theo những cách khá là khác nhau, tuy nhiên chúng cũng có nhiều vấn đề tương
tự, giải pháp tương tự cho các hệ thống trên trong một vài phương pháp kiểm thử nào
đó.[12]
Trong bài khóa luận này, tôi xin đề cập đến hai phương pháp hay được dùng để
kiểm thử cho khá nhiều các hệ thống nhúng khác nhau. Đó là phương pháp sử dụng
chương trình giả lập để mô phỏng phần cứng hệ thống, qua đó kiểm tra sự thực thi của
chương trình phần mềm. Phương pháp thứ hai là một phương pháp rất phổ biến cho kiểm
thử phần mềm nói chung, đó là kiểm thử đơn vị ( Unit test).
+ Kiểm thử bằng phương pháp chạy phần mềm trên môi trường giả lập phần
cứng.
Chạy chương trình phần mềm trên môi trường giả lập phần cứng thay vì chạy trực
tiếp trên phần cứng thật là một cách kiểm thử chương trình rất hữu ích. Người phát triển
có thể chạy thử chương trình nhúng của mình ngay trên máy PC mà không cần phải nạp
lên thiết bị thật, giúp tiết kiệm tiền mua thiết bị [14]. Hơn nữa, những thiết bị phần cứng
thật có thể hỏng nếu chương trình của ta chạy sai, hoặc đơn giản là do ta lắp ráp thiết bị
không đúng, điều đó thật nghiêm trọng nếu các thiết bị đó là đắt tiền, các phần mềm mô
phỏng sẽ giúp người phát triển tránh được những rủi ro này.

8
Không chỉ giúp tiết kiệm về tài chính, các công cụ giả lập còn giúp người phát triển
phần mềm nhúng tiết kiệm thời gian. Khi lập trình và biên dịch xong, thay vì phải loay
hoay kết nối các thiết bị phức tạp, kết nối thiết bị với máy tính để nạp chương trình và
thực thi, người lập trình có thể khởi động chương trình giả lập và chạy ngay chương
trình mình vừa viết một cách rất trực quan, qua đó kiểm tra được chương trình của mình
chạy có đúng như mong muốn dự kiến hay không.
+ Kiểm thử phần mềm nhúng bằng Unit Test.
Unit Test được sử dụng rất nhiều trong kiểm thử phần mềm vì nó là mức kiểm thử
đơn giản nhất và phát hiện ra nhiều lỗi lập trình nhất. Và đối với lập trình nhúng cũng
không phải là ngoại lệ, ta có thể dùng Unit Test để kiểm thử từng chức năng trong một
chương trình viết cho hệ thống nhúng, với Unit Test, người phát triển không khó khăn gì
trong việc tổ chức kiểm thử và phân tích kết quả kiểm thử, các lỗi lập trình sẽ được phát
hiện sớm.
Hiện nay, các Unit Test Framework dành cho lập trình nhúng chưa có nhiều như các
Unit Test Framework cho lập trình ứng dụng trên máy PC, với lập trính nhúng sử dụng
ngôn ngữ C, tiêu biểu chỉ có một vài framework là Embedded Unit (Embunit), Tessy,
Testape, Embedded Unity…Trong đó Embedded Unit là phổ biến nhất vì nó dễ sử dụng
và là một công cụ mã nguồn mở, ta có thể tải về miễn phí tại
http://embunit.sourceforge.net/ .

9
Chương 3. Lập trình nhúng cho vi điều khiển 8051 bằng
ngôn ngữ C
1. Vi điều khiển 8051
Trong khóa luận này, tôi chọn vi điều khiển 8051 để tìm hiểu và trình bày, áp dụng
các phương pháp kiểm thử phần mềm cho 8051 vì nó là vi điều khiển có giá thành rẻ,
được sử dụng rất rộng rãi, 8051 có rất nhiều tài liệu và công cụ trợ giúp phát triển và
hướng dẫn lập trình, và nó cũng có rất nhiều nhà sản xuất (nguồn cung cấp đa dạng).
8051 là một vi điều khiển rất phổ biến dùng cho các hệ thống nhúng, vi điều khiển
8051 là thành viên đầu tiên và phổ biến nhất của họ vi điều khiển 8051.
Intel 8051 — là vi điều khiển đơn tinh thể kiến trúc Harvard, lần đầu tiên được sản
xuất bởi Intel năm 1980, để dùng trong các hệ thống nhúng. Trong những năm 1980 và
đầu những năm 1990 đã rất nổi tiếng. Tuy nhiên hiện tại đã cũ và được thay thế bằng các
thiết bị hiện đại hơn, với các lõi phối hợp 8051, được sản xuất bởi hơn 20 nhà sản xuất
độc lập, như Atmel, Maxim IC, NXP Semiconductors (Philips Semiconductor trước đây),
Winbond, Silicon Laboratories, Texas Instruments và Cypress Semiconductor. Các phiên
bản của vi điều khiển 8051 tạo nên họ 8051. Tên gọi chính thức của họ vi điều khiển Intel
8051 là MCS 51.
Vào năm 1981. Hãng Intel giới thiệu một bộ vi điều khiển được gọi là 8051. Bộ vi
điều khiển này có 128 byte RAM, 4K byte ROM trên chíp, hai bộ định thời, một cổng nối
tiếp và 4 cổng (đều rộng 8 bit) vào ra tất cả được đặt trên một chíp. Lúc ấy nó được coi là
một “hệ thống trên chíp”. 8051 là một bộ xử lý 8 bit có nghĩa là CPU chỉ có thể làm việc
với 8 bit dữ liệu tại một thời điểm. Dữ liệu lớn hơn 8 bit được chia ra thành các dữ liệu 8
bit để cho xử lý. 8051 có tất cả 4 cổng vào - ra I/O mỗi cổng rộng 8 bit. Mặc dù 8051 có
thể có một ROM trên chíp cực đại là 64 K byte, nhưng các nhà sản xuất lúc đó đã cho
xuất xưởng chỉ với 4K byte ROM trên chip [1].
8051 đã trở nên phổ biến sau khi Intel cho phép các nhà sản xuất khác sản xuất và
bán bất kỳ dạng biến thế nào của 8051 mà họ thích với điều kiện họ phải để mã tương
thích với 8051. Điều này dẫn đến sự ra đời nhiều phiên bản của 8051 ( các vi điều khiển
trong họ 8051 ) với các tốc độ khác nhau và dung lượng ROM trên chíp khác nhau được
bán bởi hơn nửa các nhà sản xuất. Điều này quan trọng là mặc dù có nhiều biến thể khác

10
nhau của 8051 về tốc độ và dung lương nhớ ROM trên chíp, nhưng tất cả chúng đều
tương thích với 8051 ban đầu về các lệnh. Điều này có nghĩa là nếu ta viết chương trình
của mình cho một phiên bản nào đó thì nó cũng sẽ chạy với mọi phiên bản bất kỳ khác mà
không phân biệt nó từ hãng sản xuất nào.

Vi điều khiển 8051 cũng như họ vi điều khiển 8051 là một trong những bộ vi điều
khiển 8-bit mạnh và linh hoạt nhất, đã trở thành bộ vi điều khiển hàng đầu trong những
năm gần đây

2. Lập trình C cho 8051 với trình biên dịch SDCC


+ Ngôn ngữ C và lập trình nhúng
So với bất kỳ ngôn ngữ lập trình nào khác đang tồn tại C thực sự phù hợp và
trở thành một ngôn ngữ phát triển của hệ nhúng. Điều này không phải là cố hữu và sẽ tồn
tại mãi, nhưng tại thời điểm này thì C có lẽ là một ngôn ngữ gần gũi nhất để trở thành một
chuẩn ngôn ngữ trong thế giới hệ nhúng.
Sự thành công về phát triển phần mềm thường là nhờ vào sự lựa chọn ngôn ngữ phù
hợp nhất cho một dự án đặt ra. Cần phải tìm một ngôn ngữ để có thể đáp ứng được yêu
cầu lập trình cho các bộ xử lý từ 8 - bit đến 64 – bit, trong các hệ thống hữu hạn về bộ nhớ
vài Kbyte hoặc Mbyte. Cho tới nay, điều này chỉ có C là thực sự có thể thỏa mãn và phù
hợp nhất.
Có lẽ một thế mạnh lớn nhất của C là nó là một ngôn ngữ bậc cao mức thấp nhất.
Tức là với ngôn ngữ C chúng ta có thể điều khiển và truy cập trực tiếp phần cứng khá
thuận tiện mà không hề phải hy sinh hay đánh đổi bất kỳ một thế mạnh nào của ngôn ngữ
bậc cao. Đây cũng là một trong những tiêu chí xây dựng của những người sang lập ra
ngôn ngữ C muốn hướng tới.
Thời kỳ đầu của hệ thống nhúng, Assembly cũng là một ngôn ngữ hay được dùng để
lập trình cho các vi xử lý, với ngôn ngữ này cho phép người lập trình điều khiển và kiểm
soát hoàn toàn vi xử lý cũng như phần cứng hệ thống trong việc thực thi chương trình.
Tuy nhiên ngôn ngữ Assembly lại có nhiều nhược điểm, đó là việc học và sử dụng nó rất
khó khăn và đặc biệt khó khăn trong việc phát triển các chương trình ứng dụng lớn, phức
tạp. Chính vì vậy mà ngày nay Assembly ít được phổ cập và sử dụng.

11
+ Lập trình C cho 8051
Về cơ bản thì lập trình C cho vi điều khiển 8051, cấu trúc của chương trình cũng
giống như lập trình C cho các ứng dụng trên máy PC. Nhưng với lập trình C cho 8051, ta
chỉ cần biết số lệnh không nhiều, tuy nhiên với đặc trưng về phần cứng, ta sẽ phải nhớ
nhiều tên biến đặc biệt đã được định nghĩa sẵn để sử dụng trong chương trình, các biến
này thể hiện các thanh ghi hoặc các bit có chức năng đặc biệt của vi điều khiển.
Các kiểu dữ liệu về cơ bản giống với C chuẩn, ngoài ra còn có một số kiểu dữ liệu
đặc trưng cho vi điều khiển như kiểu sfr ( thanh ghi đặc biệt), kiểu bit, sbit….
Cấu trúc một chương trình C cho 8051[1]:
//include các file
#include <file.h>
#include <file.c>
//Khai báo biến toàn cục
unsigned char x,y;
int z=0;
//Khai báo và định nghĩa các hàm
Kiểu trả về Hàm1( đối số ) ko
{
…//Các câu lệnh
}
void Hàm2( đối số )
{
…//Các câu lệnh
}
//Hàm main ( bắt buộc chương trình nào cũng phải có )
void main(void)

12
{
…//Các câu lệnh
}
Các câu lệnh trong hàm main có thể có lời gọi các hàm đã khai báo ở trên hoặc
không. Khi có lời gọi hàm nào thì chương trình nhảy đến hàm đó thực hiện hàm đó xong
con rỏ lại quay về chương trình chính(hàm main) thực hiện tiếp các hàm hoặc câu lệnh.
Các câu lệnh trong C kết thúc bằng dấu “;”
Các comment được đặt trong dấu: Mở đầu bằng “/*” kết thúc bằng “*/” , nếu
comment trên 1 dòng thì có thể dùng dấu: “//” . Khi lập trình nên comment các câu lệnh
khối lệnh làm gì để về sau khi chương trình lớn dễ sửa lỗi.
Ngoài các hàm cơ bản, lập trình C cho 8051 còn có các hàm ngắt để xử lý ngắt :
Void Tênhàm(void) interrupt nguồnngắt using băngthanhghi
{
// các câu lệnh
}
Hàm ngắt không được phép trả lại giá trị hay truyền tham biến vào hàm, tên hàm là
bất kì , Interrupt là từ khóa chỉ hàm ngắt
+ Trình biên dịch SDCC
Giới thiệu SDCC
SDCC là một trình biên dịch C rất phổ biến cho vi điều khiển, “SDCC” là viết tắt
của Small Device C Compiler, nó là phần mềm tự do mã nguồn mở, ta có thể tải miễn phí
từ http://sdcc.sourceforge.net/ . SDCC là chương trình dịch đa đích, nó có thể biên dịch
và hỗ trợ cho nhiều loại vi điều khiển như 8051, PIC, Motorola, Zilog,...[9]
SDCC được phát triển bởi một cộng đồng đông đảo lập trình viên khắp thế giới và
rất phổ biến với người dùng Linux, SDCC cũng có phiên bản dành cho Windows. Trong
khóa luận này, tôi sử dụng phiên bản SDCC 2.5.0 dành cho Windows để biên dịch các ví
dụ về lập trình C cho 8051.
Cài đặt

13
Sau khi tải phiên bản SDCC dành cho Windows tại http://sdcc.sourceforge.net/, ta
tiến hành cài đặt, sau khi cài đặt, chương trình sẽ hỏi xem ta có muốn đưa đường dẫn của
thư mục bin chứa các file thực thi SDCC vào biến môi trường PATH không ? Ta chọn yes
và kết thúc cài đặt, lúc này ta có thể gọi trình biên dịch SDCC từ bất kì đâu.

Hình 3. Cài đặt SDCC


Ta kiểm tra phiên bản SDCC vừa cài bằng cách bật môi trường dòng lệnh của
Windows ( Comand Prompt) gõ lệnh sdcc –version [9], kết quả như sau chứng tỏ ta đã
cài đặt thành công:
“SDCC : mcs51/gbz80/z80/avr/ds390/pic16/pic14/TININative/xa51/ds400/hc08
2.5.0 #1020 (May 8 2005) (MINGW32)”.
Sử dụng SDCC
Ta có thể biên dịch 1 file .c bằng lệnh : sdcc tênfile.c
- ví dụ : sdcc test.c
file thực thi được tạo ra sẽ có đuôi là .ihx chứa mã hexa để nạp lên vi điều khiển và
chạy.

14
Khi ta có nhiều file mã nguồn, ta có thể biên dịch từng file thành các file .rel riêng
rẽ, sau đó biên dịch file chính cùng với các file .rel mà nó cần dùng [9] ( điều này giống
như biên dịch file .o khi dùng trình biên dịch GCC ).
Ví dụ : ta có 2 file delay.c và blink.c, blink.c là file chính sử dụng file delay.c, ta
biên dịch như sau :
sdcc -c delay.c // tạo file delay.rel
sdcc blink.c delay.rel // biên dịch file blink.c sử dụng delay.rel
Khi ta biên dịch một file mã nguồn, SDCC sẽ tạo ra không phải chỉ một file đích
.ihx, mà còn có một số file khác được trình biên dịch tạo ra, ta có danh sách các loại file
sẽ được tạo khi biên dịch như sau :
- File .asm : chứa mã assembly của chương trình
- File .ihx : chứa mã hexa, để nạp và chạy trên vi điều khiển, đây là file mà ta cần
- File lst: danh sách assembly code, khá có ích cho việc hiểu sâu và tối ưu mã, tại
đây ta có thể thấy mã C dọc theo mã assembly và mã máy
- File .map : chứa ánh xạ bộ nhớ được tạo bởi bộ liên kết (linker), đây là file khá
quan trọng, nó cho ta biết cách sử dụng các phần khác nhau của bộ nhớ.
- File .mem : tóm tắt về cách sử dụng bộ nhớ, thể hiện RAM và miêu tả bộ nhớ khác
- File .rel : file chứa object được tạo ra dành cho bộ liên kết
- File .rst : file danh sách assembly với lien kết chỉnh sửa thông tin
- File .sym : chứa bảng các kí hiệu
File chứa mã hexa cho các vi điều khiển có định dạng chuẩn là .hex, nên sẽ có một
số loại chip không đọc được file .ihx do SDCC tạo ra. SDCC cung cấp một công cụ
chuyển từ file .ihx sang file .hex chuẩn, đó là công cụ packihx, ta gõ lệnh như sau:
packihx tênfile.ihx > tênfile.hex
Lệnh này sẽ tạo file .hex để ta có thể nạp cho vi điều khiển.
Trình biên dịch SDCC cũng cho phép ta nhúng mã assembly vào chương trình C,
các câu lện assembly phải được đặt giữa 2 cặp từ khóa là _asm và _endasm và kết thúc
khối lệnh bằng dấu ; sau _endasm [9].

15
Ngoài ra SDCC còn cho phép ta có thể tạo các thư viện – các file .lib để có thể sử
dụng lại, sử dụng chung cho nhiều chương trình, ta có thể tạo thư viện bằng lệnh sau:
Sdcclib tênthưviện.lib tênfile.rel
Khi viết mã nguồn cho 8051 với SDCC, các chân của các cổng được viết như sau:
chân P0.0 được viết là P0_0, chân P0.1 được viết là P0_1 ….( sử dụng dấu gạch dưới
phân tách giữa cổng và chân ).
+ IDE cho lập trình 8051 với SDCC
Ta có thể sử dụng trực tiếp trình biên dịch SDCC trên môi trường dòng lệnh của
Windows, tuy nhiên nếu ta sử dụng một IDE trợ giúp cho lập trình thì việc sử dụng SDCC
sẽ hiệu quả và dễ sử dụng hơn. Ở đây, tôi sử dụng một IDE khá phổ biến cho 8051 đó là
MIDE – 51. MIDE-51là một IDE dành cho vi điều khiển 8051 trên Windows, nó là một
phần mềm tự do, ta có thể tại miễn phí tại trang http://www.opcube.com . MIDE-51 có cả
bản đóng gói đầy đủ và bản chỉ có trình soạn thảo (Editor) MIDE-51 [8].

Hình 4. trình soạn thảo MIDE-51

16
Với bản đầy đủ, nó đã tích hợp sẵn trình dịch SDCC, trình hợp ngữ, trình giả lập vi
điều khiển, ta chỉ việc cài ra và sử dụng, không cần phải cấu hình.
Với bản chỉ có trình soạn thảo, ta cần phải cấu hình cho nó, như đặt đường dẫn đến
thư mục thực thi của SDCC, đường dẫn đến trình giả lập….Mọi cấu hình đều được thiết
lập trong mục edit -> Preference.
+ Ví dụ về lập trình C cho 8051 với SDCC và MIDE-51
Ta có một chương trình C đơn giản như sau
#include <8051.h>
void delay( ) //hàm tạo trễ một khoảng thời gian
{
int i,j;
for (i = 0;i<=1000;i++)
for (j = 0;j<=1000;j++);
}
void main()
{
while (1)
{
P1_1 = 0; // led glow
delay( );
P1_1 = 1; // led off
delay( );
}
}
Đây là một chương trình đơn giản, nó làm nhấp một đèn nháy led được nối với chân
P1.1, hàm delay( ) có tác dụng tạo trễ, để khi chạy ta có thể quan sát được sự nhấp nháy
của đèn.
Ta viết đoạn mã trên vào MIDE-51, lưu lại thành file example.c. Sau đó ta biên dịch
bằng cách chọn Build hoặc bấm phím F9.

17
Sau khi biên dịch, MIDE-51 sẽ thông báo biên dịch thành công, nếu chương trình có
lỗi, nó sẽ báo có lỗi và lỗi nằm ở dòng mã nào. Các file đích được tạo ra khi biên dịch,
một điều quan trọng là MIDE sẽ tự động gọi lệnh packihx để tạo file .hex từ file .ihx, và
tự động xóa file .ihx đi. Ta chỉ việc nạp file .hex để thực thi trên vi điều khiển.

18
Chương 4. Kiểm thử chương trình cho 8051 bằng công cụ giả
lập
1. Chương trình giả lập vi điều khiển “8051 series microcontroller
simulator”.
+ 8051 series microcontroller simulator
Có rất nhiều các chương trình mô phỏng vi điều khiển 8051 trên Windows, các
chương trình này là các vi điều khiển ảo, sau khi viết mã nguồn và biên dịch, ta có thể
kiểm tra chương trình bằng cách chạy chương trình mô phỏng và kiểm tra kết quả thực thi
chương trình mà không cần dùng đến vi điều khiển thật. Ở đây tôi chọn công cụ giả lập
“8051 series microcontroller simulator” vì nó có giao diện đơn giản, dễ nhìn, dễ sử dụng
và nó miễn phí. 8051 series microcontroller simulator có thể được tải về tại
http://www.dontronics.com/8051sim.html
Chương trình giả lập này rất đơn giản, gọn nhẹ chỉ có một file thực thi duy nhất là
file sim8051.exe, ta chạy file này, chương trình sẽ có giao diện như sau:

Hình 5. chương trình giả lập 8051 series microcontroller simulator


Cách sử dụng chương trình cũng rất dễ dàng, khi đưa con trỏ chuột đến một nút
(biểu tượng) trên cửa sổ chương trình chính (hình vẽ trên), dòng status ( ở dưới cùng của
khung cửa sổ chương trình ) sẽ hiển thị chức năng của nút, trong hình trên, khi ta chưa
chọn file chương trình thực thi thì status thông báo ở đây là “Stopped”.
Chức năng của các nút như sau:

- nút : chọn file .hex để thực thi.

- nút : thực thi file đã chọn.

19
- nút : tạm dừng thực thi và giữ nguyên trạng thái của vi điều khiển.

- nút : dừng thực thi chương trình và reset vi điều khiển trở lại trạng thái ban
đầu.

- nút : chạy chương trình từng bước.

- nút : chạy đến lệnh tiếp theo


- 10 nút còn lại ở bên phải của cửa sổ chương trình có chức năng hiển thị các bảng
thông số của vi điều khiển mà ta sẽ đề cập đến ở dưới đây.
Ta có thể chọn File > open để chọn file thực thi .hex mà ta muốn kiểm thử.
Các mục trong menu view là để chọn hiển thị các bảng thông số của vi điều khiển
khi ta thực thi chương trình. Các bảng thông số ở đây là [10] :
- Bảng Processor Core : hiển thị các thông số của các thanh ghi chính, thanh ghi
đặc biệt, các cổng vào ra, thông số hiển thị ở đây là giá trị của từng bit và giá trị của toàn
bộ thanh ghi dưới dạng số hexa.
- Bảng Code viewer : hiển thị mã assembly của chương trình mà ta nạp để kiểm thử.
- Bảng Core direct memory và Core indirect memory hiển thị bộ nhớ trực tiếp và
không trực tiếp của vi điều khiển.
- Bảng Break point giúp ta tạo các điểm dừng chương trình
- Bảng ROM : hiển thị nội dung bộ nhớ ROM
- Bảng RAM : hiển thị nội dung bộ nhớ RAM
- Bảng Active Interrupt ( IQR): giúp ta tạo các ngắt
- Bảng Processor Transmit Monitor : hiển thị output của cổng Serial
- Bảng Input Data to Processor Serial Comms : hiển thị input của cổng Serial
Bảng thông số mà ta hay dùng nhất, để quan sát chương trình là bảng “Processor
Core”, ta bấm nút để hiển thị và ẩn bảng này

20
Hình 6. bảng Processor Core của chương trình giả lập 8051 series
microcontroller simulator

+ Ví dụ kiểm thử chương trình cho 8051 trên chương trình giả lập 8051 series
microcontroller simulator
Trở lại với file ví dụ example.c đã biên dịch bằng SDCC và MIDE-51 ở trên,
chương trình này có mục đích nhấp nháy đèn led được nối với chân P1.1, hay nói một
cách khác, nó làm thay đổi giá trị bit của chân P1.1 liên tục từ 0 thành 1 rồi lại từ 1 thành
0. Ta sẽ kiểm thử xem chương trình này chạy có kết quả đúng như ta mong muốn không
bằng cách thực thi nó trên 8051 series microcontroller simulator.

21
Test Case ở đây là :
- Mục đích kiểm tra: Kiểm tra sự nhấp nháy của chân P1.1 khi thực thi chương
trình example
- Kết quả mong đợi : chân P1.1 nhấp nháy ( chuyển trạng thái liên tục từ 0 sang 1).
Tiến hành test:
Ta chọn File > open để chọn file thực thi example.hex đã được biên dịch. Lúc này,
khi ta mở bảng Code viewer, nó sẽ hiển thị toàn bộ mã assembly của chương trình :

Hình 7. mã Assembly của chương trình example

22
Ta mở bảng Processor Core để theo dõi chương trình thực thi như thế nào.Bấm
để thực thi chương trình, ta sẽ thấy giá trị một số bit của một số thanh ghi thay đổi liên
tục, sự thay đổi này có tính tuần hoàn lặp đi lặp lại, đó là do vòng lặp While vô hạn.
Ta chỉ cần chú ý đến thanh ghi P1 để quan sát kết quả của chương trình, ta sẽ thấy
bit P1.1 ( bit thứ 2 từ bên phải sang) thay đổi liên tục giữa 2 giá trị 0 và 1, giá trị của cổng
P1 ở dạng số hexa sẽ thay đổi liên tục tử FD thành FF và ngược lại

Cổng P1

Hình 8. bảng Processor Core khi chạy chương trình


- Kết quả thực tế: chân P1.1 của vi điều khiển nhấp nháy.
Kết quả thực tế trùng với kết quả mà ta mong đợi, vì thế ở đây ta thấy rằng chương
trình example đã chạy đúng.
Bây giờ ta sẽ kiểm thử một ví dụ khác.
Ta thử sửa đổi chương trình example trên bằng cách thêm vào một hàm xử lý ngắt.
Chương trình mới của ta bây giờ sẽ là chương trình có cho phép ngắt, nội dung thực thi
của chương trình này là : hàm main thực hiện việc nhấp nháy chân P1.1, khi có ngắt xảy
ra từ ngắt ngoài 0 ( interrupt 0), chương trình sẽ dừng việc nhấp nháy chân P1.1 và

23
chuyển sang nhấp nháy chân P1.0 mười lần (thực hiện hàm ngắt), sau đó chương trình sẽ
quay lại nhấp nháy chân P1.1
Mã nguồn chương trình của ta bây giờ sẽ như sau
#include <8051.h>
void delay() //hàm tạo trễ một khoảng thời gian
{
int i,j;
for (i = 0;i<=1000;i++)
for (j = 0;j<=1000;j++);
}

void EX1_int0 (void) interrupt 0 {


int i = 10;
while (i>0)
{
P1_0 = 0;
delay();
P1_0 = 1;
delay();
i--;
}
}
void main()
{
EX0 = 1; // cho phép ngắt ngoài 0
EA = 1; // cho phép sử dụng ngắt toàn cục
while (1)
{
P1_1 = 0; // led bật
delay();
P1_1 = 1; // led tắt
delay();

24
}
}
Hàm void EX1_int0 (void) interrupt 0 là hàm xử lý ngắt khi có tín hiệu ngắt từ
ngắt ngoài 0 ( interrupt 0), ở đây hàm xử lý ngắt của tôi làm một việc đơn giản là nhấp
nháy chân P1.0 mười lần thay vì việc nhấp nháy chân P1.1 của hàm main.
Trong hàm main cần thiết lập hai biến EA và EX0, đây là hai bit của thanh ghi đặc
biệt IE. Như đã đề cập ở phần triến trúc của 8051, thanh ghi đặc biệt có các bit có chức
năng riêng và được đặt tên riêng, và hai bit EA và EX0 là hai bit như thế, bit EA được
thiết lập có tác dụng cho phép chương trình sử dụng ngắt ( nếu EA = 0 thì chương trình sẽ
không cho phép có ngắt khi nó đang thực hiện chương trình chính), bit EX0 được thiết lập
có tác dụng cho phép ngắt từ ngắt ngoài 0 ( interrupt 0).
Lưu đoạn mã trên thành file example1.c rồi biên dịch thành file example1.c, ta sẽ
kiểm thử sự thực thi chương trình này với chương trình giả lập.
Test Case:
- Mục đích: Kiểm tra sự nhấp nháy của P1.1 và P1.0 khi thực thi chương trình
example1.
- Cách thực hiện test: Chạy chương trình, quan sát P1.1 và P1.0, sau tó tạo ngắt
ngoài 0 ( interrupt 0), tiếp tục quan sát P1.1 và P1.0.
- Kết quả mong đợi : Ban đầu P1.1 nhấp nháy, P1.0 giữ nguyên trạng thái, sau khi
tạo ngắt, P1.1 giữ nguyên trạng thái, P1.0 nhấp nháy 10 lần, sau đó P1.1 lại nhấp nháy,
P1.0 giữ nguyên.
Tiến hành test:
Ta chạy file example1.hex với chương trình giả lập, ban đầu ta thấy nó chạy giống
như chương trình example ở lúc nãy. Bây giờ ta mở bảng Active Interrupt để tạo ngắt

Hình 9. bảng active interrupt

25
Ta bấm vào nút EX0, nút này có tác dụng tạo một tín hiệu ngắt đến từ ngắt ngoài 0,
sau đó ta sẽ thấy chân P1.1 không nhấp nháy nữa, mà chân P1.0 lại nhấp nháy 10 lần, sau
đó P1.1 lại tiếp tục nhấp nháy.

Hình 10. chương trình example1 khi có ngắt, bit P1.0 thay đổi giá trị liên tục
Như vậy, khi có ngắt, vi điều khiển sẽ dừng chương trình chính, thực hiện hàm xử lý
ngắt, sau đó lại quay lại chương trình chính.
- Kết quả thực tế : Ban đầu P1.1 nhấp nháy, P1.0 giữ nguyên trạng thái, sau khi tạo
ngắt, P1.1 giữ nguyên trạng thái, P1.0 nhấp nháy 10 lần, sau đó P1.1 lại nhấp nháy, P1.0
giữ nguyên.
Kết quả thực tế của ta cũng trùng với kết quả mong đợi, cho thấy chương trình
example1 của ta đã thực thi đúng với mong muốn.

2. Chương trình mô phỏng hệ thống mạch điện tử Proteus


+ Giới thiệu Proteus
Proteus là một bộ chương trình dùng để tạo và chạy các hệ thống mạch điện , các hệ
thống mạch có vi điều khiển và mô phỏng quá trình làm việc của hệ thống, giúp cho ta

26
hình dung trực quan hơn vào thực tế của các linh kiện điện tử và sự hoạt động của các vi
điều khiển.
Phần mềm Proteus được viết bởi công ty Labcenter Electronics . Proteus đã được sử
dụng khá rộng rãi ở nhiều nơi. Proteus đã tự khẳng định thế mạnh của nó về mô phỏng
các hệ thống mạch sát với thực tế, càng ngày nó càng được hoàn thiện và phát triển mạnh
.Proteus cung cấp cho người sử dụng hầu như toàn bộ các linh kiện điện tử để người dùng
có thể tạo ra được các mạch nguyên lý và sau cùng là chạy thử và so sánh với kết quả
thực tế. Chính vì Proteus có thể tạo và chạy được các mạch đơn giản cũng như các mạch
phức tạp nên có thể dùng nó trong giảng dạy, trong các phòng thí nhiệm điện tử cũng như
trong thực hành vi điều khiển …[3]
Vì vậy, ta có thể dùng Proteus để giả lập các hệ thống nhúng với các loại vi điều
khiển khác nhau, các loại linh kiện khác nhau, qua đó ta dùng hệ thống giả lập này để
kiểm thử các chương trình mà ta muốn nhúng trên thiết bị thật.
Trong bài khóa luận này, tôi dùng Protues để mô phỏng một hệ thống mạch đơn giản
sử dụng vi điều khiển họ 8051 như mạch đèn led.
Các ưu điểm của Proteus [3]
- Dễ dàng tạo ra một sơ đồ đơn giản từ các mạch điện đơn giản, đến các mạch có bộ
lập trình vi xử lý .
- Dễ dàng chỉnh sửa các đặc tính của linh kiện trên sơ đồ mạch: chỉnh sửa số bước
của động cơ bước, chỉnh sửa nguồn nuôi cho mạch ,thay đổi tần số hoạt động cơ bản của
vi xử lý…
- Công cụ hỗ trợ kiểm tra lỗi thiết kế trên sơ đồ mạch mô phỏng. Xem và lưu lại
phần báo lỗi .
- Chạy mô phỏng và phân tích các tính chất của mạch điện cơ bản. Công cụ hỗ trợ
cho việc chạy và mô phỏng rất mạnh và chính xác. Các công cụ và đồ thị hỗ trợ mạnh cho
việc phân tích tần số, sóng, âm thanh .. không nhưng thế phần mềm còn có thêm các máy
phân tích từ đơn giản như : đồng hồ đo Vôn, Ampe, đến các máy đo dao động ,máy tạo
sóng dao động …
- Ngoài ra Proteus còn cung cấp cho người sử dụng các công cụ mạnh mà các phần
mềm khác hầu như không có. Chẳng hạn thư viện LED với các loại màu sắc khác nhau

27
kể cả led 7 đoạn. Nhưng phần hiển thị mạnh nhất mà Proteus cung cấp là màn hình LCD,
nó có thể mô phỏng cho rất nhiều LCD từ đơn giản đến phức tạp.
- Một cái ưu điểm nữa của Proteus là có thể mô phỏng công cụ phát và thu tín hiệu
từ các mạch giao tiếp với máy tính qua công cụ RS232. Trong đó người sử dụng có thể
điều khiển được quá trình truyền phát, tốc độ Baud … giúp cho người lập trình có thể mô
phỏng các mặt truyền phát tín hiệu .
- Một điểm mạnh khác của Proteus là cung cấp cho người sử dụng công cụ biên dịch
cho các họ vi xử lý như 8051, AVR, HC11 … Qua đó tạo ra các tập tin HEX dùng để nạp
cho vi xử lý và tập tin DSI dùng để xem và chạy kiểm tra từng bước trong chương trình
mô phỏng .
- Đối với các mạch vi xử lý Proteus không những cung cấp hình ảnh thực tế của các
linh kiện xuất mà còn cung cấp cho người lập trình rất nhiều các cửa sổ thông báo các nội
dung của bộ nhớ, con trỏ, thanh ghi, …
- Proteus có một thư viện khá lớn với hơn 6000 linh kiện các loại và càng ngày càng
được bổ sung. Ngoài ra còn có keypad (ma trận phím tạo đơn giản cho người thiết kế khi
cần thao tác trên các ma trận phím ).
Khả năng ứng dụng của Proteus [3]
- Khả năng ứng dụng chính của Proteus là mô phỏng, phân tích các kết quả từ các
mạch nguyên lý. Proteus giúp cho người sử dụng có thể thấy trước mạch thiết kế chạy
đúng hay sai trước khi thiết kế trên bản mạch.
- Các công cụ phục vụ cho việc phân tích mạch có độ chính xác khá cao như đo vôn
hay ampe, máy đo dao động .
- Khả năng áp dụng chương trình Proteus vào trong giảng dạy là rất tốt cho các thầy
cũng như cho sinh viên học tập kỹ thuật điện tử vì hầu như Proteus cung cấp gần như
đầy đủ từ cơ bản đến phức tạp cho người học điện tử và vi điều khiển.
- Đối với các sinh viên thì Proteus nếu mà được sử dụng rộng dãi thì nó gần như là
thầy dạy cho chính họ ở nhà. Nó giúp cho các sinh viên tự học, tự nhiên cứu và thiết kế
thử các phần đã học và chạy xem kết quả và rút ra các bài học tốt. Điều cơ bản nhất là
tiết kiệm tiền cho sinh viên không có điều kiện mà lại ham học, ham nghiên cứu.

28
- Trong thực tế hiện nay hầu như phòng thí nhiệm điện tử nào xây dựng lên cũng
phải tốn không ít ngân sách. Nếu Proteus được ứng dụng qua một máy tính các thầy
giáo có thể cung cấp cho sinh viên hầu như toàn bộ các mạch điện đơn giản ,hơn nữa có
thể tạo ra các KIT vi xử lý dùng phục vụ cho việc thực hành vi xử lý .Qua đó các thầy
giáo có thể cung cấp cho các sinh viên các mạch điện tử phục vụ trong quá trình học tập
từ đó sinh viên có thể tự nguyên cứu các bài thực hành trước ở nhà trước khi thực hành
thực tế trên mô hình thật sự và kết quả chắc chắn không nhỏ.
Nhược điểm của Proteus [3]
Phần mềm nào cũng có nhược điểm của nó do đó Proteus cũng không tránh khỏi
các nhược điểm :
- Phần mềm do công ty của nước ngoài nên tính chất bản quyền khá cao, và hầu như
ít được biết đến nên rất khó kiếm ngoài thực tế .
- Trong khi thiết kế có nhiều phần trong Proteus chạy không theo một quy tắc nào
làm người sử dụng đôi lúc gặp khó khăn.
- Sử dụng khá phức tạp, nhất là đối với các mạch vi xử lý hay các mạch cần chỉnh
sửa các tính chất các linh kiện (do quá nhiều tính chất phải điều chỉnh).
- Phần mềm do công ty nước ngoài viết nên không có nhiều tài liệu cung cấp hướng
dẫn sử dụng .
- Hướng dẫn sử dụng trong Proteus hoàn toàn bằng tiếng anh nên đòi hỏi người sử
dụng cũng phải có một nền tảng tiếng anh cơ bản nếu muốn sử dụng nó một cách hiệu quả
(nhất là tiếng anh chuyên ngành về điện tử).
Sử dụng Proteus
Chương trình trong bộ Proteus được sử dụng để thiết kế mô phỏng các mạch điện là
ISIS.
Phiên bản tôi sử dụng ở đây là Proteus 7.2 Professional. Sau khi cài đặt, ta khởi
động Proteus bằng cách chọnStart -> Program -> Proteus 7 Professional -> ISIS 7
Professional. Dưới đây là giao diện cơ bản của Proteus :

29
Hình 11. Giao diện cơ bản của chương trình Proteus
Ta chọn các linh kiện để thiết kế hệ thống mạch bằng cách : trên menu ta chọn
Library -> Pick Device/Symbol … hoặc bấm phím P, hoặc bấm vào biểu tượng Pick
devices trên cửa sổ Devices, bảng linh kiện sẽ hiện ra, có rất nhiều các loại linh kiện và
các loại vi điều khiển để cho ta chọn lựa cho thiết kế của mình.
Ta có thể tự thiết kế hệ thống mạch mô phỏng để dùng, hoặc cũng có thể sử dụng
các hệ thống mô phỏng đã được thiết kế sẵn để chạy các chương trình của mình. Trong
thư mục cài đặt của Proteus có thư mục Samples chứa một số các ví dụ các hệ thống đã
được thiết kế sẵn cho các loại vi điều khiển như 8051, ARM, PIC… Các hệ thống mạch
đã được thiết kế có thể được lưu lại dưới dạng file .DSN, sau đó ta có thể sử dụng lại
mạch bằng cách mở file .DSN bằng Proteus, hoặc cũng có thể chia sẻ file .DSN cho
những người khác sử dụng lại mạch mô phỏng của mình.

30
Trong khóa luận này, tôi sử dụng lại thiết kế mạch của người khác để kiểm thử
chương trình của mình, đây là một thiết kế hệ thống đơn giản sử dụng vi điều khiển
AT89C51, là vi điều khiển thuộc họ 8051 của hãng Atmel rất hay được sử dụng hiện nay,
các chương trình viết cho vi điều khiển 8051 đều có thể chạy trên AT89C51.
+ Ví dụ về kiểm thử chương trình nhấp nháy Led trên Proteus
Ví dụ mà tôi trình bày ở đây là chương trình nhấp nháy 2 đèn led sử dụng vi điều
khiển AT89C51 trên Proteus.
Tôi viết một chương trình example2 để điều khiển nhấp nháy 2 đèn Led. Chương
trình này cũng tương tự như chương trình nhấp nháy Led nối với chân P1.1 trong ví dụ
example.c đã đề cập ở phần trước, chỉ khác là ở đây ta điều khiển 2 đèn Led nối với 2
chân P2.0 và P2.1. Mục đích của chương trình là làm nhấp nháy 2 Led liên tục, Led này
bật thì Led kia tắt và ngược lại.
Mã C của chương trình nhấp nháy 2 Led được lưu trong file example2.c như sau:
#include <8051.h>
void delay() //hàm tạo trễ một khoảng thời gian
{
int i,j;
for (i = 0;i<=100;i++)
for (j = 0;j<=1000;j++);
}
void main( )
{
while (1)
{
P2_0 = 0;
P2_1 = 1;
delay();
P2_0 = 1;
P2_1 = 0;
delay();
}

31
}
Ta biên dịch chương trình thành file example2.hex
Ta sẽ kiểm thử sự thực thi của chương trình này trên Proteus
Trước hết ta cần có mạch mô phỏng hệ thống trên Proteus để có thể thực thi chương
trình. File thiết kế là DK_LED.DSN, ta chỉ việc click file này, nó sẽ tự động gọi Proteus
để mở file.
Dưới đây là sơ đồ mạch mô phỏng cho chương trình nhấp nháy 2 đèn Led được thiết
kế trên Proteus [2]:

Hình 12. mạch mô phỏng AT89C51 và 2 đèn Led trên Proteus


Mạch này gồm có vi điều khiển AT89C51 kết nối với 2 đèn LED và một số linh
kiện khác, ta chỉ cần quan tâm đến 2 đèn LED mà thôi. Đèn Led xanh nối với chân P2.0,
còn đèn Led đỏ nối với chân P2.1.
Test Case:
- Mục đích: Kiểm tra sự nhấp nháy của 2 led xanh và đỏ.

32
- Kết quả mong đợi: 2 led nhấp nháy xen kẽ nhau, led xanh sang thì led đỏ tắt và
ngược lại.
Tiến hành test:
Ta nạp file example2.hex đã được tạo cho vi điều khiển bằng cách bấm chuột vào vi
điều khiển, chuột phải và chọn Edit Properties, cửa sổ Edit Component sẽ hiện ra, tạo
mục Program File ta chọn đường dẫn đến file example2.hex.
Ta chạy chương trình mô phỏng bằng cách vào mục Debug chọn execute hoặc bấm
F12 hoặc bấm vào biểu tượng thực thi ở góc trái phía dưới. Sau đó ta quan sát chương
trình thực thi trên mạch mô phỏng.

Hình 13. Hai đèn Led nhấp nháy đồng thời


- Kết quả thực tế : 2 Led có nhấp nháy, nhưng lại bật và tắt cùng lúc.
Kết quả thực tế ta thu được là 2 Led có nhấp nháy, nhưng lại bật và tắt cùng lúc, trái
với mong muốn của ta, như vậy là chương trình có lỗi.
Lỗi xảy ra có thể do ta lập trình sai, hoặc do chương trình của ta không tương ứng
với cách mắc các thiết bị. Và ở đây, khi xem lại ta sẽ thấy trên mạch mô phỏng, cách mắc
2 Led là ngược nhau, 2 chân P2.0 và P2.1 sẽ có vai trò ngược nhau ( P2.0 là cực âm còn

33
P2.1 là cực dương). Led xanh nối với P2.0 sẽ sáng khi P2_0 = 0 còn Led đỏ nối với P2.1
sẽ sáng khi P2_1 = 1. Vì vậy, đoạn mã chương trình trên của ta sẽ làm cho 2 Led sáng và
tắt đồng thời.
Do đó để 2 Led nhấp nháy xen kẽ nhau ta phải sửa lại hàm main như sau :
void main( )
{
while (1)
{
P2_0 = 0;
P2_1 = 0;
delay();
P2_0 = 1;
P2_1 = 1;
delay();
}
}
Sau đó ta biên dịch lại chương trình và chạy, quan sát lại kết quả thực thi chương
trình:

34
Hình 14. 2 Led nhấp nháy xen kẽ nhau
- Kết quả thực tế: 2 led nhấp nháy xen kẽ nhau, led xanh sang thì led đỏ tắt và ngược
lại.
Kết quả thực tế mà ta thu được lần này đã trùng với kết quả mong đợi, chương trình
của ta đã thực thi đúng.
Như vậy, chương trình của ta ban đầu ta tưởng như nó sẽ chạy đúng như mong
muốn, không cần phải kiểm tra vì mã nguồn rất đơn giản, sau khi chạy thử trên mạch mô
phỏng ta mới phát hiện ra có lỗi và sửa lại.
+ Nhận xét
Việc mô phỏng hệ thống trên Proteus cho ta nhìn thấy sự thực thi chương trình của
mình rất trực quan, tuy không thể giống 100% như chạy trên thiết bị thật nhưng cơ bản
cũng cho ta thấy chương trình của mình sẽ chạy như thế nào. Qua đó ta có thể sớm phát
hiện lỗi, tránh các rủi ro có thể khi chạy trên thiết bị thật.
Ngoài ra việc chạy mô phỏng còn giúp ta tiết kiệm thời gian, chương trình được thực
thi ngay trên máy tính thay vì phải nạp lên thiết bị.

35
Chương 5. Kiểm thử chương trình cho 8051 bằng Unit Test,
sử dụng công cụ Embedded Unit
Unit Test cũng rất hữu dụng đối với lập trình hệ thống nhúng, nó giúp người phát
triển đảm bảo tính chính xác của từng đơn vị chương trình. Ở đây, tôi sử dụng một Unit
Test Framework khá phổ biến dùng cho lập trình C nhúng là Embedded Unit ( Embunit).

1. Giới thiệu Embedded Unit


Embedded Unit là một công cụ tự do mã nguồn mở, được chia sẻ tại địa chỉ
http://embunit.sourceforge.net/ , ta có thể vào trang này để tải miễn phí mã nguồn
Embedded Unit cũng như tài liệu hướng dẫn, ví dụ chương trình minh họa.
Embedded Unit là một Test Framework (bộ khung test) cho hệ thống nhúng với
ngôn ngữ C, nó được thiết kế trên cơ sở của JUnit và CUnit theo hướng thích nghi với hệ
thống C nhúng. Một điều đặc biệt là Embedded Unit không yêu cầu thư viện C chuẩn [7].
Embedded Unit thường được sử dụng trên linux với trình biên dịch GCC và công cụ
GNU Make. Ở đây, tôi không sử dụng linux mà sử dụng Windows XP 32 bit, vì vậy tôi
cài đặt GCC và GNU Make trên Windows và dùng nó để sử dụng Embedded Unit.
Tôi cài GCC và GNU Make bằng cách cài phần mềm Dev-C++, đây là một IDE cho
lập trình C/C++ rất nổi tiếng trên Windows, nó có tích hợp bộ biên dịch GCC và cả công
cụ GNU Make, vì thế ta chỉ cần cài Dev-C++ rồi đưa đường dẫn của thư mục bin (trong
thư mục cài đặt Dev-C++) vào biến Path của Windows là có thể sử dụng được GCC và
GNU Make. Ta có thể tải Dev-C++ miễn phí tại http://bloodshed-dev-c.en.softonic.com/
Ta sử dụng Embedded Unit bằng cách thiết kế các test case và biên dịch thành 1
file thực thi, chạy file thực thi đó để xem kết quả kiểm thử ngay trên máy tính của mình,
vì thế nên ta không sử dụng trình biên dịch SDCC để chạy các phép kiểm thử.
Cấu trúc của Embedded Unit được miêu tả như hình dưới đây:

36
Hình 15. cấu trúc của Embedded Unit

2. Cải tiến để sử dụng Embedded Unit cho lập trình C cho 8051
Ta lập trình C cho 8051, chương trình C của ta sẽ có các biến đặc biệt, đó là các
thanh ghi, các bit đặc biệt, các chân của vi điều khiển, vì vậy khi ta viết chương trình
kiểm thử có các biến này, nếu ta sử dụng GCC để chạy thì sẽ báo lỗi, không thực thi được
do thư viện của GCC không có các biến đó (thiếu thư viện).
Tôi đã có một cải tiến đơn giản mà khá hiệu quả, giúp cho ta có thể chạy được các
phép kiểm thử cho 8051 với GCC mà không bị báo lỗi, đó là tạo một file thư viện 8051.h,
file này sẽ chứa các biến có tên trùng với các biến đặc biệt của 8051, có thể gọi đây là các
biến giả, có tác dụng thay thế cho các biến thật khi ta sủ dụng các phép kiểm thử. Khi viết
chương trình kiểm thử, ta sẽ include file 8051.h này vào, và khi chạy các phép kiểm thử
đó với GCC, sẽ không bị báo lỗi vì thiếu thư viện nữa.
Dưới đây là một số khai báo trong file 8051.h :
unsigned char P0;
unsigned char P1;
unsigned char P2;
…….
unsigned char TCON ;
unsigned char IE ;

37
…..
unsigned char P0_0;
unsigned char P0_1;
Các thanh ghi được khai báo kiểu unsigned char vì mỗi thanh ghi có 8 bit, giá trị
của nó sẽ nhận từ 0 đến 255, và kiểu unsigned char cũng là kiểu có 8 bit, giá trị từ 0 đến
255. Các bit đặc biệt của vi điều khiển 8051 ta cũng khai báo la kiểu unsigned char.

3. Ví dụ kiểm thử chương trình C cho 8051 với Embedded Unit


Sau đây là một ví dụ nhỏ về kiểm thử chương trình cho 8051 với Embedded Unit có
sử dụng file 8051.h ở trên
Ta có 2 file là function.h và function.c chứa khai báo và cài đặt của một số hàm
dùng cho chương trình 8051.
function.h :
int getPin3_0();
int getPort1();
function.c :
#include "function.h"
#include <8051.h>

int getPin3_0( )
{
return P3_0;
}

int getPort1( )
{
return P1;

38
}
2 file trên cài đặt 2 hàm là getPin3_0( ) và getPort1( ), hàm getPin3_0( ) có tác dụng
trả về giá trị chân P3.0 còn hàm getPort1( ) trả về giá trị của thanh ghi cổng P1.
Ta sẽ viết chương trình kiểm thử cho 2 hàm này bằng cách tạo file functionTest.c
như sau :
#include <embUnit/embUnit.h>
#include "8051.h"
#include "function.h"

static void setUp(void)


{

static void tearDown(void)


{

}
//---------------------------------------------------
static void testGetPin3_0(void)
{
P3_0=1;
TEST_ASSERT_EQUAL_INT(1, getPin3_0( ));
}

static void testGetPort1(void)


{
P1=0x41; // giá trị 65 dưới dạng hexa
TEST_ASSERT_EQUAL_INT(65, getPort1( ));
}
//----------------------------------------------------------
TestRef FunctionTest_tests(void)

39
{
EMB_UNIT_TESTFIXTURES(fixtures) {
new_TestFixture("testGetPin3_0",testGetPin3_0),
new_TestFixture("testGetPort1",testGetPort1),
};
EMB_UNIT_TESTCALLER(FunctionTest,"FunctionTest",setUp,
tearDown,fixtures);
return (TestRef)&FunctionTest;
}
//------------------------------------------------------
int main (int argc, const char* argv[])
{
TestRunner_start();
TestRunner_runTest(FunctionTest_tests());
TestRunner_end();
return 0;
}

Ta phải khai báo #include <embUnit/embUnit.h> để sử dụng Embedded Unit


Framework
#include "8051.h" là để sử dụng các biến được định nghĩa trong file 8051.h
#include "function.h" để kiểm thử các hàm được khai báo trong đó.
Giống như nhiều Unit Test Framework khác, ta bắt buộc phải khai báo 2 phương
thức setup( ) và teardown( ) để làm thủ tục khi bắt đầu chạy test và kết thúc các test, ở đây
tôi cài đặt 2 phương thức này là rỗng, không làm gì cả.
2 phương thức testGetPin3_0( ) và testGetPort1( ) là 2 phương thức test mà ta
dùng để test các hàm trong function.h
FunctionTest_tests(void) là hàm tổ chức test, nó giống như các test suite ( bộ kiểm
thử trong các công cụ unit test khác ), hàm này có kiểu trả về là TestRef, đây là kiểu con
trỏ trỏ đến kiểu Test trong Embedded Unit

40
Cuối cùng là hàm main, hàm này sử dụng các macro được định nghĩa trong
Embedded Unit để thực thi các test đã khai báo.
Các file này ta để cùng trong một thư mục, thư mục này cũng chứa file 8051.h, và
chứa 2 thư mục của Embedded Unit là embUnit và lib đã đề cập ở phần trên.
Ta tạo makefile như sau:
CC = gcc
CFLAGS = -O
INCLUDES = .
LIBS = lib
RM = rm
TARGET = FunctionTest
OBJS = functionTest.o function.o

all: $(TARGET)
$(TARGET): $(OBJS)
$(CC) -o $@ $(OBJS) -L$(LIBS) -lembUnit

.c.o:
$(CC) $(CFLAGS) -I$(INCLUDES) -c $<

clean:
-$(RM) $(TARGET) $(OBJS)

.PHONY: clean all


Test Case trong trường hợp này là:
- testGetPin3_0 :
Kiểm tra chức năng hàm getPin3_0( ).
Dữ liệu vào : P3.0 =1.
Kết quả mong đợi : getPin3_0( ) =1.
- testGetPort1:
Kiểm tra chức năng hàm getPort1( ).
Dữ liệu vào : P1=0x41.
Kết quả mong đợi : getPort1( )=65.

41
Tiến hành test:
Chạy makefile bằng cách gõ lệnh make trên môi trường dòng lệnh Command
Prompt (cmd), file thực thi FunctionTest.exe, chạy file này, nó sẽ thông báo cho ta kết
quả thực thi các phép kiểm thử như sau :
..
OK ( 2 tests)
Kết quả này có nghĩa là 2 phép kiểm thử của ta đã chạy đúng
Ta thử quan sát phép một kiểm thử chạy sai bằng cách sửa lại hàm testGetPort1( )
thành như sau :
static void testGetPort1(void)
{
P1=0x41;
TEST_ASSERT_EQUAL_INT(66, getPort1( )); // sửa 65 thành 66
}
Sau đó chạy lại makefile và chạy file thực thi FunctionTest.exe, ta sẽ nhận được kết
quả như sau:

..
FunctionTest.testGetPort1 (functionTest.c 25) exp 66 was 65
run 2 failures 1
Kết quả này cho thấy phép kiểm thử ở hàm testGetPort1( ) chạy sai, cụ thể ở dòng
25 trong file functionTest.c, kết quả mong đợi là 66 trong khi kết quả nhận được là 65.
Thông báo lỗi này ngắn gọn nhưng lại khá chi tiết, ta có thể thấy rõ được lỗi xảy ra ở đâu.

42
Phụ lục
Phụ lục A: Kiến trúc vi điều khiển 8051
Để có thể lập trình C cho hệ thống 8051 không dùng hệ điều hành, ta cần phải nắm
được cấu trúc phần cứng của vi điều khiển vì chương trình của ta làm việc trực tiếp trên
nền phần cứng.
Vi điều khiển 8051 bao gồm bộ xử lý (Control Unit) bên trong , bộ nhớ RAM và các
thanh ghi, các khối điều khiển số học và điều khiển bộ nhớ. Ngoài ra, còn có các bộ tạo
xung nhịp, kênh truyền nối tiếp và song song, các điều khiển ngắt và các cổng vào ra [1].
Sơ đồ chân của 8051
Sơ đồ chân là hình ảnh mô phỏng vi điều khiển, giống như một bản vẽ dể người ta
có thể hình dung một cách trực quan về vi điều khiển đó.
8051 có 40 chân, trong đó 4 cổng vào ra (P0,P1, P2, P3), mỗi cổng gồm 8 chân
(tương ứng với 8bit của 1 byte), và đều có chức năng nhận và xuất dữ liệu. Riêng cổng P3
là một cổng đặc biệt, còn thêm những chức năng khác như nhận ngắt, nhận và truyền dữ
liệu nối tiếp [1].
Mỗi chân của vi điều khiển là một bit, gồm 2 mức trạng thái là “cao và thấp”. 8
chân cùng loại tạo nên 1 cổng (8 bit).
VD : cổng P1 bao gồm 8 chân từ P1.0 đến P1.7
cổng P0 bao gồm 8 chân từ P0.0 đến P0.7

43
Hình 1. Sơ đồ chân của 8051 [11] .
- Từ chân 32->39: Cổng vào ra P0, tương ứng với các chân P0.0 --> P0.7 (8bit).
- Từ chân 1->8: Cổng vào ra P1.
- Từ chân 21 -> 28: Cổng vào ra P2.
- Từ chân 10->17: Cổng vào ra P3.
Riêng cổng P3, mỗi bit có thêm chức năng như dưới đây :
- P3.0 - RxD : chân nhận dữ liệu nối tiếp khi giao tiếp RS232(Cổng COM ).
- P3.1 - TxD : phần truyền dữ liệu nối tiếp khi giao tiếp RS232.
- P3.2 - INTO : interrupt 0 , ngắt ngoài 0.
- P3.3 - INT1: interrupt 1, ngắt ngoài 1.
- P3.4 - T0 : Timer0, đầu vào bộ định thời 0.
- P3.5 - T1 : Timer1, đầu vào bộ định thời 1.
- P3.6 - WR: Write, điều khiển ghi dữ liệu.

44
- P3.7 - RD: Read , điều khiển đọc dữ liệu.
- Chân Vcc(40) và chân GND(20): Cấp nguồn cho vi điều khiển. Chân 40 bạn nối
với +5V và chân 20 nối với mass (nối đất).
- Chân 18 và chân 19 (XTAL 2 và XTAL 1): Nối với bộ dao động thạch anh
(crystal) nhằm tạo xung nhịp cho VĐK. Hai chân này mỗi chân bạn nối với một đầu thạch
anh. Ngoài ra, tại mỗi chân, bạn nối với một tụ 33pF xuống mass để bù nhiệt và ổn định
hoạt động cho vi điều khiển.
- Chân 9 (RST): Dùng để Reset VĐK. Khi chân này được đưa lên mức áp cao trong
khoảng thời gian từ 2 chu kỳ máy trở lên thì VĐK sẽ được reset đưa về tình trạng lúc ban
đầu. Chân này bạn nối với một điện trở 8,2K, nối với một nút ấn đưa lên nguồn +5V. Khi
nhấn nút, chân số 9 sẽ được đưa lên mức áp cao và reset cho VĐK.
- Chân PSEN: Bạn nối lên +5V để chỉ thị sử dụng chương trình từ ROM.
- Chân 30 (ALE : Adress Latch Enable) là tín hiệu điều khiển xuất ra của 8051, nó
cho phép phân kênh bus địa chỉ và bus dữ liệu của cổng P0.
- Chân 31 (EA : Eternal Acess) cho phép chọn bộ nhớ ROM ngoài.
Đối với 8051 thì : EA = 5V : Chọn ROM nội. EA = 0V : Chọn ROM ngoại.
Thanh ghi: Mỗi thanh ghi là một ô nhớ 8 bit.
Vi điều khiển cung cấp cho chúng ta 8 thanh ghi mặc định là từ R0 đến R7. Có
những thanh ghi có chức năng đặc biệt và mỗi bit của nó đảm nhận 1 chức năng khác
nhau, mỗi bit đó có một tên riêng. Vì thế chúng ta có thể thay đổi mức trạng thái của
từng bit thay vì phải tác động lên cả thanh ghi. Điều đó sẽ giúp cho việc xử lý tín hiệu trở
nên dễ dàng hơn. Thao tác lập trình trở nên đơn giản hơn [1].
Dữ liệu trong mỗi thanh ghi là một con số từ 00H->FFH (theo hệ hexa) hay từ
00000000B đến 11111111B( theo hệ nhị phân). Như các bạn thấy các số trong hệ nhị
phân có 8 chữ số tượng trưng cho 8 bit của mỗi thanh ghi. Mỗi bit có 2 trạng thái ứng với
2 số là 0-mức thấp và 1-mức cao. Giá trị hexa chẳng qua chỉ là một cách viết gọn của
những người đã quen với công việc lập trình. Chúng ta có thể chuyển từ nhị phân sang
hexa một cách dễ dàng nhờ máy tính.

45
Vì sao viết hexa lại dễ hơn viết nhị phân. bởi vì trong lập trình vi điều khiển dữ liệu
nạp cho mỗi thanh ghi đặc biệt là cố định ứng với mỗi chức năng khác nhau.Vì vậy khi
quen rồi bạn viết bằng hexa sẽ nhanh gọn hơn. Chúng ta cũng có thể sử dụng số thập
phân.
Ngoài các thanh ghi mặc định, còn có một số những thanh ghi đặc biệt (SFR) khác
như đã đề cập ở trên trong phần “bit địa chỉ”. 8051 có 21 thanh ghi chức năng đặc biệt
SFR chiếm phần trên của Ram nội từ địa chỉ 80H đến FFH .Các thanh ghi đặc biệt mang
chức năng khác nhau chúng được cấu tạo từ 8 bit, và chúng ta có thể lấy dữ liệu trực tiếp
từ địa chỉ bit hoặc thông qua tên gọi của của chúng.
Một số thanh ghi đặc biệt là:
- Các thanh ghi của bộ định thời:
TMOD là thanh ghi chọn chế độ định thời.
TCON (định địa chỉ từng bit) là thanh ghi điều khiển chế độ định thời.
TL0 - TH0 là 2 thanh ghi quy ước byte thấp và byte cao của bộ định thời 0.
TL1 - TH1 là 2 thanh ghi quy ước byte thấp và byte cao của bộ định thời 1.
- Thanh ghi chính (thanh ghi A):
Thanh ghi tính toán chính của vi điều khiển 8051 ACC (Accumulator). Là thanh ghi
đặc biệt của 8051 dùng để thực hiện các phép toán của CPU, thường kí hiệu là A.
- Thanh ghi phụ (thanh ghi B):
Thanh ghi tính toán phụ của vi điều khiển 8051 là B. Thanh ghi B ở địa chỉ F0H
được dùng chung với thanh chứa A trong các phép toán nhân, chia. Thanh ghi B còn được
xử lý như một thanh ghi nháp. Các bit được định địa chỉ của thanh ghi B có địa chỉ từ
F0H đến F7H.

- Thanh ghi trạng thái chương trình (PSW) :


Thanh ghi trạng thái chương trình PSW là thanh ghi mô tả toàn bộ trạng thái chương
trình đang hoạt động của hệ thống
- Thanh ghi ngăn xếp (Stack Pointer) :

46
Con trỏ stack SP (stack pointer) là 1 thanh ghi 8 bit ở địa chỉ 81H. SP chứa địa chỉ
của dữ liệu hiện đang ở đỉnh của stack. Các lệnh liên quan đến satck bao gồm lệnh cất
dữ liệu vào stack và lệnh lấy dữ liệu ra khỏi stack. Việc cất vào stack làm tăng SP trước
khi ghi dữ liệu và việc lấy dữ liệu ra khỏi stack sẽ giảm SP. Vùng stack của 8051 được
giữ trong RAM nội và được giới hạn đến các địa chỉ truy xuất được bởi kiểu định địa
chỉ gián tiếp. Các lệnh PUSH và POP sẽ cất dữ liệu vào stack và lấy dữ liệu từ stack, các
lệnh gọi chương trình con (ACALL, LCALL) và lệnh trở về (RET, RETI) cũng cất và
phục hồi nội dung của bộ đếm chương trình PC (Program counter)
- Con trỏ dữ liệu DPTR :
Con trỏ dữ liệu DPTR (data pointer) được dùng để truy xuất bộ nhớ chương trình
ngoài hoặc bộ nhớ dữ liệu ngoài. DPTR là một thanh ghi 16 bit có địa chỉ là 82H (DPL,
byte thấp) và 83H (DPH, byte cao).
- Thanh ghi các cổng P0-P3 :
Các cổng P0 đến P3 cũng là những thanh ghi xuất nhập.v.v
- Thanh ghi bộ đệm truyền thông nối tiếp SBUF (Serial Data Buffer) :
Bộ đệm truyền thông được chia thành hai bộ đệm, bộ đệm truyền dữ liệu và bộ đệm
nhận dữ liệu. Khi dữ liệu được chuyển vào thanh ghi SBUF, dữ liệu sẽ được chuyển vào
bộ đệm truyền dữ liệu và sẽ được lưu giữ ở đó cho đến khi quá trình truyền dữ liệu qua
truyền thông nối tiếp kết thúc. Khi thực hiện việc chuyển dữ liệu từ SBUF ra ngoài, dữ
liệu sẽ được lấy từ bộ đệm nhận dữ liệu của truyền thông nối tiếp.
- Các thanh ghi điều khiển :
Các thanh ghi điều khiển đặc biệt như IP, IE, TMOD, TCON, SCON và PCON là
các thanh ghi điều khiển và ghi nhận trạng thái của hệ thống ngắt, bộ đếm/định thời,
truyền thông nối tiếp.
Ngắt ( Interrupt )
Ngắt là một sự kiện bên trong hoặc bên ngoài làm ngắt bộ vi điều khiển để báo cho
nó biết rằng thiết bị cần dịch vụ của nó. Mỗi khi có một thiết bị bất kỳ cần đến dịch vụ
của nó thì nó bao cho bộ vi điều khiển bằng cách gửi một tín hiệu ngắt. Khi nhận được tín
hiệu ngắt thì bộ vi điều khiển ngắt tất cả những gì nó đang thực hiện để chuyển sang phục

47
vụ thiết bị. Chương trình đi cùng với ngắt được gọi là trình dịch vụ ngắt ISR (Interrupt
Service Routine) hay còn gọi là trình quản lý ngắt (Interrupt handler).
Đối với mỗi ngắt thì phải có một trình phục vụ ngắt ISR hay trình quản lý ngắt. Khi
một ngắt được gọi thì bộ vi điều khiển chạy trình phục vụ ngắt, sau đó vi điều khiển quay
trở lại công việc đang làm trước khi có ngắt. Đối với mỗi ngắt thì có một vị trí cố định
trong bộ nhớ để giữ địa chỉ ISR của nó. Nhóm các vị trí nhớ được dành riêng để gửi các
địa chỉ của các ISR được gọi là bảng véc tơ ngắt
Bảng 1. Bảng véc tơ ngắt của 8051

Ngắt Địa chỉ ROM Cờ

Bật lại nguồn (RESET) 0000 RST

Ngắt phần cứng ngoài (INT0) 0003 IE0

Ngắt Timer0 (TF0) 000B TF0

Ngắt phần cứng ngoài 1 (INT1) 0013 IE1

Ngắt Timer1 (TF1) 001B TF1

Ngắt COM nối tiếp (RI và TI) 0023 RI hoặc TI

Tổ chức bộ nhớ
Các vi điều khiển thuộc họ 8051 đều tổ chức thành 2 không gian chương trình và dữ
liệu. Kiến trúc vi xử lý 8 bit của 8051 này cho phép truy nhập và tính toán nhanh hơn đối
với không gian dữ liệu nhờ việc phân chia 2 không gian bộ nhớ chương trình và dữ liệu
như trên. Tuy nhiên bộ nhớ ngoài được truy nhập bởi hệ thống 16 bit địa chỉ vẫn có thể
thực hiện nhờ thanh ghi con trỏ.
Bộ nhớ chương trình (ROM, EPROM) là bộ nhớ chỉ đọc, có thể mở rộng tối đa
64Kbyte. Vói họ vi điều khiển 8051, bộ nhớ chương trình được tích hợp sẵn trong chip có
kích thước nhỏ nhất là 4kByte. Với các vi điều khiển không tích hợp sẵn bộ nhớ chương

48
trình trên chip, buộc phải thiết kế bộ nhớ chương trình bên ngoài. Ví dụ sử dụng EPROM:
2764 (64Kbyte), khi đó chân PSEN phải ở mức cao (5V).

Hình 2. Cấu trúc vi điều khiển 8051


Bộ nhớ dữ liệu (RAM) tồn tại độc lập so với bộ nhớ chương trình. Họ vi điều khiển
8051 có bộ nhớ dữ liệu tích hợp trên chip nhỏ nhất là 128byte và có thể mở rộng với bộ
nhớ dữ liệu ngoài lên tới 64kByte. Với những vi điều khiển không tích hợp ROM trên
chip thì vẫn có RAM trên chip là 128byte. Khi sử dụng RAM ngoài, CPU đọc và ghi dữ
liệu nhờ tín hiệu trên các chân RD và WR. Khi sử dụng cả bộ nhớ chương trình và bộ nhớ
dữ liệu bên ngoài thì buộc phải kết hợp chân RD và PSEN bởi cổng logic AND để phân
biệt tín hiệu truy xuất dữ liệu trên ROM hay RAM ngoài[1].

Phụ lục B: Hướng dẫn sử dụng Embedded Unit


Sau khi tải về từ http://embunit.sourceforge.net/ , ta giải nén Embedded Unit, được
thư mục embunit có cấu trúc như sau [7] :

49
Hình 16. thư mục mã nguồn của Embedded Unit
Ta tạo một thư mục có tên là lib trong thư mục gốc, sau đó ta vào trong thư mục
“embunit/embUnit” ( thư mục embUnit con ở bên trong thư mục gốc), chạy makefile tại
đây, sẽ có một file thư viện libembunit.a được tạo ra trong thư mục lib vừa tạo, đây
chính là thư viện được sử dụng để chạy các phép kiểm thử.
Thư mục samples chứa một chương trình test ví dụ đã được tạo sẵn, thư mục Tests
chứa chương trình ví dụ để test chính một số file trong thư mục embUnit.
Để tạo các phép kiểm thử và chạy chúng, ta chỉ cần sử dụng thư mục embUnit và
thư mục lib, vì vậy tạm thời ta không cần quan tâm đến 2 thư mục textui và thư mục
tools, đây là 2 thư mục chứa một số tiện ích nâng cao khi sử dụng Embedded Unit.
Một số hàm assert dùng trong Embedded Unit :
Bảng 2. Các hàm assert của Embedded Unit

Assertion Ghi chú


xác nhận xâu kí tự thực và xâu
TEST_ASSERT_EQUAL_STRING(expected,actual)
mong đợi là tương đương
xác nhận số nguyên thực tế và số
TEST_ASSERT_EQUAL_INT(expected,actual)
nguyên mong đợi là tương đương
TEST_ASSERT_NULL(pointer) xác nhận con trỏ có giá trị NULL
TEST_ASSERT_MESSAGE(condition, message) xác nhận điều kiện là đúng (khác 0)
TEST_ASSERT(condition) xác nhận điều kiện là đúng (khác 0)
Thông báo xác nhận (assertion) bị
TEST_FAIL(message)
lỗi, không có test được thực hiện

50
Trong thư mục samples đã chứa các ví dụ được viết sẵn về kiểm thử sử dụng
Embedded Unit, ta vào thư mục này chạy makefile, một file thực thi sẽ được tạo ra, chạy
file này, nó sẽ hiển thị kết quả các phép kiểm thử trong ví dụ đó. Cách viết các test cũng
khá đơn giản, ta có thể xem các file mã nguồn và không có gì khó khăn để hiểu chúng.

51
Tài liệu tham khảo
[1] DKS Group, giáo trình 8051 cơ bản, nguồn http://www.ebook.edu.vn
[2] http://my.opera.com/kids196870 , mô phỏng 8051 trên Proteus
[3] Phạm Quốc Hiệp, hướng dẫn Proteus, nguồn http://www.ebook.edu.vn
[4] http://bit.kuas.edu.tw/~8051/ , 8051 Development tools.
[5] http://en.wikipedia.org/wiki/Embedded_system
[6] http://en.wikipedia.org/wiki/Software_testing
[7] http://embunit.sourceforge.net/
[8] http://mcu-programming.blogspot.com/2006/09/installing-mide-51-and-sdcc-and-
for.html
[9] http://sdcc.sourceforge.net/doc/sdccman.html/
[10] http://www.dontronics.com/8051sim.html
[11] Bashir Oyetunji, Complete 8051 Guide, University of Saskatchewan, IEEE SPARC
2006-07
[12] Bar t Broekman and Edwin Notenboom, Testing Embedded Software, Website:
www.it-minds.com, www.aw.professional.com, First Published in Great Britain in 2003,
từ trang 21 đến trang 26.
[13] Edward A. Lee, Embedded Software, November 1, 2001.
[14] Jakob Engblom, Guillaume Girard, Bengt Werner, Testing Embedded Software
using Simulated Hardware, Virtutech AB, Norrtullsgatan 15, 11327 Stockholm, Sweden.

52

You might also like