Màu nền
Font chữ
Font size
Chiều cao dòng

MỞ ĐẦU

Một lĩnh vực nổi bật của mạng cảm nhận không dây (Wireless Sensor Network- WSN) là sự kết hợp việc cảm nhận, tính toán và truyền thông vào một thiết bị nhỏ. Thông qua mạng hình lưới (mesh networking protocols), những thiết bị này tạo ra một sự kết nối rộng lớn trong thế giới vật lý. Trong khi khả năng của từng thiết bị là rất nhỏ, sự kết hợp hàng trăm thiết bị như vậy yêu cầu là phải có công nghệ mới.

Sức mạnh của WSN nằm ở chỗ khả năng triển khai một số lượng lớn các thiết bị nhỏ có thể tự thiết lập cẩu hình hệ thống. Sử dụng những thiết bị này để theo dõi theo thời gian thực, để giám sát điều kiện môi trường, để theo dõi cấu trúc hoặc tình trạng thiết bị.

Hầu hết những ứng dụng của WSN là giám sát môi trường từ xa với tần số lấy dữ liệu thấp. Ví dụ, có thể dễ dàng được giám sát sự rò rỉ của một nhà máy hoá học bởi hàng trăm cảm biến tự động kết nối thành hệ thống mạng không dây để ngay lập tức phát hiện và báo cáo sự rò rỉ. Không giống những hệ thống có dây truyền thống, chi phí triển khai cho WSN được giảm thiểu. Thay vì hàng ngàn mét dây dẫn thông qua các ống dẫn bảo vệ, người lắp đặt chỉ việc đơn giản là đặt thiết bị nhỏ gọn vào nơi cần thiết. Mạng có thể được mở rộng chỉ bằng cách đơn giản là thêm các thiết bị, không cần các thao tác phức tạp. Hệ thống cũng có khả năng hoạt động trong vài năm chỉ với một nguồn pin duy nhất.

Để giảm thiểu chi phí lắp đặt, WSN cần phải có khả năng thay đổi linh hoạt theo môi trường. Cơ chế thích nghi theo sự thay đổi mô hình mạng hay do mạng có sự thay đổi giữa các chế độ làm việc. Ví dụ cùng một hệ thống mạng giám sát sự rò rỉ trong một nhà máy hoá chất có thể được cấu hình lại thành một mạng được thiết kế từ trước để khoanh vùng nguồn rò rỉ và tìm ra đúng chỗ. Mạng cũng có thể hướng dẫn các công nhân đường đi an toàn nhất khi có sự cố khẩn cấp.

Nhìn chung, khi con người nghĩ đến mạng không dây họ sẽ nghĩ đến các thiết bị di động, PDA hay laptop. Những thiết bị này có giá thành cao và theo một mục đích cho trước và dựa trên cơ sở hạ tầng đã có trước. Ngược lại, WSN sử dụng các thiết bị nhúng nhỏ, giá thành thấp cho các ứng dụng đa dạng và không dựa trên bất kỳ cơ sở hạ tầng đã có từ trước. Không giống các thiết bị không dây truyền thống, các nút mạng WSN không cần truyền trực tiếp tới trạm gốc, mà chỉ cần truyền tới trạm gần nó, rồi lần lượt truyền về trạm gốc theo dạng truyền thông multihop.

Một ví dụ về mạng được đưa ra trong hình 1. Nó minh hoạ một ứng dụng trong nông nghiệp. Hàng trăm nút nằm rải rác trong cánh đồng liên kết với nhau, thiết lập một mô hình định tuyến, và truyền dữ liệu cho một trung tâm. Ứng dụng đòi hỏi phải thiết thực, uyển chuyển, chi phí thấp và dễ triển khai thành mạng WSN. Nếu một trong các nút lỗi, một mô hình mạng mới được lựa chọn và toàn bộ mạng vẫn tiếp tục truyền dữ liệu. Nếu có thêm nút mạng, chúng chỉ tạo nên nhiều cơ hội định tuyến hơn.

Một thách thức cơ bản của WSN là đưa các ràng buộc khắt khe vào trong một thiết bị đơn lẻ. Các hệ xử lý nhúng với bộ nhớ cỡ kilobytes phải thực hiện các giao thức mạng phức tạp theo dạng adhoc. Rất nhiều ràng buộc đối với các thiết bị được triển khai với số lượng lớn cần có kích thước nhỏ và giá thành thấp. Kích thước giảm là điều chủ yếu dẫn đến giảm giá thành, cũng như khả năng cho phép các thiết bị được sử dụng trong một dải rộng các ứng dụng.

Một khó khăn lớn là năng lượng tiêu thụ. Khi kích thước vật lý giảm, cũng làm giảm năng lượng tiêu thụ. Các ràng buộc về năng lượng sẽ tạo nên giới hạn về tính toán và lưu trữ dẫn đến phải có kiến trúc mới. Nhiều thiết bị, như điện thoại di động hay máy nhắn tin, giảm năng lượng tiêu thụ thông qua phần cứng truyền thông được thiết kế đặc biệt. Một trạm WSN cần hỗ trợ cho một hệ các giao thức ứng dụng cụ thể để làm giảm mạnh kích thước, chi phí và năng lượng tiêu thụ cho ứng dụng đó.

Bản luận văn "Thiết kế chế tạo, vận hành và đo thử nghiệm mạng cảm nhận không dây (wireless sensor network) trên cơ sở sử dụng chip vi điều khiển có mật độ tích hợp cao làm nút mạng và xây dựng phần mềm nhúng nạp trong các vi điều khiển này" sẽ tổng quát hoá WSN, đưa ra các tiêu chí đánh giá đối với một WSN cũng như tiêu chí đánh giá một nút mạng, đồng thời xây dựng một số thử nghiệm mạng cảm nhận không dây dùng VĐK CC1010 của hãng Chipcon-Nauy.

Luận văn gồm 5 chương nội dung, phần mở đầu, phần kết luận, phần phụ lục và tài liệu tham khảo.

Chương 1: Giới thiệu mạng cảm nhận không dây sẽ giới thiệu một cách tổng quan về WSN, các dạng ứng dụng của WSN và đưa ra những tiêu chí đánh giá cho WSN cũng như tiêu chí đánh giá một nút mạng cảm nhận.

Chương 2: Nút mạng sẽ đưa ra các tiêu chí đánh giá cho một nút mạng trong WSN, đồng thời giới thiệu một vi điều khiển CC1010 để làm nút mạng.

Chương 3: Các phương pháp ghép nối CC1010 với các loại đầu đo và chương trình thực hiện. Mục đích của chương này nêu các phương pháp ghép nối giữa vi điều khiển CC1010 với các loại cảm biến bao gồm các loại cảm biến số nối tiếp và cảm biến tương tự. Chương này cũng giới thiệu chi tiết về cách làm việc của CC1010 với cảm biến áp suất MS5535 cũng là một dạng cảm biến số nối tiếp. Điều này góp phần khẳng định khả năng ghép nối với nhiều loại cảm biến khác nhau của CC1010.

Chương 4: Phần mềm nhúng. Mục đích của chương này giới thiệu các bước cơ bản xây dựng một phần mềm nhúng và các phương pháp gỡ lỗi cho phần mềm nhúng.

Chương 5: Triển khai chức năng mạng và các thử nghiệm. Mục đích của chương này là đưa ra một cách xây dựng một WSN dựa trên vi điều khiển CC1010. Đa truy cập được xây dựng dưới dạng hỏi-đáp. Bảng định tuyến hình cây chứa trong các nút mạng. Các thử nghiệm đã thực hiện theo các tiêu chí độ ổn định truyền dữ liệu, khả năng tiết kiệm năng lượng của các nút mạng.

Phần kết luận tổng kết những công việc đã thực hiện và những kết quả đã đạt được đồng thời cũng đề cập đến công việc và hướng nghiên cứu trong tương lai.

Tác giả luận văn này xin gửi lời cảm ơn sâu sắc nhất đến PGS TS. Vương Đạo Vy, Khoa Điện tử viễn thông - Trường Đại học công nghệ - Đại học quốc gia Hà nội, người đã hướng dẫn tận tình và giúp đỡ tôi rất nhiều trong quá trình thực hiện luận văn này.

Tác giả

Nguyễn Thế Sơn

CHƯƠNG I

GIỚI THIỆU MẠNG CẢM NHẬN KHÔNG DÂY

1.1 Mạng cảm nhận không dây

Khái niệm mạng cảm nhận không dây dựa trên công thức đơn giản sau:

Cảm nhận + CPU + Radio = WSN

Từ công thức đơn giản trên, rất nhiều ứng dụng xuất hiện. Tuy nhiên, việc kết hợp các cảm biến, radios, và CPU vào một mạng cảm nhận không dây (wireless sensor network-WSN) đòi hỏi hiểu biết chi tiết về khả năng và giới hạn của các thành phần phần cứng, cũng như hiểu rõ các công nghệ mạng hiện đại, lý thuyết phân bố hệ thống. Một thách thức là ánh xạ toàn bộ yêu cầu hệ thống vào một thiết bị riêng lẻ. Để làm cho WSN trở nên thực tế, một kiến trúc cần được phát triển để tổng hợp các ứng dụng dựa trên khả năng của phần cứng.

Để phát triển kiến trúc hệ thống cần đi từ yêu cầu ứng dụng mức cao xuống các yêu cầu phần cứng mức thấp. Để giới hạn số các ứng dụng phải xem xét, cần tập trung vào một tập các dạng ứng dụng được sử dụng nhiều trong thực tế. Sử dụng các dạng ứng dụng này để tìm ra các yêu cầu mức hệ thống cho toàn bộ kiến trúc. Từ các yêu cầu mức hệ thống này, có thể có các yêu cầu cho các nút mạng riêng lẻ.

1.1.1 Các dạng ứng dụng của mạng cảm nhận

Có ba dạng ứng dụng của mạng cảm nhận không dây: thu thập dữ liệu môi trường, giám sát an ninh, và theo dõi đối tượng. Hầu hết các ứng dụng chủ yếu của WSN đều thuộc ba dạng này.

1.1.1.1 Thu thập dữ liệu môi trường

Mạng cảm nhận không dây thu thập dữ liệu môi trường ra đời đáp ứng cho nhu cầu thu thập thông tin về môi trường tại một tập hợp các điểm xác định trong một khoảng thời gian nhất định nhằm phát hiện xu hướng hoặc quy luật vận động của môi trường. Bài toán này được đặc trưng bởi một số lớn các nút mạng, thường xuyên cung cấp thông số môi trường và gửi về một hoặc một tập trạm gốc (base station) có kết nối với trung tâm xử lý (thường là hệ thống máy tính) phân tích, xử lý, đưa ra các phương án phù hợp hoặc cảnh báo hay đơn thuần chỉ là lưu trữ số liệu. Yêu cầu đặt ra đối với các mạng kiểu này là thời gian sống phải dài hay nói cách khác là các nút mạng phải tiêu thụ năng lượng ít. Mạng cho ứng dụng thu thập dữ liệu môi trường thường sử dụng topology dạng cây, mỗi nút mạng có một nút cha duy nhất. Trạm gốc sẽ là gốc của cây. Dữ liệu từ một nút bất kỳ sẽ được gửi đến cho nút cha của nó, nút này lại tiếp tục chuyển đến cho nút cha tiếp theo (nút ông), cứ như vậy, dữ liệu sẽ được chuyển về trạm gốc.

Những vấn đề nảy sinh với cấu hình mạng này là:

- Hiện tượng thắt cổ chai (bottleneck) khi số lượng nút mạng lớn.

- Một vài nút mạng, vì một số lý do nào đó, không hoạt động. Để mạng tiếp tục hoạt động nó phải có khả năng tự cấu hình lại, nghĩa là phải phát hiện ra các nút bị hỏng hoặc định kỳ thực hiện việc cấu hình lại mạng.

- Mạng phải có thời gian sống dài, từ vài tháng đến vài năm, cần giải quyết vấn đề tiêu thụ năng lượng của các nút mạng tối ưu nhất.

- Phần mềm nhúng phải được thiết kế và lập trình sao cho phù hợp nhất với bài toán truyền thông các thông số đo được như nhiệt độ, độ ẩm, ánh sáng... Phần mềm phải tương thích với phần cứng để hệ có khả năng hoạt động ổn định theo thời gian.

1.1.1.2 Giám sát an ninh

Một ứng dụng thứ hai của mạng cảm nhận là giám sát an ninh. Các mạng giám sát an ninh được tạo bởi các nút đặt ở những vị trí cố định trong môi trường liên tục theo dõi một hay nhiều cảm biến để nhận biết sự bất thường. Sự khác nhau chủ yếu giữa giám sát an ninh và giám sát môi trường là các mạng an ninh không thu thập bất kỳ dữ liệu nào. Điều này có tác động lớn đến việc tối ưu kiến trúc mạng. Mỗi nút thường xuyên kiểm tra trạng thái các cảm biến của chúng nhưng chỉ truyền dữ liệu khi có sự vi phạm an ninh. Việc truyền tức thời và tin cậy của thông điệp cảnh báo là yêu cầu chính của hệ thống.

Thêm vào đó, nó cần được xác nhận là mỗi nút vẫn hiện diện và hoạt động. Nếu một nút bị lỗi, nó sẽ thể hiện một sự vi phạm an ninh cần được thông báo. Đối với các ứng dụng giám sát an ninh, mạng cần được cấu hình sao cho các nút chịu trách nhiệm xác nhận trạng thái các nút khác. Một cách tiếp cận là mỗi nút ngang hàng sẽ thông báo nếu một nút không hoạt động. Mô hình tối ưu của một mạng giám sát an ninh sẽ hoàn toàn khác với mạng thu thập dữ liệu.

Trong cây thu thập số liệu, mỗi nút phải truyền dữ liệu của tất cả con cháu. Do đó, tối ưu là cây ngắn và rộng. Ngược lại, với mạng an ninh cấu hình tối ưu sẽ có mô hình mạng tuyến tính. Công suất tiêu thụ của mỗi nút chỉ tỷ lệ với số các con của nó. Trong mạng tuyến tính, mỗi nút chỉ có 1 con. Điều này phân phối đều năng lượng tiêu thụ của mạng.

Sự tiêu thụ năng lượng chủ yếu trong mạng an ninh là gặp các yêu cầu báo hiệu cảnh báo khi có sự vi phạm an ninh. Mỗi khi nhận thấy, một sự vi phạm an ninh cần được truyền tới trạm gốc ngay lập tức. Độ trễ của việc truyền dữ liệu qua mạng tới trạm gốc có ảnh hưởng nhất định tới hiệu quả của ứng dụng. Các nút mạng cần có khả năng trả lời nhanh chóng với các yêu cầu của các nút láng giềng để chuyển tiếp dữ liệu.

Trong các mạng an ninh việc giảm thời gian trễ của việc truyền cảnh báo quan trọng hơn việc giảm chi phí năng lượng khi truyền. Điều này do các sự kiện cảnh báo rất hiếm khi xảy ra. Trong mạng phòng cháy các cảnh báo gần như không bao giờ xảy ra. Đối với sự kiện xảy ra 1 lần năng lượng chủ yếu được dành cho việc truyền. Giảm độ trễ truyền sẽ làm tăng năng lượng tiêu thụ vì các nút định tuyến phải giám sát các kênh radio thường xuyên hơn.

Trong các mạng an ninh, phần lớn năng lượng tiêu thụ dành cho việc xác nhận chức năng của các nút láng giềng và chuẩn bị chuyển tiếp thông báo cảnh báo. Việc truyền dữ liệu hiện thời sẽ tốn một phần năng lượng của mạng.

1.1.1.3 Theo dõi đối tượng

Với các mạng cảm nhận không dây, các đối tượng có thể được theo dõi đơn giản gắn chúng với một nút cảm biến nhỏ. Nút cảm biến này sẽ được theo dõi khi chúng đi qua một trường các nút cảm biến được triển khai tại những vị trí đã biết. Thay vì cảm nhận dữ liệu môi trường, những nút này sẽ được triển khai để cảm nhận các thông điệp RF của các nút gắn với các đối tượng. Những nút này có thể được sử dụng như những thẻ để thông báo sự có mặt của một thiết bị. Một cơ sở dữ liệu có thể được sử dụng để ghi lại vị trí tương đối của đối tượng với các nút mạng, do đó có thể biết vị trí hiện thời của đối tượng.

Không như mạng cảm nhận hay mạng an ninh, các ứng dụng theo dõi sẽ liên tục thay đổi topology khi các nút đi qua mạng. Trong khi sự kết nối giữa các nút tại các vị trí cố định tương đối ổn định, sự kết nối tới các nút di động sẽ liên tục thay đổi. Thêm vào đó tập hợp các nút bị theo dõi sẽ liên tục thay đổi khi các nút gia nhập hay rời khỏi hệ thống. Điều chủ yếu là mạng có khả năng nhận biết một cách hiệu quả sự có mặt của các nút mới đi vào mạng.

1.1.2 Các chỉ tiêu hệ thống

Sau đây là các chỉ tiêu để đánh giá một WSN. Các chỉ tiêu chủ yếu là thời gian sống, độ bao phủ, chi phí và dễ triển khai, thời gian trả lời, độ chính xác thời gian, bảo mật, và tốc độ lấy mẫu hiệu quả. Các chỉ tiêu này lại liên quan với nhau. Thường thì khi tăng hiệu quả một tham số thì lại làm giảm hiệu quả của tham số khác, ví dụ như tăng tốc độ lấy mẫu lại làm giảm thời gian sống. Mục đích ở phần này hiểu rõ và cân bằng các chỉ tiêu với khả năng của hệ thống.

1.1.2.1 Thời gian sống

Có một giới hạn của mạng cảm nhận không dây đó là thời gian sống. Cả hai ứng dụng giám sát môi trường và giám sát an ninh các nút đều được đặt ở ngoài môi trường, không có người giám sát theo hàng tháng hay hàng năm.

Yếu tố chủ yếu giới hạn thời gian sống của mạng cảm nhận là năng lượng cung cấp. Mỗi nút cần được thiết kế quản lý năng lượng cung cấp nội bộ để tối đa thời gian sống của mạng. Trong trường hợp mạng an ninh, mỗi nút phải sống trong nhiều năm. Một nút bị lỗi sẽ làm tổn thương hệ thống an ninh.

Trong vài tình huống có thể dùng nguồn năng lượng ngoài. Tuy nhiên, vì ưu điểm chính của mạng không dây là tính linh hoạt dễ triển khai. Yêu cầu nguồn năng lượng ngoài cho tất cả các nút mạng lại mâu thuẫn với ưu điểm này. Một giải pháp thoả hiệp là có một nhóm các nút đặc biệt được cấp nguồn ngoài.

Trong hầu hết các ứng dụng, đặc điểm chính của các nút là tự cấp nguồn. Chúng sẽ có đủ năng lượng cho nhiều năm, hoặc có thể lấy năng lượng từ môi trường thông qua thiết bị khác, như năng lượng mặt trời hay nguồn áp điện. Cả hai sự lựa chọn đều yêu cầu năng lượng tiêu thụ trung bình của các nút càng ít càng tốt.

Yếu tố quan trọng quyết định thời gian sống là năng lượng tiêu thụ radio. Một nút cảm nhận không dây khi truyền hoặc nhận tín hiệu radio sẽ tiêu thụ năng lượng lớn. Năng lượng tiêu thụ này có thể giảm được bằng cách giảm năng lượng truyền, tức là giảm chu trình làm việc của radio.

1.1.2.2 Độ bao phủ

Bên cạnh thời gian sống, độ bao phủ là cũng là tham số đánh giá cho mạng không dây. Nó có thuận lợi là khả năng triển khai một mạng trên một vùng rộng lớn. Điều này làm tăng giá trị hệ thống đối với người dùng cuối. Điều quan trọng là độ bao phủ của mạng không tương đương với khoảng cách kết nối không dây được sử dụng. Kỹ thuật truyền multi-hop có thể mở rộng độ bao phủ của mạng. Về mặt lý thuyết chúng có khả năng mở rộng vô hạn. Tuy nhiên, trong một khoảng cách truyền xác định, giao thức mạng multi-hop làm tăng năng lượng tiêu thụ của các nút, và sẽ làm giảm thời gian sống của mạng. Hơn nữa, chúng đòi hỏi một mật độ tối thiểu, và sẽ làm tăng chi phí triển khai.

Ràng buộc khoảng cách dẫn đến việc mở rộng một số lượng lớn các nút. Giá trị chủ yếu của mạng cảm nhận là khả năng mở rộng. Một người dùng có thể triển khai một mạng nhỏ ban đầu và sau đó tiếp tục thêm các nút. Tăng số lượng các nút trong hệ thống sẽ ảnh hưởng tới thời gian sống. Càng nhiều điểm cảm nhận thì càng có nhiều dữ liệu được truyền và sẽ làm tăng năng lượng tiêu thụ của mạng.

1.1.2.3 Chi phí và dễ triển khai

Ưu điểm mấu chốt của mạng cảm nhận không dây là dễ triển khai. Người sử dụng không cần phải hiểu về mạng và cơ chế truyền thông khi làm việc với WSN. Để triển khai hệ thống thành công, WSN cần phải tự cấu hình. Các nút được đặt vào môi trường và có thể hoạt động ngay.

Lý tưởng là, hệ thống cần phải tự cấu hình đối với sự sắp đặt nút vật lý. Tuy nhiên, các hệ thống thực cần đặt các ràng buộc vào một sự sắp đặt nút hiện thời - các nút không thể có khoảng cách vô hạn. WSN cần có khả năng phản hồi khi những sự ràng buộc bị vi phạm. Mạng cần phải có khả năng đánh giá chất lượng của việc triển khai mạng và chỉ rõ các vấn đề tiềm ẩn. Điều đó nghĩa là các nút mạng cần có khả năng tìm kết nối và xác định chất lượng kết nối.

Thêm vào đó, hệ thống cần thích nghi đối với sự thay đổi điều kiện môi trường. Trong suốt thời gian sống, sẽ có thể thay đổi vị trí hay các đối tượng lớn có thể gây nhiễu tới sự truyền thông giữa hai nút. Mạng cần có khả năng tự cấu hình lại để khắc phục những điều này.

Việc triển khai và thiết lập cấu hình ban đầu chỉ là bước đầu tiên trong chu kỳ sống của mạng. Trong thời gian dài, tổng chi phí của hệ thống có thêm chi phí bảo dưỡng. Ứng dụng an ninh còn có yêu cầu hệ thống phải rất mạnh. Để mở rộng khả năng kiểm tra trước khi triển khai, hệ cảm nhận cần được xây dựng để có thể thực hiện việc tự bảo trì. Khi cần, nó có thể tạo ra các yêu cầu bảo trì ngoài.

Trong thực tế, một phần năng lượng được dành cho kiểm tra và bảo trì hệ thống. Việc tạo ra thông tin chẩn đoán và tái cấu hình sẽ làm giảm thời gian sống của mạng, đồng thời cũng làm giảm tốc độ lấy mẫu.

1.1.2.4 Thời gian đáp ứng

Trong các ứng dụng cảnh báo, thời gian đáp ứng hệ thống là một thông số quan trọng để đánh giá hệ thống. Một cảnh báo cần được tạo ra ngay lập tức khi nhận thấy có một sự vi phạm. Dù hoạt động năng lượng thấp, các nút cần có khả năng truyền tức thời các thông điệp qua mạng càng nhanh càng tốt. Trong khi những sự kiện như vậy là không thường xuyên, chúng có thể xảy ra tại bất cứ thời điểm nào mà không được báo trước. Thời gian đáp ứng cũng quan trọng khi điều khiển máy móc trong nhà máy. Những hệ thống này chỉ thành hiện thực nếu đảm bảo được thời gian đáp ứng.

Khả năng có thời gian đáp ứng ngắn xung đột với các kỹ thuật làm tăng thời gian sống của mạng. Thời gian sống của mạng có thể tăng bằng cách để các nút chỉ hoạt động radio trong thời gian ngắn. Nếu một nút chỉ bật radio một lần trong một phút để truyền hay nhận dữ liệu, nó không thể đáp ứng được đối với các ứng dụng cho hệ thống an ninh.

Thời gian đáp ứng có thể cải thiện bằng cách cấp nguồn cho một số nút trong toàn bộ thời gian. Những nút này có thể nghe các thông điệp cảnh báo và chuyển tiếp chúng theo đường khi cần. Tuy nhiên điều này sẽ làm giảm tính dễ triển khai hệ thống.

1.1.2.5 Độ chính xác về thời gian

Trong ứng dụng theo dõi đối tượng và giám sát môi trường các mẫu từ nhiều nút có liên quan theo thời gian để xác định các hiện tượng khác thường được theo dõi. Tính chính xác của cơ chế tương quan phụ thuộc vào tốc độ lan truyền của hiện tượng được đo. Trong trường hợp xác định nhiệt độ trung bình của một toà nhà, các mẫu chỉ được liên quan với nhau trong vòng cỡ hàng giây. Tuy nhiên, để xác định cách phản ứng của toà nhà đối với một trận động đất thì đòi hỏi độ chính xác cỡ mili giây.

Để đạt được độ chính xác theo thời gian, một mạng cần xây dựng và duy trì một thời gian cơ sở toàn cục có thể được sử dụng để sắp xếp các mẫu và các sự kiện theo thời gian. Trong một hệ phân tán, năng lượng cần được mở rộng để duy trì và phân phát đồng hồ. Thông tin đồng bộ thời gian cần liên tục được truyền giữa các nút. Tần số các thông điệp đồng bộ phụ thuộc vào yêu cầu độ chính xác của đồng hồ thời gian.

1.1.2.6 Bảo mật

Các thông tin về nhiệt độ đối với ứng dụng giám sát môi trường đường như vô hại nhưng việc giữ bí mật thông tin là rất quan trọng. Các hoạt động của một toà nhà có thể thu thập được dễ dàng bằng cách lấy thông tin về nhiệt độ và ánh sáng của toà nhà đó. Những thông tin này có thể được sử dụng để sắp xếp một kế hoạch tấn công vào một công ty. Do đó, WSN cần có khả năng giữ bí mật các thông tin thu thập được.

Trong các ứng dụng an ninh, dữ liệu bảo mật trở nên rất quan trọng. Không chỉ duy trì tính bí mật, nó còn phải có khả năng xác thực dữ liệu truyền. Sự kết hợp tính bí mật và xác thực là yêu cầu cần thiết của cả ba dạng ứng dụng.

Việc sử dụng mã hoá và giải mã sẽ làm tăng chi phí về năng lượng và băng thông. Dữ liệu mã hoá và giải mã cần được truyền cùng với mỗi gói tin. Điều đó ảnh hưởng tới hiệu suất ứng dụng do giảm số lượng dữ liệu lấy từ mạng và thời gian sống mong đợi.

1.1.2.7 Tốc độ thu thập thông tin hiệu quả

Trong một mạng thu thập dữ liệu, tốc độ thu thập thông tin hiệu quả là tham số đánh giá hiệu suất của hệ thống. Tốc độ thu thập thông tin hiệu quả là số mẫu lấy được từ mỗi nút riêng lẻ và truyền về điểm thu thập trung tâm. Thông thường, các ứng dụng thu thập dữ liệu chỉ có tốc độ lấy mẫu là 1-2 mẫu trong 1 phút.

Trong một cây thu thập dữ liệu, một nút cần điều khiển dữ liệu của tất cả các con cháu. Nếu mỗi nút con truyền một dữ liệu và một nút có 60 nút con cháu, nó phải truyền 60 lần. Thêm vào đó nó còn phải nhận 60 lần trong một chu kỳ lấy mẫu. Tốc độ và kích thước mạng ảnh hưởng tới tốc độ lấy mẫu hiệu quả.

Một cơ chế để tăng tốc độ lấy thông tin là truyền dữ liệu thô và xử lý dữ liệu nội mạng (innetwork processing). Các dạng nén không gian và thời gian có thể được sử dụng để giảm yêu cầu về băng thông trong khi vẫn duy trì được tốc độ lấy mẫu hiệu quả. Xử lý dữ liệu nội mạng có thể được sử dụng để xác định khi một sự kiện quan tâm xảy ra và tự động lưu trữ dữ liệu. Dữ liệu sau đó được truyền qua mạng multi-hop khi băng thông cho phép.

