Giao tiếp AVR với máy tính (II)

( 15 Votes )
Nội dung Các bài cần tham khảo trước

Bài 1

  1. RS232 Terminal
  2. Lập trình giao tiếp với cổng COM bằng VB và Visual C++
    Download ví dụ

IV. RS232 Terminal

     RS232 Terminal là thuật ngữ dùng chỉ các phần mềm máy tính có khả năng nhận và phát dữ liệu ra cổng COM (như một thiết bị đầu cuối). Các RS232 Terminal rất hữa dụng để kiểm tra các chương trình truyền nhận dữ liệu qua cổng COM. Hệ điều hành Windows có sẵn một RS232 Terminal gọi là “Hyper Terminal”. Công cụ này khá tốt cho mục đích giao tiếp thông thường. Để sử dụng Hyper Terminal bạn hãy vào “All Programs/ Accessories/Communications/Hyper Terminal” hoặc đơn giản là vào Run và gõ lệnh “hypertrm”. Một hộp thoại có tên “Connection Description” xuất hiện, hãy điền một tên bất kỳ cho cuộc gọi và nhấn OK. Trong hộp thoại tiếp theo, Connect to, hãy chọn cổng COM mà bạn muốn giao tiếp, và nhấn OK. Cuối cùng là hộp thoại COM Properties cho phép bạn thiết lập các thông số giao tiếp như Baudrate, Parity bit, Stop bit như trong hình 11, chú ý hãy chọn Flow control là "none"…và nhấn OK.

HyperTerminalHyperTerminalHyperTerminal

Hình 11. Thiết lập cuộc gọi.

   Giả sử bạn chạy chương trình ví dụ trong phần demo của stdio, bạn thu được giao diện HyperTerminal như trong hình 12.

HyperTerminal

