Việc thiết kế Module Ethernet trên vi điều khiển PIC18F67J60 nhằm ứng dụng đo lường và điều khiển có ý nghĩa rất lớn, có thể ứng dụng trong nhiều lĩnh vực của đời sống xã hội và trong công nghiệp. Ngoài ra, module Ethernet trên vi điều khiển PIC18F67J60 cũng phục vụ tốt cho việc học tập và nghiên cứu của sinh viên. Việc xây dựng module này liên quan đến nhiều mảng kiến thức, từ những kiến thức lý thuyết cho đến những kiến thức thực tiễn.
65 trang |
Chia sẻ: lylyngoc | Lượt xem: 3052 | Lượt tải: 4
Bạn đang xem trước 20 trang tài liệu Đề tài Module Ethernet trên vi điều khiển PIC18F67J60 và ứng dụng trong đo lường, điều khiển (Phần mềm trên MPLAB), để xem tài liệu hoàn chỉnh bạn click vào nút DOWNLOAD ở trên
thể như sau:
Bít 0: chưa sử dụng, luôn lấy giá trị 0
Bít 1: 0 ứng với gói tin bị phân mảnh, 1 ứng với gói tin không bị phân mảnh.
Bít 2: 0 ứng với gói tin thuộc phân đoạn cuối cùng của gói tin gốc, 1 ứng với gói tin không phải là phân đoạn cuối cùng của gói tin gốc.
Fragment Offset-13bít: chỉ vị trí của phân đoạn trong gói tin gốc, tính theo đơn vị 8 byte.
Time To Live-1byte: quy định thời gian tồn tại tính bằng giây của gói tin trong mạng. Thời gian này được đặt bởi trạm gửi và giảm đi (thường quy ước là 1) khi gói tin đi qua mỗi router của liên mạng. Một giá trị tối thiểu phải đủ lớn để mạng hoạt động tốt.
Protocol: Chỉ tầng giao thức kế tiếp sẽ nhận vùng dữ liệu ở trạm đích. TCP có ứng với giá trị 6, UDP ứng với giá trị 17, 1 ứng với ICMP.
Header Checksum-2byte: Dùng để phát hiện lỗi header của gói tin xảy ra trong quá trình truyền của nó.
Source IP Address-4byte: Địa chỉ IP của nơi truyền gói tin.
Destination IP Address-4byte: Địa chỉ IP của nơi nhận gói tin.
IP Option-độ dài thay đổi: Khai báo các lựa chọn do người sử dụng yêu cầu, ví dụ như: mức độ bảo mật, đường mà gói tin được gửi đi, timestamp ở mỗi router.
Padding-độ dài thay đổi: Dùng để đảm bảo phần header luôn kết thúc ở một mốc 32 bít.
Data: chứa thông tin lớp trên ,chiều dài thay đổi đến 64Kb.
2.2.3. Cấu trúc gói tin TCP
Đơn vị dữ liệu trong TCP được gọi là Segment với cấu trúc như sau:
Source Port-2 byte: số hiệu cổng TCP của trạm nguồn.
Destination Port-2byte: số hiệu cổng TCP của trạm đích.
Sequence number: số hiệu của byte đầu tiên của segment, nếu cờ SYN bật thì nó là số thứ tự gói ban đầu và byte đầu tiên được gửi có số thứ tự này cộng thêm 1. Nếu không có cờ SYN thì đây là số thứ tự của byte đầu tiên.
Acknowledgment Number-2byte: nếu cờ ACK bật thì giá trị của trường chính là số thứ tự gói tin tiếp theo mà bên nhận cần. Báo là nhận tốt các segment mà trạm đích đã gửi cho trạm nguồn.
Data offset-4bit: độ dài của phần header tính theo đơn vị từ 32 bit. Tham số này chỉ ra vị trí bắt đầu của nguồn dữ liệu.
Reserved-6 bít.
Flags: các bít điều khiển
URG: Vùng con trỏ khẩn (Urgent pointer) có hiệu lực
ACK: Vùng báo nhận ACK number có hiệu lực
PSH: Chức năng PUSH
RST: khởi động lại liên kết
SYN: đồng bộ hoá số hiệu tuần tự
FIND: không còn dữ liệu từ trạm nguồn
Window-2byte: số byte dữ liệu bắt đầu từ byte được chỉ ra trong ACK number mà trạm nguồn đã sẵn sàng để nhận.
Checksum: checksum cho cả phần header lẫn dữ liệu.
Urgent Pointer-2byte: nếu cờ URG bật thì giá trị trường này chính là số từ 16 bit mà số thứ tự gói tin (sequence number) cần dịch trái.
Option-2byte: vùng tuỳ chọn, khai báo các option của TCP trong đó có độ dài tối đa của vùng TCP data trong một segment.
Padding: phần chèn thêm vào header để đảm bảo phần header luôn kết thúc ở một mốc 32 bít
TCP data: chứa dữ liệu của tầng trên có độ dài tối đa ngầm định là 536byte. Giá trị này có thể khai báo trong trường Option.
2.2.4. Cấu trúc gói tin UDP
Vùng header của UDP có 64 bít với 4 trường :
Source Port-2byte: xác định cổng của người gửi thông tin và có ý nghĩa nếu muốn nhận thông tin phản hồi từ người nhận. Nếu không thì đặt nó bằng 0.
Destination Port-2byte: xác định cổng nhận thông tin và trường này là cần thiết.
Length-2byte: là chiều dài của toàn bộ gói tin(phần header và phần dữ liệu). Chiều dài tối thiểu là 8 byte khi gói tin không có dữ liệu, chỉ có header.
Checksum-2byte: dùng cho việc kiểm tra lỗi của phần header và phần dữ liệu.
CHƯƠNG 3. PHẦN CỨNG
3.1. Vi điều khiển PIC 18F67J60
3.1.1. Các đặc trưng của PIC 18F67J60
Vi điều khiển PIC18F67J60 là một vi điều khiển thuộc dòng vi điều khiển PIC19F97J60, do đó nó có các đặc trưng chung của họ vi điều khiển này.
3.1.1.1. Các đặc trưng chung:
Sử dụng thạch anh 25MHz cho ứng dụng Ethernet.
Bộ nhớ chương trình 128Kbyte ( 65532 lệnh).
Bộ nhớ dữ liệu 3808 byte.
Có 39 chân I/O thuộc các port A,B,C,D,E,F,G.
Có 5 bộ Timer:
Timer0 : vận hành như là 1 bộ định thời 8 bit hoặc 16 bit, 1 bộ đếm.
Timer1 : vận hành như là 1 bộ định thời 8 bit, 1 bộ đếm.
Timer2 : vận hành như là 1 bộ định thời 8 bit, 1 bộ đếm.
Timer3 : vận hành như là 1 bộ định thời 16 bít, 1 bộ đếm.
Timer4 : vận hành như là 1 bộ định thời 8 bít, 1 bộ đếm.
Có 2 module Capture/Compare/PWM.
Có 3 module EnhancedCapture/Compare/PWM.
Các giao tiếp nối tiếp MSSP (Master Synchronous Serial Port) và Enhanced USART (Universal asynchronous receiver/transmitter).
Có 11 kênh chuyển đổi A/D 10 bit.
3.1.1.2. Đặc trưng Ethernet:
Sử dụng chuẩn IEEE 802.3.
Tích hợp MAC và 10Base-T PHY.
8 kbyte bộ nhớ đệm SRAM để lưu trữ các gói tin truyền/nhận.
Có 2 led để chỉ trạng thái hoạt động.
3.1.2. Module A/D 10 bit
Vi điều khiển PIC 18F67J60 có 11 kênh chuyển đổi A/D (analog-to-digital). Module ADC cho phép chuyển đổi một tín hiệu tương tự đầu vào thành một giá trị số 10 bit tương ứng ở đầu ra.
3.1.2.1. Module A/D có 5 thanh ghi:
Thanh ghi ADRESH (A/D Result High Register).
Thanh ghi ADRESL (A/D Result Low Register).
Thanh ghi ADCON0 (A/D Control Register 0).
Thanh ghi ADCON0 (A/D Control Register 1).
Thanh ghi ADCON0 (A/D Control Register 2).
Thanh ghi ADCON0: điều khiển hoạt động của module A/D
Hình 4: Thanh ghi ADCON0.
Ta chỉ cần quan tâm đến các bit 5-0
Bit 5-2: chọn kênh A/D:
0000 = Kênh 0 (AN0)
0001 = Kênh 1 (AN1)
0010 = Kênh 2 (AN2)
0011 = Kênh 3 (AN3)
0100 = Kênh 4 (AN4)
0110 = Kênh 6 (AN6)
0111 = Kênh 7 (AN7)
1000 = Kênh 8 (AN8)
1001 = Kênh 9 (AN9)
1010 = Kênh 10 (AN10)
1011 = Kênh 11 (AN11)
Bit 1: Nếu bit ADON=1 thì module A/D đang làm việc nếu bit này là 1 và module A/D này không làm gì nếu bit này là 0.
Bit 0: ADON=1 : cho phép module A/D hoạt động.
ADON=0 : không cho phép module A/D hoạt động.
Thanh ghi ADCON1: cấu hình cho các chân A/D
Hình 5: Thanh ghi ADCON1.
Bit 5: VCFG0 = 1 nghĩa là đặt chân AN2 là VREF-
VCFG0 = 0 nghĩa là đặt VREF- = AVSS
Bit 4: VCFG0 = 1 nghĩa là đặt chân AN3 là VREF+
VCFG0 = 0 nghĩa là đặt VREF+ = AVDD
Bit 3-0: PCFG3:PCFG0 – các bit này điều khiển việc cấu hình cho các chân A/D.
Hình 6: Các bit điều khiển cấu hình cho các chân của bộ A/D.
Chú thích: (1): AN12-AN15 chỉ có trên các vi điều khiển 80 và 100 chân.
(2): AN5 chỉ có trên vi điều khiển 100 chân.
A = Analog input D= Digital I/O
Thanh ghi ADCON2: cấu hình xung clock cho bộ A/D, căn chỉnh.
Hình 7: Thanh ghi ADCON2.
Bit 7: ADFM – bit chọn định dạng cho kết quả.
Bit 5-3: ACQT2: ACQT0 các bit chọn Acquisition Time.
111 = 20 TAD
110 = 16 TAD
101 = 12 TAD
100 = 8 TAD
011 = 6 TAD
010 = 4 TAD
001 = 2 TAD
000 = 0 TAD
Bit 2-0: các bit chọn xung clock cho quá trình chuyển đổi.
111 = FRC (xung clock của bộ dao động RC)
110 = FOSC/64
101 = FOSC/16
100 = FOSC/4
011 = FRC (xung clock của bộ dao động RC)
010 = FOSC/32
001 = FOSC/8
000 = FOSC/2
3.1.2.2. Quá trình chuyển đổi A/D:
Bước 1: Cấu hình cho module A/D
Thiết lập thanh ghi ADCON1 (cấu hình chân analog, VREF, Digital I/O).
Thiết lập thanh ghi ADCON0 (cho phép bộ A/D hoạt động, chọn kênh A/D đầu vào).
Thiết lập thanh ghi ADCON2 (chọn xung clock cho bộ A/D, acquisition time).
Bước 2: Cấu hình ngắt A/D (nếu sử dụng)
Xóa bit ADIF.
Set bit ADIE.
Set bit GIE.
Bước 3: Chờ acquisition time được yêu cầu (nếu được yêu cầu).
Bước 4: Bắt đầu chuyển đổi, set bit ADCON0.
Bước 5: Chờ quá trình chuyển đổi A/D hoàn thành bằng việc chờ cho đến khi bit ADCON0 bị xóa hoặc chờ ngắt A/D.
Bước 6: Đọc kết quả các thanh ghi (ADRESH:ADRESL), xóa bit ADIF nếu được yêu cầu.
Bước 7: Để thực hiện quá trình chuyển đổi tiếp theo, quay lại bước 1 hoặc bước 2.
3.1.3. Module Ethernet
Vi điều khiển PIC18F67J60 được tích hợp sẵn module điều khiển Ethernet. Đây là một giải pháp kết nối hoàn chỉnh, bao gồm cả module Media Access Control (MAC) và Physical Layer transceiver (PHY). Module Ethernet đáp ứng tất cả các chuẩn IEEE 802.3 cho kết nối 10-BaseT cáp đôi xoắn. Có 2 LED output để báo liên kết và trạng thái hoạt động của mạng.
Hình 8: Sơ đồ khối module Ethernet.
Module Ethernet gồm 5 khối chức năng chính:
Khối truyền nhận PHY sẽ mã hóa và giải mã dữ liệu gửi hoặc nhận ở đầu RJ45.
Khối MAC phù hợp với chuẩn IEEE 802.3 cung cấp MIIP (Media Independent Interface Management) để điều khiển PHY.
Một bộ đệm RAM 8Kbyte để lưu trữ các gói tin truyền nhận.
Một khối phân xử để điều khiển sự truy cập vào bộ đệm RAM khi được DMA, khối truyền nhận yêu cầu.
Thanh ghi giao tiếp có chức năng thông dịch những dòng lệnh và tín hiệu trạng thái nội giữa module Ethernet và các thanh ghi đặc biệt của vi điều khiển SFRS.
3.2. Cảm biến nhiệt độ LM35
IC đo nhiệt độ là một mạch tích hợp nhận tín hiệu nhiệt độ chuyển thành tín hiệu điện dưới dạng dòng điện hay điện áp. Dựa vào đặc tính rất nhạy của các bán dẫn với nhiệt độ, tạo ra điện áp hoặc dòng điện tỷ lệ thuận với nhiệt độ tuyệt đối. Đo tín hiệu điện ta biết được giá trị của nhiệt độ cần đo. Sự tác động của nhiệt độ tạo ra điện tích tự do và các lỗ trống trong chất bán dẫn. Bằng sự phá vỡ các phân tử, bứt các electron thành dạng tự do di chuyển qua vùng cấu trúc mạng tinh thể tạo sự xuất hiện các lỗ trống. Làm cho tỷ lệ điện tử tự do và lỗ trống tăng lên theo quy luật hàm mũ với nhiệt độ.
Các đặc trưng của LM35:
Ngõ ra là điện áp.
Độ nhạy 10mv/10C
Sai số cực đại 1,50C khi nhiệt độ lớn hơn 1000C.
Phạm vi sử dụng :00 C=>1000 C
Cứ10mV tương ứng với 1°C, ở 00C điện áp ra là 0V, tương ứng với giá trị ADC là 0. Với Vref=2.5V, giá trị của ADC từ 0 đến 1023, lấy tròn 1000 mức. Mỗi giá trị ADC ứng với 2.5V/1000= 2.5 mV. Vậy 1 giá trị A/D ứng với 0.25 0C. Muốn tăng độ phân giải A/D ta giảm Vref.
Hình 9: LM35 DZ
3.3. Mạch nguyên lý
3.3.1. Khối mạch nguồn
Hình 10: Khối mạch nguồn
Mạch nguồn sử dụng IC ổn áp 7805 để tạo điện áp 5V để nuôi các khối sử dụng điện áp 5V và đưa tới đầu vào của IC ổn áp LM117. Tại đầu ra của LM117 là điện áp 3.3V dùng để cấp nguồn cho vi điều khiển và các khối khác trong mạch sử dụng điện áp 3.3V.
Tại đầu vào của IC 7805, dòng điện DC được cho qua một diode D3 trước khi tới đầu vào của 7805 để bảo đảm cho dòng điện qua 7805 theo 1 chiều cố định. Các tụ C15, C17, C13, C16, C19, C18 có tác dụng lọc nhiễu.
3.3.2. Khối mạch RJ45
Hình 11: Khối mạch RJ45.
Trong mạch này, sử dụng đầu cắm giao tiếp RJ45 là HR911105A của HANRUN. HR911105A được tích hợp sẵn biến áp và có 2 led để thông báo trạng thái kết nối của mạch.
Hình 12: Sơ đồ khối của HR911105A.
3.3.3. Khối mạch LCD
Hình 13: Khối mạch LCD.
Khối mạch LCD sử dụng LCD 16x2 để hiển thị địa chỉ IP hiện tại của mạch và để hiện thị các kí tự được truyền xuống từ web giao diện.
3.3.4. Khối mạch vi điều khiển PIC18F67J60
Hình 14: Jack kết nối với mạch vi điều khiển, mạch dao động ngoài, chân VDDCORE/VCAP.
Chân VDDCORE/VCAP của vi điều khiển được nối với tụ phân cực C14 xuống đất.
Bộ dao động ngoài sử dụng thạch anh 25MHz.
Hình 15: Mạch lọc, mạch reset, chân nạp cho vi điều khiển.
Các tụ C2, C3, C4, C5, C6, C7, C9 có tác dụng lọc nhiễu.
3.4 Mạch in
Hình 16: Bảng mạch chính.
Hình 17: Vi điều khiển PIC 18F67J60.
3.5 Mạch thực tế
Hình 18: Bản mạch chính
Hình 19: Vi điều khiển PIC 18F67J60
Hình 20: Mạch led và LM 35
CHƯƠNG 4. TRÌNH BIÊN DỊCH MPLAB C18 VÀ WEB SERVER
4.1. MPLAB C18
4.1.1. Giới thiệu
MPLAB C18 là một trình biên dịch C theo chuẩn ANSI dùng cho dòng PIC18 của Microchip.
Trình biên dịch MPLAB C18 và các công cụ đi kèm như linker hoặc trình biên dịch hợp ngữ được gọi từ dòng lệnh điều khiển để tạo ra 1 file .HEX để nạp vào vi điều khiển PIC18XXXX. MPLAB C18 và các công cụ đi kèm cũng có thể được gọi bên trong MPLAB IDE.
Trình biên dịch MPLAB C18 làm cho sự phát triển của các ứng dụng hệ thống nhúng dễ dàng hơn vì nó sử dụng ngôn ngữ C chuẩn.
4.1.2. Các đặc trưng của trình dịch MPLAB C18:
Tương thích với chuẩn ANSI-89.
Tích hợp MPLAB IDE để có thể dễ dàng quản lý project .
Tương thích với các module đối tượng được tạo bởi trình biên dịch hợp ngữ MPASM, cho phép kết hợp việc lập trình C và lập trình hợp ngữ trong cùng một project.
Đọc/ ghi vào bộ nhớ ngoài.
Có các thư viện mở rộng hỗ trợ cho PMW, SPI, I2C, UART, USART và thư viện toán học.
4.1.3. Quá trình tạo ra file .HEX
Quá trình tạo ra file .HEX của project để nạp vào vi điều khiển PIC18XXXX.
Đầu tiên, MPLAB C18 sẽ biên dịch file2.c và file3.c để tạo ra các object file file2.o và file3.o. MPASM biên dịch file1.asm thành object file file1.o. Sau đó, file object file4.o kết hợp với file3.o để tạo thành 1 thư viện gọi là lib1.lib. Cuối cùng, các file object còn lại liên kết cùng với file lib1.lib bởi trình liên kết MPLINK. MPLINK cũng có một linker script ở đầu vào là file script.lkr. MPLINK liên kết tất cả các file này để tạo ra các file đầu ra: output.cof, output.map, và output.hex.
Hình 21: Quá trình tạo file .HEX
4.2. Web động
Web động hay DHTML ( Dynamic HTML) có thể được định nghĩa như là một phần mềm được sử dụng cho việc mô tả sự kết hợp giữa ngôn ngữ đánh dấu siêu văn bản HTML, các stylesheet và ngôn ngữ script làm cho tài liệu trở nên sinh động.
DHTML cho phép người lập trình dễ dàng thêm các hiệu ứng cho các trang web. Ví dụ như làm động các hình ảnh và text trên trang web.
Cấu trúc của một DHTML:
DHTML example
function init() {
myObj = document.getElementById("navigation");
// .... more code
}
window.onload=init;
Often the code is stored in an external file; this is done
by linking the file that contains the JavaScript.
This is helpful when several pages use the same script:
4.3. CSS
CSS là chữ viết tắt của cụm từ tiếng Anh “Cascading Style Sheet”, là kiểu thiết kế sử dụng nhiều lớp định dạng chồng lên nhau. CSS được tổ chức World Wide Web (W3C) giới thiệu vào năm 1996. Cách đơn giản nhất để hiểu CSS là coi nó như một phần mở rộng của HTML để giúp đơn giản hóa và cải tiến việc thiết kế cho các trang web.
Một tiện ích của CSS là định nghĩa các Style (kiểu dáng, định dạng, v.v..) một lần và các trình duyệt có thể áp dụng các Style này nhiều lần trong một văn bản.
4.3.1. Ưu điểm của CSS
CSS có thể tách riêng phần định dạng ra khỏi nội dung một trang web, do đó nó sẽ rất thuận tiện khi thay đổi giao diện của một trang web.
CSS là một sợi chỉ xuyên suốt trong quá trình thiết kế một website bởi vì nó cho phép nhà thiết kế kiểm soát toàn bộ giao diện, kiểu cách và sự sắp đặt của nhiều trang hay nhiều đối tượng trong một lần định nghĩa. Để thay đổi tổng thể hay nhiều đối tượng có cùng style, chỉ cần thay đổi style đó và lập tức tất cả các thành phần áp dụng Style đó sẽ thay đổi theo. Nó giúp tiết kiệm công sức rất nhiều.
Do định nghĩa các style có thể được tách riêng ra khỏi nội dung của trang web, chúng được các trình duyệt tải một lần và sử dụng cho nhiều lần, do đó nó giúp các trang web nhẹ hơn và chạy nhanh hơn.
4.3.2. Các đặc tính cơ bản của CSS
CSS quy định cách hiển thị của các thẻ HTML bằng cách quy định các thuộc tính của các thẻ đó (font chữ, màu sắc). Để cho thuận tiện có thể đặt toàn bộ các thuộc tính của thẻ vào trong một file riêng có phần mở rộng là “.css”, thường người ta hay đặt tên nó là stylesheet.css.
CSS phá vỡ giới hạn trong thiết kế Web, bởi chỉ cần một file CSS có thể cho phép quản lí định dạng và layout trên nhiều trang khác nhau. Các nhà phát triển Web có thể định nghĩa sẵn thuộc tính của một số thẻ HTML nào đó và sau đó nó có thể dùng lại trên nhiều trang khác.
Có thể khai báo CSS bằng nhiều cách khác nhau. Có thể đặt đoạn CSS phía trong thẻ …, hoặc ghi nó ra một file riêng với phần mở rộng “.css”, ngoài ra bạn còn có thể đặt chúng trong từng thẻ HTML riêng biệt.
4.3.2.1. Cú pháp cơ bản của CSS:
css_selector_1 {thuộc_tính_1: giá_trị_của_thuộc_tính_1;thuộc_tính_2: giá_trị_của_thuộc_tính_2;...thuộc_tính_n: giá_trị_của_thuộc_tính_n;}css_selector_2 {thuộc_tính_1: giá_trị_của_thuộc_tính_1;thuộc_tính_2: giá_trị_của_thuộc_tính_2; ...thuộc_tính_n: giá_trị_của_thuộc_tính_n;}...css_selector_n {thuộc_tính_1: giá_trị_của_thuộc_tính_1;thuộc_tính_2: giá_trị_của_thuộc_tính_2;...thuộc_tính_n: giá_trị_của_thuộc_tính_n;}
4.3.2.2. Ví dụ minh họa về mã CSS:
body { background: #ffffff; /* trang Web sẽ có nền màu trắng */ font-family: Verdana; /* font chữ mặc định là Verdana */ color: #ff0000; /* màu chữ mặc định là màu đỏ */}
4.3.2.3. Thứ tự xếp lớp:
Tùy vào từng cách đặt khác nhau mà mức độ ưu tiên cho các style cũng khác nhau. Mức độ ưu tiên này tuân theo thứ tự sau:
Style nội tuyến – Style đặt trong từng thẻ HTML riêng biệt.
Stylet bên trong – Style đặt bên trong cặp thẻ … .
Style bên ngoài – Style đặt trong các file riêng có đuôi “.css”.
Style theo mặc định của trình duyệt.
4.3.3. CSS có tính kế thừa và tính kết hợp
4.3.3.1. Tính kế thừa:
Giả sử rằng ở đầu file styleshet.css khai báo cho Body có các thuộc tính sau:
Body{
Font:Arial, Verdana;
Background:#FF6600;
}
Nhưng trong trường hợp muốn khai báo cho các đối tượng nhỏ hơn nằm trong đó như Sidebar:
#sidebar{
With:300px;
Padding:10px;
Font:Tahoma,Verdana;
}
Sau đoạn khai báo này thì Sidebar sẽ có thuộc tính:
#sidebar{
background:#FF6600;
with:300px;
padding: 10px;
font: Tohoma, Verdana;
}
Như vậy, Sidebar đã kế thừa thuộc tính background của Body, và trong đó thuộc tính font là Tahoma đã đè lên thuộc tính font Arial ở lần khai báo trước.
4.3.3.2. Tính kết hợp:
Có thể định nghĩa nhiều CSS cùng một thuộc tính thay vì phải định nghĩa riêng lẻ từng cái một.
Ví dụ:
h1, h2,h3,h4{
Font-family: Tahoma,arial;
Color:#D4D4D4;
}
Thay cho việc định nghĩa riêng biệt cho từng cái:
h1{
Font-family: Tahoma,arial;
Color: #D4D4D4;
}
h2{
Font-family: Tahoma,arial;
Color:#D4D4D4;
}
……………………………
h4{
Font-family: Tahoma,arial;
Color:#D4D4D4;
}
4.4. Kỹ thuật AJAX
AJAX, viết tắt từ Asynchronous JavaScript and XML (JavaScript và XML không đồng bộ), là bộ công cụ cho phép tăng tốc độ ứng dụng web bằng cách cắt nhỏ dữ liệu và chỉ hiển thị những gì cần thiết, thay vì tải đi tải lại toàn bộ trang web. AJAX không phải một công nghệ đơn lẻ mà là sự kết hợp một nhóm công nghệ với nhau. Trong đó, HTML và CSS đóng vai hiển thị dữ liệu, mô hình DOM trình bày thông tin động, đối tượng XMLHttpRequest trao đổi dữ liệu không đồng bộ với máy chủ web, còn XML là định dạng chủ yếu cho dữ liệu truyền.
Những hoạt động của người sử dụng trên trang web sẽ tạo ra một yêu cầu HTTP tới server. Máy chủ thực hiện một số khâu xử lý như lấy lại dữ liệu, tính toán, kiểm tra sự hợp lệ của thông tin, sửa đổi bộ nhớ, sau đó gửi lại một trang HTML hoàn chỉnh tới máy khách. Tuy nhiên, phương pháp này khá bất tiện và mất thời gian. Để khắc phục hạn chế trên, các chuyên gia phát triển giới thiệu hình thức trung gian - cơ chế xử lý AJAX - giữa máy khách và máy chủ. Điều này giống như việc tăng thêm một lớp giữa cho ứng dụng để giảm quá trình "đi lại" của thông tin và giảm thời gian phản ứng. Thay vì tải lại (refresh) toàn bộ một trang, nó chỉ nạp những thông tin được thay đổi, còn giữ nguyên các phần khác. Vì thế, khi duyệt một trang hỗ trợ AJAX, người sử dụng không bao giờ nhìn thấy một cửa sổ trắng (blank) và biểu tượng đồng hồ cát - dấu hiệu cho thấy máy chủ đang thực hiện nhiệm vụ. Ví dụ, trong một website ảnh, với ứng dụng truyền thống, toàn bộ trang chứa các ảnh sẽ phải mở lại từ đầu nếu có một thay đổi nào đó trên trang. Còn khi áp dụng AJAX, DHTML chỉ thay thế đoạn tiêu đề và phần vừa chỉnh sửa, do vậy tạo nên các giao dịch trơn tru, nhanh chóng.
Hình 22: Tương tác đồng bộ trong ứng dụng web truyền thống (trên) và dị bộ trong ứng dụng AJAX.
4.4.1. Ưu điểm
Trong nhiều trường hợp, các trang web chứa rất nhiều nội dung thông thường trong trang. Nếu sử dụng các phương pháp truyền thống, những nội dụng đó sẽ phải nạp lại toàn bộ với từng yêu cầu. Tuy nhiên, nếu sử dụng Ajax, một ứng dụng web có thể chỉ yêu cầu cho các nội dung cần thiết phải cập nhật, do đó giảm lượng lớn băng thông và thời gian nạp lại trang.
Việc dùng các yêu cầu không đồng bộ (asynchronous request) cho phép giao diện người dùng của ứng dụng hiển thị trên trình duyệt giúp người dùng trải nghiệm sự tương tác cao, với nhiều phần riêng lẻ.
Việc sử dụng Ajax có thể làm giảm các kết nối đến server, do các script và các style sheet chỉ phải yêu cầu một lần.
4.4.2. Nhược điểm
Các trang web được tạo động không được ghi vào bộ lưu lịch sử lướt web của trình duyệt, do đó nút "back" (quay lui) của trình duyệt sẽ mất tác dụng quay lại trang thái trước đó của trang sử dụng Ajax, thay vào đó sẽ quay lại trang web trước đó mà người dùng ghé thăm.
Bất kỳ người dùng nào có trình duyệt không hỗ trợ Ajax hay JavaScript, hoặc đơn giản là đã bị vô hiệu hóa JavaScript, sẽ đương nhiên không thể sử dụng Ajax.
Việc thiếu các chuẩn cơ bản của Ajax đồng nghĩa với việc không có nhiều sự chọn lựa thực tiễn tốt nhất để kiểm tra các ứng dụng Ajax. Các công cụ kiểm thử cho Ajax thường không hiểu các mô hình sự kiện, mô hình dữ liệu và giao thức của Ajax.
CHƯƠNG 5. TCP/IP STACK
5.1. Cấu trúc của TCP/IP Stack
TCP/IP Stack là ứng dụng của Microchip để tạo một Webserver nhúng, hoặc các giao thức giao tiếp Enthernet hiện hành. Bao gồm các giao thức truyền dữ liệu TCP, UDP. Và hỗ trợ các module khác như: IP, ICMP, DHCP, ARP và DNS.
TCP/IP cũng có các Module sử dụng cho lớp ứng dụng như: HTTP cho Web, SMTP cho gửi và nhận Email, SNMP cho giao thức trạng thái và điều khiển. Telnet cho điều khiển từ xa, TFTP.
Hình 23: Cấu trúc của Stack.
Hình 24: So sánh cấu trúc TCP/IP tham khảo và cấu trúc Stack của Microchip.
Ngoài những module chính giống như cấu trúc TCP/IP tham khảo thì Microchip đưa thêm vào Stack 2 module mới đó là StackTask và ARPTask. StackTask quản lý sự vận hành và tất cả các module của Stack. Trong khi đó, ARPTask quản lý các dịch vụ của lớp ARP ( Address Resolution Protocol).
5.2. Hoạt động của TCP/IP Stack
TCP/IP Stack hoạt động gần giống cấu trúc của hệ điều hành thời gian thực, tức là các nhiệm vụ sẽ được chia thành các tác vụ ( ở đây là TCP, UDP, Ping,…). Tất cả hoạt động của TCP/IP sẽ được một đồng hồ chung quản lí theo Time Split. Tức là có một Timer hệ thống (Timer1), cứ 1 khoảng thời gian ngắn sẽ ngắt (gọi là 1 TICK), khi bị ngắt, hệ thống sẽ treo lại, ngữ cảnh của tất cả các tác vụ được bộ lập lịch lôi ra, xem xét tác vụ nào được chạy theo kiểu chia sẻ thời gian (vì không có mức ưu tiên cho tác vụ). Sau đó cho phép tác vụ đó chiếm quyền thực thi của CPU. Đến TICK tiếp theo, hệ thống lại treo lại, và lại lôi ngữ cảnh ra, cứ tiếp tục như vậy mãi.
Với cơ chế hoạt động này, vi điều khiển được coi như một lúc có thể vừa thực hiện TCP, vừa thực hiện UDP, Ping,…vừa có thể là Server và Client cùng một lúc.
Vì vậy, PIC nếu được thiết lập ở chế độ TCP Server/Client sẽ hoạt động đồng thời cả 2 hoạt động này. Server lắng nghe kết nối từ Client nào đó trên mạng. Còn Client thì gửi lệnh mở cổng kết nối tới một Server nào đó cũng ở trên mạng, mà ta có thể xác lập được.
Vì vậy, hoạt động của các tác vụ là độc lập với nhau, không chịu ảnh hưởng lẫn nhau.
5.2.1. Các file cần thiết
Main file: Lập trình trên file này.
ARP.c và ARP.h: Các file này được sử dụng bởi Stack để xác định địa chỉ MAC kết hợp với địa chỉ IP.
Delay.c và Delay.h: Những file này dùng để tạo độ trễ (delay) cho các hàm trong Stack.
Physical layer files: Những file này dùng để cho phép một lớp vật lý cụ thể.
Helpers.c và Helpers.h: Các file này sẽ giải thích các hàm sử dụng trong Stack.
IP.c và IP.h: Các file này cung cấp các chức năng của lớp IP cho Stack.
StackTsk.c và StackTsk.h –Các file này chứa code để khởi tạo Stack và thực hiện các hàm callback để cho Stack chạy.
Tick.c và Tick.h: Các file này tạo ra một bộ đếm thời gian để thực hiện một số chức năng thời gian trong Stack.
HardwareProfile.h: Thiết lập cấu hình cho phần cứng.
TCPIPConfig.h: Thiết lập cấu hình cho phần mềm.
MAC.h: Cung cấp các macro và cấu trúc liên quan đến phần cứng của lớp MAC.
TCPIP.h: Là file đính kèm trong Stack. Main file phải đính kèm file này.
5.2.2. Cấu trúc APP_CONFIG
Hầu hết các biến của ứng dụng liên quan của Stack được lưu trữ trong cấu trúc APP_CONFIG. Chúng bao gồm địa chỉ, cờ, chuỗi tên NBNS/SSID. Ta sẽ phải khai báo cho cấu trúc này và khởi tạo những giá trị mặc định của nó được định nghĩa trong file TCPIPConfig.h.
5.2.3. Main file
5.2.3.1. Khởi tạo
Đầu tiên, cần khởi tạo phần cứng như oscillators, LEDs, LCDs, PPS pins…
Sau đó, ta sẽ gọi các hàm khởi tạo từ thư viện. Đầu tiên là hàm TickInt(), nó khởi tạo tick timer để quản lý việc định thời của Stack. Sau đó là các hàm khởi tạo được thêm vào theo yêu cầu khởi tạo mà phần cứng yêu cầu. ví dụ như MPFSInt() để khởi tạo một cổng SPI (Serial Peripheral Interface Bus) để kết nối với thiết bị lưu trữ bộ nhớ để lưu trang web.
Khi phần cứng được khởi tạo, ta có thể cấu hình cho Stack. Hầu hết các biết của ứng dụng liên quan của Stack được lưu trong cấu trúc AppConfig. Lúc này ta có thể khởi tạo cấu trúc AppConfig theo những giá trị ta chọn.
Kết thúc khởi tạo Stack bằng việc gọi hàm StackInt(). Hàm này sẽ tự động khởi tạo các hàm cho firmware của các giao thức nếu chúng được định nghĩa trong file TCPIPConfig.h (ví dụ: TCPInit() cho TCP protocol, HTTPInt() cho HTTP hoặc HTTP2…).
5.2.3.2 Vòng lặp chính (main loop)
Khi chương trình được khởi tạo, ta sẽ tạo một vòng lặp vô hạn để thực hiện các nhiệm vụ của ứng dụng. Trong vòng lặp có hai hàm phải được gọi thường xuyên là StackTask() và StackApplications.
Hàm StackTask sẽ được gọi ở bất kỳ thời điểm nào khi Stack yêu cầu và sẽ điều khiển sự truyền nhận các gói dữ liệu.
Hàm StackApplications sẽ gọi những module ứng dụng được gọi. Ví dụ nếu sử dụng HTTP2 server, StackApplications sẽ tự động gọi hàm HTTPServer để thực hiện bất kỳ nhiệm vụ nào của HTTP đang được đợi.
Trong vòng lặp chính, ta có thể hỏi vòng cho bất kỳ sự thay đổi I/O nào và gọi bất kỳ một nhiệm vụ đặc biệt của ứng dụng mà bạn thực hiện. Để tránh tràn bộ đệm trong phần cứng hoặc vi phạm sự định thời của giao thức, ta sẽ thực hiện các nhiệm vụ trong hàm callback với các trigger định thời cơ sở.
Ta sẽ phải gọi hàm StackTask mỗi khi gọi hàm StackApplications.
5.3. Các module của Stack và APIs
Microchip TCP/IP Stack bao gồm rất nhiều module. Để sử dụng được bất kì một module nào ta phải nắm rõ mục đích của nó và APIs.
5.3.1. Announce
Module này làm cho việc phát hiện ra thiết bị trở nên dễ dàng bằng việc truyền một tin nhắn UDP trên cổng 30303 bất kỳ khi nào địa chỉ IP thay đổi. Cổng được sử dụng bởi module Announce có thể được thay đổi được bằng cách sửa ở marco trong file Announce.c
#define ANNOUNCE_PORT 30303
Giao thức Announce được thiết kế để sử dụng cho phần mềm Ethernet Device Discoverer và MCHPDetect trên máy tính.
Module Announce bao gồm 2 hàm:
AnnounceIP: AnnounceIP mở 1 socket UDP và truyền 1 gói tin đến cổng 30303. Nếu máy tính nằm trong cùng 1 subnet và tiện ích đang tìm kiếm 1 gói tin trên cổng UDP thì nó sẽ nhận gói tin này. Module này có nhiệm vụ thông báo việc thay đổi IP của mạch. Tin nhắn được hiển thị bằng phần mềm MCHPDetect.exe.
Cú pháp: void AnnounceIP();
DiscoveryTask: Hàm này được sử dụng liên tục để lắng nghe tin nhắn trên cổng Announe. Các tin nhắn có thể gửi bằng cách sử dụng công cụ Microchip Device Discoverer.
Cú pháp: void DiscoveryTask();
Các hàm trên chỉ nên được truy cập bởi chính Stack. Ứng dụng không nên gọi các hàm trên và thay đổi các biến.
5.3.2. HTTP2 server
Module HTTP2 web server và file MPFS2 liên quan của nó cho phép mạch hoạt động như một webserver. Nó tạo ra một phương pháp đơn giản để hiển thị thông tin trạng thái và điều khiển các ứng dụng bằng cách sử dụng một trình duyệt web thông thường.
Ba thành phần chính phục vụ cho module HTTP2 web server là: web pages, phần mềm MPFS2.exe và hai file nguồn CustomHTTPApp.c và HTTPPrint.h.
Hình 25: Sơ đồ khối
Web pages
Bao gồm tất cả file HTML và ảnh kèm theo, CSS Stylesheets, các file JavaScript cần thiết để hiển thị một trang web.
Phần mềm MPFS2
Phần mềm này được cung cấp bởi Microchip, các trang web được gói lại thành một định dạng và lưu trữ trong bộ nhớ chương trình flash nội hoặc bộ nhớ ngoài. Chương trình này sẽ tìm các biến động trong các trang web và tự động cập nhật các biến này trong file HTTPPrint.h.
Nếu bộ nhớ ngoài được sử dụng, phần mềm MPFS2 sẽ tạo ra một file BIN và có thể tải trực tiếp lên mạch. Còn nếu dữ liệu được lưu trong bộ nhớ chương trình flash thì phần mềm MPFS2 sẽ tạo ra một file đuôi .c và được chèn vào project.
Khi các biến động được thêm vào hoặc bỏ đi, phần mềm MPFS2 sẽ cập nhật cho file HTTPPrint.h. Sau đó ta phải dịch lại project để đảm bảo các biến mới đã được thêm vào project.
Hình 26: Phần mềm MPFS2
File CustomHTTPApp.c
Thực hiện các ứng dụng của web. Nó mô tả đầu ra cho các biến động ( thông qua hàm callbacks HTTPPrint_varname), phân tích dữ liệu được gửi thông qua trang web forms.htm ( sử dụng 2 hàm HTTPExecuteGet và HTTPExecutePost) và xác nhận thông tin truy cập ( bằng hàm HTTPAuthenticate).
File HTTPPrint.h
File này được tạo tự động bởi phần mềm MPFS2. Nó định nghĩa tất cả các biến động và tạo ra một mối liên hệ giữa các biến trong trang web và hàm callbacks HTTPPrint_varname liên quan trong file CustomHTTPApp.c.
Module HTTP2 web server bao gồm các tính năng sau:
5.3.2.1. HTTP2 Dynamic Variables
Một trong những tính năng cơ bản nhất là cập nhật cái thông tin trạng thái của mạch đến người sử dụng thông qua giao diện web. Các lệnh trong mã HTML sẽ thông báo cho server thực hiện các hàm callbacks tại thời điểm đó.
Để tạo ra một biến động, chỉ cần đặt tên của biến bên trong một cặp ký tự (~) trong mã nguồn các trang web HTML (ví dụ: ~ myVariable ~). Khi ta chạy chương trình MPFS2 để tạo ra các trang web, nó sẽ tự động định nghĩa những biến này trong file HTTPPrint.h. Ví dụ: sử dụng biến động builddate, mã HTML là:
~builddate~
Hàm callback liên quan trong file CustomHTTPApp.c sẽ in giá trị lên trang web:
void HTTPPrint_builddate(void)
{
TCPPutROMString(sktHTTP,(ROM void*)__DATE__);
}
5.3.2.2. HTTP2 Form Processing
Nhiều ứng dụng cần lấy dữ liệu từ người sử dụng. Một phương pháp thông thường sử dụng web forms.htm. web forms sử dụng 2 phương pháp GET và POST và HTTP2 web server hỗ trợ cả 2 phương pháp này.
Phương pháp GET
Phương pháp GET sẽ gán dữ liệu vào cuối URL. Dữ liệu này sẽ đứng sau dấu chấm hỏi (?) ở trên thanh địa chỉ của trình duyệt. (Ví dụ: Dữ liệu được gửi bằng phương pháp GET sẽ tự động được giải mã và được lưu trong biến mảng curHTTP.data. Vì dữ liệu này được lưu trong bộ nhớ, cho nên nó được giới hạn bởi kích thước của biến mảng curHTTP.data, mặc định là 100 bytes.
Hàm callback HTTPExecuteGet sẽ xử lý dữ liệu này và thực hiện một số nhiệm vụ cần thiết. Hai hàm HTTPGetArg và HTTPGetROMArg giúp dễ dàng lấy dữ liệu cho quá trình xử lý.
Phương pháp POST
Phương pháp POST truyền dữ liệu sau khi các header yêu cầu đã được gửi. Dữ liệu không được hiển thị trong thanh địa chỉ của trình duyệt như phương pháp GET mà chỉ được nhìn thấy bởi một công cụ bắt gói tin. Mặc dù vậy, phương pháp này sử dụng cùng cách mã hóa URL giống phương pháp GET.
HTTP2 server không thực hiện bất kỳ sự phân tích trước các dữ liệu này. Tất cả dữ liệu POST nằm trong bộ đệm TCP, vì vậy các ứng dụng sẽ truy cập trực tiếp vào bộ đệm TCP để lấy và giải mã nó. Các hàm HTTPReadPostName và HTTPReadPostValue sẽ thực hiện công việc này.
5.3.2.3. HTTP2 Authentication
Các giao thức HTTP cung cấp một phương pháp cho các máy chủ yêu cầu một tên người dùng và mật khẩu của khách hàng trước khi cấp quyền truy cập đến trang đó.
Chức năng xác thực này được hỗ trợ bởi hai hàm callback. Thứ nhất, là hàm HTTPNeedsAuth, xác định xem trang web hiện tại có yêu cầu sự xác thực hay không. Thứ hai, là hàm HTTPVerifyAuth, so sánh tên người dùng và mật khẩu với một danh sách được chấp nhận, nếu đúng sẽ cho phép truy cập, nếu sai sẽ bị từ chối truy cập.
Yêu cầu xác thực
Đầu tiên, hàm HTTPNeedsAuth sẽ được gọi để xác định xem trang có yêu cầu password hay không. Hàm này sẽ trả về giá trị để hướng dẫn HTTP server phải thực hiện như thế nào. Hàm trả về giá trị 0x80 hoặc cao hơn để cho phép truy cập vô điều kiện và trả về giá trị 0x79 hoặc thấp hơn để yêu cầu nhập lại tên người sử dụng và password. Giá trị trả lại được lưu trong curHTTP.isAuthorized để nó có thể được truy cập bởi các hàm callback trong lần tiếp theo.
Ví dụ sau đây là trường hợp đơn giản, trong đó tất cả các tập tin yêu cầu một mật khẩu để truy cập:
BYTE HTTPNeedsAuth(BYTE* cFile)
{
return 0x00;
}
Trong một số trường hợp, chỉ có một số tập tin sẽ cần phải được bảo vệ. Ví dụ thứ hai đòi hỏi một mật khẩu cho bất kỳ tập tin nằm trong thư mục /treasure:
BYTE HTTPNeedsAuth(BYTE* cFile)
{
// Compare to "/treasure" folder. Don't use strcmp here, because
// cFile has additional path info such as "/treasure/gold.htm"
if(!memcmppgm2ram((void*)cFile, (ROM void*)"treasure", 5))
return 0x00;
return 0x80;
}
Thông tin xác thực: Hàm HTTPCheckAuth xác định xem tên và password mà người dùng cung cấp có hợp lệ để truy cập hay không. Giá trị trả lại được lưu trong curHTTP.isAuthorized để nó có thể được truy cập bởi các hàm callback trong lần tiếp theo.
5.4. Cấu hình cho Stack
5.4.1. Cấu hình cho phần cứng
Hầu như việc cấu hình phần cứng được thực hiện bằng cách thêm dấu // vào trước các dòng lệnh để làm mất tác dụng của những dòng lệnh hoặc bỏ // đi để Mplab thực hiện các dòng lệnh đó, định nghĩa một loạt các macro ở phần đầu của file HardwareProfile.h.
Trong hầu hết các trường hợp, các macro dùng để khởi tạo các mạch demo phải giống như các macro dùng để định nghĩa vi điều khiển sử dụng trong mạch. Trong file HardwareProfile.h mặc định đã bao gồm các project cho một số mạch có sẵn của Microchip, được giới hạn bằng các câu lệnh tiền xử lý. Ví dụ với Explorer 16 sẽ bắt đầu bằng macro "#elif defined (EXPLORER_16)" và tiếp tục cho đến những câu lệnh tiền xử lý cho một mạch demo khác.
5.4.1.1. Tần số
Nhiều hoạt động của TCP/IP phụ thuộc vào thời gian. Để thiết lập giá trị xung clock ta thay thế giá trị của xung clock trong macro trong file HardwareProfile.h:
#define GetSystemClock() xxxxxxxxxxxxxxx
Ngoài ra còn 2 macro thiết lập xung clock khác:
GetInstructionClock () và GetPeripheralClock () cung cấp tần số lệnh và tần số cho thiết bị ngoại vi của vi điều khiển.
5.4.1.2. Bộ nhớ ngoài
Bộ nhớ ngoài dùng để lưu trữ Web nhúng, Web ở đây định dạng http và http2. Bộ nhớ dùng để lưu trữ có thể có 3 loại: SD/MMD (Memory Card), EEPROM, Flash Serial.
Nếu muốn dùng Web nhúng, ta có thể lưu trữ vào bộ nhớ nội. Lúc ấy, cần tạo một file bộ nhớ của Web định dạng MPFS. Để tạo ra file định dạng MPFS thì Microchip đã đưa ra công cụ MPFS2 trong folder /Utilities để chuyển toàn bộ dữ liệu Web thành một file duy nhất. Web phải được đưa vào một folder, đối với trình dịch C18 thì file được xuất ra là MPFSImg2.c.
Để sử dụng Web nhúng trong bộ nhớ nội, trong file TCPIPconfig.h bỏ thiết lập dùng bộ nhớ ngoài, và #include MPFSImg2.c trong chương trình maindemo.c. Đặt lại tên mặc định của Web server là index.htm trong file TCPIPConfig.h.
Bỏ lưu trữ trong EEPROM và Flash memory:
//#define MPFS_USE_EEPROM
//#define MPFS_USE_SPI_FLASH
5.4.2. Địa chỉ
5.4.2.1. Địa chỉ MAC
6 byte địa chỉ MAC cung cấp địa chỉ cho lớp giao thức Media Access Control của TCP/IP Stack. Địa chỉ MAC là địa chỉ cố định gắn liền với phần cứng.
Địa chỉ MAC được định nghĩa trong file TCPIPConfig.h. Có 6 macro được định nghĩa trong file này để thiết lập địa chỉ MAC:
#define MY_DEFAULT_MAC_BYTE1 (0x00)
#define MY_DEFAULT_MAC_BYTE2 (0x04)
#define MY_DEFAULT_MAC_BYTE3 (0xA3)
#define MY_DEFAULT_MAC_BYTE4 (0x00)
#define MY_DEFAULT_MAC_BYTE5 (0x00)
#define MY_DEFAULT_MAC_BYTE6 (0x00)
Tuy nhiên, vi điều khiển PIC 18F67J60 đã được tích hợp sẵn địa chỉ MAC cho nên ta không cần phải quan tâm đến việc thiết lập địa chỉ này.
5.4.2.2. Địa chỉ IP
Địa chỉ IP dùng để định địa chỉ cho các nút mạng trên mạng giao thức Internet. Chúng ta cần cấu hình cho mạch một địa chỉ IP.
Địa chỉ subnet là một mặt nạ bit xác định phạm vi của mạng. Nếu địa chỉ IP của bạn là 192.168.5.100, và bạn chỉ định subnet mask là 255.255.255.0, Stack sẽ cho rằng địa chỉ trong phạm vi 192.168.5.x là trên cùng một subnet mà ta đang có, và các gói tin sẽ được gửi đến bất kỳ một địa chỉ trong mạng này mà không được gửi đến nơi khác.
Gateway mặc định là địa chỉ IP của nút mạng mà nó sẽ gửi gói tin đến nếu như không được định hướng đến địa chỉ IP mà ta mong muốn. Ví dụ, nếu địa chỉ IP ta đặt nằm trong mạng con 192.268.5.x, và nếu nó muốn gửi một gói tin đến địa chỉ IP 198.175.253.160 mà không biết chính xác phải gửi đến địa chỉ đó như thế nào, nó sẽ gửi đến gateway mặc định.
Có ba phương pháp để thiết lập địa chỉ IP:
DHCP: Các module DHCP client sẽ cho phép ứng dụng tự động lấy địa chỉ IP từ máy chủ DHCP trên cùng một mạng. Việc làm này sẽ thiết lập lại địa chỉ IP, subnet mask, địa chỉ gateway, và các thông số cấu hình một số khác trong cấu trúc AppConfig. Để sử dụng DHCP ta phải nạp ba file DHCP.c; DHCPs.c ; DHCP.h và khai báo " #define STACK_USE_DHCP_CLIENT" trong TCPIPConfig.h.
AutoIP: Module này cho phép ứng dụng chọn một địa chỉ IP và tự xác nhận địa chỉ đó. Để sử dụng AutoIP ta phải nạp hai file AutoIP.c and AutoIP.h và khai báo "#define STACK_USE_AUTO_IP" trong TCPIPConfig.h.
Địa chỉ IP tĩnh: Việc sử dụng địa chỉ IP tĩnh chỉ hoạt động nếu server được cấu hình để hỗ trợ địa chỉ đó.
Nếu sử dụng DHCP và AutoIP đồng thời thì module AutoIP sẽ phát một địa chỉ trong subnet 169.254.x.x sau đó sẽ cấp một địa chỉ khác trong cùng subnet đến DHCP client được kết nối với board.
5.5. Demo module
Demo module chứa một số các ứng dụng thông thường:
Web page demo: Xây dựng 1 chương trình HTTP sử dụng HTTP2 server và điều khiển 1 số đặc trưng (hiện thị nhiệt độ, điều khiển led, viết ra LCD) thông qua giao diện web.
E-mail ( SMTP) Demo: Sử dụng e-mail client để gửi đi 1 tin nhắn khi 1 sự kiện xảy ra.
Generic TCP Client: Xây dựng 1 ứng dụng TCP Client thông qua HTTP Client example.
Generic TCP Server: Xây dựng ứng dụng TCP Server.
Ping (ICMP) demo: Xây dựng Ping Client.
Trong nội dung đồ án này em xin trình bày về web page demo, cụ thể là điều khiển led sáng tắt, viết ra LCD, hiện thị thông số nhiệt độ thông qua giao diện web.
Module HTTP web server và file đi kèm MPFS2 làm cho board như là một web server. Nó cho phép dễ dàng hiển thị thông tin lên LCD hoặc điều khiển sử dụng trình duyệt web.
5.5.1. Điều khiển led sáng tắt
- Gõ đường link trên trình duyệt http:/192.168.1.2/forms.htm.
- Chọn On/Off trong ô lựa chọn để đặt trạng thái cho từng led rồi ấn nút save để lưu trạng thái cho các led.
- Quan sát sự thay đổi của các led trên mạch.
Hình 27: Điều khiển LED và viết lên LCD.
Để thực hiện được việc này ta sử dụng phương pháp GET:
- Phương pháp Get gán dữ liệu vào phần cuối của URL. Dữ liệu được gán sau dấu “?” trên thanh địa chỉ. Dữ liệu được gửi qua phương pháp GET tự động được giải mã và lưu trong biến curHTTP.data (curHTTP là biến cấu trúc để lưu trạng thái hiện tại của kết nối HTTP, một số biến trong cấu trúc curHTTP như curHTTP.byteCount, curHTTP. isAuthorized, biến mảng curHTTP.data…), biến curHTTP.data được giới hạn 100bytes. Khi biến curHTTP.data đầy thì dữ liệu sẽ được lưu vào trong bộ nhớ.
Code trong file forms.htm
Hình 28: Code trong file forms.htm
- Giả sử ta kick vào led 1 và 3. Một chuỗi sau sẽ được gửi đến server:
GET /leds.htm?led1=1&led3=1 HTTP/1.1
- HTTP2 web server sẽ phân tích yêu cầu này và lưu dưới dạng một chuỗi trong biến curHTTP.data : "led1\01\0led3\01\0\0"
- Web server sẽ gọi hàm HTTPExecuteGet để xử lý đầu vào này. Mục đích của nó là phân tích những dữ liệu nhận được từ các tham số URL.
Code:
HTTP_IO_RESULT HTTPExecuteGet(void)
{
BYTE *ptr;
BYTE filename[20];
// Load the file name
// Make sure BYTE filename[] above is large enough for your longest name
MPFSGetFilename(curHTTP.file, filename, 20);
// If its the forms.htm page
if(!memcmppgm2ram(filename, "forms.htm", 9))
{
// Seek out each of the four LED strings, and if it exists set the LED states
ptr = HTTPGetROMArg(curHTTP.data, (ROM BYTE *)"led4");
if(ptr)
LED4_IO = (*ptr == '1');
ptr = HTTPGetROMArg(curHTTP.data, (ROM BYTE *)"led3");
if(ptr)
LED3_IO = (*ptr == '1');
ptr = HTTPGetROMArg(curHTTP.data, (ROM BYTE *)"led2");
if(ptr)
LED2_IO = (*ptr == '1');
ptr = HTTPGetROMArg(curHTTP.data, (ROM BYTE *)"led1");
if(ptr)
LED1_IO = (*ptr == '1');
}
return HTTP_IO_DONE;
}
Đầu tiên, hàm MPFSGetFilename sẽ được gọi để kiểm tra trang forms.htm được truy cập. Hàm MPFSGetFilename sẽ đọc tên file truy cập hiện tại và lưu vào trong biến filename. Sau đó ta sử dụng memcmppgm2ram(filename, "forms.htm", 9) để so sánh xem biến filename có giá trị là "forms.htm" hay không. Nếu giống nhau thì hàm sẽ trả lại giá trị 0.
Hàm HTTPGetROMArg sẽ tìm kiếm trong mảng curHTTP.data để tìm giá trị của đối số được đưa ra sau khi thực hiện phương pháp GET, cụ thể trong đoạn code này là các led1, led2, led3, led4. Hàm này sẽ trả lại một con trỏ, trỏ đến giá trị của đối số trong mảng curHTTP.data. Sau đó sẽ gán giá trị thích hợp cho led tương ứng.
5.5.2. Viết ra LCD
- Gõ đường link trên trình duyệt http:/192.168.1.2/forms.htm.
- Viết 1 chuỗi kí tự vào ô trống rồi bấm nút Save.
- Kiểm tra màn hình LCD trên board xem có hiển thị được đúng chuỗi mà ta yêu cầu hay không.
Code trong file forms.htm:
Hình 29: Code phần LCD trong file forms.htm.
5.5.2.1. HTTPExecutePost
Hàm HTTPExecutePost sẽ thực hiện một số nhiệm vụ:
Đầu tiên, lấy tên của trang web truy cập hiện tại được lưu trong biến curHTTP.file và gán cho biến filename bằng cách sử dụng hàm MPFSGetFilename.
Kiểm tra nếu trang web truy cập hiện tại đúng là forms.htm thì sẽ thực hiện hàm con HTTPPostLCD().
Thực hiện hàm con HTTPPostLCD.
Code:
HTTP_IO_RESULT HTTPExecutePost(void)
{
// Resolve which function to use and pass along
BYTE filename[20];
// Load the file name
// Make sure BYTE filename[] above is large enough for your longest name
MPFSGetFilename(curHTTP.file, filename, sizeof(filename));
#if defined(USE_LCD)
if(!memcmppgm2ram(filename, "forms.htm", 9))
return HTTPPostLCD();
#endif
return HTTP_IO_DONE;
}
5.5.2.2. Hàm HTTPPostLCD
Xác định thông số của LCD và sử dụng nó để cập nhật các dòng văn bản lên màn hình LCD trên mạch.
Hàm này có 4 trạng thái. Đầu tiên là đọc tên từ chuỗi dữ liệu được trả lại từ phương pháp POST. Nếu tên không được tìm thấy thì nó sẽ tiếp tục hỏi nhiều dữ liệu hơn. Hay nói cách khác, nếu tên được mong đợi nó sẽ đọc các giá trị liên quan và ghi lên màn hình LCD. Nếu tên không được mong đợi, các giá trị liên quan được loại bỏ và các thông số tên tiếp theo được đọc.
Trong trường hợp, chuỗi mong đợi không được tìm thấy thì hàm này sẽ trả lại HTTP_IO_NEED_DATA khi không còn dữ liệu. Trong trường hợp này, HTTP2 server sẽ bắt các lỗi và và phát ra Internal Server Error đến trình duyệt.
Các giá trị trả lại:
HTTP_IO_DONE : Nếu tham số được tìm thấy và lưu.
HTTP_IO_WAITING : Hàm này bị dừng lại và sẽ tiếp tục sau đó.
HTTP_IO_NEED_DATA : Dữ liệu mà hàm này cần chưa có.
Code:
static HTTP_IO_RESULT HTTPPostLCD(void)
{
BYTE* cDest;
#define SM_POST_LCD_READ_NAME (0u)
#define SM_POST_LCD_READ_VALUE (1u)
switch(curHTTP.smPost)
{
// Find the name
case SM_POST_LCD_READ_NAME:
// Read a name
if(HTTPReadPostName(curHTTP.data, HTTP_MAX_DATA_LEN) == HTTP_READ_INCOMPLETE)
return HTTP_IO_NEED_DATA;
curHTTP.smPost = SM_POST_LCD_READ_VALUE;
// No break...continue reading value
// Found the value, so store the LCD and return
case SM_POST_LCD_READ_VALUE:
// If value is expected, read it to data buffer,
// otherwise ignore it (by reading to NULL)
if(!strcmppgm2ram((char*)curHTTP.data, (ROM char*)"lcd"))
cDest = curHTTP.data;
else
cDest = NULL;
// Read a value string
if(HTTPReadPostValue(cDest,HTTP_MAX_DATA_LEN)== HTTP_READ_INCOMPLETE)
return HTTP_IO_NEED_DATA;
// If this was an unexpected value, look for a new name
if(!cDest)
{
curHTTP.smPost = SM_POST_LCD_READ_NAME;
break;
}
// Copy up to 32 characters to the LCD
if(strlen((char*)cDest) < 32u)
{
memset(LCDText, ' ', 32);
strcpy((char*)LCDText, (char*)cDest);
}
else
{
memcpy(LCDText, (void *)cDest, 32);
}
LCDUpdate();
// This is the only expected value, so callback is done
strcpypgm2ram((char*)curHTTP.data, "/forms.htm");
curHTTP.httpStatus = HTTP_REDIRECT;
return HTTP_IO_DONE;
}
// Default assumes that we're returning for state machine convenience.
// Function will be called again later.
return HTTP_IO_WAITING;
}
#endif
Hàm con HTTPReadPostName:
Cú pháp: HTTP_READ_STATUS HTTPReadPostName (
BYTE* cData,
WORD wLen
);
cData: để lưu trữ tên khi nó được đọc
wLen: độ dài của biến cData
Giá trị trả lại:
HTTP_READ_OK : Tên được đọc thành công.
HTTP_READ_TRUNCTATED : Toàn bộ tên không phù hợp trong bộ đệm, vì thế giá trị đã bị cắt ngắn và dữ liệu bị mất.
HTTP_READ_INCOMPLETE : Tên chưa được lưu vào bộ đệm, vì thế hàm sẽ được gọi lại sau đó.
Đọc tên từ một chuỗi URL được mã hóa. Hàm này được gọi từ hàm callback HTTPExecutePost, nó làm cho việc phân tích dữ liệu gửi đến một cách dễ dàng. Hàm này ngăn chặn việc tràn bộ đệm bằng cách buộc người lập trình xác định rõ cần bao nhiêu byte.
Hàm này sẽ đọc cho đến khi gặp kí tự “=” tiếp theo ( kí tự “=” để đánh kết thúc của tham số tên).
Hàm con HTTPReadPostValue:
Cú pháp: HTTP_READ_STATUS HTTPReadPostValue(
BYTE* cData,
WORD wLen
);
cData: để lưu trữ giá trị khi nó được đọc.
wLen: độ dài của biến cData.
Giá trị trả lại:
HTTP_READ_OK : Giá trị được đọc thành công.
HTTP_READ_TRUNCTATED : Toàn bộ giá trị không phù hợp trong bộ đệm, vì thế giá trị đã bị cắt ngắn và dữ liệu bị mất.
HTTP_READ_INCOMPLETE : Toàn bộ giá trị chưa được lưu vào bộ đệm, vì thế hàm sẽ được gọi lại sau đó.
Đọc giá trị từ một chuỗi URL được mã hóa. Hàm này được gọi từ hàm callback HTTPExecutePost, nó làm cho việc phân tích dữ liệu gửi đến một cách dễ dàng. Hàm này ngăn chặn việc tràn bộ đệm bằng cách buộc người lập trình xác định rõ cần bao nhiêu byte.
Hàm này sẽ đọc cho đến khi gặp kí tự “&” tiếp theo ( kí tự “&” để đánh kết thúc của tham số giá trị).
5.5.3. Đo nhiệt độ
- Gõ đường link trên trình duyệt http:/192.168.1.2/ dynvars.htm.
- Theo dõi nhiệt độ đo được.
Hình 30: Hiển thị giá trị nhiệt độ trên web.
Để đo được giá trị nhiệt độ em sử dụng IC LM35 để biến thông số nhiệt độ thành điện áp và đưa vào bộ biến đổi A/D 10 bit (AN4). Giá trị điện áp sẽ được biến đổi thành giá trị số tương ứng. Giá trị số này sẽ được tính toán theo công thức chuẩn để trở thành giá trị nhiệt độ thực tế.
Tham số nhiệt độ là một biến động nên sử dụng hàm gọi lại HTTPPrint_pot để thực hiện việc hiển thị tham số nhiệt độ này.
5.5.3.1. Hàm HTTPPrint_pot
void HTTPPrint_pot(void)
{
BYTE AN0String[8];
WORD ADval;
#if defined(__18CXX)
// Wait until A/D conversion is done
ADCON0bits.GO = 1; //A/D conversion status bit
while(ADCON0bits.GO);
// Convert 10-bit value into ASCII string
ADval = (WORD)ADRES;
ADval *= (WORD)330;
ADval /= (WORD)1024;
uitoa(ADval, AN0String);
#else
ADval = (WORD)ADC1BUF0;
//ADval *= (WORD)10;
//ADval /= (WORD)102;
uitoa(ADval, (BYTE*)AN0String);
#endif
TCPPutString(sktHTTP, AN0String);
}
Trong khi ADCON0bits.GO=1 tức là bộ biến đổi A/D vẫn đang hoạt động ta gán giá trị đã được biến đổi trên thanh ghi chứa kết quả ADRES cho biến Adval. Sau đó áp dụng công thức chuyển đổi từ giá trị số sau phép biến đổi A/D thành giá trị nhiệt độ như sau: Adval= ((Adval*3.3)/1024)*100 ( trong đó giá trị 3.3 là giá trị của VREF). Tiếp theo là ép kiểu biến Adval thành kiểu byte và lưu vào biến AN0String. Cuối cùng là sử dụng hàm TCPPutString để lưu giá trị của biến AN0String vào socket của TCP.
5.5.3.2. Code trong file dynvars.htm
Hình 31: Code trong file dynvars.htm
Do tham số nhiệt độ là một biến động thay đổi theo thời gian vì thế phải sử dụng một câu lệnh javascript để cập nhật giá trị của nhiệt độ theo thời gian. Đó là sử dụng hàm setTimeout để cập nhật biến nhiệt độ.
KẾT LUẬN
Việc thiết kế Module Ethernet trên vi điều khiển PIC18F67J60 nhằm ứng dụng đo lường và điều khiển có ý nghĩa rất lớn, có thể ứng dụng trong nhiều lĩnh vực của đời sống xã hội và trong công nghiệp. Ngoài ra, module Ethernet trên vi điều khiển PIC18F67J60 cũng phục vụ tốt cho việc học tập và nghiên cứu của sinh viên. Việc xây dựng module này liên quan đến nhiều mảng kiến thức, từ những kiến thức lý thuyết cho đến những kiến thức thực tiễn.
Những kết quả chính thực hiện được
Tìm hiểu nguyên lý chung chuẩn truyền thông Ethernet do IEEE 802.3 quy định, tìm hiểu kiến thức về họ giao thức TCP/IP.
Kết nối thành công mạch mạch demo với máy tính thông qua chuẩn truyền thông Ethernet.
Lập trình cho mạch demo bằng phần mềm MPLAB C18, sử dụng thư viện TCP/IP Stack của hãng Microchip để thực hiện điều khiển các ứng dụng cơ bản như bật tắt đèn LED, viết lên LCD một chuỗi kí tự và đo tham số nhiệt độ qua web giao diện.
Lập trình web giao diện để đo lường, điều khiển của mạch demo trên máy tính.
Đánh giá những kết quả đã đạt được
Điều khiển chính xác các đèn LED và viết chính xác các chuỗi kí tự mà ta mong muốn lên LCD, kết quả đo nhiệt độ là khá chính xác với sai số nằm trong phạm vi cho phép. Mạch hoạt động ổn định.
Tuy nhiên, một số mặt hạn chế đó là đề tài mới chỉ là thực hiện kết nối trực tiếp giữa mạch demo với máy tính thông qua chuẩn truyền thông Ethernet mà chưa thực hiện được kết nối mạch với switch.
Với kết quả bước đầu là kết nối thành công mạch demo với máy tính thông qua chuẩn truyền thông Ethernet và thực hiện đo lường và điều khiển một số ứng dụng cơ bản đã khẳng định khả năng phát triển của đề tài.
Hướng phát triển tiếp theo của đề tài:
Trong thời gian tới, em sẽ tiếp tục nghiên cứu phát triển đề tài theo một số hướng sau đây:
Kết nối mạch với switch.
Thực hiện các ứng dụng điều khiển và đo lường phức tạp hơn để phục vụ cho cuộc sống như điều khiển nhà thông minh qua internet và phục vụ trong công nghiệp, thay thế các chuẩn truyền thông cũ như RS485, RS232…
Các file đính kèm theo tài liệu này:
- final_49.doc