1.1.3 Các chỉ tiêu nút mạng

Sau đây là những chỉ tiêu để đánh giá một nút mạng trong WSN. Mục đích là qua các chỉ tiêu đánh giá đó để có thể lựa chọn loại VĐK thích hợp và cũng để xây dựng hệ thống hiệu quả.

1.1.3.1 Năng lượng

Để đạt được yêu cầu duy trì năng lượng hoạt động trong nhiều năm thì các nút mạng cần phải tiêu thụ năng lượng rất thấp. Việc tiêu thụ năng lượng thấp chỉ đạt được bằng cách kết hợp các thành phần phần cứng năng lượng thấp và chu trình hoạt động ngắn. Trong thời gian hoạt động, truyền thông radio sẽ tiêu thụ một phần năng lượng đáng kể trong tổng mức tiêu thụ năng lượng của nút mạng. Các thuật toán và các giao thức cần được phát triển để giảm hoạt động truyền nhận radio. Điều này có thể đạt được bằng cách sử dụng sự tính toán cục bộ để giảm luồng dữ liệu nhận được từ cảm biến. Ví dụ, các sự kiện từ nhiều nút cảm biến có thể được kết hợp cùng nhau thành một nhóm các nút trước khi truyền một kết quả đơn lẻ qua mạng cảm nhận.

1.1.3.2 Tính mềm dẻo

Các nút mạng phải có khả năng thích nghi cao để thích hợp với các ngữ cảnh khác nhau. Mỗi một ứng dụng sẽ yêu cầu về thời gian sống, tốc độ lấy mẫu, thời gian đáp ứng và xử lý nội mạng khác nhau. Một kiến trúc WSN cần phải đủ mềm dẻo để cung cấp một dải rộng các ứng dụng. Thêm vào đó, vì lý do chi phí mỗi thiết bị sẽ chỉ có phần cứng và phần mềm cho một ứng dụng cụ thể. Kiến trúc cần phải đơn giản để kết hợp giữa phần cứng và phần mềm. Vì vậy, những thiết bị này đòi hỏi một mức độ cao về tính modul của phần cứng và phần mềm trong khi vẫn giữ được tính hiệu quả.

1.1.3.3 Sức mạnh

Để hỗ trợ cho các yêu cầu về thời gian sống, mỗi nút cần phải càng mạnh càng tốt. Trong sự thực tế, hàng trăm nút mạng sẽ hoạt động trong nhiều năm. Để đạt được điều này, hệ thống cần được xây dựng để vẫn có thể hoạt động khi một nút bị lỗi. Modul hoá hệ thống là một công cụ mạnh để phát triển hệ thống. Bằng cách chia chức năng hệ thống thành các thành phần con độc lập, mỗi chức năng có thể được kiểm tra đầy đủ trước khi kết hợp chúng thành một ứng dụng hoàn chỉnh. Để làm điều này, các thành phần hệ thống phải độc lập đến mức có thể và có giao tiếp chặt chẽ, để ngăn chặn các tương tác không mong đợi. Để tăng sức mạnh hệ thống khi nút bị lỗi, một WSN cũng cần có khả năng đối phó với nhiễu ngoài. Các mạng thường cùng tồn tại cùng với các hệ thống không dây khác, chúng cần có khả năng để thích nghi theo các hành động khác nhau. Nó cũng phải có khả năng hoạt động trong môi trường đã có các thiết bị không dây khác hoạt động với một hay nhiều tần số. Khả năng tránh tắc nghẽn tần số là điều cốt yếu để đảm bảo một sự triển khai thành công.

1.1.3.4 Bảo mật

Để đạt được mức độ bảo mật mà ứng dụng yêu cầu, các nút riêng lẻ cần có khả năng thực hiện sự mã hoá phức tạp và thuật toán xác thực. Truyền dữ liệu không dây rất dễ bị chặn. Chỉ có một cách bảo mật dữ liệu là mã hoá toàn bộ dữ liệu truyền. CPU cần có khả năng tự thực hiện các thao tác mật mã. Để bảo mật toàn bộ dữ liệu truyền, các nút cần tự bảo mật dữ liệu của chúng. Trong khi chúng không có lượng lớn dữ liệu lưu bên trong, chúng sẽ phải lưu các khoá mã hoá được sử dụng trên mạng. Nếu những khoá này bị lộ, tính bảo mật của mạng sẽ mất. Để có được tính bảo mật tốt, cần phải rất khó để lấy được khoá mã hóa từ một nút.

1.1.3.5 Truyền thông

Một chỉ tiêu đánh giá cho bất kỳ WSN là tốc độ truyền, năng lượng tiêu thụ và khoảng cách. Trong khi độ bao phủ của mạng không bị giới hạn bởi khoảng cách truyền của các nút riêng biệt, khoảng cách truyền có một ảnh hưởng quan trọng tới mật độ tối thiểu có thể chấp nhận được. Nếu các nút được đặt rất xa nó không thể tạo được kết nối với mạng liên kết hoặc với một nút dự trữ để có được độ tin cậy cao. Nếu khoảng cách truyền radio thoả mãn một mật độ nút cao, các nút thêm vào sẽ làm tăng mật độ hệ thống tới một mức độ nào đó cho phép. Tốc độ truyền cũng có ảnh hưởng lớn đến hiệu suất của nút mạng. Tốc độ truyền cao hơn làm cho khả năng lấy mẫu hiệu quả hơn và năng lượng tiêu thụ của mạng ít hơn. Khi tốc độ tăng, việc truyền mất ít thời gian hơn và do đó đòi hỏi ít năng lượng hơn. Tuy nhiên, khi tăng tốc độ cũng thường làm tăng năng lượng tiêu thụ radio. Mọi thứ trở nên bằng nhau, một tốc độ cao sẽ tăng hiệu suất hệ thống. Tuy nhiên, tăng tốc độ có ảnh hưởng lớn tới năng lượng tiêu thụ và yêu cầu tính toán của nút. Tổng thể, lợi ích của việc tăng tốc độ có thể được bù lại bởi các yếu tố khác.

1.1.3.6 Tính toán

Hai việc tính toán cho nút mạng tập trung chủ yếu vào xử lý dữ liệu nội mạng và quản lý các giao thức truyền thông không dây mức thấp. Có những yêu cầu giới hạn về mặt thời gian thực đối với truyền thông và cảm biến. Khi dữ liệu tới trên mạng, CPU cần điều khiển đồng thời radio và ghi lại/giải mã (record/decode) dữ liệu tới. Tốc độ truyền cao hơn đòi hỏi tính toán nhanh hơn. Điều tương tự cũng đúng đối với xử lý dữ liệu cảm biến. Các cảm biến tương tự có thể phát ra hàng ngàn mẫu trong một giây. Các thao tác xử lý cảm biến nói chung bao gồm lọc số, trung bình hoá, nhận biết ngưỡng, phân tích phổ... Để tăng khả năng xử lý cục bộ, các nút láng giềng có thể kết hợp dữ liệu với nhau trước khi truyền đi trên mạng. Các kết quả từ nhiều nút mạng có thể được tổng hợp cùng nhau. Xử lý nội mạng này đòi hỏi thêm tài nguyên tính toán. Ngoài ra, ứng dụng xử lý dữ liệu có thể tiêu thụ một lượng tính toán phụ thuộc vào các phép toán được thực hiện.

1.1.3.7 Đồng bộ thời gian

Để hỗ trợ sự tương quan thời gian đọc cảm biến và chu trình hoạt động ngắn của ứng dụng thu thập dữ liệu, các nút cần duy trì đồng bộ thời gian chính xác với các thành viên khác trong mạng. Các nút cần ngủ và thức dậy cùng nhau để chúng có thể định kỳ truyền thông cho nhau. Các lỗi trong cơ chế tính thời gian sẽ tạo nên sự không hiệu quả dẫn đến làm tăng chu trình làm việc. Trong các hệ phân tán, việc trôi clocks theo thời gian là do cơ chế tính thời gian không chính xác. Phụ thuộc vào nhiệt độ, điện áp, độ ẩm, thời gian dựa theo dao động sẽ không như nhau. Cần có cơ chế đồng bộ hoá cao để bù lại những sự không chính xác như vậy.

1.1.3.8 Kích thước và chi phí

Kích thước vật lý và giá thành của mỗi nút riêng lẻ có ảnh hưởng tới sự dễ dàng và chi phí khi triển khai. Tổng chi phí vật tư và chi phí triển khai ban đầu là hai yếu tố chủ chốt dẫn đến việc chấp nhận các công nghệ WSN. Với một ngân sách cố định, việc giảm giá thành trên mỗi nút sẽ làm cho có khả năng mua thêm nhiều nút, triển khai một mạng thu thập với mật độ cao hơn, và thu thập được nhiều dữ liệu hơn. Kích thước vật lý cũng ảnh hưởng tới sự dễ dàng khi triển khai mạng. Các nút nhỏ hơn có thể được đặt ở nhiều vị trí hơn và được sử dụng trong nhiều tình huống hơn. Trong tình huống theo dõi nút đối tượng, các nút nhỏ hơn, rẻ hơn sẽ tăng khả năng theo dõi nhiều đối tượng hơn.

1.2 Một số hướng phát triển trong lĩnh vực WSN

1.2.1 Hệ điều hành nhỏ TinyOS

TinyOS là hệ điều hành sử dụng trong WSN do Trường đại học Berkeley nghiên cứu và phát triển. TinyOS sử dụng cơ chế đa truy cập S-MAC [18], sử dụng ngôn ngữ nesC [8]. Truyền thông trong mạng sử dụng TinyOS là dạng multihop. TinyOS có kích thước nhỏ, mã nguồn mở, dùng mô hình hướng sự kiện, với bộ lập lịch đơn giản cho phép vi điều khiển xử lý nhiều tác vụ song song trong sự hạn chế về tài nguyên tính toán và không gian nhớ. TinyOS sử dụng bộ lập lịch thao tác kiểu FIFO kết nối mềm dẻo giữa phần cứng và các ứng dụng. TinyOS cung cấp giao diện mạng tiện dụng, dùng mô hình truyền thông Active Message (AM), phổ biến và hiệu quả trong tính toán song song hiệu năng cao. TinyOS do vậy, đã tạo ra khả năng giao tiếp mạnh cho các nút mạng trong WSN.

TinyOS tạo ra khả năng giao tiếp mạnh cho các nút mạng trong WSN. Hiện tại TinyOS đang được nghiên cứu, chuyển đổi để làm việc với VĐK CC1010, là loại VĐK sẽ được dùng để xây dựng các thử nghiệm trong khuôn khổ luận văn.

Dựa trên TinyOS và các đặc trưng của CC1010, kiến trúc phần mềm nhúng cho WSN được đề xuất như biểu diễn ở hình 1.2. Tầng trung gian giữa TinyOS và CC1010 là thư viện HAL (Hardware Abstraction Library), cho phép TinyOS tương tác với phần cứng.

Tầng phía trên TinyOS là giao thức dẫn đường trong WSN. Nó vừa cho phép truyền dữ liệu an toàn vừa hạn chế hiện tượng thắt cổ chai. Tầng trên cùng là các ứng dụng đặc thù cho WSN bao gồm: module tự cấu hình mạng và tự cầu hình lại mạng, module thực hiện việc đo các thông số môi trường và chuyển về cho trạm gốc. Hai module này hoạt động theo chế độ định kỳ: sau một khoảng thời gian nhất định, nó được bộ định thời của CC1010 đánh thức và chuyển sang hoạt động; thực hiện xong nhiệm vụ, lại chuyển về nghỉ. Thời gian cấu hình lại hệ thống và đo dữ liệu không giống nhau và phụ thuộc vào từng ứng dụng cụ thể.

Mô hình mạng sử dụng TinyOS là mạng hình cây có dạng sau:

1.2.2 Zigbee

Zigbee là hiệp hội được sáng lập bởi các công ty: Chipcon, Ember, Freescale, Honeywell, Mitsubishi, Motorola, Philips và Samsung. Chuẩn Zigbee ra đời nhằm thiết lập một tiêu chuẩn mới cho mạng không dây với mục đích tiết kiệm năng lượng cho nút mạng.

1.2.2.1 Ngăn xếp Zigbee

Zigbee phát triển lớp mạng và lớp ứng dụng trên cơ sở lớp MAC và lớp vật lý của chuẩn IEEE 802.11.4. Lớp mạng hỗ trợ ba mô hình mạng: Mạng hình sao, Mạng lưới và Mạng hình cây

Lớp Vật lý

Lớp Vật lý được thiết kế có sự tích hợp cao với chi phí thấp.

Lớp MAC

Lớp MAC được thiết kế để hoạt động với nhiều dạng topology. MAC cho phép các thiết bị ít chức năng (reduced functionality device - RFD) không cần nhiều ROM hay RAM. Lớp MAC được thiết kế để kiểm soát số lượng lớn các thiết bị.

Lớp mạng

Lớp mạng được thiết kế cho phép mở rộng không gian mạng mà không đòi hỏi năng lượng truyền cao. Lớp mạng cũng có thể kiểm soát lượng lớn các nút mạng. Các chức năng của nút mạng là:

• Khởi tạo mạng.

• Gia nhập hay rời khỏi mạng

• Cấu hình nút mạng mới

• Cấp địa chỉ: khả năng của bộ điều phối để gán địa chỉ nút mới gia nhập

• Đồng bộ hoá trong một mạng: khả năng đồng bộ hóa giữa các nút mạng thông qua theo dõi thông tin dẫn đường beacons hay thăm dò (polling).

• Bảo mật

• Định tuyến: Sử dụng thuật toán định tuyến Adhoc On-demand Vector (AODV)

1.2.2.2 Các mô hình mạng của Zigbee:

Trong đó:

ZigBee Coordinator: luôn phải có một thiết bị này trong mạng Zigbee. Nhiệm vụ chủ yếu là:

- Thiết lập mạng

- Quản lý các nút mạng

- Truyền beacon

- Lưu trữ thông tin nút mạng

- Thường hoạt động ở trạng thái nhận

- Không cần khả năng tiết kiệm năng lượng

ZigBee Router: thiết bị định tuyến trong mạng. Không cần khả năng tiết kiệm năng lượng

ZigBee End Device: nút mạng

- Được thiết kế để dùng nguồn acquy, tiết kiệm năng lượng.

- Tìm một mạng có sẵn

- Truyền nhận dữ liệu

- Có thể ngủ trong một khoảng thời gian

1.3 Kết luận

Chương 1 khái quát các khái niệm và các dạng ứng dụng mạng cảm nhận không dây. Có ba dạng ứng dụng của mạng cảm nhận không dây, đó là: Thu thập dữ liệu môi trường, Giám sát an ninh và Theo dõi đối tượng. Hầu hết ứng dụng mạng cảm nhận không dây đều rơi vào một trong ba dạng ứng dụng này. Mỗi dạng ứng dụng đều có những mục đích và nguyên tắc làm việc khác nhau, qua đó đòi hỏi phải có thiết kế hệ thống khác nhau. Tuy nhiên các dạng ứng dụng khác nhau đó đều có các chỉ tiêu đánh giá hệ thống như đã nói ở trên, đó là: thời gian sống, độ bao phủ, giá thành và tính dễ triển khai, thời gian đáp ứng, độ chính xác về thời gian, bảo mật và tốc độ thu thập thông tin hiệu quả. Tuỳ từng ứng dụng cụ thể mà các chỉ tiêu trên có các cách đánh giá khác nhau.

CHƯƠNG 2

NÚT MẠNG

2.1 Giới thiệu một số VĐK có thể làm nút mạng cảm nhận

Vấn đề lựa chọn VĐK để xây dựng nút mạng là một vấn đề quan trọng. Việc chọn VĐK hợp lý sẽ làm cho qúa trình xây dựng hệ thống được rút ngắn, hệ thống hoạt động ổn định, tin cậy và đạt các chỉ tiêu đề ra.

Từ các chỉ tiêu nút mạng đã nói ở Chương 1, các tiêu chí quan trọng để chọn VĐK như sau:

o Tiêu thụ năng lượng thấp.

o Tích hợp ADC để có thể ghép nối với cảm biến tương tự.

o Bộ nhớ chương trình cũng như bộ nhớ dữ liệu có kích thước hợp lý.

o Kích thước vật lý nhỏ.

o Có công cụ phát triển giúp người phát triển xây dựng hệ thống dễ dàng và thuận tiện như: sử dụng ngôn ngữ cấp cao, có các thư viện hỗ trợ cho việc cảm nhận cũng như truyền nhận không dây, hỗ trợ gỡ lỗi...

o Giá thành rẻ.

Hiện giờ có 3 họ VĐK trên thị trường có thể thoả mãn các tiêu chí trên:

- Họ VĐK MSP430 của Texas.

- Họ VĐK ATMEGA của Atmel.

- VĐK CC1010 của hãng Chipcon.

Các VĐK nói trên đều thỏa mãn các tiêu chí đề ra. Tuy nhiên, hai họ VĐK đầu tiên không có tích hợp truyền nhận không dây, vì thế nếu sử dụng những VĐK như vậy sẽ phải có thêm mạch truyền nhận không dây bên ngoài, quá trình xây dựng hệ thống sẽ phức tạp. VĐK CC1010 được lựa chọn nhờ có tích hợp truyền nhận không dây, do đó việc chọn VĐK CC1010 làm nút mạng hợp lý hơn chọn các VĐK khác.

2.2 Giới thiệu Vi điều khiển CC1010

2.2.1 Các đặc điểm chính:

- Thu phát không dây 300-1000 MHz.

- Dòng tiêu thụ rất thấp (9,1 mA trong chế độ nhận).

- Độ nhạy cao (-107 dBm).

- Có thể lập trình cho công suất đầu ra tới +10 dBm.

- Tốc độ truyền RF có thể đạt 76.8 kbit/s.

- Cần rất ít thành phần ngoài

- Đo được cường độ RF (RSSI)

- Tương thích họ VĐK 8051

- 32 kB Flash, 2048 + 128 Byte SRAM

- 3 kênh ADC 10 bit, 4 timers / 2PWMs, 2 UARTs, RTC, Watchdog, SPI, mã hoá DES, 26 cổng I/O

- Có khả năng gỡ lỗi sử dụng chương trình dịch Keil μVision2 IDE qua cổng nối tiếp

- Điện áp 2.7 - 3.6 V

- 64-lead TQFP (Thin Quad Flat Pack)

2.2.2 Cổng

Có 4 cổng I/O P0, P1, P2, P3 với 26 chân cổng. Mỗi cổng có 2 thanh ghi tương ứng: thanh ghi cổng P0, P1, P2, P3 và thanh ghi hướng (P0DIR, P1DIR, P2DIR, P3DIR). Mỗi bit trong thanh ghi Px có một bit hướng tương ứng trong thanh ghi PxDIR.y. Đặt PxDIR.y = 1 sẽ làm cho Px.y là cổng nhận dữ liệu (input) và đặt PxDIR.y = 1 sẽ làm cho Px.y là cổng xuất dữ liệu (output)

2.2.3 Ngắt

CC1010 có tổng cộng 15 nguồn ngắt, chia sẻ 12 đường ngắt. Mỗi ngắt có một mức ưu tiên, vector ngắt, cờ cho phép ngắt và cờ báo ngắt.

Bảng 1. Ngắt và các tham số

Ngắt Mức ưu tiên tự nhiên Điều khiển mức ưu tiên Vector ngắt Cờ cho phép ngắt Cờ ngắt

Ngắt Flash/debug 0 - 0x33 EICON.PDIE EICON.PDIF

Ngắt ngoài 0 1 IP.PX0 0x03 IE.EX0 TCON.IE0

Ngắt Timer 0 2 IP.PT0 0x0B IE.ET0 TCON.TF0

Ngắt ngoài 1 3 IP.PX1 0x13 IE.EX1 TCON.IE1

Ngắt Timer 1 4 IP.PT1 0x1B IE.ET1 TCON.TF1

Ngắt truyền nối tiếp 0 5

IP.PS0 0x23 IE.ES0 SCON0.TI 0

Ngắt nhận nối tiếp 0 SCON0.RI 0

Ngắt truyền nối tiếp 1 6

IP.PS1 0x3B IE.ES1 SCON1.TI 1

Ngắt nhận nối tiếp 1 SCON1.RI 1

Ngắt truyền/nhận RF 7 EIP.PRF 0x43 EIE.RFIE EXIF.RFIF

Ngắt Timer 2 8 EIP.PT2 0x4B EIE.ET2 EXIF.TF2

Ngắt ADC 9 EIP.PAD 0x53 EIE.ADIE

và ADCON2.

ADCIE EXIF.ADIF

ADCON2.

ADCIF

Ngắt mã hoá/giải mã DES EIE.ADIE

CRPCON.

CRPIE EXIF.ADIF

CRPCON.

CRPIF

Ngắt Timer 3 10 EIP.PT3 0x5B EIE.ET3 EXIF.TF3

Ngắt thời gian thực 11 EIP.PRTC 0x63 EIE.RTCIE EICON.RTCIF

2.2.3.1 Mặt nạ ngắt

IE.EA là cờ cho phép ngắt toàn bộ các ngắt, ngoại trừ ngắt Flash/Debug. Khi cờ IE.EA được thiết lập, mỗi ngắt bị che bởi cờ cho phép ngắt được liệt kê ở bảng 1. Khi cờ IE.EA bị xoá, tất cả các ngắt bị che, ngoại trừ ngắt Flash/Debug, có bit che ngắt riêng, EICON.FDIE.

2.2.3.2 Xử lý ngắt

Khi một ngắt được cho phép xảy ra, CPU nhảy tới địa chỉ phục vụ ngắt tương ứng với ngắt đó (ISR), như chỉ ra ở bảng 1. CC1010 thực hiện ISR để hoàn thành trừ khi một ngắt khác có mức ưu tiên cao hơn xảy ra. Mỗi ISR kết thúc với lệnh RETI. Sau khi thực hiện lệnh RETI, CC1010 quay trở lại lệnh tiếp theo sau lệnh đã được thực hiện trước khi xảy ra ngắt. Nếu lệnh đang thực hiện là RETI, hay đang ghi vào các thanh ghi IP, IE, EIP, EIE, CC1010 hoàn thành thêm một lệnh trước khi phục vụ ngắt.

2.2.3.3 Thứ tự ưu tiên

Các ngắt có 2 giai đoạn ưu tiên: mức ngắt và mức tự nhiên. Mức ngắt được ưu tiên trước mức tự nhiên.

Mức ngắt có 2 mức: thấp và cao. Ngắt có mức ưu tiên là cao sẽ có thể ngắt ngang chương trình phục vụ ngắt có mức ưu tiên thấp hơn. Nếu các ngắt có cùng mức ưu tiên mà cùng xảy ra đồng thời, ngắt nào có mức ưu tiên tự nhiên thấp nhất sẽ được phục vụ trước.

2.2.4 Biến đổi ADC

Bộ biến đổi ADC của CC1010 có độ phân dải 10 bit, được điều khiển bởi các thanh ghi ADCON và ADCON2. Có ba kênh vào ADC, được chọn bởi ADCON.ADADR. Thanh ghi này cũng được sử dụng để chọn chân AD1 như là điện áp tham chiếu ngoài (khi sử dụng AD0). Khi chân AD1 được dùng như tham chiếu ngoài, chỉ có hai lối vào ADC được sử dụng. Đầu ra ADC là đơn cực, nghĩa là giá trị 0 tương ứng với 0V và 1023 tương ứng với điện áp tham chiếu (1.25 V hoặc VDD phụ thuộc vào bit ADCREF). Điện áp tham chiếu analog được điều khiển bởi ADCON.ADCREF. ADCON.AD_PD cần đặt bằng 1 khi không sử dụng ADC để tiết kiệm năng lượng. Biến đổi ADC được bắt đầu sau 5µs sau khi xoá bit điều khiển ADCON.ADCRUN khi sử dụng VDD hay nguồn tham chiếu ngoài, hoặc 100 µs khi sử dụng tham chiếu trong 1.25V.

2.2.5 Bộ định thời

CC1010 có 4 bộ định thời Timer 0, Timer 1, Timer 2, Timer 3 hoạt động như là bộ định thời hay bộ đếm (Timer/Counter) trong đó Timer2 và Timer3 còn có thể hoạt động như bộ điều chế độ rộng xung (PWM - Pulse Width Modulation).

2.2.5.1 Time 0/ Timer 1

Timer/Counter 0 và 1 có thể được lập trình và hoạt động độc lập theo 4 chế độ, được điều khiển bởi các thanh ghi TMOD và TCON. Các chế độ có thể như sau:

- 13 bit Timer/Counter (Mode 0)

- 16 bit Timer/Counter (Mode 1)

- 8 bit Timer/Counter tự động nạp lại (Mode 2)

- 2 Timer 8 bit (chỉ dùng cho Timer 0, Mode 0)

Chi tiết về các chế độ, cách điều khiển sử dụng 2 thanh ghi TCON và TMOD xin xem thêm phần Tài liệu tham khảo [6].

2.2.5.2 Timer 2/ Timer 3

Ngoài tính năng như là bộ định thời, Timer 2 và 3 có thể được sử dụng như bộ điều chế độ rộng xung PWM. Nếu xoá bit TCON2.M2/TCON2.M3 thì sẽ là bộ định thời. Nếu thiết lập bit TCON2.M2/TCON2.M3 thì sẽ là PWM. Khi đó chân P3.4 và chân P3.5 là chân phát xung đầu ra tương ứng cho Timer2/Timer3. Chu kỳ TnPWM đối với Timer n như sau:

Trong đó thời gian ở trạng thái cao Tnh là:

Điều này có nghĩa là trong chế độ PWM, nếu Tn = 0 thì có mức thấp ở đầu ra và nếu Tn = 255 thì có mức cao.

Trong đó giá trị các thanh ghi Tn và TnPRE được đặt từ trước.

2.2.6 Bộ thu phát không dây (RF Transceiver)

2.2.6.1 Miêu tả chung

Bộ thu phát CC1010 UHF RF được thiết kế cho những ứng dụng tiêu thụ năng lượng thấp và điện áp thấp. Mạch thu phát được dành cho ISM (công nghiệp, khoa học và y học) và SRD (Short Range Device) dải tần 315, 433, 868 và 915 MHz, nhưng có thể dễ dàng lập trình để hoạt động trong dải tần 300-1000 MHz. Các thông số chính của CC1010 có thể được lập trình thông qua các thanh ghi chức năng đặc biệt (Special Function Registers - SFRs), làm cho CC1010 rất mềm dẻo và dễ sử dụng bộ thu phát vô tuyến. Rất ít các thành phần tích cực đòi hỏi cho hoạt động của bộ thu phát RF.

Một sơ đồ khối được đơn giản hoá của bộ thu phát RF được thể hiện ở hình 2.1. Chỉ các chân tín hiệu analog được thể hiện cùng với bus dữ liệu SFR bên trong để thiết lập giao tiếp RF và để truyền và nhận dữ liệu.

Trong chế độ nhận, tín hiệu vào RF được khuếch đại bởi bộ khuếch đại ồn thấp (low-noise amplifier LNA) và được chuyển thành trung tần (intermediate frequency - IF) bởi bộ trộn (MIXER). Trong giai đoạn trung tần (IF STAGE) tín hiệu được khuếch đại và lọc trước khi đưa tới bộ giải điều chế (DEMOD). Như một lựa chọn, một tín hiệu RSSI hay IF sau khi trộn được đưa vào AD2. Sau khi giải điều chế, tín hiệu số được đưa tới thanh ghi RFBUF. Ngắt có thể được sinh ra theo mỗi bit hay mỗi byte nhận được (EXIF.RFIF).

Trong chế độ truyền, dao động được điều khiển bởi điện áp (VCO) được đưa trực tiếp tới khuếch đại công suất (PA). Đầu ra RF là khoá dịch chuyển tần số (frequency shift keyed - FSK) bởi luồng bit được đưa tới thanh ghi RFBUF. Ngắt có thể được sinh ra cho mỗi bit hay byte được truyền (EXIF.RFIF). Mạch chuyển bên trong T/R làm cho giao tiếp với antenna dễ dàng và sử dụng rất ít thành phần ngoại vi.