Hình 12. Giao diện Hyper Terminal.

     Trong bài học này, tôi giới thiệu một chương trình Terminal có tên Hercules của HW group (http://www.hw-group.com/products/hercules/index_en.html). Đây là một Terminal miễn phí rất tốt, dễ sử dụng và ổn định. Ngoài chức năng RS232 Terminal, Hercules còn được dùng cho các giao diện khác như TCP, UDP…Bạn chỉ cần download chương trình về và chạy file Hercules.exe. Bạn thu được giao diện Hercules như sau:

Hercules

Hình 13. Giao diện phần mềm Hercules.

     Hãy chọn tab Serial để giao tiếp với cổng COM, thiết lập các thông số như tên cổng, Baudrate, Data frame…rồi nhấn nút Open, bạn đã sẵn sàng để sử dụng Hercules. 
     Giả sử bạn có 3 cổng COM ảo tên là COM2, COM3 nối với nhau. Hãy sử dụng ví dụ trong phần stdio, trong mạch điện mô phỏng Proteus của ví dụ hãy xóa thiết bị ảo Terminal. Hãy thêm vào một thiết bị tên là COMPIM bằng cách search với keyword là COMPIM (hoặc chạy file AVR_STD_Terminal.DSN trong thư mục AVR_STD của ví dụ trên). Kết nối như trong hình 14. Sau đó right click vào COMPIM để vào hộp thoại “Edit component”, đổi thông số Physical port thành CÒM, đổi Virtual Baud Rate thành 38400. Chạy lại mô phỏng bạn sẽ thấy kết quả hiển thị trên Hercules như trong hình 14. Type 1 phím bất kỳ để thấy mã ASCII.
      Đây là ví dụ cho phép bạn giao tiếp giữa chương trình AVR mô phỏng trong Proteus và ứng dụng chạy trên Windows thông qua các cổng COM ảo. Nó thực chất là một dạng giao tiếp máy tính bằng cổng COM, dành cho trường hợp bạn chưa có mạch AVR thật. Mấu chốt nằm ở thiết bị COMPIM trong Proteus. COMPIM thực chất là mô hình cổng COM  tồn tại trên máy tính của bạn. Trong trường hợp này chúng ta dùng Eltima VSPE (hoặc VSPD) để tạo 2 cổng COM ảo trên máy tính là COM2 và COM3, chúng được đấu chéo với nhau. Chúng ta set COMPIM trong Proteus là  COM2 trong khi cổng trên Hercules là COM3. Khi chạy mô phỏng, AVR sẽ gởi dữ liệu ra COMPIM (tức COM2), COM2 truyền đến COM3 và hiển thị trên Hercules. Chúng ta có thể tự viết các chương trình trên Windows để nhận và gởi giá trị qua COM thay cho Hercules. Trong phần tiếp theo tôi sẽ hướng dẫn bạn tạo chương trình như thế.

Hercules

Hình 14. Kết hợp mô phỏng và Hercules. 

V. Lập trình giao tiếp với cổng COM bằng Visual Basic và Visual C++

     Các chương trình Terminal đề cập ở trên là một dạng ứng dụng giao tiếp  giữa máy tính và vi điều khiển ở mức độ đơn giản. Trong nhiều trường hợp, yêu cầu giao tiếp đòi hỏi mức độ phức tạp cao hơn, ví dụ lưu trữ dữ liệu hay vẽ đồ thị biến thiên, thì người dùng cần phải tự viết các chương trình trên máy tính của riêng mình. Phần này tôi hướng dẫn bạn các viết chương trình trên máy tính để truyền và nhận dữ liệu từ cổng COM bằng 2 ngôn ngữ lập trình Visual Basic và Visual C++ (6.0) trên nền Windows. Chú ý, mục đích bài viết này là về AVR nên phần viết ứng dụng trên Windows tôi chỉ trình bày một cách đơn giản cốt cho bạn nắm được nguyên lý. Để phát triển các ứng dụng phức tạp hơn người đọc cần tự trang bị cho mình kiến thức về lập trình trên Windows. Trong tất cả các hướng dẫn bên dưới tôi giả sử là người đọc ít nhất biết được cách tạo Project trong Visual Basic hoặc/và Visual C++.

1. Viết chương trình giao tiếp cổng COM bằng Visual Basic 6.0

    Kể từ các phiên bản Windows 2000 về sau, việc giao tiếp với các cổng máy tính truyền thống, như cổng LPT, trong Windows tương đối khó khăn. Tuy nhiên, với cổng COM thì có điều may mắn là Microsoft có cung cấp một công cụ (thật ra là một control – điều khiển) có tên gọi là “Microsoft Communication Control” hay viết tắt là MSComm. MSComm xuất hiện trong các phần mềm lập trình nổi tiếng của MS như Visual Basic hay Visual C++ dưới dạng một “điều khiển”. Vì là một “điều khiển” được thiết kế sẵn cho cổng COM nên MSComm chứa tất cả các công cụ cần thiết để giao tiếp với cổng này, công việc của người viết chương trình chỉ đơn giản là khai báo và sử dụng. Để minh họa cách sử dụng MSComm trong Visual Basic, hãy làm theo hướng dẫn bên dưới.
     Chạy Visual Basic 6, vào menu “File/New Project” và tạo một “Standard EXE”. Bạn sẽ thấy một Project có tên là “Project1” kèm một hộp thoại nền (form chính) có tên Form1 xuất hiện. Bạn có thể đặt tên bất kỳ cho Project và form chính. Hãy quan sát ví dụ trong hình 15. Từ thanh công cụ Toolbox hãy click vào control “textbox” và vẽ lên “form” chính 2 textbox tên là txtOuput và txtInput (xem hình 15) (đổi tên các textbox trong cửa sổ Properties  nằm ở gốc thấp, bên phải).  với txtOutput, hãy set thông số Multiple thành True và ScrollBars thành  “3 – Both”

VB

Hình 15. Giao diện Visual Basic 6.

Tiếp theo hãy đưa control MSComm vào form chính.  Theo mặc định, control MSComm không có sẵn trong Toolbox của Visual Basic, chúng ta cần thêm vào Toolbox trước khi sử dụng. Để thêm MSComm vào Toolbox, chọn Menu “Project/Components” bạn sẽ thấy một hộp thoại tên Components xuất hiện như trong hình 16. Tìm và click chọn vào ô “Microsoft Comm Control 6.0” như trong hình và nhấn OK. Lúc này, quan trong Toolbox của VB bạn sẽ thấy icon của MSComm xuất hiện. Click vào icon này và vẽ 1 đối tượng MSComm lên form chính (xem lại hình 15). Giữ tên mặc định của đối tượng này là MSComm1.

VB     VB

Hình 16. Thêm công cụ MSComm vào Project.

Viết code:
     Mục đích của ví dụ này như sau: dữ liệu nhận về từ cổng COM sẽ hiển thị trên textbox txtOutput, và khi người dùng type 1 ký tự vào txtInput ký tự sẽ được truyền đi qua cổng COM.
Trước hết, hãy doubleclick vào form chính, viết đoạn code sau vào sự kiện Form_Load():
VB

      Mục đích của đoạn code này là cài đặt các thông số cho MSComm1. 
      - Thông số CommPort = 3 nghĩa là chúng ta muốn kết nối với cổng COM3. Thông số này do người dùng thay đổi tùy theo cổng COM chúng ta muốn giao tiếp. 
      - Thông số Setting = “38400, N, 8,1”  nghĩa là tốc độ Baud=38400, không sử dụng bit Parity, độ dài khung truyền bằng 8 và có 1 bit Stop.  
      -  RThreshold = 1 nghĩa là khi có 1 ký tự đến cổng COM, ngắt nhận dữ liệu sẽ xảy ra.
      -  InputLen = 1 nghĩa là khi đọc dữ liệu từ bộ đệm nhận, chúng ta sẽ đọc lần lượt 1 ký tự (1 byte).
      -  PortOpen = True tức cho phép “mở” cổng COM để sẵn sàng giao tiếp.
     Tiếp theo, doubleclick vào biểu tượng của MSComm1 trên form chính để viết code vào sự kiện MSComm1_onComm():
VB

      Sự kiện onComm() thực chất là trình phục vụ ngắt nhận dữ liệu của MSComm. Khi có 1 byte dữ liệu gởi đến bộ đệm của cổng COM (số lượng byte do RThreshold quy định) thì sự kiện onComm sẽ xảy ra (ngắt xảy ra), trong sự kiện này chúng ta sẽ viết code để nhận và xử lý dữ liệu. Dòng 2 chúng ta khai báo 1 biến tạm thời tên là InputText với kiểu dữ liệu string. Chú ý là sự kiện onComm có thể xảy ra do nhiều nguyên nhân, ở đây chúng ta chỉ quan tâm đến trường hợp dữ liệu truyền đến, dòng 3 là một dạng “lọc” sự kiện, chúng ta chỉ thực hiện các dòng code bên trong khi mà sự kiện comEvReceive xảy ra (dữ liệu được nhận về): If Me.MSComm1.CommEvent = comEvReceive Then. Việc quan trọng duy nhất để đọc dữ liệu được gởi đến COM là đọc bộ đệm Input của MSComm như trong dòng code 4: InputText = MSComm1.Input. Sau dòng lệnh này dữ liệu sẽ được chứa trong biến tạm InputText. Tiếp theo chúng ta chỉ cần cộng dồn các ký tự nhận về vào nội dung của Textbox txtOutput để hiển thị lên màn hình (dòng 5) : txtOutput.Text = txtOutput.Text + InputText. Dòng code 6 làm nhiệm vụ đưa con trỏ đến cuối nội dung của txtOutput để tiện cho việc quan sát dữ liệu.
Cuối cùng, doubleclick vào Textbox txtInput và tìm sự kiện KeyPress để viết các dòng code sau:
VB
     Sự kiện txtInput_KeyPress xảy ra khi người dùng nhấn 1 phím nào đó vào txtInput. Dòng code Me.MSComm1.Output = Chr(KeyAscii) thực hiện việc gởi giá trị của KeyAscii ra  cổng COM, trong đó KeyAscii là mã Ascii của phím được nhấn.
     Bạn đã hoàn tất viết chương trình truyền nhận dữ liệu qua cổng COM bằng Visual Basic. Để kiểm tra chương trình của bạn, hãy thực hiện mô phỏng theo các bước sau:
      -  Dùng 1 trong 2 phần mềm VSPD hoặc VSPE để tạo 2 cổng COM ảo là COM2 và COM3, đấu chéo chúng với nhau (xem lại phần cổng COM ảo). 
      -  Tìm trong thư mục chứa ví dụ AVR_STD và chạy file mô phỏng bằng phần mềm Proteus  AVR_STD_Terminal.DSN.
      -  Quay lại Visual Basic, nhấn nút Run hoặc F5 để chạy Project vừa mới viết. 
      -  Nhấn Run trong Proteus để mô phỏng mạch điện AVR_STD_Terminal.DSN. Bạn sẽ thấy kết một số text xuất hiện trông txtOutput như trong hình 17. Click vào txtInput và type bất kỳ một phím nào đó để xem kết quả. So sánh với mô phỏng trong hình 14 bạn thấy nét tương đồng. Như thế bạn đã thành công khi tự viết cho mình 1 ứng dụng giap tiếp với cổng COM bằng Visual Basic.

2. Viết chương trình giao tiếp cổng COM bằng Visual C++ 6.0

     Phần này chúng ta sẽ thực hiện một ví dụ truyền nhận qua cổng COM tương tự như ví dụ ở phần trên nhưng sử dụng Visual C++ (VC++) của Microsoft. Mục đích chính là hướng dẫn cách sử dụng MSComm trong VC++, vì thế tôi sẽ trình bày rất sơ sài những phần như tạo Project trong VC++. Bạn đọc cần tự trang bị thêm kiến thức về lập trình VC++. Một trong những tài liệu rất hay cho người mới học lập trình VC là “Teach Yourself Visual C++ 6 in 21 Days” của  “Sams Teach Yourself”, bạn có thể tìm đọc nếu thấy cần thiết.
     Từ VC++ hãy vào menu “File/New” để tạo 1 Project mới. Chọn loại Project là “MFC AppWizard (exe)”, trong Ô Project Name đặt tên cho Project là AVR_PC, nhấn OK. Trong hộp thoại thứ 2 hãy chọn “Dialog based” cho loại Project, và nhấn Finish để tạo Project (các bước khác để mặc định).

 VC

Hình 17. Tạo Project MFC trong VC++6.

      Khi Project mới được tạo sẽ có 1 hộp thoại chính (Dialog) xuất hiện với 2 button “OK” và “Cancel” trên đó. Dùng công cụ “Edit” để thêm vào 2 “Edit box” và sắp xếp lại giao diện như hình 19. Right click vào các Edit box và chọn Proterties từ các Popup_menu, lần lượt đổi ID của 2 Edit box thành IDC_OUTPUT và IDC_INPUT.
      Cũng giống như trong VB, Control MSComm không xuất hiện mặc định trong Toolbox của VC++, chúng ta cần thêm vào khi muốn sử dụng control này. Hãy vào menu “Project/Add to Project/ Components and Controls…”. Khi hộp thoại “Components and Control Gallery” xuất hiện bạn chọn vào thư mục “Registered ActiveX Controls” và tìm đến file “Microsoft Communications Control, Version 6.0” rồi nhấn nút insert, nhấn OK khi được hỏi bất kỳ câu hỏi gì, sau đó nhấn nút Close để đóng hộp thoại lại. Lúc này icon của MSComm sẽ xuất hiện trong Toolbox của VC++ như trong hình 19. Click chọn icon của MSComm và vẽ 1 control vào Dialog chính của Project. Theo mặc định Control này có tên IDC_MSCOMM1. 

 VC    VC

Hình 18. Thêm Control MSComm vào Toolbox trong VC++.

VC 

Hình 19. Giao diện chương trình trong Visual C++.

      Việc lập trình trong VC++ tương đối khó hơn VB (cho người mới tìm hiểu). Các thuộc tính của các Control như Edit box không được truy cập trực tiếp như Textbox trong VB. Ví dụ để gán và hiển thị một chuỗi hay số lên Edit box chúng ta phải thực hiện gán và cập nhật dữ liệu qua các biến trung gian. Ở bước này chúng ta đi tạo 2 biến cho 2 Edit box. Nhấn vào menu “View/ClassWizard” hoặc tổ hợp phím “Ctrl+W” , trong hộp thoại  “MFC ClasWizard” hãy chọn tab “Member Variables”. Click vào dòng IDC_OUTPUT (chính là edit phía trên), nhấn vào nút “Add vatiable…” và điền tên biến là “m_txtOutput” với kiểu biến là CString như trong hình 20. Lặp lại các bước trên để tạo 1 biến tên “m_txtInput” cho “IDC_INPUT”. Cuối cùng là tạo 1 biến có tên “m_comm” cho IDC MSCOMM1. Nhấn OK để đóng hộp thoại MFC ClassWizard. Từ bây giờ, chúng ta chỉ cần nhớ 3 biến “m_txtOutput”, “m_txtInput”, “m_comm” khi muốn truy cập các Edit boxes và MSComm trong lúc viết code.

 VC

Hình 20. Tạo biến txtOutput cho Edit box IDC_OUTPUT.

Viết Code:
     Nhấn Ctrl+W để mở lại ClassWizard, lần này chọn tab “Message Maps", trong ô “Class name” đảm bảo rằng “CAVR_PCDlg” được chọn. Trong ô “Object IDS” hãy chọn "CAVR_PCDlg”, ô “Messages” tìm và chọn "WM_INITDIALOGS” sau đó nhấn vào nút “Edit Code” (xem hình 21).

 VC

Hình 21. Bắt đầu viết code.

      Bây giờ bạn có thể viết code cho sự kiện “OnInitDilaog()”, đây là sự kiện xảy ra khi bạn chạy chương trình và Dialog chính được khởi động. Vì thế chúng ta sẽ cài đặt các thông số cho m_comm vào đây (m_comm là tên biến đại diện cho control IDC_MSCOMM1 mà chúng ta đã tạo ở các bước trên). Hãy thêm các dòng sau vào sau dòng “// TODO: Add extra initialization here”: 

 VC

     Năm dòng code trên tương ứng với 5 dòng trong phần Form_Load() khi viết Project bằng VB mà chúng ta đã khảo sát ở trên, vì thế tôi không cần giải thích thêm cho các dòng code này.
     Tiếp theo chúng ta sẽ viết code cho sự kiện onComm (ngắt nhận) của control MSComm, trước khi viết code hãy nhấn Ctrl+W để hiện hộp thoại ClassWizard và thực hiện 6 bước như trong hình 22 để thêm sự kiện onComm vào Project. 

 VC

Hình 22. Thêm sự kiện onComm để nhận dữ liệu từ cổng COM. 

 Viết đoạn code sa vào sự kiện onComm:
VC

      Như đã trình bày ở trên, m_comm là biến đại diện cho MSComm việc thao tác với cổng COM bây giờ thực hiên thông qua biến m_comm. Trong dòng 4 chúng ta khai báo 1 biến phụ strInput có kiểu CString dùng chứa giá trị nhận về sau này.  Cũng giống như trong VB, sự kiện onComm có thể xảy ra do nhiều nguyên nhân, chúng ta chỉ quan tâm đến trường hợp có dữ liệu đến bộ đệm, dòng 5 cho phép ‘lọc” ra sự kiện cần thiết: if (m_comm.GetCommEvent()==2 ). Dòng 6 chúng ta khai báo 1 biến phụ tên in_dat với kiểu COleVariant. COleVariant là lớp (class) của MFC, tên gọi của nó là sự kết hợp của C + OLE +VARIANT trong đó OLE là “Object Linking Embedded” là một kiểu đối tượng không có sẵn mà được “nhúng” vào, MSComm là một loại OLE. VARIANT là một kiểu biến chưa xác định. Khi bạn có môt biến x, đôi khi bạn muốn gán giá trị số cho x nhưng cũng có khi bạn lại muốn gán chuỗi ký tự cho x. Khi đó hãy khai bao x là VARIANT. Trong trường hợp MSComm, dữ liệu vào và ra của đối tượng này thuộc dạng “chưa xác định” hay VARIANT. Trong dòng 7 chúng ta chỉ đơn giản nhận giá trị từ m_comm về biến in_dat: in_dat = m_comm.GetInput().  Dòng tiếp theo chúng ta “trích” thành phần chuỗi ký tự từ biến in_dat và gán cho biến strInput: strInput=in_dat.bstrVal (một cách tương đối có thể hiểu đổi in_dat thành CString và gán cho strInput). Chúng ta phải trích CString vì các Edit box chỉ hiển thị được CString. Để hiển thị dữ liệu nhận về lên Edit box (IDC_OUTPUT) chúng ta cộng dồn biến m_txtOutput (biến đại diện của Edit box IDC_OUTPUT) bằng dòng lệnh 9: m_txtOutput+=strInput. Cuối cùng, để cho giá trị của biến m_txtOutput cập nhật lên Edit box chúng ta phải gọi hàm UpdateData với tham số FALSE như dòng 10: UpdateData(FALSE) (đây là cách làm việc của Visual C++). 
     Các dòng code từ 12 đến 14 được dùng với mục đích đưa con trỏ về cuối dòng của Edi box sau khi kết thúc quá trình nhận dữ liệu. Bạn có thể bỏ qua nếu thấy không cần thiết.
     Viêc cuối cùng là viết code cho Edit box bên dưới (IDC_INPUT) để khi chúng ta gõ (type) vào đấy, ký tự sẽ được gởi đến cổng COM. Nhấn Ctrl+W và thực hiện các bước bên dưới để thêm vào sự kiện onChange. 

 VC

Hình 23. Thêm sự kiện onChange cho IDC_INPUT.

     Hãy viết đoạn code sau vào sự kiện onChange của Edit box Input: 

VC

     Khi người dùng type 1 ký tự nào đó vào Edit box, sự kiện onChange xảy ra, khi đó chúng ta sẽ trích ký tự cuối cùng trong nội dung của Edit box bên dưới mà đại diện là biến m_txtInput bằng dòng lệnh 11: tmpStr=m_txtInput.Right(1). Trong đó tmpStr là một biến tạm khai báo ở dòng 9. Chú ý rất quan trong khi muốn đọc nội dung của Edit box chúng ta cần gọi hàm UpdateData với tham số TRUE trước đó như trong dòng 10. Sau cùng, gọi phương phương thức SetOutput của đối tượng MSComm để gởi giá trị ra cổng COM: m_comm.SetOutput(COleVariant(tmpStr)). Để gởi một ký tự (hay chuỗi ký tự) ra cổng COM trước hết chúng ta cần “ép kiểu” ký tự đó về COleVariant vì như đã trình bày, MSComm chỉ làm việc với COleVaraint. Đoạn COleVariant(tmpStr) thực hiện việc “ép kiểu” này. 
     Sau khi viết xong đoạn code cho sự kiện onChange bạn có thể nhấn tổ hợp phím Ctrl+F5 để chạy chương trình. Dùng mạch điện AVR_STD_Terminal.DSN và chạy mô phỏng như trong phần lập trình với VB. Kết quả thu được sẽ như trong hình 24.

 VC

Hình 24. Giao tiếp giữa AVR và Visual C++.

Mời bạn tham khảo thêm phần mềm gCOM, một công cụ giao tiếp, lưu trữ dữ liệu và vẽ đồ thị cổng COM