Chƣơng trình khảo sát quan hệ áp suất độ cao cột nƣớc

Một phần của tài liệu Ghép nối đầu đo áp suất cho nút mạng cảm nhận không dây với phần mềm nhúng (Trang 58 - 84)

Module sensor áp suất được ghép với nút mạng sử dụng vi điều khiển 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 áp suất, xử lý dữ liệu thu được và truyền không dây định kỳ số liệu đo này về một nút mạng CC1010 khác nối với máy tính xách tay hoặc máy tính để bàn. Sơ đồ khảo sát thực nghiệm như hình 3.1 và các dụng cụa thí nghiệm như hình 3.2.

Hình 3.2: Đầu đo và các nút mạng cảm nhận.

Độ lớn giá trị tần số để CC1010 cung cấp để cảm biến áp suất thực hiện biến đổi ADC, độ lớn gía trị tần số nhịp đồng bộ quá trình truyền và nhận giữa hai vi mạch này, cùng các giá trị địa chỉ dữ liệu, việc xử lý các 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 chương trình nhúng như sau:

Khởi tạo các tham số:

- khởi tạo RF, ADC, TIMER - khởi tạo sensor cảm biến

Đọc ba kênh ADC

truyền dữ liệu không dây

nhận dữ liệu không dây

truyền thông tin về máy tính Đọc dữ liệu cảm biến áp suất

Hình 3.3: giải thuật phần mềm nhúng trong CC1010 của nút Master.

Ý 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.4kbps.

Khởi tạo ADC:

- Điện áp tham chiếu 3.5V internal. - 10 bit single.

Khởi tạo timer:

Sử dụng Timer2 ở 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.

Khởi tạo sensor cảm biến:

- Đưa các chân lối vào và chân đồng bộ quá trình đọc ghi cho cảm biến về trạng thái 0.

- Đọc các hệ số lưu trong cảm biến áp suất.

Đọc ba 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 cảm biến áp suất:

- Reset cảm biến.

- Gửi lệnh cho cảm biến để chọn tham số cần đọc: nhiệt độ hay áp suất. - Đọc dữ liệu trả lời từ cảm biến.

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ố áp suất rồi truyền về trung tâm.

Chương trình nhúng cụ thể: #include <stdio.h> #include <stdlib.h> #include <ctype.h> #include <string.h> #include <chipcon/reg1010.h> #include <chipcon/cc1010eb.h> #include <chipcon/hal.h> #include <chipcon/cul.h> #include <chipcon/vt100.h> // Water-height packet:

#define TBC_NODE_ID_LENGTH 2 // word #define TBC_NODE_NAME_LENGTH 20

#define TBC_TEMP_OFFSET (TBC_NODE_ID_LENGTH + TBC_NODE_NAME_LENGTH) #define TBC_TEMP_LENGTH 2

#define TBC_TEMP0_OFFSET (TBC_TEMP_OFFSET + TBC_TEMP_LENGTH)

#define TBC_TEMP0_LENGTH 2

#define TBC_DATA_LEN (TBC_TEMP0_OFFSET + TBC_TEMP0_LENGTH)

// Radio related:

#define TBC_RX_INTERVAL 50 #define TBC_PREAMBLE_COUNT 4 // Node registration #define TBC_INVALID_NODE_INDEX 255 #define TBC_UNUSED_NODE_ID 0x0000 // Speed related

byte xdata waitMultiplier;

// The height "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 nodeTemps[TBC_MAX_NODE_COUNT];

word xdata nodeLastT[TBC_MAX_NODE_COUNT];

// SPP variables

SPP_SETTINGS xdata sppSettings; SPP_RX_INFO xdata RXI;

SPP_TX_INFO xdata TXI;

byte xdata rxDataBuffer[TBC_DATA_LEN]; byte xdata txDataBuffer[TBC_DATA_LEN];

// Function prototypes

void tbcTransmit (void); void tbcReceive (void); void tbcPrintTable (void);

// Unit name, stored in Flash

byte code flashUnitName[TBC_NODE_NAME_LENGTH];

// RAM buffer for Flash copy

byte xdata ramBufNonAligned[128];

//--- // MAIN PROGRAM

//--- void main (void) {

byte xdata n; byte xdata m; #ifdef FREQ868 // 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: 19.2 kBaud

// Data Format: NRZ // RF output power: 4 dBm // IF/RSSI: RSSI Enabled

RF_RXTXPAIR_SETTINGS code RF_SETTINGS = { 0xA3, 0x2F, 0x15, // Modem 0, 1 and 2

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 }; #endif #ifdef FREQ915 // X-tal frequency: 14.745600 MHz // RF frequency A: 915.027455 MHz Rx // RF frequency B: 915.027455 MHz Tx // RX Mode: Low side LO

// Frequency separation: 64 kHz // Data rate: 19.2 kBaud

// Data Format: NRZ // RF output power: 4 dBm // IF/RSSI: RSSI Enabled

RF_RXTXPAIR_SETTINGS code RF_SETTINGS = { 0xA3, 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 }; #endif #ifdef FREQ433 // X-tal frequency: 14.745600 MHz // RF frequency A: 433.302000 MHz Rx // RF frequency B: 433.302000 MHz Tx // RX Mode: Low side LO