Bộ tổ hợp tần số tạo ra dao động bên trong được đưa tới MIXER trong chế độ nhận và PA trong chế độ truyền. Bộ tổ hợp tần số bao gồm một dao động thạch anh (XOSC), bộ nhận biết pha (phase detector - PD), bơm nạp (CHARGE PUMP), bộ lọc (internal loop filter - LPF), VCO, và các bộ chia tần (/R và /N). Một tinh thể ngoài có thể được nối vào XOSC. VCO chỉ cần một cuộn cảm ngoài.

2.2.6.2 Mạch ứng dụng RF

Bộ thu phát RF đòi hỏi rất ít các ngoại vi. Một mạch ứng dụng điển hình được thể hiện ở hình 2.2. Các giá trị của các thành phần này xin xem thêm phần Tài liệu tham khảo [6].

Tương ứng vào/ra

Cặp C31/L32 là đầu vào cho nơi nhận của bộ nhận, và nội trở của L32 có tác dụng định thiên (bias) một chiều. C41, L41 và C42 được sử dụng để tương ứng với bộ truyền có trở kháng 50 Ohm. Một bộ chuyển mạch trong T/R làm cho nó có khả năng cùng nối với đầu vào và đầu ra và thích hợp với bộ thu phát 50Ω trong cả hai chế độ RX và TX. VCO được tích hợp hoàn toàn trừ cuộn cảm L101.

Lọc

Các thành phần bên ngoài (ví dụ RF LC hay lọc răng cưa) có thể được sử dụng để cải tiến hiệu năng cho các ứng dụng riêng biệt. Nếu lọc răng cưa được sử dụng, nó chỉ có tác dụng cho RX (phải sử dụng chuyển mạch ngoài RX/TX).

Nguồn cung cấp

Các tụ tách và lọc nguồn cần được sử dụng (không chỉ ra trong mạch ứng dụng). Các tụ này càng gần chân nguồn càng tốt. Vị trí và kích thước của tụ tách và lọc nguồn là rất quan trọng để đạt được độ nhạy tốt nhất.

Chú ý rằng các giá trị hợp thành cho 868 và 915 MHz có thể là như nhau. Tuy nhiên, rất quan trọng là cách bố trí được tối ưu hoá để lựa chọn cuộn cảm VCO để làm cho tần số hoạt động được chính xác. Cuộn cảm VCO phải được đặt rất sát và đối xứng với các chân tương ứng (L1 và L2). Chipcon cung cấp cách bố trí tham khảo để đạt được hiệu năng cao nhất.

2.2.6.3 Điều khiển bộ thu phát RF và quản lý năng lượng

Thanh ghi RFMAIN điều khiển chế độ hoạt động (RX hay TX), sử dụng hai thanh ghi tần số và các chế độ tiết kiệm năng lượng (power down). Theo cách này CC1010 có được sự mềm dẻo để quản lý công suất RF để đạt được chính xác năng lượng tiêu thụ đòi hỏi và các ứng dụng chỉ sử dụng pin. Các chế độ tiết kiệm năng lượng khác nhau được điều khiển thông qua các bit riêng biệt trong thanh ghi RFMAIN. Các bit này điều khiển phần RX, TX, bộ tổ hợp tần số và dao động thạch anh. Sự điều khiển riêng biệt này có thể dùng để tối ưu hoá làm cho dòng tiêu thụ thấp nhất có thể trong các ứng dụng nào đó. Một thứ tự bật nguồn điển hình để đạt được dòng tiêu thụ thấp nhất được thể hiện ở hình 2.3. Hình vẽ giả thiết rằng tần số A dùng cho RX và tần số B dùng cho TX. Nếu không gặp trường hợp này, đảo lại thiết lập F_REG.

2.2.6.4 Điều chế dữ liệu và các chế độ dữ liệu

Có bốn chế độ dữ liệu khác nhau được xác định cho truyền và nhận, có thể lập trình được qua MODEM0.DATA_FORMAT. Các chế độ này khác nhau ở cách mã hoá dữ liệu, cách dữ liệu đến và đi được và được chấp nhận, và liệu có sự đồng bộ hoá luồng bit hay không. Định dạng dữ liệu cần được chọn trước khi bộ thu phát RF hoạt động. Hai trong số các chế độ, chế độ đồng bộ NRZ và chế độ đồng bộ Manchester, truyền hay nhận dữ liệu có tốc độ baud được thiết lập trong MODEM0.BAUDRATE. Modem thực hiện việc đồng bộ hoá luồng bit trong suốt quá trình nhận. Trong chế độ Manchester modem cũng thực hiện mã hoá và giải mã Manchester. Các chế độ NRZ và Manchester chấp nhận và truyền dữ liệu theo cả hai cách một bit hay một byte trong cùng một thời điểm, lập trình được qua RFCON.BYTEMODE. Trong hầu hết các ứng dụng có hai chế độ được khuyên dùng. Dữ liệu truyền đi hay nhận về được đặt trong thanh ghi RFBUF. Trong quá trình truyền hay nhận cần biết có dữ liệu đến hay đi, từng bit hay từng byte phụ thuộc vào RFCON.BYTEMODE, được báo hiệu bằng cách tạo ra (EXIF.RFIF.) Phụ thuộc vào liệu ngắt RF được cho phép hay không (EIE.RFIE), việc truyền hay nhận dữ liệu có thể được điều khiển bởi chương trình phục vụ ngắt hay có thể được thực hiện bằng cách hỏi (polling). Trong quá trình nhận khi sử dụng chế độ NRZ hay Manchester, nhận biết tín hiệu dẫn đường bằng phần cứng và nhận biết dấu hiệu bắt đầu một frame có thể sử dụng các thanh ghi PDET và BSYNC. Hai chế độ khác, Transparent mode và UART mode, chỉ đơn giản là truyền số liệu FSK modem và thanh ghi RFBUF và UART0, cho phép lựa chọn tốc độ và mã hoá dữ liệu. Khi sử dụng UART0 trong chế độ UART chân P3.1 không được sử dụng cho UART output và có thể sử dụng như một cổng I/O. Chipcon khuyên rằng các chế độ đồng bộ được sử dụng. Các chế độ dữ liệu khác bỏ qua mạch quyết định dữ liệu của bộ thu phát RF và không hỗ trợ chế độ bytemode. Chế độ Transparent mode chỉ dùng để kiểm thử.

Mã hoá Manchester

Trong chế độ Manchester data clock được truyền cùng với dữ liệu. '1' được mã hoá bằng tần số cao f1 theo sau là tần số thấp hơn f0. '0' được mã hoá bằng tần số thấp f0 theo sau là tần số cao hơn f1. Điều này được minh hoạ ở hình 2.4.

2.2.6.5 Tốc độ Baud

Tốc độ từ 0.6 kBaud tới 76.8 kBaud được thiết lập trong bit điều khiển MODEM0.BAUDRATE. MODEM0.XOSC_FREQ cũng phải được thiết lập tuỳ vào tinh thể thạch anh đang sử dụng. Tốc độ baud được tính theo công thức sau:

RF_BAUDRATE là tốc độ tính theo kBaud, BAUDRATE và XOSC_FREQ là các bit điều khiển trong MODEM0. Sử dụng một trong các thạch anh chuẩn đặt trong MODEM0.XOSC_FREQ sẽ tạo ra các tốc độ chuẩn 0.6, 1.2, 2.4, 4.8, 9.6, 19.2, 38.4 hay 76.8 kBaud. Các tần số thạch anh khác nhau sẽ xác định các tốc độ khác nhau như miêu tả ở trên. Tốc độ baud tới 19.2 kBaud có thể được tạo ra cho bởi bất kỳ tần số thạch anh nào. Tốc độ lớn hơn 19.2 kBaud cần có thêm các sự kết hợp như bảng 2.

Bảng 2. Tốc độ baud theo tần số thạch anh

MODEM0.

BAUDRATE

/XOSC fxosc (MHz)

RF_BAUDRATE

(kBaud) 3.6864

7.3728

11.0592

14.7456

18.4320

22.1184

0.6 0/0 0/1 0/2 0/3 0/4 0/5

1.2 1/0 1/1 1/2 1/3 1/4 1/5

2.4 2/0 2/1 2/2 2/3 2/4 2/5

4.8 3/0 3/1 3/2 3/3 3/4 3/5

9.6 4/0 4/1 4/2 4/3 4/4 4/5

19.2 5/0 5/1 5/2 5/3 5/4 5/5

38.4 NA 5/0 NA 5/1 NA 5/2

76.8 NA NA NA 5/0 NA NA

2.2.6.6 Truyền và nhận dữ liệu

Trong chế độ Transparent hay UART dữ liệu đi hay đến được đưa trực tiếp tới bộ điều chế trong chế độ truyền và được nhận trực tiếp trong chế độ nhận. Trong các chế độ NRZ và Manchester, dữ liệu được lưu tại RFBUF như được minh hoạ ở hình 2.5. Việc lưu như vậy có những ảnh hưởng cần được xem xét khi nhận hay truyền dữ liệu, nhất là trong chế độ bytemode.

Quá trình truyền

Khi truyền dữ liệu theo bytemode (RFCON.BYTEMODE=1), một thanh ghi 8-bit sẽ dịch từng bit tới bộ điều chế, MSB (bit cao nhất) trước tiên, và chu kỳ phụ thuộc vào tốc độ được lựa chọn. Khi thanh ghi dịch này rỗng sẽ nạp một byte mới từ RFBUF tiếp tục dịch bit. Nội dung của thanh ghi RFBUF không đổi sau khi thanh ghi dịch lấy dữ liệu từ nó. Một ngắt được tạo ra (EICON.RFI) và RFBUF có thể được nạp với byte dữ liệu mới. Nếu một byte mới không được ghi vào trong chu kỳ tám bit (chu kỳ tám bit trong chế độ NRZ và chu kỳ 16 baud trong chế độ Manchester), thời điểm tiếp theo thanh ghi dịch rỗng sẽ lấy lại dữ liệu cũ từ RFBUF. Chẳng hạn khi truyền một tín hiệu dẫn đường bao gồm '0' và '1' thay đổi, nó chỉ cần ghi byte vào RFBUF một lần và chờ tới khi số các byte cần truyền tín hiệu dẫn đường được truyền đi. Ở chế độ bitmode (RFCON.BYTEMODE=0), cũng xảy ra tương tự, nhưng chỉ một bit tại một thời điểm. Theo đó, thanh ghi dịch sẽ nạp bit mới từ RFBUF.0 sau khi truyền một bit đi, và ngắt RF được tạo ra để báo có bit mới được nạp. Để có thể ghi bit tiếp theo vào RFBUF.0 trong một chu kỳ bit ở tốc độ cao, nên sử dụng vòng quét nhanh (tight polling loop) thay vì thủ tục truyền dựa trên ngắt. Để bắt đầu truyền dữ liệu ngay khi có thể, bit/byte đầu tiên được truyền được ghi vào RFBUF trước khi bộ điều chế hoạt động (RFMAIN.TX_PD=0). Nó sẽ ngay lập tức được nạp vào thanh ghi dịch và một yêu cầu ngắt được tạo ra cho bit/byte thứ hai. Điều này đặc biệt quan trọng khi tính đến việc lưu dữ liệu tại cuối một quá trình truyền. Khi byte cuối cùng của một frame hay packet được nạp vào thanh ghi dịch nó vẫn không được truyền đi. Như vậy yêu cầu ngắt được tạo ra tại cùng thời điểm không bị dừng đối với cả phần analog hay digital của một quá trình truyền. Quá trình truyền không thể kết thúc được một cách an toàn cho tới chu kỳ 9 bit cuối cùng trong chế độ bytemode và chu kỳ 2 bit trong chế độ bitmode, khi bit cuối cùng được dịch và được truyền tới antenna. Một giải pháp đơn giản là luôn luôn truyền hai byte mở rộng trong chế độ bytemode hay hai bit mở rộng trong chế độ bitmode ở cuối quá trình truyền dữ liệu. Điều này không gây ra vấn đề gì trong thực tế

Quá trình nhận

Khi nhận dữ liệu lược đồ đệm sẽ hoạt động ngược với quá trình truyền. Từng bit từ bộ giải điều chế được dịch vào thanh ghi dịch 8-bit, MSB trước tiên: Khi thanh ghi dịch đầy nó được nạp vào RFBUF và một yêu cầu ngắt được sinh ra (EICON.RFIF). Byte cần được đọc trong chu kỳ một byte (chu kỳ 8 baud trong chế độ NRZ và 16 baud trong chế độ Manchester). Nếu không, nó sẽ bị ghi đè bởi byte nhận được tiếp theo và dữ liệu sẽ bị mất. Trong chế độ bitmode quá trình đệm cũng xảy ra tương tự, nhưng mỗi bit tại một thời điểm. Theo đó, khi một bit mới tới từ bộ giải điều chế thanh ghi dịch sẽ lưu nó và lưu bit cuối cùng vào RFBUF.0, lần lượt tạo ra các yêu cầu ngắt RF để có thể đọc các bit mới. Để có thể đọc bit tiếp theo từ RFBUF.0 trong chu kỳ một bit ở tốc độ cao nên sử dụng vòng quét nhanh thay vì dựa vào ngắt. Không có sự cân nhắc đặc biệt nào đối với thời điểm bắt đầu hay kết thúc quá trình nhận.

2.2.7 Module CC1010EM

Để dễ dàng và thuận tiện cho việc phát triển các ứng dụng sử dụng CC1010, hãng Chipcon cũng cung cấp module CC1010 EM (Evaluation module), trên đó có tích hợp hầu hết các linh kiện cần cho việc xây dựng một nút mạng như:

- VĐK CC1010

- Dao động thạch anh

- Antena

- Một cảm biến nhiệt độ đưa vào chân AD1

- Các chân cổng

Việc xây dựng thử nghiệm trong khuôn khổ luận văn cũng dùng module CC1010EM. Việc thử nghiệm sau này đã cho thấy rằng module này đã đáp ứng được các chức năng cơ bản nút mạng đó là chức năng mạng và chức năng cảm nhận. Tuy nhiên, giá thành module này còn đắt (khoảng 150USD) trong khi giá thành VĐK CC1010 rất rẻ (khoảng 10USD) nên việc nghiên cứu chế tạo module này ở Việt Nam để hạ giá thành là rất cần thiết.

2.3 Kết luận

Chương này đã giới thiệu các một số loại VĐK có thể được dùng làm nút mạng trong WSN theo các tiêu chí: năng lượng tiêu thụ thấp, tính mềm dẻo, sức mạnh của nút mạng, tính bảo mật, truyền thông, khả năng tính toán, kích thước của nút mạng. Từ các chỉ tiêu đánh giá đó đã chọn được loại vi điều khiển CC1010 của hãng Chipcon (Nauy) để làm nút mạng. Đây là loại vi điều khiển tương thích họ 8051 thông dụng, sử dụng ngôn ngữ lập trình C và chương trình dịch Keil µVision2.0. Bên cạnh đó Chipcon cũng cung cấp các thư viện làm việc với CC1010 làm cho việc viết chương trình trở nên dễ dàng và thuận tiện.

CHƯƠNG 3

CÁC PHƯƠNG PHÁP GHÉP NỐI VỚI CÁC LOẠI ĐẦU ĐO VÀ CHƯƠNG TRÌNH THỰC HIỆN CHỨC NĂNG THU THẬP DỮ LIỆU

3.1 Giới thiệu cảm biến

3.1.1 Khái niệm

Trong các hệ thống đo lường điều khiển mọi quá trình đều được đặc trưng bởi các trạng thái như nhiệt độ, áp suất, tốc độ, momen...Các biến trạng thái này thường là các đại lượng không điện. Nhằm mục đích điều chỉnh, điều khiển các quá trình ta cần thu thập thông tin, đo đạc, theo dõi sự biến thiên của các biến trạng thái của quá trình. Các bộ cảm biến thực hiện chức năng này, chúng thu nhận, đáp ứng với các tín hiệu và kích thích, là tai mắt của các hoạt động khoa học và công nghệ của con người.

Các bộ cảm biến thường được định nghĩa theo nghĩa rộng là thiết bị cảm nhận và đáp ứng với các tín hiệu và kích thích.

Trong mô hình mạch, ta có thể coi bộ cảm biến như một mạng hai cửa, trong đó cửa vào là biến trạng thái cần đo x và cửa ra là đáp ứng y của bộ cảm biến với kích thích đầu vào x.

Phương trình mô tả quan hệ giữa đáp ứng y và kích thích x của bộ cảm biến có dạng:

y = f(x)

Trong các hệ thống đo lường - điều khiển hiện đại, quá trình thu thập và xử lý tín hiệu thường do máy tính đảm nhiệm.

Trong sơ đồ hình 3.1, quá trình (đối tượng) được đặc trưng bằng các biến trạng thái và được các bộ cảm biến thu nhận. Đầu ra của bộ vi xử lý được phối ghép với cơ cấu chấp hành nhằm tác động lên quá trình (đối tượng). Đây là sơ đồ điều khiển tự động (qúa trình), trong đó bộ cảm biến đóng vai trò cảm nhận, đo đạc và đánh giá các thông số của hệ thống. Bộ vi xử lý làm nhiệm vụ xử lý thông tin và đưa ra tín hiệu điều khiển quá trình.

3.1.2 Phân loại các bộ cảm biến

3.1.2.1 Theo nguyên lý chuyển đổi giữa đáp ứng và kích thích

Hiện tượng Chuyển đổi đáp ứng và kích thích

Vật lý Nhiệt điện

Quang điện

Quang từ

Điện từ

Quang đàn hồi

Từ điện

Nhiệt từ

Nhiệt quang

Hoá học Biến đổi hoá học

Biến đổi điện hoá

Phân tích phổ

Sinh học Biến đổi sinh hoá

Biến đổi vật lý

Hiệu ứng trên cơ thể sống

Phân tích phổ

3.1.2.2 Theo dạng kích thích

Kích thích Các đặc tính của kích thích

Âm thanh - Biên, pha, phân cực

- Phổ

- Tốc độ truyền sóng

Điện - Điện tích, dòng điện

- Điện thế, điện áp

- Điện trường

- Điện dẫn, hằng số điện môi

Từ - Từ trường (biên, pha, phân cực, phổ)

- Từ thông, cường độ từ trường

- Độ từ thẩm

Quang - Biên, pha, phân cực, phổ

- Tốc độ truyền

- Hệ số phát xạ, khúc xạ

- Hệ số hấp thụ, hệ số bức xạ

Cơ - Vị trí

- Lực, áp suất

- Gia tốc, vận tốc

- Ứng suất, độ cứng

- Momen

- Khối lượng, tỷ trọng

- Vận tốc chất lưu, độ nhớt

Nhiệt - Nhiệt độ

- Thông lượng

- Nhiệt dung, tỷ nhiệt

Bức xạ - Kiểu

- Năng lượng

- Cường độ

3.1.2.3 Theo tính năng

- Độ nhạy

- Độ chính xác

- Độ phân giải

- Độ chọn lọc

- Độ tuyến tính

- Công suất tiêu thụ

- Dải tần

- Độ trễ - Khả năng quá tải

- Tốc độ đáp ứng

- Độ ổn định

- Tuổi thọ

- Điều kiện môi trường

- Kích thước, trọng lượng

3.1.2.4 Theo phạm vi sử dụng

- Công nghiệp

- Nghiên cứu khoa học

- Môi trường, khí tượng

- Thông tin, viễn thông

- Nông nghiệp

- Dân dụng

- Giao thông

- Vũ trụ

- Quân sự

3.1.2.5 Theo thông số mô hình mạch thay thế

Các bộ cảm biến có thể phân chia theo thông số:

- Cảm biến tích cực (có nguồn) đầu ra là nguồn áp hoặc nguồn dòng.

- Cảm biến thụ động (không nguồn) được đặc trưng bởi các thông số R,L,C,M... tuyến tính hoặc phi tuyến.

3.1.2.6 Theo dạng tín hiệu đầu ra

- Cảm biến có đầu ra là tín hiệu tương tự

- Cảm biến đầu ra là tín hiệu số

3.1.3 Các đặc trưng cơ bản của bộ cảm biến

3.1.3.1 Hàm truyền

Quan hệ giữa đáp ứng và kích thích của bộ cảm biến có thể cho dưới dạng bảng giá trị, đồ thị hoặc biếu thức toán học. Gọi x là kích thích, y là tín hiệu đáp ứng, hàm truyền cho ta quan hệ giữa đáp ứng và kích thích. Hàm truyền có thể được biểu diễn dưới dạng tuyến tính, phi tuyến, logarit, hàm luỹ thừa hoặc hàm mũ

Quan hệ tuyến tính giữa đáp ứng và kích thích có dạng:

y = ax + b

Ở đây a là hằng số bằng tín hiệu ra khi tín hiệu vào bằng không, b là độ nhạy, y là một trong các đặc trưng của tín hiệu ra, có thể là biên độ, tần số hoặc pha tuỳ theo các tính chất của bộ cảm biến

Hàm truyền logarit có dạng:

y = 1 + blnx

Dạng mũ:

y = aekx

Dạng luỹ thừa:

y = ao + a1xk với k là hằng số

Các bộ cảm biến phi tuyến không thể được đặc trưng bằng các hàm truyền kể trên, trong trường hợp này ta phải sử dụng các hàm gần đúng bậc cao.

Đối với hàm truyền phi tuyến hoặc hàm truyền ở chế độ động, độ nhạy b phải được định nghĩa theo biểu thức:

Trong nhiều trường hợp ta có thể làm gần đúng hàm truyền phi tuyến bằng phương pháp tuyến tính hoá từng đoạn

3.1.3.2 Độ lớn của tín hiệu vào

Là giá trị lớn nhất của tín hiệu đặt vào bộ cảm biến mà sai số không vượt quá ngưỡng cho phép.

3.1.3.3 Sai số và độ chính xác

Các bộ cảm biến cũng như các dụng cụ đo lường khác, ngoài đại lượng cần đo (cảm nhận) còn chịu tác động của nhiều đại lượng vật lý khác gây nên sai số giữa giá trị đo được và giá trị thực của đại lượng cần đo. Gọi ∆x là độ lệch tuyệt đối giữa giá trị đo và giá trị thực x, sai số tương đối của bộ cảm biến được tính bằng:

Δ% =

Khi đánh giá sai số của cảm biến ta thường phân chúng thành hai loại: sai số hệ thống và sai số ngấu nhiên.

Sai số hệ thống là sai số không phụ thuộc vào số lần đo, có giá trị không đổi hoặc thay đổi chậm theo thời gian đo và thêm vào một độ lệch không đổi giữa giá trị thực và giá trị đo được. Sai số hệ thống thường do sự thiếu hiểu biết về hệ đo, do điều kiện sử dụng không tốt

Sai số ngẫu nhiên là sai số xuất hiện có độ lớn và chiều không xác định.

3.1.4 Cảm biến số nối tiếp và cách ghép nối

Nhìn chung cảm biến là một thiết bị được thiết kế thu thập thông tin về một đối tượng và chuyển đổi thành tín hiệu điện. Một cảm biến cổ điển có thể chia làm 4 phần như hình 3.2. Khối đầu tiên là khối cảm nhận (ví dụ, điện trở, điện dung, bán dẫn, vật liệu áp điện, photodiode, cầu điện trở, ...). Tín hiệu từ phần cảm nhận thường bị ảnh hưởng bởi nhiễu. Do đó, cần có các kỹ thuật xử lý tín hiệu như khuếch đại, tuyến tính hoá, bù và lọc để giảm những tác động đó.

Nếu có nhiều thành phần cảm nhận được sử dụng trong cùng một chip, cần phải có bộ hợp kênh. Trong trường hợp thu thập dữ liệu, tín hiệu từ cảm biến có dạng nối tiếp hay song song. Chức năng này có thể nhận ra bởi bộ biến đổi tương tự-số hay tần số-số. Khối cuối cùng là bus giao tiếp cảm biến. Một hệ thống thu thập dữ liệu có thể có cấu hình dạng hình sao trong đó mỗi cảm biến được nối với một bộ hợp kênh số. Khi sử dụng số lượng lớn các cảm biến, tổng độ dài cáp và số các kết nối tại bộ hợp kênh có thể rất lớn. Vì lý do đó cần có hệ thống tổ chức bus, nối tất cả các dữ liệu nguồn với các nơi nhận. Hệ thống bus điều khiển tất cả các dữ liệu truyền và được nối tới một giao tiếp phù hợp mà cảm biến có thể gửi dữ liệu tới máy tính.

Sơ đồ giao tiếp của cảm biến số nối tiếp với vi điều khiển được thể hiện ở hình 3.3. Một vi điều khiển thường sử dụng xử lý tín hiệu số (ví dụ, lọc số), chuyển đổi tương tự-số, tần số-mã, tính toán và các chức năng giao tiếp. Vi điều khiển có thể kết hợp hay trang bị với các giao tiếp chuẩn. Nhiều vi điều khiển có cả bus giao tiếp 2 dây I2C, có thể truyền với khoảng cách ngắn (vài mét) hay giao diện nối tiếp RS-232/485 cho truyền khoảng cách dài.

Cảm biến số nối tiếp khác cảm biến tương tự ở bus giao tiếp. Cảm biến tương tự thường đưa tín hiệu tương tự dạng dòng điện hay điện áp về vi điều khiển, sau đó vi điều khiển phải thực hiện việc chuyển đổi tương tự-số rồi mới đọc dữ liệu. Còn trong cảm biến số nối tiếp, việc chuyển đổi tương tự-số được thực hiện ngay trong cảm biến, giá trị chuyển đổi sau đó được đưa về vi điều khiển dưới dạng các xung nối tiếp thể hiện giá trị của cảm biến. Điều này sẽ khắc phục được nhiễu tác động lên bus giao tiếp.

Để gửi lệnh đọc dữ liệu cho cảm biến, vi điều khiển trước tiên phải xác lập xung dữ liệu DATA, sau đó phát xung đồng bộ SCK. Việc gửi các xung dữ liệu được thực hiện cho tới khi bit cuối cùng của DATA được gửi đi. Khi đọc dữ liệu từ cảm biến thì vi điều khiển phải phát xung SCK trước, sau đó đọc giá trị xung dữ liệu dạng bit từ cảm biến. Các bit dữ liệu nhận được sau đó sẽ được kết hợp lại thành dữ liệu dạng byte

Thông thường, để đọc dữ liệu từ cảm biến số nối tiếp theo các bước sau:

- Vi điều khiển gửi tín hiệu Start cho cảm biến để bắt đầu quá trình đọc dữ liệu. Tín hiệu Start thường là một chuỗi xung có định dạng

- Khi cảm biến nhận được tín hiệu này sẽ khởi tạo lại các tham số. Sau khi khởi tạo xong, cảm biến gửi lại thông báo ACK cho vi điều khiển.

- Vi điều khiển sau khi nhận được ACK từ cảm biến sẽ gửi lệnh đọc dữ liệu cho cảm biến.

- Cảm biến khi nhận được lệnh đọc dữ liệu từ vi điều khiển sẽ thu thập dữ liệu, biến đổi AD rồi truyền dữ liệu dạng số về cho vi điều khiển.

Các ưu điểm của cảm biến số nối tiếp:

- Năng lượng tiêu thụ thấp: năng lượng tiêu thụ của cảm biến chủ yếu xảy ra lúc lấy thông tin và thực biến đổi A/D. Bằng việc cho phép/không cho phép đọc dữ liệu sẽ kiểm soát được năng lượng tiêu thụ. Khi cảm biến không làm việc thì năng lượng tiêu thụ là thấp nhất.

- Khả năng chống nhiễu lớn: cảm biến sử dụng đường truyền số, do vậy rất khó bị ảnh hưởng bởi nhiễu lúc truyền số liệu.

- Độ chính xác cao: Việc tự chuẩn hoá cho phép giảm sai số hệ thống. Việc sử dụng thuật toán thống kê và các thuật toán trung bình trọng số cho phép làm giảm sai số ngẫu nhiên gây nên bởi nhiễu.

- Giao tiếp đơn giản, chỉ dùng ít dây: cảm biến số truyền nối tiếp nên chỉ dùng ít dây để truyền dữ liệu. Thông thường, để giao tiếp dữ liệu với vi điều khiển chỉ cần 2 đường tín hiệu, một đường là xung đồng bộ do vi điều khiển phát ra, một đường là dữ liệu đọc về.

- Dải đo rộng.

- Kích thước nhỏ.

3.2 Ghép nối giữa CC1010 với các loại cảm biến:

3.2.1 Ghép nối với cảm biến áp suất MS5535:

Cảm biến áp suất MS5535 cũng là cảm biến số nối tiếp. Nó cũng có cùng nguyên tắc làm việc như cảm biến số nối tiếp đã giới thiệu ở trên. Tuy nhiên nó cũng có sự khác biệt. Đó là chân dữ liệu DATA có 2 chân là DIN và DOUT, đồng thời có thêm 1 chân Master Clock (MCLK) để làm xung nhịp cho MS5535. Sơ đồ giao tiếp giữa vi điều khiển CC1010 và MS5535 như sau:

Trong đó:

MCLK: Master Clock của MS5535

DIN: chân dữ liệu vào cho MS5535

DOUT: chân dữ liệu ra cho MS5535

SCLK: Serial Clock, đồng bộ quá trình đọc ghi dữ liệu cho MS5535

Trong sơ đồ trên hình 3.5, các cổng P0.3 được định nghĩa làm cổng vào dữ liệu, P1.0, P1.1, và P3.4 làm cổng ra dữ liệu. Để xử lý tình huống này, sử dụng các lệnh chương trình như sau:

clr P1DIR.0 ;for SCLK MS5535

clr P1DIR.0 ;for DIN MS5535

setb P0DIR.3 ;for DOUT MS5535

clr P2DIR.3 ;for MSCLK MS5535

Trong đó ghi mức "1" ra cổng P0.0 các lệnh được hiểu như sau:

clr P0DIR.0 ; đặt bit hướng là ghi ra

setb P0.0 ; xuất dữ liệu

Giá trị dữ liệu và tín hiệu trên các cổng vào ra này được xác định nhờ sử dụng các bộ định thời/đếm và chế độ ngắt của vi mạch CC1010.

Các bộ định thời, các ngắt, tín hiệu SCLK, MCLK và đầu đo MS-5535.

CC1010 có 4 timer/counter trong đó có 2 timer/counter theo chuẩn 8051, 2 Timer còn lại là timer 3 và timer 4, hoạt động ở chế độ timer hoặc chế độ điều chế độ rộng xung PWM (Pulse Width Modultion). Timer 2 /Timer 3 làm việc ở chế độ PWM khi thiết lập bit TCON2.M2/TCON2.M3. Các cổng P3.4 / P3.5 lúc này là các lối ra, thông qua việc lập các bit hướng P3DIR.4 / P3DIR.5. Chu kỳ PWM TnPWM đối với timer n được tính là:

Trong đó thời gian ở trạng thái cao Tnh là:

Điều này có nghĩa là trong chế độ PWM, nếu Tn = 0 thì có mức thấp ở đầu ra và nếu Tn = 255 thì có mức cao. Trong sơ đồ hình 3.6, Timer2 ở chế độ PWM tạo xung Master clock. cho MS-5535, tần số 29kHz. Tần số này phát trên cổng P3.4 bằng các lệnh:

orl TCON2,#0x01 ;đặt Timer 2 ở chế độ PWM

mov T2Pre,#1 ;đặt chu kỳ PWM bằng 29kHz

mov T2,#128 ;xung vuông đối xứng

setb TR2 ;bắt đầu phát xung

Làm tương tự như vậy cũng thu được chuỗi xung SCLK phát trên cổng P1.0.

Chương trình thực hiện

Chương trình làm việc với MS5535 theo các bước sau:

Bước 1: Khởi tạo MS5535.

- Đặt bit hướng P3.4, P1.1, P1.0 là hướng xuất dữ liệu ra (output) tương ứng là các chân MCLK, DIN và SCLK của MS5535.

- Đặt bit hướng P0.3 là hướng đọc dữ liệu vào tương ứng (input) là chân DOUT của MS5535.

- Phát xung tần số 29 kHz ra cổng P3.4 để làm Master Clock cho MS5535.

- Đọc các hệ số bù nhiệt của MS5535.

Bước 2: Đọc các tham số áp suất và nhiệt độ của MS5535.

- Reset MS5535.

- Phát lệnh cho MS5535. Lệnh ở đây có thể là đọc nhiệt độ hay áp suất.

- Đọc giá trị trả về từ MS5535.

- Dựa trên giá trị trả về và các hệ số đọc được ở bước 1, tính giá trị nhiệt độ và áp suất tương ứng.

Chi tiết về làm việc với đầu đo áp suất MS5535 xin xem thêm phần tham khảo [13] và chương trình ở phần phụ lục.

3.2.2 Ghép nối với cảm biến nhiệt độ dạng tương tự

ADCi: ADC0, ADC1, ADC2

Các lối vào AD0, AD1, AD2 của CC1010 có điện áp tham chiếu chọn là 1,25V hoặc VDD, sử dụng chung một ADC trên cơ sở hợp kênh lối vào. Thí dụ, trong hệ thống nói trên, lối ra của đầu đo nhiệt độ được đưa tới AD0 và chương trình khởi tạo qúa trình chuyển đổi tương tự số qua ADC phải tiến hành bằng lệnh:

mov ADCON,#0Ch

tức là chọn kênh AD0, điện áp tham chiếu 1,25V internal, bộ biến đổi ADC ở chế độ hoạt động (active ADC). Lệnh bắt đầu chuyển đổi ADC:

setb ADCRUN

Khi ADC thực hiện xong việc chuyển đổi tương tự-số, bit ADCRUN được xóa tự động. Thời gian đợi chuyển đổi thể hiện qua việc quét bit ADCRUN:

jb ADCRUN,$

Giá trị chuyển đổi đọc ở 2 thanh ghi ADDATL(7:0) và ADDATH(9:8). Giá trị đọc được từ 0 đến 1023 tương ứng với điện áp lối vào từ 0 vôn đến 1,25 vôn.

Chương trình thực hiện

Chương trình đọc giá trị ADC thực hiện theo các bước sau:

Bước 1: Khởi tạo ADC

- Đặt bộ biến đổi ADC về chế độ single.

- Đặt điện áp tham chiếu là 1,25V

Bước 2: Đọc giá trị ADC

- Chọn kênh ADC

- Ra lệnh đọc ADC

- Chờ cho ADC biến đổi xong

- Đọc giá trị chuyển đổi

3.3 Kết luận:

Chức năng cảm nhận là một trong những chức năng chính của một nút mạng trong WSN. Do đó nút mạng cần phải có khả năng ghép nối được với nhiều loại cảm biến khác nhau.

Chương III đã giới thiệu tổng quan về cảm biến nói chung và các bước cụ thể để giao tiếp giữa vi điều khiển và cảm biến số nối tiếp. Đồng thời đã xây dựng được cách làm việc cụ thể với cảm biến áp suất MS5535 cũng là loại cảm biến số nối tiếp. Việc giao tiếp giữa cảm biến số nối tiếp được thực hiện qua các chân cổng của CC1010. Còn việc giao tiếp giữa cảm biến tương tự với vi điều khiển được thực hiện qua 3 lối vào tương tự của CC1010, đó là các chân AD0, AD1, AD2. Qua đó cho thấy rằng CC1010 hoàn toàn có thể làm việc được với nhiều loại cảm biến khác nhau, bao gồm cả cảm biến tương tự và cảm biến số.

CHƯƠNG 4

PHẦN MỀM NHÚNG

4.1 Phần mềm nhúng

4.1.1 Tổng quan về phần mềm nhúng

Phần mềm nhúng đang có những bước đột phá mới, tạo ra những cuộc cách mạng triệt để trong tương lai. Lý do của sự phát triển này xuất phát từ những nhu cầu bức thiết của thực tế và những bước tiến mạnh mẽ trong công nghệ phần cứng. Một phần mềm nhúng phải kết hợp chặt chẽ với môi trường của nó bao gồm phần cứng và các hệ thống liên quan. Nó có những ràng buộc về tốc độ xử lý, dung lượng bộ nhớ và mức tiêu thụ điện năng... Một phần mềm nhúng tốt là phần mềm phải đảm bảo các yếu tố trên và đó cũng là hướng phát triển quan trọng của các phần mềm nhúng. Điểm mấu chốt của các phần mềm nhúng ngày nay là việc lựa chọn các phương pháp thực thi của một chức năng giống như một thành phần phần cứng nhưng theo một cách riêng. Vì vậy mà không thể bỏ đi các tính năng "cứng" của phần mềm như các phần mềm truyền thống khác. Một phần mềm nhúng ngày nay được phát triển theo cách sau:

o Liên kết phần mềm nhúng từ dưới lên trên, từ các lớp trừu tượng đến các chức năng hệ thống.

o Liên kết phần mềm nhúng với các nền lập trình được - các nền hỗ trợ nó cung cấp các phương tiện cần thiết để đánh giá xem các ràng buộc đưa ra có thỏa mãn hay không.

Để làm được như vậy thì thực chất cần phải phát triển các kỹ thuật hình thức ở mức trừu tượng để có những đánh giá sớm cùng với các nhóm công cụ và phương pháp đúng đắn. Mặt khác cũng cần phải xem xét phần mềm nhúng và kiến trúc phần cứng của nó trong một tổng thể cân đối. Do phải thỏa mãn nhiều yếu tố khác nhau về phần cứng, môi trường, giá thành, hiệu năng nên tồn tại nhiều thách thức trong phát triển phần mềm nhúng ngày nay, như:

o Tăng cường việc tái sử dụng.

o Đồng thiết kế phần cứng, phần mềm.

o Xây dựng mô hình các thuộc tính phi chức năng.

o Chuyển đổi các phần mềm thành các dịch vụ thông qua các thành phần phần mềm.

o Kiến trúc hệ thống và kiến trúc phần mềm.

o Đánh giá và kiểm định mức hệ thống.

o Tương thích phần cứng và phần mềm nhờ các cấu trúc có thể định cấu hình lại và các thành phần Plug and Play.

o Xây dựng các hệ thống có khả năng tổ hợp được nhờ các thành phần phần mềm có thể tái sử dụng.

4.1.2 Các bước cơ bản xây dựng một phần mềm nhúng

Phần mềm nhúng viết cho các họ vi xử lý có thể sử dụng các ngôn ngữ khác nhau như C/C++ hoặc Assembler. Tuỳ theo tiêu chí xây dựng hệ thống mà lựa chọn ngôn ngữ thích hợp. Từ đó cũng chọn chương trình dịch thích hợp. Ngày nay, do nhu cầu phát triển hệ thống nhanh, bảo trì dễ dàng nên ngôn ngữ được lựa chọn thường là ngôn ngữ cấp cao như C/C++.

Quy trình xây dựng một phần mềm bất kỳ thường trải qua các bước sau:

- Tìm hiểu bài toán

- Phân tích

- Thiết kế

- Viết chương trình

- Kiểm thử

Việc xây dựng phần mềm nhúng cũng tuân theo trình tự các bước như trên. Ngoài ra, phần mềm nhúng còn có đặc trưng là làm việc trực tiếp với phần cứng. Do đó để kiểm soát quá trình làm việc với các thành phần chấp hành có đúng đắn hay không là điều đặc biệt quan trọng.

4.1.3 Phần mềm nhúng viết cho CC1010

Phần mềm nhúng viết cho CC1010 được viết bằng ngôn ngữ C, sử dụng các thư viện cho CC1010 do hãng Chipcon cung cấp, chương trình biên dịch Keil uVision 2.0

Chương trình dịch Keil uVision 2.0 do hãng Keil Elektronik GmbH xây dựng là một môi trường phát triển tích hợp (IDE) dùng để xây dựng các chương trình cho các họ VĐK tương thích 8051 của Intel. Đây là bộ chương trình dịch cho phép người viết chương trình soạn thảo chương trình, dịch chương trình và gỡ lỗi trên cùng một môi trường. Chương trình dịch hỗ trợ cho cả ngôn ngữ C và Assembly.

Hãng Chipcon cũng cung cấp bộ thư viện CC1010IDE hỗ trợ cho việc xây dựng phần mềm cho VĐK CC1010. Đây là bộ thư viện giúp cho việc xây dựng chương trình cho CC1010 được dễ dàng và nhanh chóng.

CC1010IDE dựa trên công cụ phát triển "uVision2" của hãng Keil ™ Elektronik GmbH. Công cụ này cung cấp một khung (framework) cho hầu hết các đặc điểm của CC1010IDE và cũng hỗ trợ hầu hết cho các VĐK họ 8051. Trình soạn thảo là một công cụ chủ yếu để soạn thảo các file nguồn và file hợp ngữ. Nó cũng cung cấp các chức năng trợ giúp khác như giao diện đồ hoạ (Graphic User Interface - GUI), cần cho mô phỏng/gỡ lỗi (mã lệnh dạng hợp ngữ, thanh ghi, bộ nhớ, các cửa sổ theo dõi, bước lệnh, ...). Thêm vào đó, IDE cũng cung cấp các giao diện với thư viện liên kết động (Dynamic Linking Library - DLL) được sử dụng để mô phỏng và gỡ lỗi trên mạch. Một điểm đặc biệt của bộ dịch là có thể chuyển các file nguồn được viết bằng C sang dạng hợp ngữ, để sau đó có thể tối ưu hoá mã lệnh. Dạng hợp ngữ sau đó được chuyển thành các file đối tượng (mã máy hoặc dữ liệu nhị phân). Cuối cùng, bộ liên kết đưa ra dạng file thực thi dạng Intel HEX và có thể nạp vào bộ nhớ Flash của VĐK.

Mô hình của một phần mềm nhúng viết cho CC1010 như sau:

Các file định nghĩa phần cứng - Hardware Definition Files (HDF)

Các file định nghĩa phần cứng định nghĩa địa chỉ các thanh ghi, ánh xạ vectơ ngắt và các hằng số phần cứng khác. Chúng cũng thường dùng các macro cho CC1010EB, và các định nghĩa hỗ trợ hợp ngữ và ngôn ngữ C.

Thư viện phần cứng - Hardware Abstraction Library (HAL)

Để hỗ trợ việc phát triển chương trình nhanh chóng và dễ dàng, Chipcon cung cấp thư viện các macro và các hàm truy cập phần cứng C1010 dễ dàng. Những thư viện này nằm trong Thư Viện Phần Cứng (HAL) và thi hành một giao tiếp phần cứng trừu tượng đối với chương trình người dùng. Nhờ đó chương trình người dùng có thể truy cập ngoại vi của vi điều khiển, thông qua các lời gọi hàm/macro, mà không cần hiểu chi tiết về phần cứng.

Thư viện HAL hỗ trợ các chức năng sau:

- Truyền nhận không dây

- Đo cường độ RSSI

- Truyền nhận RS232

- Làm việc với ADC

- Xử lý thời gian thực

- Mã hoá DES

- Thiết lập các bộ định thời

- Làm việc với các cổng

Thư viện tiện ích Chipcon - Chipcon Utility Library (CUL)

Bên cạnh module HAL CC1010IDE cũng cung cấp một thư viện cho truyền thông RF đặt trong Thư Viện Tiện Ích (CUL). Thư viện này thường dùng cho các ứng dụng RF điển hình, và cung cấp một giao thức RF đầy đủ.

Thư viện CUL hỗ trợ các chức năng sau:

- Truyền nhận không dây

- Tính toán Mã dư vòng (CRC)

- Xử lý Thời gian thực (Realtime Clock)

Cả hai thư viện HAL và CUL đều hỗ trợ Truyền nhận không dây và xử lý thời gian thực. Tuy nhiên, các hàm ở thư viện CUL làm việc ở mức cao hơn, người viết chương trình cũng dễ dàng và tiện lợi hơn, nhưng bù lại cũng kém mềm dẻo hơn so với sử dụng các hàm ở thư viện HAL. Do vậy, đối với những ứng dụng đòi hỏi sự phức tạp thì thường dùng thư viện HAL.

Phần mềm WSN viết cho CC1010

Phần mềm viết cho nút mạng cho WSN cần thực hiện những chức năng cơ bản sau:

o Cảm nhận

o Tính toán

o Truyền thông

Một thách thức là phải thực hiện tất cả những công việc trên vào một VĐK bị ràng buộc về mặt tài nguyên. Điều đó đòi hỏi chương trình viết càng ngắn và càng tốn ít bộ nhớ càng tốt, trong khi vẫn đảm bảo việc viết chương trình nhanh, bảo trì và nâng cấp dễ dàng.

Việc thực hiện cảm nhận và tính toán đã được đề cập chi tiết tại chương III. Còn thực hiện việc truyền thông, chương trình sử dụng các hàm trong bộ thư viện HAL của Chipcon.

Chương trình truyền thông cho CC1010 thực hiện theo các bước sau:

o Khởi tạo RF: thiết lập tần số RF, tốc độ truyền, cách điều chế tín hiệu, công suất phát. Trong chương trình cụ thể, các thông số trên lần lượt có giá trị là: 868MHz, 2.4kb/s, mã hoá Manchester, 4 dBm. Các khai báo này được đặt trong một cấu trúc RF_SETTINGS được khai báo như sau:

RF_RXTXPAIR_SETTINGS code RF_SETTINGS = {

0x4B, 0x2F, 0x15, // Modem 0, 1 and 2: Manchester, 2.4 kBaud

0x75, 0xA0, 0x00, // Freq A

0x58, 0x32, 0x8D, // Freq B

0x01, 0xAB, // FSEP 1 and 0

0x40, // PLL_RX

0x30, // PLL_TX

0x6C, // CURRENT_RX

0xF3, // CURRENT_TX

0x32, // FREND

0xFF, // PA_POW 4dBm

0x00, // MATCH

0x00, // PRESCALER

};

Việc khởi tạo RF theo các bước trình tự sau:

halRFCalib(&RF_SETTINGS, &RF_CALDATA); //chuẩn hoá RF

INT_GLOBAL_ENABLE (INT_OFF); //cấm ngắt toàn cục

INT_SETFLAG (INUM_RF, INT_CLR); //xoá ngắt RF

INT_PRIORITY (INUM_RF, INT_HIGH); //mức ưu tiên ngắt RF là cao

RF_SET_BYTEMODE(); //RF hoạt động ở chế độ byte

RF_SET_PREAMBLE_COUNT(PREAMBLE_BYTE_COUNT); //thiết lập số //byte dẫn đường

RF_SET_SYNC_BYTE(RF_SUITABLE_SYNC_BYTE);//thiết lập byte đồng bộ

MODEM1=(MODEM1&0x03)|0x24; //lọc trung bình

// Reset preamble detection

PDET &= ~0x80;

PDET |= 0x80;

INT_ENABLE (INUM_RF, INT_OFF); //cấm ngắt ngắt RF

INT_GLOBAL_ENABLE (INT_ON); //cho phép ngắt toàn cục

o Nhận dữ liệu RF: việc nhận dữ liệu RF thông qua ngắt. Mỗi khi nhận được một byte, VĐK sinh ra một ngắt. Chương trình xử lý ngắt có nhiệm vụ đưa byte này vào một bộ đệm. Khi toàn bộ gói tin đã nhận xong, ngắt này bị cấm để chờ xử lý xong bộ đệm.

Quá trình nhận một byte từ bộ đệm RFBUF vào bộ đệm chương trình như sau:

//nhận một byte từ RFBUF vào bộ đệm rf_rx_buf tại vị trí rf_rx_index;

rf_rx_buf[rf_rx_index] = RF_RECEIVE_BYTE();

rf_rx_index++; //tăng chỉ số lên 1

Byte đầu tiên của bộ đệm chương trình rf_rx_buf[0] lưu độ dài gói tin. Việc nhận dữ liệu kết thúc khi rf_rx_index bằng giá trị độ dài gói tin, nghĩa là:

rf_rx_index = rf_rx_buf[0];

Sau khi toàn bộ gói tin RF đã nhận được, chương trình sẽ phân tích gói tin, lọc ra các dữ liệu cần thiết. Nếu là nút Master, nó sẽ truyền dữ liệu nhận được về PC qua cổng RS232. Nếu là Slave, nó sẽ thực hiện việc cảm nhận, tính toán rồi truyền dữ liệu về Master.

o Truyền dữ liệu RF: việc truyền dữ liệu RF được thực hiện bởi các hàm/macro trong thư viện HAL của Chipcon như sau:

halRFSetRxTxOff(RF_TX, &RF_SETTINGS, &RF_CALDATA);//turn on TX

RF_START_TX(); //bắt đầu truyền

halRFSendPacket(PREAMBLE_BYTE_COUNT,&txDataBuffer[0], 4); //truyền dữ liệu tại txDataBuffer với độ dài là 4

halRFSetRxTxOff(RF_RX,&RF_SETTINGS,&RF_CALDATA);//turn on //RX

RF_START_RX(); // bắt đầu chế độ nhận

INT_SETFLAG (INUM_RF, INT_CLR); //xoá cờ ngắt RF

INT_ENABLE (INUM_RF, INT_ON); //cho phép ngắt RF

4.1.4 Gỡ lỗi

4.1.4.1 Giới thiệu

Gỡ lỗi là một phần không thể thiếu khi phát triển phần mềm, đặc biệt là phần mềm nhúng. Việc gỡ lỗi cẩn thận, chi tiết giúp cho phát hiện những lỗi chương trình mà người viết nhiều khi không lường hết được, điều đó giúp cho chương trình có độ ổn định và tin cậy cao. Ngoài việc kiểm tra tính đúng đắn của thuật toán hay các kết quả nhận được sau khi xử lý dữ liệu nào đó, gỡ lỗi còn cho phép biết cụ thể sự làm việc giữa chương trình với thành phần chấp hành tại từng tình huống cụ thể. Điều đó cho phép người viết chương trình biết đoạn chương trình đó có đúng theo thiết kế hay không.

Có ba dạng gỡ lỗi đang được dùng phổ biến, đó là:

- Giám sát ROM (ROM Monitor)

- Mô phỏng trên mạch (In-circuit Emulator)

- Gỡ lỗi trên chip (On-chip debug)

Trước khi xét từng trường hợp cụ thể trên, hãy xét các định nghĩa sau:

Code Dowload nạp chương trình từ PC xuống bộ nhớ hệ thống đích (RAM hoặc flash ROM) với mục đích là thực thi chương trình

Go/Halt/Step Cho phép điều khiển thực thi của mã lệnh trong trình gỡ lỗi

CodeBreakpoints Cho phép dừng chương trình thực thi khi lệnh đã chỉ ra được thực hiện. Breakpoints thường hoạt động bằng cách chèn một lệnh đặc biệt tại vị trí cần theo dõi (còn được gọi là Software breakpoints) hay giám sát các bus của vi điều khiển sử dụng một bộ so sánh và dừng chương trình khi một lệnh cụ thể được thực hiện (Hardware breakpoints)

Data Access Breakpoints. Cho phép dừng chương trình khi một vị trí bộ nhớ được truy cập để đọc hay ghi.

Complex/Advanced Breakpoints. Cho phép mô tả breakpoints ví dụ một dải địa chỉ được chỉ ra hay một mặt nạ được sử dụng cho phép thiết lập các điều kiện "không quan tâm". Hơn nữa, một breakpoint chỉ xuất hiện khi một chuỗi các sự kiện đã định nghĩa trước xảy ra, ví dụ khi thực hiện một lệnh cho trước theo sau bởi một thao tác ghi dữ liệu tại địa chỉ xác định thì sẽ xác nhận breakpoint (nghĩa là dừng chương trình)

Memory/Register Access. Cho phép trình gỡ lỗi đọc thanh ghi hay bộ nhớ.

"On-the-fly" Access. Các chức năng gỡ lỗi vẫn được hoàn thành trong khi vi điều khiển vẫn đang thực thi. Rất nhiều ứng dụng nhúng thực hiện điều khiển thời gian thực như cánh tay máy... và gỡ lỗi những ứng dụng như vậy ở giai đoạn khởi động/dừng là không thực tế khi dừng VĐK sẽ làm cho hệ thống khởi động lại (và như vậy phần gỡ lỗi khởi động lại toàn bộ). "On-the-fly" áp dụng điều này cho phép truy cập các biến mà không phải dừng chương trình.

Real-time Trace and Watchpoints. Cung cấp một cơ chế bắt (catch) luồng chương trình (hoặc dữ liệu truy cập) theo thời gian thực. Thông thường, thông tin lần vết được tạo ra từ VĐK, bắt và gắn tem thời gian và lưu bởi bộ mô phỏng. Watchpoints hoạt động giống Breakpoints, tuy nhiên thay vì dừng VĐK chúng đơn giản là chỉ ra điều kiện đặt trước đã xảy ra và có thể dùng bộ mô phỏng lọc hay bắt các thông tin lần vết. Lần vết theo thời gian thực là điểm mạnh cho gỡ lỗi của các hệ thống nhúng. Nếu một ứng dụng thường xuyên đổ vỡ khi ngắt do tràn ngăn xếp, sử dụng lần vết thời gian thực có khả năng bắt được những gì ứng dụng thực hiện trước khi đổ vỡ và như vậy xác định được nguyên nhân của vấn đề (bằng cách xem lại chuỗi lệnh ghi được trước khi đổ vỡ).

4.1.4.2 Các dạng gỡ lỗi

4.1.4.2.1 Giám sát ROM (ROM Monitor)

Một monitor là một đoạn mã chạy trong hệ thống đích sẽ được gỡ lỗi. Trình gỡ lỗi, chạy trên PC giao tiếp với monitor thông qua cổng dành riêng trên hệ thống đích (thường là cổng nối tiếp hay ethernet). Trình gỡ lỗi truyền các lệnh tới Monitor và chờ trả lời. Một ví dụ điển hình là yêu cầu đọc bộ nhớ tại một vị trí xác định với một độ dài nào đó. Monitor rất thông dụng và rẻ tiền, tuy nhiên chúng có những hạn chế sau:

• Monitor nằm trong bộ nhớ đích, làm mất không gian của ứng dụng và phải nạp vào bộ nhớ trước khi gỡ lỗi.

• Monitor đòi hỏi một cổng dành riêng trên thiết bị đích để truyền tới PC.

• Monitor chỉ có thể chạy nếu đích đã chạy, do đó gỡ lỗi một đích "chết" hay không boot là không thể.

• Gỡ lỗi ở Flash hay ROM với một Monitor sẽ không thể ghi vào bộ nhớ hệ thống đích khi đặt software breakpoints.

4.1.4.2.2 Mô phỏng trên mạch (In-Circuit Emulator)

Một hệ mô phỏng trên mạch (In-Circuit Emulator, ICE) hoạt động bằng cách thay thế mạch VĐK và mô phỏng các chức năng của nó. ICE nối với PC và được điều khiển bởi một trình gỡ lỗi. The ICE cung cấp cái nhìn vào bên trong sự hoạt động bên trong của VĐK được mô phỏng. Mô phỏng một VĐK là nhiệm vụ rất phức tạp và thường được thực hiện sử dụng các phiên bản đặc biệt của VĐK gọi là thiết bị "bond-out" cung cấp chức năng cơ bản của ICE. Tuy nhiên, chi phí để sản xuất Bond-outs rất đắt, vì lý do đó nên một số nhà cung cấp VĐK có sự thay đổi bằng cách dùng Field Programmable Gate Arrays (FPGAs). FPGAs là một giải pháp trong một vài trường hợp, tuy nhiên chúng không chạy nhanh bằng các thiết bị bond-out hay các mạch mô phỏng tương tự (VD chuyển đổi số-tương tự) và như vậy cần thêm mạch bên ngoài.

4.1.4.2.3 Gỡ lỗi On-Chip