// Data rate: 19.2 kBaud // Data Format: NRZ

// RF output power: 10 dBm // IF/RSSI: RSSI Enabled

RF_RXTXPAIR_SETTINGS code RF_SETTINGS = { 0xA3, 0x2F, 0x0E, // Modem 0, 1 and 2

0x58, 0x00, 0x00, // Freq A 0x41, 0xFC, 0x9C, // Freq B 0x02, 0x80, // FSEP 1 and 0 0x60, // PLL_RX 0x48, // PLL_TX 0x44, // CURRENT_RX 0x81, // CURRENT_TX 0x0A, // FREND 0xFF, // PA_POW 0xC0, // MATCH 0x00, // PRESCALER }; #endif // Calibration data

RF_RXTXPAIR_CALDATA xdata RF_CALDATA; // 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);

// Seed the random generator: halRandomNumberGen(&n, 1); halRandomNumberGen(&m, 1); srand((n << 8) + m); waitMultiplier = 1; // ADC setup halConfigADC(ADC_MODE_SINGLE | ADC_REFERENCE_INTERNAL_1_25, CC1010EB_CLKFREQ, 0); ADC_SELECT_INPUT(ADC_INPUT_AD0); ADC_POWER(TRUE); // RF/SPP setup

sppSetupRF(&RF_SETTINGS, &RF_CALDATA, TRUE); sppSettings.myAddress = TBC_MY_SPP_ADDRESS; sppSettings.rxTimeout = TBC_RX_INTERVAL;

sppSettings.txAckTimeout = TBC_PREAMBLE_COUNT;

RXI.maxDataLen = TBC_DATA_LEN; RXI.pDataBuffer = rxDataBuffer; TXI.destination = SPP_BROADCAST; TXI.flags = 0x00; TXI.pDataBuffer = txDataBuffer; TXI.dataLen = TBC_DATA_LEN;

// Initialize the SPP timer

sppStartTimer(CC1010EB_CLKFREQ); SPP_INIT_TIMEOUTS();

// 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;

}

// Setup UART0 for polled I/O

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

// Get our name

VT100_GO_TOP_LEFT();

// Removed so that CC1010EM can operate stand-alone /* printf("\nEnter node name (use up to 20 characters):"); scanf("%s", &nodeNames[0][0]);*/

// Load name from Flash

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

// Get our ID from CRC16(our name)

nodeIDs[0] = culFastCRC16Block(&nodeNames[0][0], TBC_NODE_NAME_LENGTH, CRC16_INIT);

// 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]; } // Loop forever while (TRUE) { tbcTransmit(); tbcPrintTable(); tbcWaitRandom();

tbcReceive(); tbcWaitRandom(); }

} // main

//--- // void tbcWaitRandom (void)

// Description:

// Wait for a random number of msecs (0 to 255*8=2040) // Note: The function uses busy waiting

//--- void tbcWaitRandom (void) {

byte xdata time; byte xdata n;

time = rand();

for (n = 0; n < waitMultiplier; n++) { halWait (time, CC1010EB_CLKFREQ); }

} // tbcWaitRandom

//--- // void tbcTransmit (void)

//

// Description:

// Update our temperature value (ADC) and transmit together with our node // ID and node name.

void tbcTransmit (void) { word xdata temp;

// Indicate transmission RLED = LED_ON; YLED = LED_ON;

// Power up the ADC and sample the water-height ADC_SELECT_INPUT(ADC_INPUT_AD0); ADC_POWER(TRUE);

ADC_SAMPLE_SINGLE();

temp = ADC_GET_SAMPLE_10BIT();

// Update the TX buffer and the table with the new water-height txDataBuffer[TBC_TEMP_OFFSET] = (temp >> 8) & 0xFF; txDataBuffer[TBC_TEMP_OFFSET + 1] = temp & 0xFF; nodeTemps[0] = temp;

nodeLastT[0] = (int) sppGetTime(); YLED = LED_OFF;

// Transmit the water-height sppSend(&TXI);

do { /*nothing*/ } while (sppStatus() != SPP_IDLE_MODE); RLED = LED_OFF;

} // tbcTransmit

//--- // void tbcReceive (void)

// Description:

// Receive a water-height broadcast packet and register it in the table // Heights older than 30 secs get thrown out

//--- void tbcReceive (void) {

byte xdata n,m,o; byte xdata nodeIndex; word xdata nodeID;

// Throw out "old" nodes (no updates during the last 30 seconds) for (n = 0; n < TBC_MAX_NODE_COUNT; n++) {

if (((int) sppGetTime() - nodeLastT[n]) > 3000) {

// Re-organize the list (by moving the remaining nodes up one index) for (m = n; m < (TBC_MAX_NODE_COUNT - 1); m++) {

nodeIDs[m] = nodeIDs[m + 1];

for (o = 0; o < TBC_NODE_NAME_LENGTH; o++) { nodeNames[m][o] = nodeNames[m + 1][o];

} nodeTemps[m] = nodeTemps[m + 1]; nodeLastT[m] = nodeLastT[m + 1]; } } }