Do vấn đề chi phí và giá thành của ICE, rất nhiều nhà cung cấp tích hợp mạch gỡ lỗi vào trong chip. Motorola là nhà cung cấp đầu tiên và Chế độ gỡ lỗi nền tảng (Background Debug Mode - BDM) là một trong các chuẩn gỡ lỗi on-chip được biết đến rộng rãi. Mạch gỡ lỗi on-chip thường giao tiếp với thế giới bên ngoài thông qua giao diện nối tiếp với JTAG ngày càng là chuẩn thông dụng. (JTAG - Joint Test Action Group, tên của chuẩn IEEE 1149.1)

Máy tính giao tiếp với hệ thống thông qua một bộ mô phỏng JTAG, cung cấp một giao diện JTAG và một kết nối USB/Ethernet tới PC. Tất cả các nhà cung cấp sẽ chuẩn hoá bộ kết nối gỡ lỗi on-chip nối bộ mô phỏng tới hệ thống đích.

Hỗ trợ thiết kế Gỡ lỗi On-chip là một yêu cầu của VĐK vì nếu không có hỗ trợ thiết kế sẽ không thể hay có giá rất cao để đưa ra công cụ gỡ lỗi. Các lý do chính là:

• Sử dụng bộ nhớ Flash để lưu chương trình sẽ rất khó hay không thể đối với các công cụ mở rộng để xác định câu lệnh hiện thời sẽ được thực hiện.

• Với các VĐK tốc độ cao thì ICE không thể dừng chương trình thực thi trước khi nó thi hành lệnh cần thiết.

• Các kiến trúc RISC (Reduced instruction set computer) và on-chip rất khó để xác định các lệnh đã được nạp (fetched) và các lệnh đã được thực hiện.

• Với các hệ hướng ứng dụng hay theo yêu cầu của khách hàng, Systems-On-a Chip (SOCs) sẽ phải thiết kế lại một bộ mô phỏng vi xử lý cho từng thiết kế SOC riêng lẻ.

Gỡ lỗi on-chip giải quyết tất cả những vấn đề trên và cũng có các chức năng điều khiển thời gian thực như nạp chương trình, go/step/halt, truy cập bộ nhớ/thanh ghi và breakpoints. Các hệ gỡ lỗi on-chip hiện nay cũng có chức năng lần vết thời gian thực. Để tối thiểu hoá yêu cầu băng thông, thông tin lần vết được nén bởi giao diện gỡ lỗi trước khi đưa ra ngoài (hay lưu trong chip). Bộ mô phỏng sau đó giải nén thông tin nhận được và xây dựng lại luồng chương trình hiện thời để hiển thị trong trình gỡ lỗi.

4.1.4.3 Tóm tắt về gỡ lỗi

Đặc điểm ROM Monitor ICE On-chip debug

Code Download Có Có Có

Go/Halt/Step Có Có Có

Code Breakpoints Có Có Có

Data Access Breakpoints Không Có Có

Complex/Advanced

Breakpoints Không Có Có

Truy cập

Bộ nhớ/Thanh ghi Có Có Có

Intrusive Có Không Không

Truy cập "On-the-fly" Không Có Có

Real-time Trace

and Watchpoints Không Có Có

Giá thành Thấp Cao Trung bình

Kết nối Kết nối đơn giản với PC Cơ chế kết nối phức tạp Kết nối đơn giản giữa đích và công cụ gỡ lỗi

Ưu điểm Giá thành thấp Có đầy đủ các đặc điểm, không giới hạn hardware breakpoints. Có đầy đủ các đặc điểm, giá thành chấp nhận được. Hỗ trợ nhiều loại VĐK, hỗ trợ tốc độ cao

Nhược điểm Bị giới hạn chức năng. Đòi hỏi tài nguyên hệ thống Giá thành cao, khó kết nối, thường chỉ dùng cho những VĐK chuyên dụng Đòi hỏi thiết kế riêng và các chân mở rộng cho VĐK

4.1.4.4 Gỡ lỗi cho CC1010

CC1010 có hỗ trợ gỡ lỗi và dạng gỡ lỗi là dạng ROM Monitor. Bộ công cụ phát triển cho CC1010 bao gồm phần cứng và phần mềm. Phần cứng là module CC1010EB vừa làm nhiệm vụ điều khiển nạp chương trình vào module CC1010EM, vừa làm nhiệm vụ hỗ trợ gỡ lỗi cho chương trình. Phần mềm là bộ thư viện CC1010IDE đã giới thiệu ở trên, ngoài việc cung cấp các thư viện chương trình còn cung cấp thư viện gỡ lỗi. Phần Monitor được nạp vào CC1010 phục vụ quá trình gỡ lỗi có tên là BootLoader có kích thước 2322 byte. BootLoader phải được nạp vào CC1010 trước khi thực hiện việc gỡ lỗi.

Ví dụ về gỡ lỗi cho CC1010: Code Breakpoints

Mục đích: Kiểm tra dạng xung Reset mà CC1010 phát tới cảm biến áp suất MS5535 có đúng theo yêu cầu hay không.

Giả sử hàm làm việc này là: void resetMS5535(). Xung reset là 2 chuỗi xung DIN và SCLK của MS5535 lệch pha nhau, mỗi chuỗi gồm 21 xung. Chương trình dịch cụ thể là Keil uVision 2.0. Thiết bị kiểm tra là dao động ký số.

Trình tự các bước như sau:

- Nối cáp từ cổng Parallell của PC với cổng Parallell của CC1010EM. Đây là cáp giao tiếp để nạp chương trình.

- Nối cáp từ cổng RS232 của PC với cổng Serial 1 của CC1010EB. Đây là giao tiếp cho quá trình gỡ lỗi.

- Nạp chương trình Bootloader vào CC1010EM.

- Kẹp đầu đo kênh 1 của dao động ký vào chân DIN của MS5535.

- Kẹp đầu đo kênh 2 của dao động ký vào chân SCLK của MS5535.

- Đặt chế độ đo của dao động ký ở dạng trigger. Điều này giúp cho dao động ký dừng lấy mẫu khi lấy được 1 chùm xung.

- Đặt Code BreakPoint tại lời gọi hàm resetMS5535()

- Chạy chương trình ở chế độ gỡ lỗi đến lời gọi hàm resetMS5535(), sau đó chạy qua lời gọi này một bước rồi dừng lại (nhấn phím F10). Trên màn hình dao động ký sẽ xuất hiện dạng xung mà chương trình vừa phát, qua đó sẽ biết dạng xung đó có đúng với dạng xung cần thiết hay không.

4.2 Kết luận

Chương 4 đã giới thiệu tổng quan về phần mềm nhúng, các bước xây dựng cũng như các thách thức khi phát triển một phần mềm nhúng.

Gỡ lỗi là một phần không thể thiếu khi phát triển phần mềm nói chung và phần mềm nhúng nói riêng. Nó sẽ góp phần xây dựng phần mềm nhúng đạt độ ổn định và tin cậy cao. Ở đây đã giới thiệu ba dạng gỡ lỗi, đó là: Giám sát ROM, Mô phỏng trên mạch, Gỡ lỗi On-chip, và phân tích ưu nhược điểm của từng dạng. Phần cuối cùng minh hoạ các bước cụ thể khi gỡ lỗi cho chương trình viết cho CC1010 dùng để đọc giá trị áp suất MS5535.

CHƯƠNG 5

TRIỂN KHAI CHỨC NĂNG MẠNG VÀ

CÁC THỬ NGHIỆM

Việc thử nghiệm chức năng mạng đã thực hiện những công việc sau:

- Thử nghiệm mạng gồm hai nút mạng:

• Khảo sát quan hệ độ cao cột nước - áp suất

• Khảo sát độ ổn định của cảm biến áp suất theo nhiệt độ

• Khảo sát khí áp tại khu vực Hà nội trong 10 ngày từ 08/06/2005 đến 18/06/2005

• Kiểm tra làm việc dài ngày và mức tiêu thụ điện của hệ thống

- Thử nghiệm mạng gồm nhiều nút mạng:

• Xây dựng mạng gồm 3 nhiều nút mạng, truyền thông theo dạng multihop

5.1 Thử nghiệm mạng gồm 2 nút mạng:

Sơ đồ tổ chức tổng quát của mạng này như sau:

5.1.1 Khảo sát quan hệ độ cao cột nước - áp suất:

Module MS5535 được ghép với CC1010 và với phần mềm nhúng thích hợp sẽ tạo thành một điểm đo độc lập, tự động đo giá trị áp suất, nhiệt độ, xử lý dữ liệu thu được và truyền không dây định kỳ số liệu đo này về cho một CC1010 khác nối với máy tính xách tay hoặc máy tính để bàn. Sơ đồ ghép nối cụ thể MS5535 và CC1010 thể hiện trong hình 3.5.

Như đã chỉ ra trong hình 3.5, nguồn nuôi dùng chung cho MS5535 và CC1010, MCLK là tần số CC1010 cung cấp để MS5535 thực hiện biến đổi ADC, SCLK là tần số nhịp đồng bộ quá trình truyền và nhận giữa hai vi mạch này, tín hiệu DIN do CC1010 cung cấp, địa chỉ đến 6 hệ số bù nhiệt được nhà sản xuất chip chuẩn hoá và nhớ trong chip, địa chỉ đến dữ liệu nhiệt độ và dữ liệu áp suất riêng biệt. DOUT là lối ra các dữ liệu khác nhau của MS5535, tương ứng yêu cầu của CC1010. Độ lớn giá trị tần số MCLK, SCLK, các giá trị địa chỉ dữ liệu, việc xử lý các loại dữ liệu đọc được đều do phần mềm nhúng trong CC1010 thực hiện. Phần mềm này còn thực hiện chức năng truyền/nhận dữ liệu không dây giữa hai CC1010 và truyền về máy tính. Giải thuật của phần mềm này cho trên hình 5.3.

Ý nghĩa của các bước trong sơ đồ thuật toán:

Khởi tạo RF:

- Mã hoá dữ liệu: Manchester

- Tốc độ truyền dữ liệu: 2,4 kb/s

Khởi tạo ADC:

- Điện áp tham chiếu: 1,25 V internal

- 10 bit single.

Khởi tạo Timer:

Sử dụng Timer 2 ở chế độ điều chế độ rộng xung, tần số 29kHz, dạng xung vuông đối xứng. Xung này dùng làm Master Clock (MCLK) cho cảm biến áp suất MS5535.

Khởi tạo MS5535:

- Đưa các chân SCLK và DIN của MS5535 về trạng thái 0

- Đọc các hệ số lưu trong MS5535

Đọc 3 kênh ADC:

- Chọn kênh cần đọc

- Phát lệnh chuyển đổi ADC

- Chờ cho đến khi chuyển đổi ADC kết thúc

- Đọc giá trị ADC từ hai thanh ghi ADCDATH và ADCDATL

Đọc dữ liệu MS5535:

- Reset MS5535

- Gửi lệnh cho MS5535 để chọn tham số cần đọc: nhiệt độ hay áp suất.

- Đọc dữ liệu trả lời từ MS5535

Chờ nhận lệnh từ máy tính:

Nếu có lệnh yêu cầu gửi dữ liệu về trung tâm, Slave sẽ đọc các tham số nhiệt độ áp suất rồi truyền về trung tâm.

Một thí nghiệm đơn giản như trình bày ở hình 5.2, những kết quả đo được cho trong bảng 3, đồ thị tương ứng biểu diễn trên hình 5.4.

Bảng 3. Số liệu đo áp suất theo độ cao cột nước

Độ cao (cm)

(h=H1-H2) Áp suất (mbar)

Lần 1 Lần 2 Lần 3 Lần 4 Lần 5 Trung bình

0 986 986 986 986 986 986

20 1012 1010 1010 1011 1011 1010.8

40 1031 1031 1031 1030 1030 1030.6

60 1054 1054 1052 1052 1052 1052.8

80 1069 1070 1070 1070 1070 1069.8

100 1088 1088 1088 1088 1088 1088

120 1111 1111 1111 1111 1111 1111

140 1127 1127 1127 1127 1127 1127

160 1149 1149 1149 1149 1149 1149

233 1214 1214 1214 1215 1215 1214.4

313 1290 1290 1290 1290 1290 1290

5.1.2 Khảo sát độ ổn định của phép đo áp suất khi thay đổi nhiệt độ

Đầu đo được đặt trong môi trường nhiệt độ thay đổi từ 160C đến 420C và đo giá trị khí áp tại một vị trí, trong khoảng thời gian ngắn. Số liệu đo được phản ánh qua đồ thị tương ứng cho trên hình 5.5.

5.1.3 Kiểm tra làm việc dài ngày và mức tiêu thụ điện của hệ thống

Trong CC1010, CPU, biến đổi ADC, truyền nhận RF, v.v...không làm việc đồng thời. Chu kỳ nghỉ và chu kỳ hoạt động có tần số nhịp khác nhau. Quản trị chặt chẽ quá trình này sẽ tiết kiệm được năng lượng tiêu thụ bởi hệ thống. CC1010 có 3 chế độ làm việc:

+ Tích cực (Active Mode), chế độ 8051 chạy bình thường, xung Clock là tần số dao động của tinh thể thạch anh chính. Dòng tiêu thụ phụ thuộc vào tần số đó;

+ Chế độ nghỉ (Idle Mode): 8051 không hoạt động, các ngoại vi vẫn hoạt động bình thường. Thoát ra khỏi chế độ nghỉ bằng: Ngắt (Interrupt), thiết lập lại (Reset), Tắt - bật nguồn;

+ Chế độ tắt nguồn (Power-Down Mode): 8051 và các ngoại vi không hoạt động, chỉ clock cho ADC hoạt động. Nó là chế độ tiết kiệm năng lượng nhất, thoát khỏi chế độ này bằng Reset hoặc Tắt - bật nguồn.

Thử nghiệm tiết kiệm năng lượng khi truyền giữa Master và Slave. Slave thu thập dữ liệu nhiệt độ, áp suất truyền cho Master. Thời gian nghỉ giữa 2 lần truyền là 30 phút. Nuôi Slave là pin điện thoại di động loại 3.6V-580mAh. Slave ở chế độ nghỉ, chỉ khi thu thập số liệu truyền cho Master, Slave mới ở chế độ tích cực, chu trình hoạt động theo giải thuật sau:

Dòng tiêu thụ của Slave đo được như sau: không phát RF, chỉ thu thập số liệu, dòng 17mA, mất khoảng 5 giây do lấy số liệu trung bình 4 lần liên tiếp. Khi phát RF, không thu thập số liệu, dòng 35mA.

Với tốc độ truyền 2,4kb/s, mỗi gói tin dài 22 byte, thời gian truyền gói tin là:

22*8(bit)/2400 = 73ms.

Để Master nhận dữ liệu một cách tin cậy, Slave phát 5 gói tin cùng 1 nội dung, tổng thời gian phát là:

73*5 = 365ms ≈ 0,4s.

Chế độ nghỉ, dòng 0,5mA. Thời gian của chế độ này (tính trong vòng 1 giờ) là:

3600 - 2*5(giây) - 2*0,4 = 3589.2 s.

Như vậy, dòng tiêu thụ trung bình trong 1 giờ là:

(17*5*2 + 35*0,3*2 + 0,5*3589)/3600 = 0,55 mA ≈ 0,6mA.

Thời gian hoạt động lý tưởng của Slave với tính toán như trên là:

580/0.6 = 967 giờ = 40 ngày (thực tế có thể đạt 50% giá trị này).

Với Master, việc tiết kiệm năng lượng không đặt thành vấn đề vì nó được đặt cùng máy tính ở trung tâm, nơi có sẵn nguồn điện lưới. Sơ đồ hoạt động của Master như sau:

5.1.4 Khảo sát số liệu khí áp tại Hà nội

Việc khảo sát số liệu khí áp tại Hà nội được thực hiện liên tục trong vòng 10 ngày từ 08/06/2005 đến 18/06/2005 nhằm mục đích phục vụ dự báo thời tiết. Sau đây là kết quả khảo sát:

Bảng 4. Số liệu khí áp tại Hà Nội từ 08 đến 18/06/2005

Thời gian (giờ) Áp suất (mBar) Thời gian (giờ) Áp suất (mBar) Thời gian (giờ) Áp suất (mBar)

6:00 991 72:00 991 144:00 994

12:00 990 78:00 993 150:00 992

18:00 989 84:00 992 156:00 995

24:00 988 90:00 990 162:00 994

30:00 992 96:00 989 168:00 995

36:00 993 102:00 988 174:00 994

42:00 991 108:00 991 180:00 995

48:00 993 114:00 999 186:00 994

54:00 999 120:00 991 192:00 995

57:00 1004 126:00 990 198:00 993

60:00 990 132:00 989 204:00 993

66:00 987 138:00 990 210:00 994

216:00 995

Khí áp là thông số cơ bản để dự báo sự thay đổi thời tiết, đặc biệt khi biết sự thay đổi khí áp trong vòng một giờ dP/dt. Thông tin thay đổi khí áp liên quan đến thay đổi thời tiết đã được tổng kết như sau:

dP/dt > 2,5mb/h: khí áp cao mức trung bình, không ổn định

0,5mb/h < dP/dt < 2,5mb/h: Khí áp cao trong thời gian dài, thời tiết rất ổn định

- 0,5mb/h < dP/dt < 0,5mb/h: Thời tiết ổn định

- 2,5mb/h < dP/dt < - 0,5mb/h: Khí áp thấp trong thời gian dài, trời mưa liên tục

dP/dt < -2,5mb/h: khí áp thấp trung bình, dông tố, không ổn định.

Như vậy, từ kết quả đo có thể dự báo rằng sẽ có mưa trong các ngày 10 và 12/06/ 2005.

5.2 Thử nghiệm mạng gồm nhiều nút mạng

Mạng được tổ chức theo sơ đồ hình cây theo dạng sau:

Master và Slave đều là Vi điều khiển CC1010

Master giao tiếp với máy tính trung tâm qua đường RS232.

Các Slave giao tiếp với nhau hoặc với Master qua đường truyền không dây

Master và Slave đều phải chứa toàn bộ topology của mạng, qua đó mỗi nút sẽ biết đường đi để truyền gói tin đến đích.

Topology của mạng được xây dựng ngay từ lúc viết chương trình.

Khi một nút nhận được lệnh truyền từ nút cha, nó sẽ xem địa chỉ đích:

- Nếu địa chỉ đích chính là nó, nó sẽ gửi dữ liệu về cho nút cha.

- Nếu không, nó sẽ tìm trong bảng địa chỉ:

o Nếu tồn tại một đường đi từ nó tới nút đích, nó sẽ chuyển tiếp gói tin tới chặng tiếp theo. Chặng tiếp theo chính là nút con của nó có khả năng tới đích.

o Nếu không tồn tại đường đi thì không làm gì cả.

5.2.1 Biểu diễn cây trong bộ nhớ

Biểu diễn cây bằng danh sách các con của mỗi đỉnh

Với mỗi đỉnh của cây, ta thành lập một danh sách các đỉnh con của nó theo thứ tự từ trái sang phải. Ở đây ta sử dụng một mảng để lưu giữ các đỉnh của cây. Mỗi thành phần của mảng là một tế bào chứa thông tin gắn với mỗi đỉnh và danh sách các đỉnh con của nó. Danh sách các đỉnh con của một đỉnh có thể biểu diễn bởi mảng hoặc bởi danh sách liên kết. Tuy nhiên, vì số con của mỗi đỉnh có thể thay đổi nhiều nên ta sẽ sử dụng danh sách liên kết. Như vậy mỗi tế bào mô tả của cây là một bản ghi gồm 2 trường: trường id là địa chỉ của nút mạng, trường next là con trỏ trỏ tới danh sách các con của đỉnh đó. Giả sử các đỉnh của cây được đánh số từ 1 đến N. Với cách cài đặt này, ta có thể khai báo cấu trúc dữ liệu biểu diễn cây như sau:

#define N 11

struct node

{

int id;

node *next;

}

node tree[N];

Trong khai báo trên, Member biểu diễn các thành phần của danh sách các con, còn Node biểu diễn các đỉnh của cây. Với cách cài đặt này, cấu trúc dữ liệu biểu diễn cây trong hình trên được minh hoạ như sau:

1

2

3

4 .

5

6 .

7

8 .

9 .

10 .

11 .

Ta có nhận xét rằng, trong cách cài đặt này, với mỗi đỉnh k ta xác định được ngay con trưởng của nó. Chẳng hạn, với cây trong hình trên, con trưởng của đỉnh 3 là đỉnh 6, con trưởng của đỉnh 5 là đỉnh 9, còn đỉnh 6 không có con. Phép toán tìm con trưởng EldestChild(k) có thể được mô tả như sau:

int EldestChild(int k, Tree T)

{

node *p;

if(T[k])

{

p = T[k].next;

return pid;

}

else return -1; //không tìm thấy con

}

Tuy nhiên trong cách cài đặt này, việc tìm cha và em liền kề của mỗi đỉnh lại không đơn giản. Chẳng hạn, để tìm cha của đỉnh k, ta phải duyệt các danh sách các con của mỗi đỉnh. Nếu phát hiện ra trong danh sách các con của đỉnh m có chứa k thì Parent(k) = m. Hàm Parent(k) được xác định như sau:

int Parent(int k, Tree T)

{

node *p;

BOOL found;

i = 0;

while(i<N)

{

p = T[i].next;

while(p)

{

if(pid = = k) return i

else p = pnext;

}

i++;

}

return -1; //không tìm thấy cha

}

Một cách tương tự (duyệt danh sách các con), ta cũng có thể tìm được em liền kề của mỗi đỉnh. Hàm tìm em liền kề NextSibling(k) như sau:

int NextSibling(int k, Tree T)

{

node *p;

i = 0;

while(i < N)

{

p = T[i].next;

while(p)

{

if(pid = = k)

{

p = pnext;

if(p) return pid;

else return -1; //không có em liền kề

}

else p = pnext;

}

i++;

}

return -1;

}

Khi Master muốn gửi thông tin cho một nút k nào đó, ta phải tìm đường đi từ Master tới nút k. Muốn vậy, từ nút k trong topology của mạng lưu trong Master, ta tìm nút cha của nó, sau đó cứ tìm ngược lên trên cho tới Master. Toàn bộ các nút tìm được chính là đường đi từ Master tới nút k. Các nút tìm được này sẽ được lưu trong một mảng để từ Master, thông qua mảng đó có thể tới được nút k. Mảng này được khai báo như sau:

int RoutingTable[N];

Ví dụ trong sơ đồ hình cây trên, đường đi từ Master tới nút 11 được lưu trong bảng như sau: [1, 3, 7, 11, -1, -1, -1, -1, -1, -1, -1]

Hàm xây dựng bảng định tuyến RoutingTable như sau:

//Hàm này tìm đường đi từ Master tới nút k, Master có địa chỉ là 1

void FindHops(int k, Tree T)

{

int par,i,j;

for(i=0; i<N; i++) RoutingTable [i] = -1;

i = 0;

j = k;

do

{

par = Parent(j, T);

RoutingTable [i] = par;

j = par;

i++;

}while ( par != 1)

}

5.2.2 Định dạng dữ liệu truyền

Truyền dữ liệu từ Master tới Endpoint:

Định dạng dữ liệu truyền từ Master qua các chặng trung gian cho Endpoint như sau:

Len + NextHop + DestAddress + Command + CRC

Truyền dữ liệu về Master:

Định dạng dữ liệu của Endpoint truyền về trung tâm như sau:

Len + ParentAddress + DestAddress + Command + ADC0 + ADC1 + ADC2 + P + CRC

Trong đó:

Endpoint: là nút mạng cuối cùng mà Master muốn gửi gói tin đến.

Len: độ dài gói tin, 1byte

DestAddress: Địa chỉ của Endpoint, 1 byte

NextHop: Địa chỉ của nút kế tiếp có thể tới đích

ParentAddress: địa chỉ của nút cha của nút hiện thời, 1 byte.

Command: lệnh gửi cho Endpoint phải thi hành, 1 byte

ADC0, ADC1, ADC2: các giá trị nhiệt độ đọc từ 3 kênh này, 2 byte

P: giá trị áp suất đọc từ cảm biến áp suất MS5535, 2 byte

CRC: Mã dư vòng, 2 byte

5.3 Kết luận

Việc thử nghiệm được tiến hành từ xây dựng mạng gồm hai nút mạng đến xây dựng mạng có nhiều nút mạng. Phần xây dựng mạng có 2 nút mạng đã tiến hành các thử nghiệm như: khảo sát quan hệ độ cao cột nước - áp suất, khảo sát độ ổn định của phép đo áp suất theo nhiệt độ, khảo sát khí áp tại Hà nội và kiểm tra vấn đề tiết kiệm năng lượng. Kết quả thử nghiệm còn cho thấy độ chính xác và tính tuyến tính của cảm biến áp suất MS5535. Một kết quả cũng rất quan trọng của việc thử nghiệm là vi điều khiển CC1010 tiêu thụ năng lượng thấp, một tiêu chí quan trọng của WSN.

Phần xây dựng mạng gồm nhiều nút mạng được tiến hành trên 3 nút mạng, 2 nút là Slave, 1 nút Master. Các nút mạng đều dùng vi điều khiển CC1010 của hãng Chipcon. Mạng được xây dựng theo dạng adhoc, bảng định tuyến dạng cây được nhớ cố định trong các nút mạng. Theo chu kỳ, cứ 2 giây nút Master lại gửi yêu cầu lấy dữ liệu tại một nút mạng. Gói tin yêu cầu lấy dữ liệu từ nút Master tới nút Slave sẽ đi qua các nút trung gian để tới nút cần gửi. Khi nút Slave nhận được yêu cầu từ Master, nó sẽ thu thập thông tin môi trường như nhiệt độ, áp suất rồi gửi về Master cũng theo đường đi vừa rồi. Việc thăm dò của Master được thực hiện vòng tròn cho tới nút mạng cuối cùng.

Kết quả các thực nghiệm cho thấy việc truyền nhận dữ liệu ổn định và tin cậy, không bị xung đột.

KẾT LUẬN

Bản luận văn đã đưa ra kiến trúc tổng quát và chỉ ra các yêu cầu chủ yếu cần đạt được khi xây dựng một WSN, đó là: năng lượng tiêu thụ, kích thước, tính mềm dẻo, độ chính xác theo thời gian. Những đặc điểm này cần được thể hiện trong hệ thống WSN. Hệ thống phải có khả năng mềm dẻo để thích hợp với dải rộng các yêu cầu của ứng dụng. Các dạng ứng dụng chủ yếu của WSN là: thu thập dữ liệu môi trường, mạng an ninh, và theo dõi đối tượng. Mỗi dạng ứng dụng có sự khác nhau căn bản về truyền thông và các giao thức cần được hỗ trợ bởi kiến trúc phần cứng.

Yêu cầu quan trọng của một nút mạng là có kích thước bé, tiêu thụ năng lượng thấp và có tích hợp truyền nhận không dây, từ đó đã chọn loại vi điều khiển CC1010 do hãng Chipcon-NaUy chế tạo có độ tích hợp cao, truyền nhận RF, tiêu thụ năng lượng thấp để làm nút mạng và xây dựng hệ thống thực nghiệm.

Bản luận văn cũng đã giới thiệu về phần mềm nhúng, các yêu cầu về phần mềm nhúng cho các nút mạng và vấn đề gỡ lỗi cho phần mềm nhúng. Gỡ lỗi sẽ làm cho phần mềm trở nên ổn định và tin cậy, dễ bảo trì. Trong lĩnh vực phần mềm nhúng có ba phương pháp gỡ lỗi, đó là: Giám sát ROM, Mô phỏng trên mạch và Gỡ lỗi Onchip.

Hai chức năng quan trọng nhất của một nút mạng trong WSN là chức năng mạng và chức năng cảm nhận. Chức năng cảm nhận của nút mạng đòi hỏi một nút mạng phải có khả năng ghép nối được với nhiều loại cảm biến. Điều đó cho phép một nút mạng có thể thu thập được nhiều thông tin khác nhau theo nhiều cách khác nhau. Một nút mạng như vậy có khả năng thích nghi cao với nhiều dạng ứng dụng. Từ các nghiên cứu lý thuyết tổng quát về cảm biến, bản luận văn đã đưa ra các phương pháp ghép nối VĐK với các loại cảm biến tương tự cũng như cảm biến số.

Phần thực nghiệm đã tiến hành các thử nghiệm ở mức hệ thống mạng WSN và xây dựng phần mềm nhúng cho các nút mạng. Các thử nghiệm chức năng mạng đã được thực hiện bao gồm:

- Xây dựng được mạng không dây gồm 2 nút mạng sử dụng vi điều khiển CC1010 nối với đầu đo áp suất MS5535. Kết quả thử nghiệm cho thấy hệ thống làm việc chính xác, ổn định.

- Xây dựng mạng gồm 2 nút mạng để đánh giá khả năng tiết kiệm năng lượng của nút mạng. Kết quả nút mạng hoạt động liên tục, có thể sống trong nhiều ngày.

- Xây dựng mạng gồm nhiều nút mạng truyền theo dạng multihop. Bảng định tuyến được tổ chức theo dạng cây, được nhớ trong tất cả các nút, qua đó mỗi nút trung gian sẽ biết được nút tiếp theo của gói tin hiện thời để có thể đến đích.

Từ các kết quả thực nghiệm trên cho thấy: Việc xây dựng một WSN bước đầu đã đạt được một số kết quả mang tính cơ bản, cho phép tiếp tục phát triển và đi sâu nghiên cứu theo hướng đã xác lập. Việc theo dõi các thông số môi trường trở nên dễ dàng và tiện lợi, người sử dụng chỉ cần ngồi tại một chỗ cũng có thể giám sát các thông số đó nhằm phục vụ các công việc của mình như: dự báo thời tiết, phòng chống cháy rừng, các ứng dụng trong nông nghiệp... Các thử nghiệm dùng module CC1010EM cho thấy rằng việc dùng vi điều khiển CC1010 cho WSN là hoàn toàn khả thi.

Áp dụng các công nghệ cho WSN vào thực tế như: đa truy cập, định tuyến, truyền thông multihop đã được tích hợp sẵn trong TinyOS là hướng nghiên cứu tiếp theo của đề tài.

TÀI LIỆU THAM KHẢO

Tài liệu Tiếng Việt

[1] Đinh Mạnh Tường (2002), "Cấu trúc dữ liệu và thuật toán", Nhà xuất bản khoa học và kỹ thuật.

[2] Vương Đạo Vy, Nguyễn Thế Sơn, Phùng Công Phi Khanh, Hòa Quang Dự, "Xây dựng hệ tự động đo khí áp sử dụng cảm biến áp suất MEMS và các thí nghiệm kiểm tra", tóm tắt các báo cáo Hội thảo Quốc gia lần thứ VIII, Hải Phòng 25-27/08/2005, Một số vấn đề chọn lọc của công nghệ thông tin và truyền thông, Chủ đề Mã nguồn mở, tr. 79, Hải phòng 08/2005

[3] Vương Đạo Vy, Nguyễn Thế Sơn, "Hệ tự động đo thông số môi trường theo thời gian thực, truyền dữ liệu không dây liên tục, dài ngày có kích thước nhỏ, giá thành thấp, tiêu thụ năng lượng ít", tóm tắt các báo cáo Hội nghị Vật lý toàn quốc lần thứ VI, tr. 297, Hà nội 11/2005

[4] Vũ Duy Lợi (2002), "Mạng thông tin máy tính", Nhà xuất bản Thế giới.

Tài liệu Tiếng Anh

[5] Alec Woo and David Culler, "A transmission control scheme for media access in sensor networks," in Proceedings of the ACM/IEEE International Conference on Mobile Computing and Networking, Rome, Italy, July 2001, ACM.

[6] Chipcon, CC1010 DataSheet, www.chipcon.com

[7] Chipcon, CC1010 IDE Manual, www.chipcon.com

[8] David Gay, Philip Levis, Robert von Behren, "The nesC Language: A Holistic Approach to Networked Embedded Systems", University of California, Berkeley, http://webs.cs.berkeley.edu

[9] E. Jason Riedy, Robert Szewczyk (2000), "Power and Control in Networked Sensors"

[10] Hugh O'Keeffe, R&D Director, Ashling Microsystems Ltd (2006), "Embedded Debugging"

[11] Jason Hill (2000), "A Software Architecture Supporting Networked Sensors", University of California, Berkeley

[12] Jason Lester Hill (2000), "System Architecture for Wireless Sensor Networks", University of California, Berkeley

[13] MS5534 DataSheet, http://www.intersema.ch

[14] MS5535 DataSheet, http://www.intersema.ch

[15] Nikolay Kirianaki, Sergey Yurish, Nestor Shpak, Vadim Deynega (2001), "Smart sensors for electrical and non-electrical, physical and chemical variables: tendencies and perspectives", John Wiley & Sons Ltd

[16] Patrick Kinney, Kinney Consulting LLC - Chair of IEEE 802.15.4 Task Group, Secretary of ZigBee BoD, Chair of ZigBee Building Automation Profile WG (2 october 2003), "ZigBee Technology: Wireless Control that Simply Works"

[17] Vuong Dao Vy, Nguyen The Son, Phung Cong Phi Khanh, College of Technology VNU (December 2005), "The automatic measure system contains the pieszoresistive pressure sensor in MEMS architecture and the experiment for checking", International conference on Mecha-Electronic, Malaixia

[18] Wei Ye, John Heidemann, Deborah Estrin (2002), "An Energy-Efficient MAC Protocol for Wireless Sensor Networks", University of California, Berkeley

[19] ZigBee Specification, www.zigbee.org

PHỤ LỤC

Phụ lục 1: Chương trình khảo sát quan hệ độ cao cột nước-áp suất

Phần mềm viết cho Master bao gồm các file: Common.h, Master.c

Phần mềm viết cho Slave bao gồm các file: Common.h, Slave.c, Slave.h, MS5535.c, MS5535.h

1. Common.h

#ifndef common_h

#define common_h// Only include this header file once

#include <stdio.h>

#include <stdlib.h>

#include <ctype.h>

#include <string.h>

#include <chipcon/reg1010.h>

#include <chipcon/cc1010eb.h>

#include <chipcon/hal.h>

#define CLKFREQ CC1010EB_CLKFREQ

#define PREAMBLE_BYTE_COUNT 18

#define PREAMBLE_BITS_SENSE_INIT 81

#define PREAMBLE_BITS_SENSE 16

#define CMD_GET_PARAMS 1

void RFSetup(void);

void setupTimer0();

void InitRF(void);

void PrepareRX(RF_RXTXPAIR_SETTINGS* RF_SETTINGS);

void Wait1sec (void);

void SelectClockMode(char iMode);

#endif

2. MS5535.h

#ifndef __MS5535_H__

#define __MS5535_H__

#include <chipcon/reg1010.h>

#include <chipcon/hal.h>

#include <chipcon/cc1010eb.h>

sbit P_MSCLK = P2^3;

sbit P_SCLK = P1^0;

sbit P_DIN = P1^1;

sbit P_DOUT = P0^3;

#define CLKFREQ CC1010EB_CLKFREQ //18432

#define DUTY_CYCLE 128

//MS5535

#define MS5535_W1 0x0157

#define MS5535_W2 0x00d7

#define MS5535_W3 0x0137

#define MS5535_W4 0x00b7

#define MS5535_P 0x002f

#define MS5535_T 0x004f

#define SCLK_W 1

#define true 1

#define false 0

void reset();

void SerialSendLsbFirst(char pattern, char nbr_clock);

word SerialGet16();

word getW (word index); // 1 to 4

word getD1 (word *error_pt);

word ConvertWtoC5535 (int ix, word W1, word W2, word W3, word W4);

void WaitOnePulse();

void setSCLK(bit status);

void setDIN(bit status);

bit getDOUT();

word waitOnDoutFall();

void calcPT5535 (word *pressure, word *temperature, word d1_arg, word d2_arg);

word readMS5535param1(word type);

void readMS5535Values(word *p,word *t);

void readMS5535Coefficients();

void InitMS5535();

void wait(word t_wait);

//void setupTimer0(word timeout);

void SetupCounter0();

word GetCounter();

#endif

3. MS5535.c

#include "MS5535.h"

word xdata w1,w2,w3,w4;

word xdata c1,c2,c3,c4,c5,c6;

void InitMS5535()

{

PORTDIRBIT(1, 0, POUT); //for SCLK MS5535

PORTDIRBIT(1, 1, POUT); //for DIN MS5535

PORTDIRBIT(0, 3, PIN); //for DOUT MS5535

PORTDIRBIT(2, 3, POUT); //for MSCLK MS5535

// Setup PWM2 pin direction

PORTDIRBIT(3, 4, POUT);

P_SCLK = 0;

P_DIN = 0;

halWait (20, CLKFREQ); //delay 20ms

// Configure timer 2 as a PWM timer, max timeout interval

halConfigTimer23(TIMER2 | TIMER23_PWM, 0, CLKFREQ);

PWM2_SET_PERIOD(1);

PWM2_SET_DUTY_CYCLE(DUTY_CYCLE);

TIMER2_RUN(FALSE);

readMS5535Coefficients();

}

//reset sequence

void resetMS5535()

{

byte xdata i;

P_SCLK = 0;

P_DIN = 0;

wait(2);

for(i=0;i<21;i++)

{

if(i<16) P_DIN = !P_DIN;

P_SCLK = 0; wait(2);

P_SCLK = 1; wait(2);

}

P_SCLK = 0;

halWait (SCLK_W, CLKFREQ); //delay 1ms

halWait (SCLK_W, CLKFREQ); //delay 1ms

return;

}

word readMS5535param(word type)

{

word xdata d;

byte xdata i,n;

if((type==MS5535_P) || (type==MS5535_T)) n=9;

else n=11;

resetMS5535();

P_SCLK = 0;

wait(2);

//setup

for(i=0;i<=n;i++)

{

P_DIN = type & 0x1;

type = type >> 1;

P_SCLK = 0;

wait(2);

P_SCLK = 1;

wait(2);

}

P_SCLK = 0; wait(2);

P_SCLK = 1; wait(2);

P_SCLK = 0; wait(2);

P_SCLK = 1; wait(2);

P_SCLK = 0;

halWait (50, CLKFREQ); //delay 1ms

//read data

d = 0;

for(i=0;i<16;i++)

{

P_SCLK = 1;

wait(2);

P_SCLK = 0;

d = (d<<1) | P_DOUT;

wait(2);

}

P_SCLK = 1; wait(2);

P_SCLK = 0; wait(2);

return d;

}

void readMS5535Values(word *p,word *t)

{

double xdata dt, off, sens, pressure1,temperature1;

double xdata fd1, fd2, x;

word xdata d1_arg, d2_arg;

d1_arg = readMS5535param(MS5535_P);

d2_arg = readMS5535param(MS5535_T);

d1_arg = d1_arg & 0xFFFF;

d2_arg = d2_arg & 0xFFFF;

fd1 = (double) d1_arg;

fd2 = (double) d2_arg;

dt = -10000.0 + fd2 - (8.0 * c5);

off = 10000.0 + c2 + ( ( ( c4-250.0) * dt ) / 4096.0);

sens = 3000.0 + (c1 / 2.0) + ( ( ( c3+200.0) * dt ) / 8192.0);

pressure1 = 1000.0 + (( sens * (fd1- off)) / 4096.0);

temperature1 = ( 200 + (( dt * (c6+100.0) ) / 2048.0));

*p = (word)pressure1;

*t = (word)temperature1;

}

void readMS5535Coefficients()

{

w1 = readMS5535param1(MS5535_W1);

w2 = readMS5535param1(MS5535_W2);

w3 = readMS5535param1(MS5535_W3);

w4 = readMS5535param1(MS5535_W4);

c1 = w1 >> 3;

c2 = ((w1 & 0x7)<<10) | (w2>>6);

c3 = w3 >> 6;

c4 = w4 >>7;

c5 = ((w2 & 0x3f) << 6) | (w3 & 0x3f);

c6 = w4 & 0x7f;

}

word readMS5535param1(word type)

{

word xdata d;

byte xdata i,n;

n=11;

resetMS5535();

wait(2);

for(i=0;i<=n;i++)

{

P_DIN = type & 0x1;

type = type >> 1;

P_SCLK = 0; wait(2);

P_SCLK = 1; wait(2);

}

P_SCLK = 0; wait(2);

P_SCLK = 1; wait(2);

P_SCLK = 0; wait(2);

halWait (50, CLKFREQ); //delay 50ms

//read data

d = 0;

for(i=0;i<16;i++)

{

P_SCLK = 1; wait(2);

P_SCLK = 0;

d = (d<<1) | P_DOUT; wait(2);

}

P_SCLK = 1; wait(2);

P_SCLK = 0; wait(2);

return d;

}

void wait(word t_wait)

{

word xdata i;

i = 0;

while(i<t_wait) i++;

}

void SetupCounter0()

{

TMOD = TMOD | 0x5; //16bit counter

TH0 = TL0 = 0;

TR0 = 1;

}

word GetCounter()

{

word xdata counter;

TR0 = 0;

counter = TH0;

counter = (counter << 8)|TL0;

TH0=TL0=0;

TR0=1;

return counter;

}

4. Master.c

#include "..\common\common.h"

// Temperature packet:

#define TBC_NODE_ID_LENGTH 2 // word

#define TBC_NODE_NAME_LENGTH 5 //20

#define TBC_TEMP_OFFSET (TBC_NODE_ID_LENGTH + TBC_NODE_NAME_LENGTH)

#define TBC_TEMP_LENGTH 2

#define TBC_TEMP_OFFSET1 (TBC_NODE_ID_LENGTH + TBC_NODE_NAME_LENGTH + TBC_TEMP_LENGTH)

#define TBC_TEMP_LENGTH1 2

#define TBC_TEMP_OFFSET2 (TBC_TEMP_OFFSET1 + TBC_TEMP_LENGTH1)

#define TBC_TEMP_LENGTH2 2

#define TBC_TEMP_OFFSET3 (TBC_TEMP_OFFSET2 + TBC_TEMP_LENGTH2)

#define TBC_TEMP_LENGTH3 2

#define TBC_TEMP_OFFSET4 (TBC_TEMP_OFFSET3 + TBC_TEMP_LENGTH3)

#define TBC_TEMP_LENGTH4 2

#define TBC_TEMP_OFFSET5 (TBC_TEMP_OFFSET4 + TBC_TEMP_LENGTH4)

#define TBC_TEMP_LENGTH5 2

#define TBC_DATA_LEN (TBC_TEMP_OFFSET5 + TBC_TEMP_LENGTH5)

// Radio related:

#define MY_ADDRESS 1

// Node registration

#define INVALID_NODE_INDEX 255

#define UNUSED_NODE_ID 0x0000

#define MAJOR_PERIOD 600//360000

#define RF_RX_BUF_SIZE 50

#define TEST_STRING_LENGTH 10

// The temperature "table":

#define MAX_NODE_COUNT 16

word xdata nodeIDs[MAX_NODE_COUNT];

byte xdata nodeNames[MAX_NODE_COUNT][TBC_NODE_NAME_LENGTH];

word xdata nodeTemps[MAX_NODE_COUNT];

word xdata nodeTemps1[MAX_NODE_COUNT];

word xdata nodeTemps2[MAX_NODE_COUNT];

word xdata nodeTemps3[MAX_NODE_COUNT];

word xdata nodeTemps4[MAX_NODE_COUNT];

word xdata nodeTemps5[MAX_NODE_COUNT];

word xdata nodeLastT[MAX_NODE_COUNT];

byte xdata rxDataBuffer[TBC_DATA_LEN];

byte xdata txDataBuffer[TBC_DATA_LEN];

// Function prototypes

void Receive (void);

void PrintTable (void);

void CmdGetParams(void);

void RFSetup(void);

void setupTimer0();

void InitRF(void);

void PrepareRX(RF_RXTXPAIR_SETTINGS* RF_SETTINGS);

void Wait1sec (void);

bit bPolled;

byte xdata rf_rx_buf[50];

byte xdata rf_rx_index;

unsigned long xdata TMajorPeriod;

bit bRF_RXdone;

// X-tal frequency: 14.745600 MHz

// RF frequency A: 868.277200 MHz Rx

// RF frequency B: 868.277200 MHz Tx

// RX Mode: Low side LO

// Frequency separation: 64 kHz

// Data rate: 2.4 kBaud

// Data Format: Manchester

// RF output power: 4 dBm

// IF/RSSI: RSSI Enabled

RF_RXTXPAIR_SETTINGS code RF_SETTINGS = {

0x4B, 0x2F, 0x15, // Modem 0, 1 and 2: Manchester, 2.4 kBaud

//0x43, 0x2F, 0x15, // Modem 0, 1 and 2: NRZ, 2.4 kBaud

//0xA1, 0x2F, 0x29, // Modem 0, 1 and 2: NRZ, 38.4 kBaud

//0xA0, 0x2F, 0x52, // Modem 0, 1 and 2: NRZ, 76.8 kBaud

0x75, 0xA0, 0x00, // Freq A

0x58, 0x32, 0x8D, // Freq B

0x01, 0xAB, // FSEP 1 and 0

0x40, // PLL_RX

0x30, // PLL_TX

0x6C, // CURRENT_RX

0xF3, // CURRENT_TX

0x32, // FREND

0xFF, // PA_POW

0x00, // MATCH

0x00, // PRESCALER

};

RF_RXTXPAIR_CALDATA xdata RF_CALDATA;

//----------------------------------------------------------------------------

// MAIN PROGRAM

//----------------------------------------------------------------------------

void main (void)

{

byte xdata n;

// Initialize peripherals

WDT_ENABLE(FALSE);

RLED_OE(TRUE); YLED_OE(TRUE); GLED_OE(TRUE); BLED_OE(TRUE);

RLED = LED_OFF;

// Startup macros for speed and low power consumption

MEM_NO_WAIT_STATES();

FLASH_SET_POWER_MODE(FLASH_STANDBY_BETWEEN_READS);

// Reset the node IDs

for (n = 0; n < MAX_NODE_COUNT; n++) {

nodeIDs[n] = UNUSED_NODE_ID;

}

// Reset our name buffer

for (n = 0; n < TBC_NODE_NAME_LENGTH; n++) {

nodeNames[0][n] = 0x00;

}

// Setup UART0 for polled I/O

UART0_SETUP(57600, CLKFREQ, UART_NO_PARITY | UART_RX_TX | UART_POLLED);

nodeIDs[0] = MY_ADDRESS;

setupTimer0();

RFSetup();

halRFCalib(&RF_SETTINGS, &RF_CALDATA); // Calibration

halRFSetRxTxOff(RF_TX, &RF_SETTINGS, &RF_CALDATA);// Turn on RF for RX

RF_START_TX();

halRFReadRSSIlevel(RSSI_MODE_INIT);

while (TRUE)

{

if(bPolled)

{

InitRF();

n=0;

CmdGetParams();

PrepareRX(&RF_SETTINGS);

n++;

bPolled = 0;

}

Receive();

}

} // main

void Receive (void)

{

byte xdata n,i;

byte xdata nodeIndex;

word xdata nodeID;

if(!bRF_RXdone) return;

BLED = !BLED;

if(rf_rx_buf[0]==RF_SUITABLE_SYNC_BYTE) {

for(i=0;i<TBC_DATA_LEN;i++) {

rxDataBuffer[i]= rf_rx_buf[i+2];

}

nodeID = (rxDataBuffer[0] << 8) + rxDataBuffer[1];// Get the node ID

for (n = 0; n < MAX_NODE_COUNT; n++) {

if (nodeIDs[n] == nodeID) {

nodeIndex = n;

break;

}

else if (nodeIDs[n] == UNUSED_NODE_ID){

nodeIndex = n;

break;

}

else{

nodeIndex = INVALID_NODE_INDEX;

}

}

// Update the table

if (nodeIndex != INVALID_NODE_INDEX){

nodeIDs[nodeIndex] = nodeID;

for (n = 0; n < TBC_NODE_NAME_LENGTH; n++) {

nodeNames[nodeIndex][n] = rxDataBuffer[n + TBC_NODE_ID_LENGTH];

}

nodeTemps[nodeIndex] = (rxDataBuffer[TBC_TEMP_OFFSET] << 8) + rxDataBuffer[TBC_TEMP_OFFSET + 1];

nodeTemps1[nodeIndex] = (rxDataBuffer[TBC_TEMP_OFFSET1] << 8) + rxDataBuffer[TBC_TEMP_OFFSET1 + 1];

nodeTemps2[nodeIndex] = (rxDataBuffer[TBC_TEMP_OFFSET2] << 8) + rxDataBuffer[TBC_TEMP_OFFSET2 + 1];

nodeTemps3[nodeIndex] = (rxDataBuffer[TBC_TEMP_OFFSET3] << 8) + rxDataBuffer[TBC_TEMP_OFFSET3 + 1];

nodeTemps4[nodeIndex] = (rxDataBuffer[TBC_TEMP_OFFSET4] << 8) + rxDataBuffer[TBC_TEMP_OFFSET4 + 1];

nodeTemps5[nodeIndex] = (rxDataBuffer[TBC_TEMP_OFFSET5] << 8) + rxDataBuffer[TBC_TEMP_OFFSET5 + 1];

nodeLastT[nodeIndex] = 0;

}

PrintTable();

}

InitRF();

} // Receive

void PrintTable (void)