// Receive the packet (if any) YLED = LED_ON;

do { /*nothing*/ } while (sppStatus() != SPP_IDLE_MODE); YLED = LED_OFF;

// Process the packet

if (RXI.status == SPP_RX_FINISHED) { GLED = LED_ON;

// Get the node ID

nodeID = (rxDataBuffer[0] << 8) + rxDataBuffer[1];

// Get the node's index in the water-height table for (n = 0; n < TBC_MAX_NODE_COUNT; n++) { if (nodeIDs[n] == nodeID) {

nodeIndex = n; break;

} else if (nodeIDs[n] == TBC_UNUSED_NODE_ID) { nodeIndex = n; break; } else { nodeIndex = TBC_INVALID_NODE_INDEX; } }

// Update the table

if (nodeIndex != TBC_INVALID_NODE_INDEX) { nodeIDs[nodeIndex] = nodeID;

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

TBC_NODE_ID_LENGTH]; }

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

} } else { GLED = LED_OFF; } } // tbcReceive //--- // void tbcPrintTable (void)

//

// Description:

// Executes keyboard commands (change of the waiting multiplier) // Prints the water-height table to the terminal window

//--- void tbcPrintTable (void) {

int xdata n,m; float xdata fTemp; word xdata timeDiff;

// Receive key strokes if (RI_0) {

if (isdigit(UART0_RECEIVE())) { waitMultiplier = toint(UART0_RECEIVE()); } else if (UART0_RECEIVE() == 'd') { for (n = 1; n < TBC_MAX_NODE_COUNT; n++) { nodeIDs[n] = TBC_UNUSED_NODE_ID; } } else if (UART0_RECEIVE() == 'n') { memset(&nodeNames[0][0],0,TBC_NODE_NAME_LENGTH); printf("\nEnter node name (use up to 20 characters):");

scanf("%s", &nodeNames[0][0]);

// Write new name into Flash

halCopy2Flash(flashUnitName,&nodeNames[0][0],TBC_NODE_NAME_LENGTH, ramBufNonAligned, CC1010EB_CLKFREQ);

// Get our ID from CRC16(our name)

nodeIDs[0] = culFastCRC16Block(&nodeNames[0][0], TBC_NODE_NAME_LENGTH, CRC16_INIT);

// 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++) {

} } } // Header: VT100_GO_TOP_LEFT(); // Items:

printf("DO SAU CUA NUOC:");

for (n = 0; n < TBC_MAX_NODE_COUNT; n++) { if (nodeIDs[n] == TBC_UNUSED_NODE_ID) { continue;

}

// Node number and ID:

printf("\n%01X. (0x%X) ", n, nodeIDs[n]); // Node name: for (m = 0; m < TBC_NODE_NAME_LENGTH; m++) { UART0_WAIT_AND_SEND(nodeNames[n][m]); } // mức nước: fTemp = nodeTemps[n];

printf(" - ADC: %d", nodeTemps[n]); fTemp -= 122;

fTemp /= 1.5625;

// Time after the last update

timeDiff = abs((int) sppGetTime() - nodeLastT[n]) * 10; printf(" - AGE (msecs): %d", timeDiff);

VT100_CLEAR_LINE_RIGHT(); }

// Available keyboard input options VT100_INSERT_BLANK_LINE();

printf("\nPress '0'-'9' to change the waiting multiplier"); VT100_CLEAR_LINE_RIGHT();

printf("\nPress 'd' to empty the table"); VT100_CLEAR_LINE_RIGHT();

printf("\nPress 'n' to give the unit a new name"); VT100_CLEAR_LINE_RIGHT();

VT100_CLEAR_SCREEN_DOWN();

} // tbcPrintTable

// 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 {

return; }

3.4. Kết luận.

Ở chương 3 này tôi đã giới thiệu tổng quan về chương trình nhúng cũng như các bước xây dựng một chương trình nhúng. Từ đó đưa ra một chương trình nhúng cụ thể cho việc ghép nối đầu đo áp suất - mức nước với nút mạng cảm nhân không dây sử dụng vi điều khiển CC1010.

Việc thử nghiệm với nút mạng được tiến hành từ mạng gồm hai nút mạng đến nhiều nút mạng để khảo sát quan hệ áp suất - mức nước. Kết quả thực nghiệm cho thấy vi điều khiển CC1010 tiêu thụ mức năng lượng thấp, một tiêu chí quan trọng của mạng cảm nhận không dây; đồng thời cũng cho thấy việc truyền nhận dữ liệu ổn định và tin cậy, không xảy ra xung đột.

PHẦN KẾT LUẬN

Bản luận văn đã giới thiệu về bộ cảm biến cũng như một số đặc trưng cơ bản của nó như: hàm truyền, độ lớn tín hiệu vào, sai số và độ chính xác. Từ đó giới thiệu về

Một phần của tài liệu Ghép nối đầu đo áp suất cho nút mạng cảm nhận không dây với phần mềm nhúng (Trang 58 - 84)

Tải bản đầy đủ (PDF)

(84 trang)