{

int xdata n;

float xdata fTemp;

for (n = 0; n < MAX_NODE_COUNT; n++) {

if (nodeIDs[n] == UNUSED_NODE_ID) {

continue;

}

printf("%d", nodeIDs[n]);

printf(" %d", nodeTemps[n]); //ad0

fTemp = nodeTemps1[n]; //ad1

fTemp -= 492;

fTemp /= 8.192;

if(fTemp<0) fTemp=0;

printf(" %.1f", fTemp);

printf(" %d", nodeTemps2[n]); //ad2

printf(" %d", nodeTemps3[n]); //ms5535_p

printf(" %d", nodeTemps4[n]); //ms5535_t

printf(" %d", n); //level

printf(" %d

", n);

}

} // PrintTable

// Flash interrupt handler (do nothing)

// We need to handle the interrupt even though we do not do anything.

// If not, the program will not run correctly except under the debugger,

// which has its own Flash interrupt handler

void FlashIntrHandler(void) interrupt INUM_FLASH

{

INT_SETFLAG(INUM_FLASH, INT_CLR);

return;

}

// RF interrupt service routine:

void RF_ISR (void) interrupt INUM_RF

{

INT_SETFLAG (INUM_RF, INT_CLR);

if(!bRF_RXdone) {

// Get RF receive data

rf_rx_buf[rf_rx_index] = RF_RECEIVE_BYTE();

if(rf_rx_index==0) {

RF_LOCK_AVERAGE_FILTER(TRUE);

if(rf_rx_buf[rf_rx_index] != RF_SUITABLE_SYNC_BYTE) RLED = LED_ON;

}

rf_rx_index++;

if(rf_rx_index > TBC_DATA_LEN + 3) {

rf_rx_index = 0;

bRF_RXdone = 1;

PDET &= ~0x80;

PDET |= 0x80;

INT_ENABLE(INUM_RF, INT_OFF);

}

}

YLED = !YLED;

return;

}

//timer 10ms

void TIMER0_ISR() interrupt INUM_TIMER0

{

TF0 = 0;

TH0 = 0xd0;

TL0 = 0;

TR0 = 1;

if(TMajorPeriod == 0) {

bPolled = 1;

TMajorPeriod = MAJOR_PERIOD + 1;

}

TMajorPeriod--;

}

void CmdGetParams()

{

INT_ENABLE (INUM_RF, INT_OFF);

GLED = LED_ON;

txDataBuffer[0]=0x02; //address

txDataBuffer[1]=CMD_GET_PARAMS; //command

txDataBuffer[2]=0; //reserve

halRFSetRxTxOff(RF_TX, &RF_SETTINGS, &RF_CALDATA);

RF_START_TX();

halRFSendPacket(PREAMBLE_BYTE_COUNT, &txDataBuffer[0], 3);

GLED = LED_OFF;

INT_SETFLAG (INUM_RF, INT_CLR);

}

void setupTimer0()

{

TMajorPeriod = 0;

bPolled = 0;

TH0 = 100;

TL0 = 100;

TMOD = TMOD | 0x1; //timer0 mode1-16 bit timer

INT_ENABLE(INUM_TIMER0, INT_ON);

INT_GLOBAL_ENABLE (INT_ON);

CKCON = CKCON & 0xf7;

TF0 = 1;

}

// Setup RF

void RFSetup(void)

{

InitRF();

halRFCalib(&RF_SETTINGS, &RF_CALDATA);

halRFSetRxTxOff(RF_TX, &RF_SETTINGS, &RF_CALDATA);

INT_GLOBAL_ENABLE (INT_OFF);// Disable global interrupt

// Setup RF interrupt

INT_SETFLAG (INUM_RF, INT_CLR);

INT_PRIORITY (INUM_RF, INT_HIGH);

// Select RF bytemode

RFCON |= 0x01;

// Enable RF interrupt based on bytemode

RF_SET_BYTEMODE();

// Setup preamble configuration

RF_SET_PREAMBLE_COUNT(PREAMBLE_BYTE_COUNT);

RF_SET_SYNC_BYTE(RF_SUITABLE_SYNC_BYTE);

// Make sure avg filter is free-running + 22 baud settling time

MODEM1=(MODEM1&0x03)|0x24;

// Reset preamble detection

PDET &= ~0x80; PDET |= 0x80;

INT_ENABLE (INUM_RF, INT_OFF);

// Enable global interrupt

INT_GLOBAL_ENABLE (INT_ON);

}

void InitRF(void)

{

bRF_RXdone = 0;

rf_rx_index = 0;

}

void PrepareRX(RF_RXTXPAIR_SETTINGS* RF_SETTINGS)

{

halRFSetRxTxOff(RF_RX, RF_SETTINGS, &RF_CALDATA);

RF_START_RX();

INT_ENABLE (INUM_RF, INT_ON);

}

void Wait1sec (void)

{

halWait (250, CLKFREQ);

halWait (250, CLKFREQ);

halWait (250, CLKFREQ);

halWait (250, CLKFREQ);

} // Wait1sec

5. Slave.c

#include "ms5535.h"

#include <stdio.h>

#include <stdlib.h>

#include <ctype.h>

#include <string.h>

#include <chipcon/reg1010.h>

#include <chipcon/cc1010eb.h>

#include <chipcon/hal.h>

#define CLKFREQ CC1010EB_CLKFREQ

#define PREAMBLE_BYTE_COUNT 18

#define PREAMBLE_BITS_SENSE_INIT 81

#define PREAMBLE_BITS_SENSE 16

#define CMD_GET_PARAMS 1

// Temperature packet:

#define TBC_NODE_ID_LENGTH 2 // word

#define TBC_NODE_NAME_LENGTH 5 //20

#define TBC_TEMP_OFFSET (TBC_NODE_ID_LENGTH + TBC_NODE_NAME_LENGTH)

#define TBC_TEMP_LENGTH 2

#define TBC_TEMP_OFFSET1 (TBC_NODE_ID_LENGTH + TBC_NODE_NAME_LENGTH + TBC_TEMP_LENGTH)

#define TBC_TEMP_LENGTH1 2

#define TBC_TEMP_OFFSET2 (TBC_TEMP_OFFSET1 + TBC_TEMP_LENGTH1)

#define TBC_TEMP_LENGTH2 2

#define TBC_TEMP_OFFSET3 (TBC_TEMP_OFFSET2 + TBC_TEMP_LENGTH2)

#define TBC_TEMP_LENGTH3 2

#define TBC_TEMP_OFFSET4 (TBC_TEMP_OFFSET3 + TBC_TEMP_LENGTH3)

#define TBC_TEMP_LENGTH4 2

#define TBC_TEMP_OFFSET5 (TBC_TEMP_OFFSET4 + TBC_TEMP_LENGTH4)

#define TBC_TEMP_LENGTH5 2

#define TBC_DATA_LEN (TBC_TEMP_OFFSET5 + TBC_TEMP_LENGTH5)

// Radio related:

#define TBC_MY_SPP_ADDRESS 2

#define TBC_RX_INTERVAL 50

// Node registration

#define TBC_INVALID_NODE_INDEX 255

#define TBC_UNUSED_NODE_ID 0x0000

#define MAJOR_PERIOD 1500

#define MINOR_PERIOD 100

#define AVG_COUNT 10

// The temperature "table":

#define TBC_MAX_NODE_COUNT 16

word xdata nodeIDs[TBC_MAX_NODE_COUNT];

byte xdata nodeNames[TBC_MAX_NODE_COUNT][TBC_NODE_NAME_LENGTH];

word xdata nodeLastT[TBC_MAX_NODE_COUNT];

bit initrunflag = 1;

byte xdata rxDataBuffer[TBC_DATA_LEN];

byte xdata txDataBuffer[TBC_DATA_LEN];

bool xdata bSample;

// Unit name, stored in Flash

byte code flashUnitName[TBC_NODE_NAME_LENGTH];

// RAM buffer for Flash copy

byte xdata ramBufNonAligned[128];

bit bPolled;

byte xdata rf_rx_buf[50];

byte xdata rf_rx_index;

unsigned long xdata TMajorPeriod;

bit bRF_RXdone;

// Function prototypes

void tbcWait1sec (void);

void GetParameters (void);

void RFProc();

void RFSetupReceive (void);

void PrepareRX(RF_RXTXPAIR_SETTINGS* RF_SETTINGS);

void InitRF(void);

void RFSetup(void);

// X-tal frequency: 14.745600 MHz

// RF frequency A: 868.277200 MHz Rx

// RF frequency B: 868.277200 MHz Tx

// RX Mode: Low side LO

// Frequency separation: 64 kHz

// Data rate: 2.4 kBaud

// Data Format: Manchester

// RF output power: 4 dBm

// IF/RSSI: RSSI Enabled

RF_RXTXPAIR_SETTINGS code RF_SETTINGS = {

0x4B, 0x2F, 0x15, // Modem 0, 1 and 2: Manchester, 2.4 kBaud

//0x43, 0x2F, 0x15, // Modem 0, 1 and 2: NRZ, 2.4 kBaud

//0xA1, 0x2F, 0x29, // Modem 0, 1 and 2: NRZ, 38.4 kBaud

//0xA0, 0x2F, 0x52, // Modem 0, 1 and 2: NRZ, 76.8 kBaud

0x75, 0xA0, 0x00, // Freq A

0x58, 0x32, 0x8D, // Freq B

0x01, 0xAB, // FSEP 1 and 0

0x40, // PLL_RX

0x30, // PLL_TX

0x6C, // CURRENT_RX

0xF3, // CURRENT_TX

0x32, // FREND

0xFF, // PA_POW

0x00, // MATCH

0x00, // PRESCALER

};

RF_RXTXPAIR_CALDATA xdata RF_CALDATA;

//----------------------------------------------------------------------------

// MAIN PROGRAM

//----------------------------------------------------------------------------

void main (void)

{

byte xdata n;

// Initialize peripherals

WDT_ENABLE(FALSE);

// Startup macros for speed and low power consumption

MEM_NO_WAIT_STATES();

FLASH_SET_POWER_MODE(FLASH_STANDBY_BETWEEN_READS);

halRFCalib(&RF_SETTINGS, &RF_CALDATA);// Calibrate

RLED_OE(TRUE); YLED_OE(TRUE); GLED_OE(TRUE); BLED_OE(TRUE);

RLED = LED_OFF; YLED = LED_OFF; GLED = LED_OFF; BLED = LED_OFF;

bRF_RXdone = 0;

rf_rx_index = 0;

halConfigADC(ADC_MODE_SINGLE | ADC_REFERENCE_INTERNAL_1_25, CLKFREQ, 0);

// Reset the node IDs

for (n = 0; n < TBC_MAX_NODE_COUNT; n++) {

nodeIDs[n] = TBC_UNUSED_NODE_ID;

}

// Reset our name buffer

for (n = 0; n < TBC_NODE_NAME_LENGTH; n++) {

nodeNames[0][n] = 0x00;

}

// Load name from Flash

memcpy(&nodeNames[0][0],flashUnitName,TBC_NODE_NAME_LENGTH);

nodeIDs[0] = TBC_MY_SPP_ADDRESS;

// Prepare the id+name part of the packet

txDataBuffer[0] = (nodeIDs[0] >> 8) & 0xFF;

txDataBuffer[1] = nodeIDs[0] & 0xFF;

for (n = 0; n < TBC_NODE_NAME_LENGTH; n++) {

txDataBuffer[n + TBC_NODE_ID_LENGTH] = nodeNames[0][n];

}

InitMS5535();

RFSetupReceive ();

// Loop forever

while (TRUE)

{

RFProc();

}

} // main

void tbcWait1sec (void)

{

halWait (250, CLKFREQ);

halWait (250, CLKFREQ);

halWait (250, CLKFREQ);

halWait (250, CLKFREQ);

} // tbcWait1sec

void GetParameters(void)

{

word xdata temp;

word xdata temp1;

word xdata temp2;

word xdata temp3;

word xdata temp4;

word xdata p;

word xdata i;

temp = 0;

temp1 = 0;

temp2 = 0;

temp3 = 0;

temp4 = 0;

// Indicate transmission

for(i=0;i<4;i++)

{

TIMER2_RUN(TRUE);

halWait (1, CLKFREQ);

readMS5535Values(&temp3,&temp4);

TIMER2_RUN(FALSE);

if(i==0) p = temp3;

else p = (p+temp3)/2;

tbcWait1sec();

}

ADC_POWER(TRUE);

// Power up the ADC and sample the temperature

ADC_SELECT_INPUT(ADC_INPUT_AD0);

ADC_SAMPLE_SINGLE();

temp = ADC_GET_SAMPLE_10BIT();

ADC_SELECT_INPUT(ADC_INPUT_AD1);

ADC_SAMPLE_SINGLE();

temp1 = ADC_GET_SAMPLE_10BIT();

ADC_SELECT_INPUT(ADC_INPUT_AD2);

ADC_SAMPLE_SINGLE();

temp2 = ADC_GET_SAMPLE_10BIT();

ADC_POWER(FALSE);

// Update the TX buffer and the table with the new temperature

txDataBuffer[TBC_TEMP_OFFSET] = (temp >> 8) & 0xFF;

txDataBuffer[TBC_TEMP_OFFSET + 1] = temp & 0xFF;

txDataBuffer[TBC_TEMP_OFFSET1] = (temp1 >> 8) & 0xFF;

txDataBuffer[TBC_TEMP_OFFSET1 + 1] = temp1 & 0xFF;

txDataBuffer[TBC_TEMP_OFFSET2] = (temp2 >> 8) & 0xFF;

txDataBuffer[TBC_TEMP_OFFSET2 + 1] = temp2 & 0xFF;

txDataBuffer[TBC_TEMP_OFFSET3] = (temp3 >> 8) & 0xFF;

txDataBuffer[TBC_TEMP_OFFSET3 + 1] = temp3 & 0xFF;

txDataBuffer[TBC_TEMP_OFFSET4] = (temp4 >> 8) & 0xFF;

txDataBuffer[TBC_TEMP_OFFSET4 + 1] = temp4 & 0xFF;

txDataBuffer[TBC_TEMP_OFFSET5] = 0;//(temp5 >> 8) & 0xFF;

txDataBuffer[TBC_TEMP_OFFSET5 + 1] = 0;//temp5 & 0xFF;

} // tbcTransmit

// Flash interrupt handler (do nothing)

// We need to handle the interrupt even though we do not do anything.

// If not, the program will not run correctly except under the debugger,

// which has its own Flash interrupt handler

void FlashIntrHandler(void) interrupt INUM_FLASH

{

INT_SETFLAG(INUM_FLASH, INT_CLR);

return;

}

//timer 10ms

void TIMER0_ISR() interrupt INUM_TIMER0

{

TF0 = 0;

TH0 = 0xd0;

TL0 = 0;

TR0 = 1;

if(TMajorPeriod==0)

{

bSample = 1;

TMajorPeriod = MAJOR_PERIOD + 1;

}

TMajorPeriod--;

}

void RF_ISR (void) interrupt INUM_RF

{

INT_ENABLE(INUM_RF, INT_OFF);

INT_SETFLAG (INUM_RF, INT_CLR);

if(!bRF_RXdone) {

// Get RF receive data

rf_rx_buf[rf_rx_index] = RF_RECEIVE_BYTE();

if(rf_rx_index==0){

RF_LOCK_AVERAGE_FILTER(TRUE);

if(rf_rx_buf[rf_rx_index] != RF_SUITABLE_SYNC_BYTE) RLED = LED_ON;

}

rf_rx_index++;

if(rf_rx_index>/*rf_rx_buf[1]+1*/6){

rf_rx_index = 0;

bRF_RXdone = 1;

PDET &= ~0x80;

PDET |= 0x80;

}

}

INT_ENABLE(INUM_RF, INT_ON);

GLED = !GLED;

return;

}

void RFProc()

{

if(!bRF_RXdone) return;

if(rf_rx_buf[0]==RF_SUITABLE_SYNC_BYTE){

INT_ENABLE(INUM_RF, INT_OFF);

if(rf_rx_buf[3]==CMD_GET_PARAMS) {

GetParameters();

halRFSetRxTxOff(RF_TX, &RF_SETTINGS, &RF_CALDATA);

RF_START_TX();

halRFSendPacket(PREAMBLE_BYTE_COUNT,&txDataBuffer[0],TBC_DATA_LEN);

PrepareRX(&RF_SETTINGS);

}

}

InitRF();

}

void RFSetupReceive (void)

{

// Disable global interrupt

INT_GLOBAL_ENABLE (INT_OFF);

// Setup RF interrupt

INT_SETFLAG (INUM_RF, INT_CLR);

INT_PRIORITY (INUM_RF, INT_HIGH);

INT_ENABLE (INUM_RF, INT_ON);

// Enable RF interrupt based on bytemode

RF_SET_BYTEMODE();

// Setup preamble configuration

RF_SET_PREAMBLE_COUNT(PREAMBLE_BYTE_COUNT);

RF_SET_SYNC_BYTE(RF_SUITABLE_SYNC_BYTE);

// Make sure avg filter is free-running + 22 baud settling time

MODEM1=(MODEM1&0x03)|0x24;

// Reset preamble detection

PDET &= ~0x80;

PDET |= 0x80;

halRFSetRxTxOff(RF_RX, &RF_SETTINGS, &RF_CALDATA);

// Start RX

RF_START_RX();

// Enable global interrupt

INT_GLOBAL_ENABLE (INT_ON);

}

void InitRF(void)

{

bRF_RXdone = 0;

rf_rx_index = 0;

}

void PrepareRX(RF_RXTXPAIR_SETTINGS* RF_SETTINGS)

{

halRFSetRxTxOff(RF_RX, RF_SETTINGS, &RF_CALDATA);

RF_START_RX();

INT_ENABLE (INUM_RF, INT_ON);

}

void Wait1sec (void)

{

halWait (250, CLKFREQ);

halWait (250, CLKFREQ);

halWait (250, CLKFREQ);

halWait (250, CLKFREQ);

} // Wait1sec

// Setup RF

void RFSetup(void)

{

InitRF();

halRFCalib(&RF_SETTINGS, &RF_CALDATA);

halRFSetRxTxOff(RF_OFF, &RF_SETTINGS, &RF_CALDATA);

// Disable global interrupt

INT_GLOBAL_ENABLE (INT_OFF);

// Setup RF interrupt

INT_SETFLAG (INUM_RF, INT_CLR);

INT_PRIORITY (INUM_RF, INT_HIGH);

// Select RF bytemode

RFCON |= 0x01;

// Enable RF interrupt based on bytemode

RF_SET_BYTEMODE();

// Setup preamble configuration

RF_SET_PREAMBLE_COUNT(PREAMBLE_BYTE_COUNT);

RF_SET_PREAMBLE_COUNT(16);

RF_SET_SYNC_BYTE(RF_SUITABLE_SYNC_BYTE);

// Make sure avg filter is free-running + 22 baud settling time

MODEM1=(MODEM1&0x03)|0x24;

// Reset preamble detection

PDET &= ~0x80;

PDET |= 0x80;

// Enable global interrupt

INT_GLOBAL_ENABLE (INT_ON);

}

Phụ lục 2: Chương trình thử nghiệm vấn đề tiết kiệm năng lượng

Phần mềm viết cho Master bao gồm các file: Common.h, Master.c

Phần mềm viết cho Slave bao gồm các file: Common.h, Slave.c, Slave.h, MS5535.c, MS5535.h

1. Common.h

#ifndef common_h

#define common_h// Only include this header file once

#include <stdio.h>

#include <stdlib.h>

#include <ctype.h>

#include <string.h>

#include <chipcon/reg1010.h>

#include <chipcon/cc1010eb.h>

#include <chipcon/hal.h>

/**************************************************************************

* RF RX/TX-pair settings extracted from Chipcon's SmartRF studio *

**************************************************************************/

RF_RXTXPAIR_SETTINGS code RF_SETTINGS = {

0x4B, 0x2F, 0x15, // Modem 0, 1 and 2

0xAA, 0x80, 0x00, // Freq A

0x5C, 0xF4, 0x02, // Freq B

0x01, 0xAB, // FSEP 1 and 0

0x58, // PLL_RX

0x30, // PLL_TX

0x6C, // CURRENT_RX

0xF3, // CURRENT_TX

0x32, // FREND

0xFF, // PA_POW

0x00, // MATCH

0x00, // PRESCALER

};

// Calibration data

RF_RXTXPAIR_CALDATA xdata RF_CALDATA;

#define PREAMBLE_BYTE_COUNT 18

#define PREAMBLE_BITS_SENSE_INIT 81

#define PREAMBLE_BITS_SENSE 16

#endif

2. Slave.c

#include "ms5535.h"

#include "..\common\common.h"

// Temperature packet:

#define TBC_NODE_ID_LENGTH 2 // word

#define TBC_NODE_NAME_LENGTH 5 //20

#define TBC_TEMP_OFFSET (TBC_NODE_ID_LENGTH + TBC_NODE_NAME_LENGTH)

#define TBC_TEMP_LENGTH 2

#define TBC_TEMP_OFFSET1 (TBC_NODE_ID_LENGTH + TBC_NODE_NAME_LENGTH + TBC_TEMP_LENGTH)

#define TBC_TEMP_LENGTH1 2

#define TBC_TEMP_OFFSET2 (TBC_TEMP_OFFSET1 + TBC_TEMP_LENGTH1)

#define TBC_TEMP_LENGTH2 2

#define TBC_TEMP_OFFSET3 (TBC_TEMP_OFFSET2 + TBC_TEMP_LENGTH2)

#define TBC_TEMP_LENGTH3 2

#define TBC_TEMP_OFFSET4 (TBC_TEMP_OFFSET3 + TBC_TEMP_LENGTH3)

#define TBC_TEMP_LENGTH4 2

#define TBC_TEMP_OFFSET5 (TBC_TEMP_OFFSET4 + TBC_TEMP_LENGTH4)

#define TBC_TEMP_LENGTH5 2

#define TBC_DATA_LEN (TBC_TEMP_OFFSET5 + TBC_TEMP_LENGTH5)

// Radio related:

#define TBC_MY_SPP_ADDRESS 2

#define TBC_RX_INTERVAL 50

// Node registration

#define TBC_INVALID_NODE_INDEX 255

#define TBC_UNUSED_NODE_ID 0x0000

#define MAJOR_PERIOD 1500//30000:5minutes, 360000:1 hour, 1500: 15sec

#define MINOR_PERIOD 100

#define AVG_COUNT 10

// Speed related

byte xdata waitMultiplier;

// The temperature "table":

#define TBC_MAX_NODE_COUNT 16

word xdata nodeIDs[TBC_MAX_NODE_COUNT];

byte xdata nodeNames[TBC_MAX_NODE_COUNT][TBC_NODE_NAME_LENGTH];

word xdata nodeLastT[TBC_MAX_NODE_COUNT];

bit initrunflag = 1;

unsigned long xdata TMajorPeriod;

byte xdata rxDataBuffer[TBC_DATA_LEN];

byte xdata txDataBuffer[TBC_DATA_LEN];

byte xdata avgcnt;

bool xdata bSample;

// Function prototypes

void tbcWait1sec (void);

void GetParameters (void);

void setupTimer0();

void RFSetupTransmit (void);

void SelectClockMode(char iMode);

// Unit name, stored in Flash

byte code flashUnitName[TBC_NODE_NAME_LENGTH];

// RAM buffer for Flash copy

byte xdata ramBufNonAligned[128];

byte xdata received_byte;

word xdata counter,counter2;

//----------------------------------------------------------------------------

// MAIN PROGRAM

//----------------------------------------------------------------------------

void main (void)

{

byte xdata n;

byte xdata m;

// Initialize peripherals

WDT_ENABLE(FALSE);

RLED_OE(TRUE); YLED_OE(TRUE); GLED_OE(TRUE); BLED_OE(TRUE);

// Startup macros for speed and low power consumption

MEM_NO_WAIT_STATES();

FLASH_SET_POWER_MODE(FLASH_STANDBY_BETWEEN_READS);

// ADC setup

halConfigADC(ADC_MODE_SINGLE | ADC_REFERENCE_INTERNAL_1_25, CLKFREQ, 0);

RFSetupTransmit();

// Reset the node IDs

for (n = 0; n < TBC_MAX_NODE_COUNT; n++) {

nodeIDs[n] = TBC_UNUSED_NODE_ID;

}

// Reset our name buffer

for (n = 0; n < TBC_NODE_NAME_LENGTH; n++) {

nodeNames[0][n] = 0x00;

}

// Load name from Flash

memcpy(&nodeNames[0][0],flashUnitName,TBC_NODE_NAME_LENGTH);

nodeIDs[0] = TBC_MY_SPP_ADDRESS;

// Prepare the id+name part of the packet

txDataBuffer[0] = (nodeIDs[0] >> 8) & 0xFF;

txDataBuffer[1] = nodeIDs[0] & 0xFF;

for (n = 0; n < TBC_NODE_NAME_LENGTH; n++) {

txDataBuffer[n + TBC_NODE_ID_LENGTH] = nodeNames[0][n];

}

InitMS5535();

// Configure realtime clock to support wake-up from IDLE

halConfigRealTimeClock(15);

// Enable realtime clock (implicit: interrupt enable)

RTC_RUN(TRUE);

SelectClockMode(1);

// Loop forever

while (TRUE){

if(bSample){

SelectClockMode(0);

BLED = LED_ON;

GetParameters();

halRFSetRxTxOff(RF_TX, &RF_SETTINGS, &RF_CALDATA);

halRFSendPacket(PREAMBLE_BYTE_COUNT, txDataBuffer, TBC_DATA_LEN);

halRFSetRxTxOff(RF_OFF, &RF_SETTINGS, &RF_CALDATA);

GLED = !GLED;

tbcWait1sec();

halRFSetRxTxOff(RF_TX, &RF_SETTINGS, &RF_CALDATA);

halRFSendPacket(PREAMBLE_BYTE_COUNT, txDataBuffer, TBC_DATA_LEN);

halRFSetRxTxOff(RF_OFF, &RF_SETTINGS, &RF_CALDATA);

GLED = !GLED;

bSample = 0;

BLED = LED_OFF;

SelectClockMode(1);

}

}

}//main

void tbcWait1sec (void)

{

halWait (250, CLKFREQ);

halWait (250, CLKFREQ);

halWait (250, CLKFREQ);

halWait (250, CLKFREQ);

} // tbcWait1sec

void GetParameters(void)

{

word xdata temp, temp1, temp2, temp3, temp4, p, i;

temp = 0; temp1 = 0; temp2 = 0; temp3 = 0; temp4 = 0;

// Indicate transmission

for(i=0;i<4;i++) {

TIMER2_RUN(TRUE);

halWait (1, CLKFREQ);

readMS5535Values(&temp3,&temp4);

TIMER2_RUN(FALSE);

if(i==0) p = temp3;

else p = (p+temp3)/2;

tbcWait1sec();

}

ADC_POWER(TRUE);

// Power up the ADC and sample the temperature

ADC_SELECT_INPUT(ADC_INPUT_AD0);

ADC_SAMPLE_SINGLE();

temp = ADC_GET_SAMPLE_10BIT();

ADC_SELECT_INPUT(ADC_INPUT_AD1);

ADC_SAMPLE_SINGLE();

temp1 = ADC_GET_SAMPLE_10BIT();

ADC_SELECT_INPUT(ADC_INPUT_AD2);

ADC_SAMPLE_SINGLE();

temp2 = ADC_GET_SAMPLE_10BIT();

ADC_POWER(FALSE);

// Update the TX buffer and the table with the new temperature

txDataBuffer[TBC_TEMP_OFFSET] = (temp >> 8) & 0xFF;

txDataBuffer[TBC_TEMP_OFFSET + 1] = temp & 0xFF;

txDataBuffer[TBC_TEMP_OFFSET1] = (temp1 >> 8) & 0xFF;

txDataBuffer[TBC_TEMP_OFFSET1 + 1] = temp1 & 0xFF;

txDataBuffer[TBC_TEMP_OFFSET2] = (temp2 >> 8) & 0xFF;

txDataBuffer[TBC_TEMP_OFFSET2 + 1] = temp2 & 0xFF;

txDataBuffer[TBC_TEMP_OFFSET3] = (temp3 >> 8) & 0xFF;

txDataBuffer[TBC_TEMP_OFFSET3 + 1] = temp3 & 0xFF;

txDataBuffer[TBC_TEMP_OFFSET4] = (temp4 >> 8) & 0xFF;

txDataBuffer[TBC_TEMP_OFFSET4 + 1] = temp4 & 0xFF;

txDataBuffer[TBC_TEMP_OFFSET5] = 0;//(temp5 >> 8) & 0xFF;

txDataBuffer[TBC_TEMP_OFFSET5 + 1] = 0;//temp5 & 0xFF;

} // tbcTransmit

void setupTimer0()

{

TMajorPeriod = 0;

bSample = 0;

TH0 = 100;

TL0 = 100;

TMOD = TMOD | 0x1; //timer0 mode1-16 bit timer

INT_ENABLE(INUM_TIMER0, INT_ON);

INT_GLOBAL_ENABLE (INT_ON);

CKCON = CKCON & 0xf7;

IE = IE|0x80;

TF0 = 1;

}

// Flash interrupt handler (do nothing)

// We need to handle the interrupt even though we do not do anything.

// If not, the program will not run correctly except under the debugger,

// which has its own Flash interrupt handler

void FlashIntrHandler(void) interrupt INUM_FLASH

{

INT_SETFLAG(INUM_FLASH, INT_CLR);

return;

}

//timer 10ms

void TIMER0_ISR() interrupt INUM_TIMER0

{

TF0 = 0;

TH0 = 0xd0;

TL0 = 0;

TR0 = 1;

if(TMajorPeriod==0) {

bSample = 1;

TMajorPeriod = MAJOR_PERIOD+1;

}

TMajorPeriod--;

}

// Setup RF for RX

void RFSetupTransmit (void)

{

halRFCalib(&RF_SETTINGS, &RF_CALDATA);

// Turn on RF for TX

halRFSetRxTxOff(RF_TX, &RF_SETTINGS, &RF_CALDATA);

INT_ENABLE(INUM_RF, INT_OFF);

// Select RF bytemode

RFCON |= 0x01;

// Enable RF interrupt based on bytemode

RF_SET_BYTEMODE();

// Setup preamble configuration

RF_SET_PREAMBLE_COUNT(16);

RF_SET_SYNC_BYTE(RF_SUITABLE_SYNC_BYTE);

// Make sure avg filter is free-running + 22 baud settling time

MODEM1=(MODEM1&0x03)|0x24;

// Reset preamble detection

PDET &= ~0x80;

PDET |= 0x80;

}

//================================================================

void SelectClockMode(char iMode)

{

if(iMode==0) {

// Enable high speed XOSC, switch clock source, then disable 32kHz XOSC

XOSC_ENABLE(TRUE);

MAIN_CLOCK_SET_SOURCE(CLOCK_XOSC);

X32_ENABLE(FALSE);

PCON = PCON & 0xfe; //disable idle mode

}

else if(iMode==1) {

// Enable 32kHz oscillator, wait 0.5s to stabilize,

// then switch clock source, then disable high-speed XOSC

X32_INPUT_SOURCE(X32_USING_CRYSTAL);

X32_ENABLE(TRUE);

halWait(250, CC1010EB_CLKFREQ);

halWait(250, CC1010EB_CLKFREQ);

MAIN_CLOCK_SET_SOURCE(CLOCK_X32);

XOSC_ENABLE(FALSE);

PCON = PCON | 0x01; //enable idle mode

}

}

// ISR (interrupt service routine) for RTC, priority 11

// The interrupt must be cleared by software

void isr_rtc() interrupt INUM_RTC

{

//RTC_RUN(FALSE);

bSample = 1;

INT_SETFLAG(INUM_RTC, INT_CLR);

RLED = !RLED;

}

3. MS5535.h

Sử dụng lại file MS5535.h của phụ lục 1

4. MS5535.c

Sử dụng lại file MS5535.c của phụ lục 1

Phụ lục 3: Chương trình thử nghiệm truyền đa bước (multihop)

Phần mềm viết cho Master bao gồm các file: Common.h, Master.c, Tree.c, Tree.h

Phần mềm viết cho Slave bao gồm các file: Common.h, Slave.c, Slave.h, MS5535.c, MS5535.h, Tree.c, Tree.h

1. Common.h

#ifndef common_h

#define common_h// Only include this header file once

#include <stdio.h>

#include <stdlib.h>

#include <ctype.h>

#include <string.h>

#include <chipcon/reg1010.h>

#include <chipcon/cc1010eb.h>

#include <chipcon/hal.h>

#define CLKFREQ CC1010EB_CLKFREQ

#define CMD_ACK 0xF0

#define CMD_NACK 0xFF

#define CMD_RTS 0xFE

#define CMD_CTS 0xFD

#define CMD_SYNC 0xFC

#define CMD_HELLO 0xE0

#define CMD_GET_PARAMS 1

#define PREAMBLE_BYTE_COUNT 18

#define PREAMBLE_BITS_SENSE_INIT 81

#define PREAMBLE_BITS_SENSE 16

#define MASTER_ADDR 1

void RFSetup(void);

void setupTimer0();

void InitRF(void);

void PrepareRX(RF_RXTXPAIR_SETTINGS* RF_SETTINGS);

void Wait1sec (void);

void SelectClockMode(char iMode);

#endif

2. Master.c

#include "..\common\common.h"

#include "..\common\tree.h"

// Temperature packet:

#define NODE_ID_OFFSET 0

#define NODE_ID_PARENT_OFFSET 1

#define NODE_ID_NEXTHOP_OFFSET 2

#define NODE_CMD_OFFSET 3

#define TEMP_OFFSET 4

#define TEMP_LENGTH 2

#define TEMP_OFFSET1 (TEMP_OFFSET + TEMP_LENGTH)

#define TEMP_LENGTH1 2

#define TEMP_OFFSET2 (TEMP_OFFSET1 + TEMP_LENGTH1)

#define TEMP_LENGTH2 2

#define TEMP_OFFSET3 (TEMP_OFFSET2 + TEMP_LENGTH2)

#define TEMP_LENGTH3 2

#define TEMP_OFFSET4 (TEMP_OFFSET3 + TEMP_LENGTH3)

#define TEMP_LENGTH4 2

#define TEMP_OFFSET5 (TEMP_OFFSET4 + TEMP_LENGTH4)

#define TEMP_LENGTH5 2

#define DATA_LEN (TEMP_OFFSET5 + TEMP_LENGTH5)

// Radio related:

#define MY_ADDRESS 1

// Node registration

#define INVALID_NODE_INDEX 255

#define UNUSED_NODE_ID 0x0000

#define MAJOR_PERIOD 200

#define MINOR_PERIOD 10

#define RF_RX_BUF_SIZE 50

#define TEST_STRING_LENGTH 10

#define N_NODES 11

word xdata nodeIDs,nodeLastT;

word xdata nodeTemps, nodeTemps1,nodeTemps2, nodeTemps3, nodeTemps4, nodeTemps5;

byte xdata rxDataBuffer[DATA_LEN], txDataBuffer[DATA_LEN];

// Function prototypes

void Receive (void);

void PrintTable (byte nodeindex);

void CmdGetParams(char node);

void RFSetup(void);

void setupTimer0();

void InitRF(void);

void PrepareRX(RF_RXTXPAIR_SETTINGS* RF_SETTINGS);

void Wait1sec (void);

byte xdata rf_rx_index,rf_rx_buf[50];

unsigned long xdata TMajorPeriod;

bit bRF_Rxdone,bPolled;

// X-tal frequency: 14.745600 MHz

// RF frequency A: 868.277200 MHz Rx

// RF frequency B: 868.277200 MHz Tx

// RX Mode: Low side LO

// Frequency separation: 64 kHz

// Data rate: 2.4 kBaud

// Data Format: Manchester

// RF output power: 4 dBm

// IF/RSSI: RSSI Enabled

RF_RXTXPAIR_SETTINGS code RF_SETTINGS = {

0x4B, 0x2F, 0x15, // Modem 0, 1 and 2: Manchester, 2.4 kBaud

//0x43, 0x2F, 0x15, // Modem 0, 1 and 2: NRZ, 2.4 kBaud

//0xA1, 0x2F, 0x29, // Modem 0, 1 and 2: NRZ, 38.4 kBaud

//0xA0, 0x2F, 0x52, // Modem 0, 1 and 2: NRZ, 76.8 kBaud

0x75, 0xA0, 0x00, // Freq A

0x58, 0x32, 0x8D, // Freq B

0x01, 0xAB, // FSEP 1 and 0

0x40, // PLL_RX

0x30, // PLL_TX

0x6C, // CURRENT_RX

0xF3, // CURRENT_TX

0x32, // FREND

0xFF, // PA_POW

0x00, // MATCH

0x00, // PRESCALER

};

RF_RXTXPAIR_CALDATA xdata RF_CALDATA;

//----------------------------------------------------------------------------

// MAIN PROGRAM

//----------------------------------------------------------------------------

void main (void)

{

byte xdata n;

BuildTree();

// Initialize peripherals

WDT_ENABLE(FALSE);

RLED_OE(TRUE); YLED_OE(TRUE); GLED_OE(TRUE); BLED_OE(TRUE);

RLED = LED_OFF;

// Startup macros for speed and low power consumption

MEM_NO_WAIT_STATES();

FLASH_SET_POWER_MODE(FLASH_STANDBY_BETWEEN_READS);

// Setup UART0 for polled I/O

UART0_SETUP(57600, CLKFREQ, UART_NO_PARITY | UART_RX_TX | UART_POLLED);

nodeIDs = MY_ADDRESS;

setupTimer0();

RFSetup();

// Calibration

halRFCalib(&RF_SETTINGS, &RF_CALDATA);

// Turn on RF for RX

halRFSetRxTxOff(RF_TX, &RF_SETTINGS, &RF_CALDATA);

RF_START_TX();

halRFReadRSSIlevel(RSSI_MODE_INIT);

n=2;

// Loop forever

while (TRUE) {

if(bPolled) {

InitRF();

CmdGetParams(n);

PrepareRX(&RF_SETTINGS);

n++;

if(n>N_NODES) n=2;

bPolled = 0;

}

Receive();

}

} // main

void Receive (void)

{

byte xdata i;

word xdata nodeID,crc,crc1;

if(!bRF_RXdone) return;

crc = culFastCRC16Block(&rxDataBuffer[1], DATA_LEN, CRC16_INIT);

crc1 = rxDataBuffer[DATA_LEN];

crc1 = (crc1<<8)|rxDataBuffer[DATA_LEN-1];

if(crc!=crc1) return;

INT_ENABLE(INUM_RF, INT_OFF);

if(rf_rx_buf[0]==RF_SUITABLE_SYNC_BYTE && rf_rx_buf[3]==MY_ADDRESS)

{

BLED = !BLED;

for(i=0;i<DATA_LEN;i++) {

rxDataBuffer[i]= rf_rx_buf[i+3];

}

// Get the node ID

nodeID = rxDataBuffer[3]; //Endpoint

// Update the table

if (nodeID != INVALID_NODE_INDEX) {

nodeIDs = nodeID;

nodeTemps = (rxDataBuffer[TEMP_OFFSET] << 8) + rxDataBuffer[TEMP_OFFSET + 1];

nodeTemps1 = (rxDataBuffer[TEMP_OFFSET1] << 8) + rxDataBuffer[TEMP_OFFSET1 + 1];

nodeTemps2 = (rxDataBuffer[TEMP_OFFSET2] << 8) + rxDataBuffer[TEMP_OFFSET2 + 1];

nodeTemps3 = (rxDataBuffer[TEMP_OFFSET3] << 8) + rxDataBuffer[TEMP_OFFSET3 + 1];

nodeTemps4 = (rxDataBuffer[TEMP_OFFSET4] << 8) + rxDataBuffer[TEMP_OFFSET4 + 1];

nodeTemps5 = (rxDataBuffer[TEMP_OFFSET5] << 8) + rxDataBuffer[TEMP_OFFSET5 + 1];

nodeLastT = 0;

}

PrintTable(nodeID);

}

InitRF();

INT_ENABLE(INUM_RF, INT_ON);

} // Receive

void PrintTable (byte nodeindex)

{

float xdata fTemp;

printf("%d", nodeIDs);

// Temperature:

printf(" %d", nodeTemps); //ad0

fTemp = nodeTemps1; //ad1

fTemp -= 492;

fTemp /= 8.192;

if(fTemp<0) fTemp=0;

printf(" %.1f", fTemp);

printf(" %d", nodeTemps2); //ad2

printf(" %d", nodeTemps3); //ms5535_p

printf(" %d", nodeTemps4); //ms5535_t

printf(" %d", nodeindex/*nodeTemps5[n]*/); //level

// Time after the last update

//timeDiff = abs((int) sppGetTime() - nodeLastT[n]) * 10;

printf(" %d

", nodeindex/*timeDiff*/);

} // PrintTable

// Flash interrupt handler (do nothing)

// We need to handle the interrupt even though we do not do anything.

// If not, the program will not run correctly except under the debugger,

// which has its own Flash interrupt handler

void FlashIntrHandler(void) interrupt INUM_FLASH

{

INT_SETFLAG(INUM_FLASH, INT_CLR);

return;

}

// RF interrupt service routine:

void RF_ISR (void) interrupt INUM_RF

{

INT_ENABLE(INUM_RF, INT_OFF);

INT_SETFLAG (INUM_RF, INT_CLR);

if(!bRF_RXdone) {

// Get RF receive data

rf_rx_buf[rf_rx_index] = RF_RECEIVE_BYTE();

if(rf_rx_index==0) {

RF_LOCK_AVERAGE_FILTER(TRUE);

if(rf_rx_buf[rf_rx_index] != RF_SUITABLE_SYNC_BYTE) RLED = LED_ON;

}

rf_rx_index++;

if(rf_rx_index > rf_rx_buf[1] + 3) {

rf_rx_index = 0;

bRF_RXdone = 1;

PDET &= ~0x80;

PDET |= 0x80;

INT_ENABLE(INUM_RF, INT_OFF);

YLED = !YLED;

return;

}

}

INT_ENABLE(INUM_RF, INT_ON);

YLED = !YLED;

return;

}

//timer 10ms

void TIMER0_ISR() interrupt INUM_TIMER0

{

TF0 = 0;

TH0 = 0xd0;

TL0 = 0;

TR0 = 1;

if(TMajorPeriod == 0) {

bPolled = 1;

TMajorPeriod = MAJOR_PERIOD + 1;

}

TMajorPeriod--;

}

void CmdGetParams(char node)

{

char xdata nexthop;

INT_ENABLE (INUM_RF, INT_OFF);

GLED = LED_ON;

nexthop = FindNextHop(MY_ADDRESS,node);

txDataBuffer[0] = MY_ADDRESS; //source address

txDataBuffer[1] = nexthop; //next hop

txDataBuffer[2] = node; //Endpoint address

txDataBuffer[3] = CMD_GET_PARAMS; //command

halRFSetRxTxOff(RF_TX, &RF_SETTINGS, &RF_CALDATA);

RF_START_TX();

halRFSendPacket(PREAMBLE_BYTE_COUNT, &txDataBuffer[0], 4);

GLED = LED_OFF;

halRFSetRxTxOff(RF_RX, &RF_SETTINGS, &RF_CALDATA);

RF_START_RX();

INT_SETFLAG (INUM_RF, INT_CLR);

INT_ENABLE (INUM_RF, INT_ON);

}

void setupTimer0()

{

TMajorPeriod = 0;

bPolled = 0;

TH0 = 100;

TL0 = 100;

TMOD = TMOD | 0x1; //timer0 mode1-16 bit timer

INT_ENABLE(INUM_TIMER0, INT_ON);

INT_GLOBAL_ENABLE (INT_ON);

CKCON = CKCON & 0xf7;

TF0 = 1;

}

// Setup RF

void RFSetup(void)

{

InitRF();

halRFCalib(&RF_SETTINGS, &RF_CALDATA);

halRFSetRxTxOff(RF_TX, &RF_SETTINGS, &RF_CALDATA);

// Disable global interrupt

INT_GLOBAL_ENABLE (INT_OFF);

// Setup RF interrupt

INT_SETFLAG (INUM_RF, INT_CLR);

INT_PRIORITY (INUM_RF, INT_HIGH);

// Select RF bytemode

RFCON |= 0x01;

// Enable RF interrupt based on bytemode

RF_SET_BYTEMODE();

// Setup preamble configuration

RF_SET_PREAMBLE_COUNT(PREAMBLE_BYTE_COUNT);

RF_SET_SYNC_BYTE(RF_SUITABLE_SYNC_BYTE);

// Make sure avg filter is free-running + 22 baud settling time

MODEM1=(MODEM1&0x03)|0x24;

// Reset preamble detection

PDET &= ~0x80;

PDET |= 0x80;

INT_ENABLE (INUM_RF, INT_OFF);

// Enable global interrupt

INT_GLOBAL_ENABLE (INT_ON);

}

void InitRF(void)

{

bRF_RXdone = 0;

rf_rx_index = 0;

}

void PrepareRX(RF_RXTXPAIR_SETTINGS* RF_SETTINGS)

{

halRFSetRxTxOff(RF_RX, RF_SETTINGS, &RF_CALDATA);

RF_START_RX();

INT_ENABLE (INUM_RF, INT_ON);

}

void Wait1sec (void)

{

halWait (250, CLKFREQ); halWait (250, CLKFREQ);

halWait (250, CLKFREQ); halWait (250, CLKFREQ);

} // Wait1sec

3. Slave.c

#include "ms5535.h"

#include "..\common\common.h"

#include "..\common\tree.h"

#include <cul.h>

#include <stdio.h>

#include <stdlib.h>

#include <ctype.h>

#include <string.h>

#include <chipcon/reg1010.h>

#include <chipcon/cc1010eb.h>

#include <chipcon/hal.h>

// Temperature packet:

//#define NODE_ID_LENGTH 1

#define NODE_ID_OFFSET 0

#define NODE_ID_PARENT_OFFSET 1

#define NODE_ID_NEXTHOP_OFFSET 2

#define NODE_CMD_OFFSET 3

#define TEMP_OFFSET 4

#define TEMP_LENGTH 2

#define TEMP_OFFSET1 (TEMP_OFFSET + TEMP_LENGTH)

#define TEMP_LENGTH1 2

#define TEMP_OFFSET2 (TEMP_OFFSET1 + TEMP_LENGTH1)

#define TEMP_LENGTH2 2

#define TEMP_OFFSET3 (TEMP_OFFSET2 + TEMP_LENGTH2)

#define TEMP_LENGTH3 2

#define TEMP_OFFSET4 (TEMP_OFFSET3 + TEMP_LENGTH3)

#define TEMP_LENGTH4 2

#define TEMP_OFFSET5 (TEMP_OFFSET4 + TEMP_LENGTH4)

#define TEMP_LENGTH5 2

#define DATA_LEN (TEMP_OFFSET5 + TEMP_LENGTH5)

// Radio related:

#define MY_ADDRESS 3

#define RX_INTERVAL 50

// Node registration

#define INVALID_NODE_INDEX 255

#define UNUSED_NODE_ID 0x0000

#define MAJOR_PERIOD 1500

#define MINOR_PERIOD 100

#define AVG_COUNT 10

// The temperature "table":

#define MAX_NODE_COUNT 16

word xdata nodeIDs[MAX_NODE_COUNT];

word xdata nodeTemps[MAX_NODE_COUNT];

word xdata nodeTemps1[MAX_NODE_COUNT];

word xdata nodeTemps2[MAX_NODE_COUNT];

word xdata nodeTemps3[MAX_NODE_COUNT];

word xdata nodeTemps4[MAX_NODE_COUNT];

word xdata nodeTemps5[MAX_NODE_COUNT];

word xdata nodeLastT[MAX_NODE_COUNT];

bit initrunflag = 1;

byte xdata rxDataBuffer[DATA_LEN];

byte xdata txDataBuffer[DATA_LEN];

bool xdata bSample;

byte ParentID; //ID of parent

void RandomWait(byte waitMultiplier);

// RAM buffer for Flash copy

byte xdata ramBufNonAligned[128];

bit bPolled;

byte xdata rf_rx_buf[50];

byte xdata rf_rx_index;

unsigned long xdata TMajorPeriod;

bit bRF_RXdone;

// Function prototypes

void tbcWait1sec (void);

void GetParameters (void);

void RFProc();

void RFSetupReceive (void);

void PrepareRX(RF_RXTXPAIR_SETTINGS* RF_SETTINGS);

void InitRF(void);

void Receive (void);

// X-tal frequency: 14.745600 MHz

// RF frequency A: 868.277200 MHz Rx

// RF frequency B: 868.277200 MHz Tx

// RX Mode: Low side LO

// Frequency separation: 64 kHz

// Data rate: 2.4 kBaud

// Data Format: Manchester

// RF output power: 4 dBm

// IF/RSSI: RSSI Enabled

RF_RXTXPAIR_SETTINGS code RF_SETTINGS = {

0x4B, 0x2F, 0x15, // Modem 0, 1 and 2: Manchester, 2.4 kBaud

//0x43, 0x2F, 0x15, // Modem 0, 1 and 2: NRZ, 2.4 kBaud

//0xA1, 0x2F, 0x29, // Modem 0, 1 and 2: NRZ, 38.4 kBaud

//0xA0, 0x2F, 0x52, // Modem 0, 1 and 2: NRZ, 76.8 kBaud

0x75, 0xA0, 0x00, // Freq A

0x58, 0x32, 0x8D, // Freq B

0x01, 0xAB, // FSEP 1 and 0

0x40, // PLL_RX

0x30, // PLL_TX

0x6C, // CURRENT_RX

0xF3, // CURRENT_TX

0x32, // FREND

0xFF, // PA_POW

0x00, // MATCH

0x00, // PRESCALER

};

RF_RXTXPAIR_CALDATA xdata RF_CALDATA;

byte xdata n;

int xdata k;

//----------------------------------------------------------------------------

// MAIN PROGRAM

//----------------------------------------------------------------------------

void main (void)

{

BuildTree();

// Initialize peripherals

WDT_ENABLE(FALSE);

// Enable the LEDs

RLED_OE(TRUE); YLED_OE(TRUE); GLED_OE(TRUE); BLED_OE(TRUE);

RLED = LED_OFF; YLED = LED_OFF; GLED = LED_OFF; BLED = LED_OFF;

// Startup macros for speed and low power consumption

MEM_NO_WAIT_STATES();

FLASH_SET_POWER_MODE(FLASH_STANDBY_BETWEEN_READS);

halRFCalib(&RF_SETTINGS, &RF_CALDATA); // Calibrate

halRFSetRxTxOff(RF_RX, &RF_SETTINGS, &RF_CALDATA); // Turn on RF for RX

// ADC setup

halConfigADC(ADC_MODE_SINGLE | ADC_REFERENCE_INTERNAL_1_25, CLKFREQ, 0);

// Reset the node IDs

for (n = 0; n < MAX_NODE_COUNT; n++) {

nodeIDs[n] = UNUSED_NODE_ID;

}

nodeIDs[0] = MY_ADDRESS;

// Prepare the id+name part of the packet

txDataBuffer[0] = nodeIDs[0];

InitMS5535();

RFSetupReceive ();

// Loop forever

while (TRUE) {

RFProc();

}

} // main

void tbcWait1sec (void)

{

halWait (250, CLKFREQ); halWait (250, CLKFREQ);

halWait (250, CLKFREQ); halWait (250, CLKFREQ);

} // tbcWait1sec

void GetParameters(void)

{

word xdata temp, temp1, temp2, temp3, temp4;

temp = 0;temp1 = 0;temp2 = 0;temp3 = 0;temp4 = 0;

// Indicate transmission

TIMER2_RUN(TRUE);

halWait (1, CLKFREQ);

readMS5535Values(&temp3,&temp4);

TIMER2_RUN(FALSE);

ADC_POWER(TRUE);

// Power up the ADC and sample the temperature

ADC_SELECT_INPUT(ADC_INPUT_AD0);

ADC_SAMPLE_SINGLE();

temp = ADC_GET_SAMPLE_10BIT();

ADC_SELECT_INPUT(ADC_INPUT_AD1);

ADC_SAMPLE_SINGLE();

temp1 = ADC_GET_SAMPLE_10BIT();

ADC_SELECT_INPUT(ADC_INPUT_AD2);

ADC_SAMPLE_SINGLE();

temp2 = ADC_GET_SAMPLE_10BIT();

ADC_POWER(FALSE);

// Update the TX buffer and the table with the new temperature

txDataBuffer[4] = (temp >> 8) & 0xFF;

txDataBuffer[5] = temp & 0xFF;

txDataBuffer[6] = (temp1 >> 8) & 0xFF;

txDataBuffer[7] = temp1 & 0xFF;

txDataBuffer[8] = (temp2 >> 8) & 0xFF;

txDataBuffer[9] = temp2 & 0xFF;

txDataBuffer[10] = (temp3 >> 8) & 0xFF;

txDataBuffer[11] = temp3 & 0xFF;

txDataBuffer[12] = (temp4 >> 8) & 0xFF;

txDataBuffer[13] = temp4 & 0xFF;

txDataBuffer[14] = 0;//(temp5 >> 8) & 0xFF;

txDataBuffer[15] = 0;//temp5 & 0xFF;

} // tbcTransmit

// Flash interrupt handler (do nothing)

// We need to handle the interrupt even though we do not do anything.

// If not, the program will not run correctly except under the debugger,

// which has its own Flash interrupt handler

void FlashIntrHandler(void) interrupt INUM_FLASH

{

INT_SETFLAG(INUM_FLASH, INT_CLR);

return;

}

//timer 10ms

void TIMER0_ISR() interrupt INUM_TIMER0

{

TF0 = 0;

TH0 = 0xd0;

TL0 = 0;

TR0 = 1;

if(TMajorPeriod==0) {

bSample = 1;

TMajorPeriod = MAJOR_PERIOD + 1;

}

TMajorPeriod--;

}

void RF_ISR (void) interrupt INUM_RF

{

INT_ENABLE(INUM_RF, INT_OFF);

INT_SETFLAG (INUM_RF, INT_CLR);

if(!bRF_RXdone)

{

// Get RF receive data

rf_rx_buf[rf_rx_index] = RF_RECEIVE_BYTE();

if(rf_rx_index==0){

RF_LOCK_AVERAGE_FILTER(TRUE);

if(rf_rx_buf[rf_rx_index] != RF_SUITABLE_SYNC_BYTE) RLED = LED_ON;

}

rf_rx_index++;

if(rf_rx_index>rf_rx_buf[1] + 3){

bRF_RXdone = 1;

PDET &= ~0x80;

PDET |= 0x80;

INT_ENABLE(INUM_RF, INT_OFF);

YLED = !YLED;

return;

}

}

INT_ENABLE(INUM_RF, INT_ON);

YLED = !YLED;

return;

}

void RFProc()

{

byte xdata SourceAddr,NextHop,EndpointAddr;

word xdata crc,crc1;

if(!bRF_RXdone) return;

if(rf_rx_index==0) return;

crc = culFastCRC16Block(&rf_rx_buf[1], DATA_LEN-2, CRC16_INIT);

crc1 = rf_rx_buf[DATA_LEN-2];

crc1 = (crc1<<8) | rf_rx_buf[DATA_LEN-1];

if(crc!=crc1) return;

if(rf_rx_buf[0]==RF_SUITABLE_SYNC_BYTE)

{

INT_ENABLE(INUM_RF, INT_OFF);

SourceAddr = rf_rx_buf[2];

NextHop = rf_rx_buf[3];

EndpointAddr = rf_rx_buf[4];

if(NextHop == MY_ADDRESS) {

if(SourceAddr == Parent(MY_ADDRESS)) {

if(EndpointAddr == MY_ADDRESS) { //Endpoint

GetParameters();

txDataBuffer[0] = MY_ADDRESS;

txDataBuffer[1] = Parent(MY_ADDRESS); //nexthop=parent

txDataBuffer[2] = MY_ADDRESS;

txDataBuffer[3] = CMD_GET_PARAMS;

halRFSetRxTxOff(RF_TX, &RF_SETTINGS, &RF_CALDATA);

RF_START_TX();

halRFSendPacket(PREAMBLE_BYTE_COUNT, &txDataBuffer[0], DATA_LEN);

}

else { //forward down tree

Receive();

NextHop = FindNextHop(MY_ADDRESS, EndpointAddr);

rxDataBuffer[0] = MY_ADDRESS;

rxDataBuffer[1] = NextHop;

halRFSetRxTxOff(RF_TX, &RF_SETTINGS, &RF_CALDATA);

RF_START_TX();

halRFSendPacket(PREAMBLE_BYTE_COUNT, &rxDataBuffer[0], 4);

}

}

else { //forward up tree

Receive();

NextHop = Parent(MY_ADDRESS);

rxDataBuffer[0] = MY_ADDRESS;

rxDataBuffer[1] = NextHop;

halRFSetRxTxOff(RF_TX, &RF_SETTINGS, &RF_CALDATA);

RF_START_TX();

halRFSendPacket(PREAMBLE_BYTE_COUNT, &rxDataBuffer[0], DATA_LEN);

}

}

}

PrepareRX(&RF_SETTINGS);

InitRF();

}

void RFSetupReceive (void)

{

bRF_RXdone = 0;

rf_rx_index = 0;

// Disable global interrupt

INT_GLOBAL_ENABLE (INT_OFF);

// Setup RF interrupt

INT_SETFLAG (INUM_RF, INT_CLR);

INT_PRIORITY (INUM_RF, INT_HIGH);

INT_ENABLE (INUM_RF, INT_ON);

// Enable RF interrupt based on bytemode

RF_SET_BYTEMODE();

// Setup preamble configuration

RF_SET_PREAMBLE_COUNT(PREAMBLE_BYTE_COUNT);

RF_SET_SYNC_BYTE(RF_SUITABLE_SYNC_BYTE);

// Make sure avg filter is free-running + 22 baud settling time

MODEM1=(MODEM1&0x03)|0x24;

// Reset preamble detection

PDET &= ~0x80;

PDET |= 0x80;

halRFSetRxTxOff(RF_RX, &RF_SETTINGS, &RF_CALDATA);

// Start RX

RF_START_RX();

// Enable global interrupt

INT_GLOBAL_ENABLE (INT_ON);

}

void InitRF(void)

{

bRF_RXdone = 0;

rf_rx_index = 0;

}

void PrepareRX(RF_RXTXPAIR_SETTINGS* RF_SETTINGS)

{

halRFSetRxTxOff(RF_RX, RF_SETTINGS, &RF_CALDATA);

RF_START_RX();

INT_ENABLE (INUM_RF, INT_ON);

}

void Wait1sec (void)

{

halWait (250, CLKFREQ); halWait (250, CLKFREQ);

halWait (250, CLKFREQ); halWait (250, CLKFREQ);

} // Wait1sec

void Receive (void)

{

byte xdata i;

if(!bRF_RXdone) return;

if(rf_rx_buf[0]==RF_SUITABLE_SYNC_BYTE && rf_rx_buf[3]==MY_ADDRESS) {

BLED = !BLED;

for(i=0;i<DATA_LEN;i++) {

rxDataBuffer[i] = rf_rx_buf[i+2];

}

}

} // Receive

void RandomWait(byte waitMultiplier)

{

byte xdata time;

byte xdata i;

time = rand();

for (i = 0; i < waitMultiplier; i++) {

halWait (time, CLKFREQ);

}

}

4. MS5535.h

Sử dụng lại file MS5535.h của phụ lục 1

5. MS5535.c

Sử dụng lại file MS5535.c của phụ lục 1

6. Tree.h

#if !defined tree_h

#define tree_h

#define N_NODES 11

struct node

{

unsigned char id;

struct node *next;

};

int EldestChild(int k);

int Parent(int k);

int NextSibling(int k);

void FindHops(int k);

void BuildTree();

char FindNextHop(int curNode,int dest);

int IsChild(int curNode, int k);

#endif

7. Tree.c

#include "tree.h"

struct node xdata Tree[N_NODES+1];

struct node xdata member[N_NODES+1];

int xdata RoutingTable[N_NODES+1];

//Tim con truong cua nut co id = k

int EldestChild(int k)

{

struct node xdata *p;

if(k <= N_NODES) {

p = Tree[k].next;

return p->id;

}

else return -1; //không tìm thấy con

}

//xac dinh xem nut k co la con cua nut curNode khong

int IsChild(int curNode, int k)

{

struct node xdata *p;

p = Tree[curNode].next;

while(p) {

if(p->id == k) return 1;

p = p->next;

}

return 0;

}

//Tim cha cua nut co id = k

int Parent(int k)

{

struct node xdata *p;

unsigned char xdata i;

i = 1;

while(i<=N_NODES) {

p = Tree[i].next;

while(p) {

if(p->id == k) return i;

else p = p->next;

}

i++;

}

return -1; //không tìm thay cha

}

//tim em lien ke cua nut co id = k

int NextSibling(int k)

{

struct node xdata *p;

unsigned char xdata i;

i = 1;

while(i <= N_NODES) {

p = Tree[i].next;

while(p) {

if(p->id == k) {

p = p->next;

if(p) return p->id;

else return -1; //không có em lien ke

}

else p = p->next;

}

i++;

}

return -1;

}

//tim duong di tu Master toi nut k

void FindHops(int k)

{

unsigned char xdata par,i,j;

for(i=0; i<=N_NODES; i++) RoutingTable [i] = -1;

i = 0;

j = k;

do{

par = Parent(j);

RoutingTable [i] = par;

j = par;

i++;

}while (par != 1 && i<=N_NODES);

}

//Tim nut tiep theo cua nut curNode de truyen

char FindNextHop(int curNode,int dest)

{

unsigned char xdata i,j,nexthop;

i = 0;

nexthop = j = dest;

while(j != curNode && i<=N_NODES) {

nexthop = j;

j = Parent(j);

i++;

}

return nexthop;

}

/* Tree:

// 1

// / \

// 2 3

// / \ / | \

// 4 5 6 7 8

// / \ |

// 9 10 11

*/

void BuildTree()

{

unsigned char xdata i;

for(i=0; i<=N_NODES; i++) {

Tree[i].id = i;

Tree[i].next = 0;

member[i].id = i;

member[i].next = 0;

}

member[2].next = &member[3];

member[3].next = 0;

member[4].next = &member[5];

member[5].next = 0;

member[6].next = &member[7];

member[7].next = &member[8];

member[8].next = 0;

member[9].next = &member[10];

member[10].next = 0;

Tree[1].next = &member[2];

Tree[2].next = &member[4];

Tree[3].next = &member[6];

Tree[5].next = &member[9];

Tree[7].next = &member[11];

}

Bạn đang đọc truyện trên: Truyen2U.Pro