版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
第5章TinyOS應(yīng)用開發(fā)5.1概述5.2TinyOS編程方法5.3串口通信5.4射頻通信5.5ADC信息采集小結(jié)
5.1概述
TinyOS應(yīng)用開發(fā)是學(xué)習(xí)TinyOS的核心,是直接面向用戶的,本章將從以下兩個(gè)方面講解TinyOS的開發(fā)技術(shù):
TinyOS的編程方法:包括在TinyOS開發(fā)過程中所使用的與平臺(tái)相關(guān)的硬件資源的編程方法以及與平臺(tái)相關(guān)的應(yīng)用編程方法。
TinyOS特殊的實(shí)例編程:包括基于CC2530的串口通信、無(wú)線射頻的點(diǎn)對(duì)點(diǎn)通信和CC2530芯片ADC的信息采集。
5.2TinyOS編程方法
由于TinyOS的體系結(jié)構(gòu)采用分層式結(jié)構(gòu),因此TinyOS的編程的基本思想也基于分層結(jié)構(gòu),即上層調(diào)用下層,其分層結(jié)構(gòu)大致可以分為底層驅(qū)動(dòng)層、中間層和應(yīng)用層,其結(jié)構(gòu)如圖5-1所示。圖5-1TinyOS編程分層結(jié)構(gòu)
5.3串口通信
本節(jié)將講解TinyOS操作系統(tǒng)的CC2530與PC機(jī)串口通信,包括CC2530串口的配置、串口通信相關(guān)組件及接口的使用以及TinyOS操作系統(tǒng)下串口通信協(xié)議的分析。另外本節(jié)還通過兩個(gè)串口的實(shí)例講解串口的用法。
5.3.1串口配置
在TinyOS操作系統(tǒng)中,平臺(tái)采用的芯片配置同樣由組件和接口來(lái)完成。本書中采用CC2530的串口0進(jìn)行傳輸,完成CC2530串口相關(guān)配置的組件為底層組件HplCC2530UartP組件。HplCC2530UartP組件位于“cygwin\opt\mytinyos\tos\chips\cc2530\uart\”目錄中,其主要代碼如代碼5-1所示?!敬a5-1】HplCC2530UartP.nc
moduleHplCC2530UartP
{
//串口初始化接口
providesinterfaceInitasUart0Init;
//TX控制接口
providesinterfaceStdControlasUart0TxControl;
//RX控制接口
providesinterfaceStdControlasUart0RxControl;
//串口發(fā)送接收設(shè)置接口
providesinterfaceHplCC2530UartasHplUart0;
usesinterfaceMcuPowerState;
}在HplCC2530UartP文件中對(duì)串口進(jìn)行初始化,并且設(shè)置了用戶所需要的波特率。在本節(jié)內(nèi)容中,將波特率設(shè)置為57600,具體代碼如代碼5-2所示?!敬a5-2】HplCC2530UartP.nc
/*串口的初始化*/
commanderror_tUart0Init.init()
{
//采用串口備用位置1
PERCFG&=~0x01;
//選擇P0口作為串口
P0SEL=0x3c;//00111100
//采用UART模式,接收使能
U0CSR|=0x80|0x40;
/*串口波特率的設(shè)置采用57600*/
U0GCR=0x0b;
U0BAUD=216;
returnSUCCESS;
}5.3.2通信幀格式
TinyOS2.x為串口通信提供了專用通信協(xié)議,即HDLC協(xié)議幀,其以0x7e作為幀分隔字符,0x7d作為轉(zhuǎn)義字符。在TinyOS2.x的串口通信組件中維護(hù)了10個(gè)狀態(tài)位,接收路徑和發(fā)送路徑各有一個(gè)狀態(tài)位,用于表示是否使用轉(zhuǎn)義符(有關(guān)HDLC幀格式以及相關(guān)內(nèi)容請(qǐng)參照實(shí)踐4的知識(shí)拓展)。
TinyOS2.x串口協(xié)議數(shù)據(jù)幀具體格式如圖5-2所示。圖5-2串口協(xié)議數(shù)據(jù)幀格式5.3.3相關(guān)組件及接口
TinyOS2.x版本的串口協(xié)議??梢詣澐譃?個(gè)功能組件,自底層至上層分別是原始串口組件、編碼/裝幀組件、協(xié)議組件、分派組件和用戶接口組件。其組件關(guān)系如圖5-3所示。圖5-3串口組件關(guān)系
1.原始串口組件
在TinyOS2.x版本中原始串口組件為串口的硬件接口層組件,位于平臺(tái)目錄tos/platforms下。一般情況此組件的命名與平臺(tái)相關(guān),不同的平臺(tái)命名方式不同。本書以mytinyos平臺(tái)為例講解。
原始串口組件在mytinyos平臺(tái)中名為PlatformSerialC,其位于“mytinyos\tos\platforms\cc2530”目錄下。在項(xiàng)目的開發(fā)過程中,可以調(diào)用此組件通過串口直接將硬件平臺(tái)的數(shù)據(jù)輸出至PC機(jī),即數(shù)據(jù)并沒有被TinyOS封裝成串口數(shù)據(jù)幀格式。此組件提供的接口如代碼5-3所示。【代碼5-3】PlatformSerialC.nc
configurationPlatformSerialC
{
providesinterfaceStdControl;
providesinterfaceUartStream;
providesinterfaceUartByte;
}其中各個(gè)接口的作用如下:
StdControl:開啟串口。
UartStream:控制發(fā)送接收字節(jié)。
UartStream:發(fā)送和接收字節(jié)流。
以下內(nèi)容將實(shí)現(xiàn)任務(wù)描述5.D.1,使用PlatformSerialC組件實(shí)現(xiàn)CC2530與PC機(jī)的串口通信。按照TinyOS的編程方法,首先要編寫主組件與頂層配件,其次編寫其他組件與Makefile文件。此任務(wù)中需要完成以下工作:
首先在“mytinyos/apps”目錄下新建一個(gè)名為DhSerial的文件夾。
其次,在DhSerial文件夾創(chuàng)建頂層配件DhSerialAppC,核心應(yīng)用模塊命名為DhSerialC.nc,在核心應(yīng)用模塊組件中使用PlatformSerialC中的接口進(jìn)行串口傳輸。
最后編寫Makefile文件。
編譯程序,下載至設(shè)備中,連接串口,觀察現(xiàn)象。
(1)創(chuàng)建DhSerial文件夾。
打開Cygwin,在“mytinyos/apps”目錄下,輸入mkdirDhSerial,創(chuàng)建文件夾,具體操作如圖5-4所示。圖5-4創(chuàng)建DhSerial文件夾
(2)創(chuàng)建DhSerialAppC.nc。
DhSerialAppC.nc為整個(gè)任務(wù)的頂層配件組件,在此組件中實(shí)現(xiàn)了組件之間的綁定關(guān)系。其具體代碼如描述5.D.1DhSerialAppC.nc所示?!久枋?.D.1】DhSerialAppC.nc
configurationDhSerialAppC
{
}
implementation
{
componentsDhSerialC;
componentsMainC;
DhSerialC.Boot->MainC.Boot;
componentsPlatformSerialC;
DhSerialC.StdControl->PlatformSerialC.StdControl;
DhSerialC.UartStream->PlatformSerialC.UartStream;
}在此組件中主要做了以下兩個(gè)工作:
在此組件中將DhSerialC組件的啟動(dòng)接口與系統(tǒng)的系統(tǒng)的啟動(dòng)接口綁定在一起,當(dāng)系統(tǒng)啟動(dòng)時(shí)將調(diào)用DhSerialC組件的啟動(dòng)接口,使整個(gè)程序啟動(dòng)起來(lái)。
將DhSerialC組件的與串口相關(guān)的接口綁定到PlatformSerialC組件上,以便于進(jìn)行串口的傳輸。
(3)創(chuàng)建DhSerialC.nc。
DhSerialC.nc組件是整個(gè)任務(wù)的核心應(yīng)用模塊,在此組件中通過UartStream接口實(shí)現(xiàn)了CC2530與PC機(jī)的串口通信,具體代碼如描述5.D.1DhSerialC.nc所示?!久枋?.D.1】DhSerialC.nc
moduleDhSerialC
{ uses
{ interfaceBoot;
interfaceStdControl;
interfaceUartStream;
}
}
implementation
{ uint8_tm_send_buf[100];
voidshowMenu()
{ strcpy(m_send_buf,"qingdaodonghexinxi");
//通過UartStream.send可以發(fā)送字節(jié)數(shù)據(jù)
callUartStream.send(m_send_buf,strlen(m_send_buf));
} /*啟動(dòng)事件處理函數(shù)*/
eventvoidBoot.booted()
{ callStdControl.start();
showMenu();
}
asynceventvoidUartStream.sendDone(uint8_t*buf,uint16_tlen,error_terror)
{
}
/**重新發(fā)送剛才接收的字符進(jìn)行回顯*/
taskvoidshowMenuTask()
{ showMenu();
} /**如果沒有調(diào)用receive接收,則每接收到一個(gè)數(shù)據(jù)就會(huì)觸發(fā)此事件*/
asynceventvoidUartStream.receivedByte(uint8_tbyte)
{
}
/*在接收完receive命令欲接收的長(zhǎng)度后會(huì)調(diào)用此事件*/
asynceventvoidUartStream.receiveDone(uint8_t*buf,uint16_tlen,error_terror)
{
}
}
(4)編寫Makefile文件。
在Makefile文件中指明任務(wù)的頂層配件,并規(guī)定編譯規(guī)則,其具體代碼如描述5.D.1Makefile文件所示。
【描述5.D.1】Makefile文件
COMPONENT=DhSerialAppC
CFLAGS+=-I$(TOSDIR)/lib/T2Hack
include$(MAKERULES)
(5)實(shí)驗(yàn)結(jié)果。
將設(shè)備通過串口線連接至PC機(jī),將程序編譯下載至設(shè)備中,打開串口,將波特率配置為57600,按下復(fù)位按鍵,可以觀察到CC2530向PC機(jī)通過串口傳送“qingdaodonghexinxi”的字符串。實(shí)驗(yàn)結(jié)果如圖5-5所示。圖5-5任務(wù)描述5.D.1實(shí)驗(yàn)結(jié)果
2.編碼/裝幀組件
編碼裝幀組件是通過HdlcTranslateC組件來(lái)實(shí)現(xiàn)的,此組件主要負(fù)責(zé)串口協(xié)議的中的起始和結(jié)束幀字節(jié)F。HdlcTranslateC組件位于“cygwin\opt\mytinyos\tos\lib\serial”目錄下,其主要代碼如代碼5-4所示。【代碼5-4】HdlcTranslateC.nc
moduleHdlcTranslateC
{
providesinterfaceSerialFrameComm;
uses{
interfaceUartStream;
interfaceLeds;
}
}在HdlcTranslateC組件中向上層提供了SerialFrameComm接口,在SerialFrameComm接口完成了一個(gè)串口數(shù)據(jù)幀的裝幀任務(wù),即在數(shù)據(jù)幀頭和幀尾添加開始和結(jié)束幀字節(jié)F(0x7e)。
向下層調(diào)用PlatformSerialC組件提供的UartStream接口完成串口傳輸。
其組件關(guān)系圖如圖5-6所示。
SerialFrameComm接口用于分隔協(xié)議數(shù)據(jù)幀,其中SerialFrameComm接口的具體代碼如代碼5-5所示。圖5-6HdlcTranslateC組件關(guān)系圖【代碼5-5】SerialFrameComm.nc
interfaceSerialFrameComm
{ asynccommanderror_tputDelimiter();
asynccommanderror_tputData(uint8_tdata);
asynccommandvoidresetSend();
asynccommandvoidresetReceive();
asynceventvoiddelimiterReceived();
asynceventvoiddataReceived(uint8_tdata);
asynceventvoidputDone();
}
3.協(xié)議組件
協(xié)議組件是通過SerialP組件來(lái)實(shí)現(xiàn)的,此組件主要用來(lái)實(shí)現(xiàn)串口通信協(xié)議的協(xié)議字節(jié)和P和序號(hào)字節(jié)S,本書中的協(xié)議字節(jié)取值為Serial.h文件中的SERIAL_PROTO_PACKET_NOACK。
SerialP組件位于“mytinyos\tos\lib\serial”目錄下,其主要代碼如代碼5-6所示?!敬a5-6】SerialP.nc
moduleSerialP{
provides
{ interfaceInit;
interfaceSplitControl;
interfaceSendBytePacket;
interfaceReceiveBytePacket;
}
uses
{ interfaceSerialFrameComm;
interfaceLeds;
interfaceStdControlasSerialControl;
interfaceSerialFlush;
}
}
SerialP組件提供兩個(gè)面向字節(jié)的接口,即SendBytePacket接口和ReceiveBytePacket接口,分別用于數(shù)據(jù)的發(fā)送和接收。
從節(jié)點(diǎn)發(fā)送到主機(jī)時(shí),SerialP組件負(fù)責(zé)封裝上層組件(分派組件)的數(shù)據(jù)包。上層組件通過調(diào)用SendBytePacket接口的startSend命令來(lái)初始化數(shù)據(jù)包的發(fā)送工作。
從主機(jī)發(fā)送到節(jié)點(diǎn)時(shí),即節(jié)點(diǎn)處于接收狀態(tài),上層組件通過調(diào)用ReceiveBytePacket接口接收數(shù)據(jù)。
4.分派組件
分派組件是通過SerialDispatcherC組件來(lái)實(shí)現(xiàn)的,SerialDispatcherC組件負(fù)責(zé)處理協(xié)議組件接收到的數(shù)據(jù)包,它通過SerialDispatcherP組件使用SerialP組件提供的SendBytePacket接口和ReceiveBytePacket接口,并提供帶參數(shù)的Send接口和Receive接口。這兩個(gè)接口的參數(shù)為串口協(xié)議的包格式分派字節(jié)D,它決定了message_t中的數(shù)據(jù)包格式。SerialDispatcherC組件位于“mytinyos/tos/lib/serial”目錄下,代碼如代碼5-7所示。【代碼5-7】SerialDispatcherC.nc
configurationSerialDispatcherC
{ provides
{ interfaceInit;
interfaceSplitControl;
interfaceReceive[uart_id_t];
interfaceSend[uart_id_t];
}
uses
{ interfaceSerialPacketInfo[uart_id_t];
interfaceLeds;
}
}implementation
{
componentsSerialP,newSerialDispatcherP(),
HdlcTranslateC,
PlatformSerialC;
Send=SerialDispatcherP;
Receive=SerialDispatcherP;
SerialPacketInfo=SerialDispatcherP.PacketInfo;
SplitControl=SerialP;
Init=SerialP;
Leds=SerialP;
Leds=SerialDispatcherP;
Leds=HdlcTranslateC;
SerialDispatcherP.ReceiveBytePacket->SerialP;
SerialDispatcherP.SendBytePacket->SerialP;
SerialP.SerialFrameComm->HdlcTranslateC;
SerialP.SerialControl->PlatformSerialC;
HdlcTranslateC.UartStream->PlatformSerialC;
}通過上述代碼可以看出,SerialDispatcherC組件連接到了前述原始串口組件PlatformSerialC。另外SerialDispatcherC組件經(jīng)過SerialP組件收發(fā)的數(shù)據(jù)包中放置了一個(gè)字節(jié)的包頭,即包格式標(biāo)識(shí)符。其具體值采用SerialDispacherC組件的uart_id_t參數(shù)值TOS_SERIAL_ACTIVE_MESSAGE_ID。
通過帶參數(shù)的SerialPacketInfo接口、SerialDispatcherC組件能夠處理各種各樣的數(shù)據(jù)包格式,SerialPacketInfo接口具體代碼如代碼5-8所示。
【代碼5-8】SerialPacketInfo.nc
interfaceSerialPacketInfo
{
asynccommanduint8_toffset();
asynccommanduint8_tdataLinkLength(message_t*msg,uint8_tupperLen);
asynccommanduint8_tupperLength(message_t*msg,uint8_tdataLinkLen);
}
其中此命令的各個(gè)接口的功能描述如下:
offset():獲得包頭在message_t中的偏移量。發(fā)送數(shù)據(jù)時(shí):SerialDispatcherC組件先發(fā)送數(shù)據(jù)包類型,然后再導(dǎo)出數(shù)據(jù)字節(jié),起始位置由調(diào)用offest()函數(shù)獲得的索引值確定。
接收數(shù)據(jù)時(shí):當(dāng)SerialDisPatcherC組件收到由SerialP組件發(fā)出第一個(gè)字節(jié)時(shí),先將其保存為數(shù)據(jù)包類型,同時(shí)調(diào)用offSet()命令以便在message_t中確定偏移量,然后將數(shù)據(jù)字節(jié)導(dǎo)入并填充到message_t的緩沖區(qū)。
dataLinkLength():根據(jù)已知upperLen,獲得下層傳輸?shù)膁ataLinkLen,等于upperLen+包頭大小。
upperLength():根據(jù)已知upperLen,獲得下層傳輸?shù)膁ataLinkLen,等于upperLen+包頭大小。
5.用戶接口組件
在實(shí)際編程時(shí),官方推薦使用SerialActiveMessageC組件進(jìn)行串口編程。SerialActiveMessageC組件是一個(gè)平臺(tái)無(wú)關(guān)的主動(dòng)消息組件,工作在串口通信協(xié)議棧之上,它是一個(gè)配件,將SerialActiveMessageP組件連接到SerialDispatcherC組件(最終再連接到原始串口組件PlatformSerialC)。
SerialActiveMessageP組件是一個(gè)通用組件,因此可用于各種數(shù)據(jù)包級(jí)的通信層之上,在此組件中可以根據(jù)需要是否設(shè)定發(fā)送信息的源地址、目的地址及組號(hào)。
(1)?SerialActiveMessageC.nc。
SerialActiveMessageC組件位于“mytinyos\tos\lib\serial”目錄下,其具體代碼如代碼5-9所示?!敬a5-9】SerialActiveMessageC.nc
#include"Serial.h"
configurationSerialActiveMessageC
{ provides
{ interfaceSplitControl;
interfaceAMSend[am_id_tid];
interfaceReceive[am_id_tid];
interfacePacket;
interfaceAMPacket;
interfacePacketAcknowledgements;
}
usesinterfaceLeds;
}implementation
{ componentsnewSerialActiveMessageP()asAM,SerialDispatcherC;
componentsSerialPacketInfoActiveMessagePasInfo,MainC;
MainC.SoftwareInit->SerialDispatcherC;
Leds=SerialDispatcherC;
SplitControl=SerialDispatcherC;
AMSend=AM;
Receive=AM;
Packet=AM;
AMPacket=AM; PacketAcknowledgements=AM;
AM.SubSend->SerialDispatcherC.Send[TOS_SERIAL_ACTIVE_MESSAGE_ID];
AM.SubReceive->SerialDispatcherC.Receive[TOS_SERIAL_ACTIVE_MESSAGE_ID];
SerialDispatcherC.SerialPacketInfo[TOS_SERIAL_ACTIVE_MESSAGE_ID]->Info;
}
此組件將SerialPackerInfoActiveMessageP組件連接到SerialDispatcherC組件,其中SerialDispatcherC組件的uart_id_t參數(shù)是TOS_SERIAL_ACTIVE_MESSAGE_ID,其定義在serial.h文件中,定義如代碼5-10所示。【代碼5-10】serial.h
#ifndefSERIAL_H
#defineSERIAL_H
#include"AM.h"
typedefuint8_tuart_id_t;
enum
{ //包格式分派字節(jié)
TOS_SERIAL_ACTIVE_MESSAGE_ID=0,
TOS_SERIAL_CC1000_ID=1,
TOS_SERIAL_802_15_4_ID=3,
TOS_SERIAL_UNKNOWN_ID=255,
};
(2)?SerialActiveMessageP.nc。
SerialActiveMessageP組件位于“mytinyos\tos\lib\serial”目錄下,其具體代碼如代碼5-11所示。【代碼5-11】SerialActiveMessageP.nc
#include<Serial.h>
genericmoduleSerialActiveMessageP()
{ provides
{ interfaceAMSend[am_id_tid];
interfaceReceive[am_id_tid];
interfaceAMPacket;
interfacePacket;
interfacePacketAcknowledgements;
} uses
{ interfaceSendasSubSend;
interfaceReceiveasSubReceive;
}
}
implementation
{
serial_header_t*ONEgetHeader(message_t*ONEmsg)
{
returnTCAST(serial_header_t*ONE,(uint8_t*)msg+offsetof(message_t,data)-sizeof(serial_header_t));
} serial_metadata_t*getMetadata(message_t*msg)
{
return(serial_metadata_t*)(msg->metadata);
}
commanderror_tAMSend.send[am_id_tid](am_addr_tdest,
message_t*msg,
uint8_tlen)
{ serial_header_t*header=getHeader(msg);
if(len>callPacket.maxPayloadLength())
{ returnESIZE;
} header->dest=dest;
/*為了防止通信有問題,找到更好的解決辦法,暫時(shí)不設(shè)定源地址和組ID*/
//header->src=callAMPacket.address();
//header->group=TOS_AM_GROUP;
header->type=id;
header->length=len;
returncallSubSend.send(msg,len);
}
在此組件中設(shè)定了串口通信消息的頭部格式,即目的地址、源地址、組ID、長(zhǎng)度、消息類型。但是由于串口傳輸還不是很完善,因此TinyOS開發(fā)組為了找到較好的通信方案,可以先不賦予消息的源地址和組ID號(hào)。5.3.4串口編程
以下內(nèi)容將實(shí)現(xiàn)任務(wù)描述5.D.2,使用TinyOS串口協(xié)議實(shí)現(xiàn)CC2530與PC機(jī)的串口通信,并分析其數(shù)據(jù)。完成此任務(wù)中需要完成以下工作:
首先在mytinyos/apps目錄下新建一個(gè)名為TestSerial的文件夾(參照任務(wù)5.D.1)。
其次在TestSerial文件夾創(chuàng)建頂層配件TestSerialAppC,主組件命名為TestSerialC.nc,并編寫程序。在TestSerialC組件中主要使用SerialActiveMessageC組件的接口來(lái)實(shí)現(xiàn)串口通信。
編寫Makefile文件。
編譯程序,下載至設(shè)備中,連接串口,觀察現(xiàn)象并分析數(shù)據(jù)。
1.?TestSerialAppC.nc
TestSerialAppC.nc為整個(gè)任務(wù)的頂層配件組件,在此組件中實(shí)現(xiàn)了組件之間的綁定關(guān)系。其具體代碼如描述5.D.2TestSerialAppC.nc所示。【描述5.D.2】TestSerialAppC.nc
#include"TestSerial.h"
configurationTestSerialAppC{}
implementation{
componentsTestSerialCasApp,LedsC,MainC;
componentsSerialActiveMessageCasAM;
componentsnewTimerMilliC();
App.Boot->MainC.Boot;
App.Control->AM;
App.Receive->AM.Receive[AM_TEST_SERIAL_MSG];
App.AMSend->AM.AMSend[AM_TEST_SERIAL_MSG];
App.Leds->LedsC;
App.MilliTimer->TimerMilliC;
App.Packet->AM;
}在此組件中使用了MainC組件、LedsC組件、SerialActiveMessageC組件和TimerMillic組件,其中綁定關(guān)系如下:
TestSerialC組件的Boot接口綁定到MainC組件上。
TestSerialC組件的Control接口、Receive接口、AMSend接口綁定到SerialActiveMessageC組件上。
TestSerialC組件的Leds接口綁定到LedsC組件上,定時(shí)器MilliTimer接口綁定到TimerMilliC組件上。
2.?TestSerialC.nc
TestSerialC組件是整個(gè)任務(wù)的主組件,在此組件中通過串口數(shù)據(jù)包負(fù)載部分的封裝以及發(fā)送,具體代碼如描述5.D.2TestSerialC.nc所示?!久枋?.D.2】TestSerialC.nc
#include"Timer.h"
#include"TestSerial.h"
moduleTestSerialC
{
uses
{
interfaceSplitControlasControl;
interfaceLeds;
interfaceBoot;
interfaceReceive;
interfaceAMSend;
interfaceTimer<TMilli>asMilliTimer;
interfacePacket;
}
}implementation
{
message_tpacket;
boollocked=FALSE;
uint16_tcounter=0;
eventvoidBoot.booted()
{
callControl.start();
}
eventvoidMilliTimer.fired()
{
counter++;
if(locked)
{
return;
} else
{
//在要發(fā)送的數(shù)據(jù)前面添加數(shù)據(jù)幀頭
test_serial_msg_t*rcm=(test_serial_msg_t*)call Packet.getPayload(&packet,sizeof(test_serial_msg_t));
if(rcm==NULL)
{
return;
}
if(callPacket.maxPayloadLength()<sizeof(test_serial_msg_t))
{ return;
}
//要發(fā)送的數(shù)據(jù)
rcm->counter=counter;
//調(diào)用發(fā)送函數(shù)將數(shù)據(jù)發(fā)送至PC機(jī)
if(callAMSend.send(AM_BROADCAST_ADDR,&packet, sizeof(test_serial_msg_t))==SUCCESS)
{
callLeds.led0On();
locked=TRUE;
}
}
} eventmessage_t*Receive.receive(message_t*bufPtr,
void*payload,uint8_tlen)
{
}
//發(fā)送數(shù)據(jù)完成之后,觸發(fā)AMSend.sendDone事件
eventvoidAMSend.sendDone(message_t*bufPtr,error_terror)
{
if(&packet==bufPtr)
{
//點(diǎn)亮LED2
callLeds.led1On();
locked=FALSE;
}
} eventvoidControl.startDone(error_terr)
{
if(err==SUCCESS)
{
callMilliTimer.startPeriodic(1000);
}
}
eventvoidControl.stopDone(error_terr)
{
}
}
3.?TestSerial.h
除了TestSerialAppC組件和TestSerialC組件之外,還需要編寫TestSerial.h。在TestSerial.h文件中定義了串口傳送消息的AM類型以及要傳送數(shù)據(jù)的結(jié)構(gòu)體,其具體代碼如描述5.D.2TestSerial.h所示?!久枋?.D.2】TestSerial.h
#ifndefTEST_SERIAL_H
#defineTEST_SERIAL_H
typedefnx_structtest_serial_msg{
nx_uint16_tcounter;
}test_serial_msg_t;
enum{
AM_TEST_SERIAL_MSG=0x89,//AM類型
};
#endif
4.?Makefile文件
在Makefile文件中指明任務(wù)的頂層配件,并規(guī)定編譯規(guī)則,其具體代碼如描述5.D.2Makefile文件所示。
【描述5.D.2】Makefile文件
COMPONENT=TestSerialAppC
include$(MAKERULES)
5.實(shí)驗(yàn)結(jié)果
將程序編譯下載至設(shè)備中,并將設(shè)備通過串口連接線與PC機(jī)相連,,打開串口,將波特率配置為57600,按下復(fù)位按鍵,可以觀察到CC2530向PC機(jī)通過串口傳送數(shù)據(jù)。實(shí)驗(yàn)結(jié)果如圖5-7所示。圖5-7串口通信結(jié)果其中,接收到15個(gè)字節(jié)的數(shù)據(jù),按照串口協(xié)議包的格式分析如下:
第1個(gè)字節(jié)0x7E為幀字節(jié)。
第2個(gè)字節(jié)0x45為協(xié)議字節(jié)。
第3個(gè)字節(jié)0x00為包格式分派字節(jié),之后從0xFF~0x01為Payload載荷區(qū),其中:
第4~5字節(jié)0xFFFF為目的地址。
第6~7字節(jié)0x0000為源地址,因?yàn)樵诔绦蛑蝎@得的源地址返回值為“0”,所以源地址為0x0000。第8個(gè)字節(jié)0x02為傳輸數(shù)據(jù)的長(zhǎng)度。
第9個(gè)字節(jié)0x00為組ID,因?yàn)楸纠虥]有規(guī)定確切的組ID,因此返回值為0x00。
第10個(gè)字節(jié)0x89為串口數(shù)據(jù)包的AM類型。
第11~12個(gè)字節(jié)為傳輸?shù)臄?shù)據(jù)。
第13~14個(gè)字節(jié)為CRC的校驗(yàn)值。
第15個(gè)字節(jié)為數(shù)據(jù)包的結(jié)束字節(jié),一般為0x7E。
5.4射頻通信
在TinyOS系統(tǒng)中,無(wú)線通信模型是基于主動(dòng)消息模式的通信模型。主動(dòng)消息模式是一個(gè)面向消息通信的高性能通信模式。在無(wú)線傳感器網(wǎng)絡(luò)中采用主動(dòng)消息機(jī)制的主要目的是使無(wú)線傳感器節(jié)點(diǎn)的計(jì)算和通信重疊,讓軟件層的通信原語(yǔ)能夠與節(jié)點(diǎn)的硬件能力匹配,充分節(jié)省無(wú)線傳感器節(jié)點(diǎn)的有限存儲(chǔ)空間。
本節(jié)內(nèi)容將介紹主動(dòng)消息機(jī)制、無(wú)線射頻通信的相關(guān)接口和組件以及點(diǎn)對(duì)點(diǎn)無(wú)線傳輸程序的編寫。5.4.1主動(dòng)消息概述
在主動(dòng)消息通信方式中,每個(gè)消息都維護(hù)一個(gè)應(yīng)用層的子程序。當(dāng)目標(biāo)節(jié)點(diǎn)接收到這個(gè)消息后,就會(huì)把消息中的數(shù)據(jù)作為參數(shù),并傳遞給應(yīng)用層的子程序進(jìn)行處理,應(yīng)用層的子程序一般完成消息數(shù)據(jù)包的解包操作、計(jì)算處理或發(fā)送響應(yīng)消息等工作。
為了讓主動(dòng)消息更適合無(wú)線傳感器網(wǎng)絡(luò)的需求,主動(dòng)消息需要至少提供兩個(gè)最基本的通信機(jī)制:
帶確認(rèn)信息的消息傳遞:當(dāng)消息發(fā)送成功后,接收方會(huì)發(fā)送一個(gè)確認(rèn)幀進(jìn)行數(shù)據(jù)接收確認(rèn)。有明確的消息地址和消息分發(fā):發(fā)送一條消息必須有明確的消息接收者和消息發(fā)送者。
在TinyOS系統(tǒng)中主動(dòng)消息通信機(jī)制的實(shí)現(xiàn)可以通過系統(tǒng)通信組件來(lái)實(shí)現(xiàn),用戶可以通過調(diào)用系統(tǒng)組件實(shí)現(xiàn)高層的通信組件。5.4.2相關(guān)組件及接口
TinyOS系統(tǒng)提供了很多與底層通信相關(guān)接口,并提供了實(shí)現(xiàn)這些接口的組件,其中最常用的組件有AMSenderC組件、AMReceiverC組件、ActiveMessageC組件等。這些接口組件都使用一個(gè)共同的消息緩存區(qū),稱為message_t。
1.?message_t
message_t是一個(gè)抽象的數(shù)據(jù)類型,通常被作為通信底層的數(shù)據(jù)結(jié)構(gòu),其定義在C:\cygwin\opt\mytinyos\tos\chips\cc2530\net\types目錄下的message.h文件中,其具體代碼如代碼5-12所示?!敬a5-12】message.h
typedefnx_structmessage_t
{
nx_uint8_theader[sizeof(message_header_t)];
nx_uint8_tdata[TOSH_DATA_LENGTH];
nx_uint8_tfooter[sizeof(message_footer_t)];
nx_uint8_tmetadata[sizeof(message_metadata_t)];
}message_t;其中,message_t中有四個(gè)元素,每個(gè)元素的說明如下:
header:為消息的頭部。
data:為有效載荷去,即數(shù)據(jù)。
footer:為消息的尾部。
metadata:為元數(shù)據(jù)。
其中header、footer和metadata都是不透明的,不能直接訪問,而data字段的訪問必須通過Packet接口、AMPacket接口或其他一些接口。
2.?AMSenderC.nc
AMSenderC組件用于數(shù)據(jù)的發(fā)送,此組件所在目錄為“cygwin\opt\tinyos-2.x\tos\system”,其代碼如代碼5-13所示。【代碼5-13】AMSenderC.nc
genericconfigurationAMSenderC(am_id_tAMId)
{
provides
{
interfaceAMSend;
interfacePacket;
interfaceAMPacket;
interfacePacketAcknowledgementsasAcks;
}
}
implementation
{
……
}其中:
AMSend接口:是基本主動(dòng)消息的發(fā)送接口,AMSend接口在發(fā)送命令里指定了AM目標(biāo)地址。
Packet接口:提供對(duì)message_t抽象數(shù)據(jù)類型的基本訪問。
AMPacket接口:類似與Packet接口,提供對(duì)message_t抽象數(shù)據(jù)類型的AM訪問。
PacketAknowledgements接口:提供信息確認(rèn)機(jī)制接口,提供確認(rèn)幀請(qǐng)求和發(fā)送。
在實(shí)際編寫程序中,應(yīng)用層可以直接調(diào)用AMSenderC組件進(jìn)行數(shù)據(jù)的發(fā)送,其發(fā)送數(shù)據(jù)過程示例如示例5-1所示。
【示例5-1】發(fā)送示例
//要發(fā)送數(shù)據(jù)的結(jié)構(gòu)體
typedefnx_structBlinkToRadioMsg
{
nx_uint16_tnodeid;
nx_uint16_tcounter;
}BlinkToRadioMsg;
message_tpkt;BlinkToRadioMsg*btrpkt;
//調(diào)用Packet獲得發(fā)送數(shù)據(jù)的載荷部分
btrpkt=(BlinkToRadioMsg*)callPacket.getPayload(&pkt,sizeof(BlinkToRadioMsg));
btrpkt->nodeid=TOS_NODE_ID;
btrpkt->counter=counter++;
//調(diào)用AMSend接口將數(shù)據(jù)發(fā)送出去
if(callAMSend.send(AM_BROADCAST_ADDR,&pkt,sizeof(BlinkToRadioMsg))==SUCCESS)
{
callLeds.led0Toggle();
}
3.?AMReceiverC.nc
AMReceiverC組件用于數(shù)據(jù)的接收,此組件所在目錄為cygwin\opt\tinyos-2.x\tos\system,具體代碼如代碼5-14所示。
【代碼5-14】AMReceiverC.nc
genericconfigurationAMReceiverC(am_id_tamId)
{
provides
{
interfaceReceive;
interfacePacket;
interfaceAMPacket;
}
}其中:
Receive接口:最基本的消息接收接口,提供了接收消息時(shí)觸發(fā)的事件函數(shù)。
Packet接口:同AMSender.Packet接口,提供message_t抽象類型的基本訪問。
AMPacket接口:同AMSender.AMPacket接口。
針對(duì)于示例5-1中的發(fā)送示例的接收部分如示例5-2所示。【示例5-2】
接收示例
/*當(dāng)有數(shù)據(jù)需要接收時(shí),將會(huì)觸發(fā)接收事件*/
eventmessage_t*Receive.receive(message_t*msg,void*payload,uint8_tlen)
{
//如果接收到數(shù)據(jù)長(zhǎng)度與要發(fā)送的數(shù)據(jù)長(zhǎng)度相同將執(zhí)行LED閃爍命令
if(len==sizeof(BlinkToRadioMsg))
{
callLeds.led2Toggle();
}
returnmsg;
}
4.?ActiveMessageAddressC.nc
ActiveMessageAddressC組件提供獲得和設(shè)定節(jié)點(diǎn)的地址,位于cygwin\opt\tinyos-2.x\tos\system,具體代碼如代碼5-15所示?!敬a5-15】ActiveMessageAddressC.nc
moduleActiveMessageAddressC@safe()
{
provides
{
interfaceActiveMessageAddress;
asynccommandam_addr_tamAddress();
asynccommandvoidsetAmAddress(am_addr_ta);
}
}其中,ActiveMessageAddress:提供獲得和設(shè)定節(jié)點(diǎn)AM地址的命令,但是通常情況下不建議使用此接口,因?yàn)樾薷腁M地址可能會(huì)破壞網(wǎng)絡(luò)堆棧。
5.?ActiveMessageC.nc
ActiveMessageC組件是一個(gè)與平臺(tái)相關(guān)的組件,該組件提供了發(fā)送接收接口。以上講述的AMSenderC組件、AMReceiverC組件等都是TinyOS系統(tǒng)自帶的組件。而ActiveMessageC組件將通信相關(guān)接口綁定到底層的相關(guān)硬件驅(qū)動(dòng),不同的平臺(tái)其實(shí)現(xiàn)形式不同。在mytinyos平臺(tái)中此組件位于cygwin\opt\mytinyos\tos\platforms\cc2530目錄下,具體代碼如代碼5-16所示?!敬a5-16】ActiveMessageC.nc
configurationActiveMessageC
{
provides
{
interfaceSplitControl;
interfaceAMSend[uint8_tid];
interfaceReceive[uint8_tid];
interfaceReceiveasSnoop[uint8_tid];
interfaceSendNotifier[am_id_tid];
interfacePacket;
interfaceAMPacket;
interfacePacketAcknowledgements;
interfaceLowPowerListening;
interfacePacketLink;
interfacePacketTimeStamp<TRadio,uint32_t>asPacketTimeStampRadio;
interfacePacketTimeStamp<TMilli,uint32_t>asPacketTimeStampMilli;
}
}
ActiveMessageC組件集AMSenderC組件和AMReceiveC組件的功能于一體,既能實(shí)現(xiàn)數(shù)據(jù)的發(fā)送又能實(shí)現(xiàn)數(shù)據(jù)的接收,因此一般在實(shí)際的開發(fā)過程中建議使用ActiveMessageC組件進(jìn)行編程。其中以下的任務(wù)描述5.D.3就使用ActiveMessageC組件進(jìn)行數(shù)據(jù)的發(fā)送與接收。5.4.3點(diǎn)對(duì)點(diǎn)傳輸
以下內(nèi)容將實(shí)現(xiàn)任務(wù)描述5.D.3,使用兩個(gè)CC2530節(jié)點(diǎn)進(jìn)行點(diǎn)對(duì)點(diǎn)通信,并通過數(shù)據(jù)的發(fā)送和接收控制LED閃爍。完成此任務(wù)中需要完成以下工作:
首先在mytinyos/apps目錄下新建一個(gè)名為BlinkToRadio的文件夾(參照任務(wù)5.D.1)。
其次在BlinkToRadio的文件夾創(chuàng)建頂層配件BlinkToRadioAppC,主組件命名為BlinkToRadioC.nc,在BlinkToRadioC.nc組件中使用ActiveMessageC組件提供的發(fā)送和接收等接口實(shí)現(xiàn)數(shù)據(jù)的通信。
編寫Makefile文件。
編譯程序,下載至設(shè)備中,連接串口,觀察現(xiàn)象并分析數(shù)據(jù)。
1.?BlinkToRadioAppC.nc
BlinkToRadioAppC.nc為整個(gè)任務(wù)的頂層配件組件,在此組件中實(shí)現(xiàn)了組件之間的綁定關(guān)系。其具體代碼如描述5.D.3BlinkToRadioAppC.nc所示?!久枋?.D.3】BlinkToRadioAppC.nc
#include<Timer.h>
#include“BlinkToRadio.h”
configurationBlinkToRadioAppC
{
}
implementation
{
componentsMainC;
componentsLedsC;
componentsBlinkToRadioCasApp;
componentsnewTimerMilliC()asTimer0;
componentsActiveMessageC; App.Boot->MainC.Boot;
App.Leds->LedsC.Leds;
App.Timer0->Timer0;
App.Packet->ActiveMessageC;
App.AMPacket->ActiveMessageC;
App.AMSend->ActiveMessageC.AMSend[uniqueCount("BlinkToRadio")];
App.AMControl->ActiveMessageC;
App.Receive->ActiveMessageC.Receive[uniqueCount("BlinkToRadio")];
App.PacketAcknowledgements->ActiveMessageC;
}在此組件中使用了MainC組件、LedsC組件、ActiveMessageC組件、TimerMillic組件、AMSenderC組件和AMReceiverC組件,其中綁定關(guān)系如下:
BlinkToRadioC組件的Boot接口綁定到MainC組件上。
BlinkToRadioC組件的Leds接口綁定到LedsC組件上。
定時(shí)器MilliTimer接口綁定到TimerMilliC組件上。
BlinkToRadioC組件的Packet接口、AMPacket接口、AMSend接口、AMControl接口、Receive接口和PacketAckhnowledgements接口綁定到ActiveMessageC組件上。
2.?BlinkToRadioC.nc
BlinkToRadioC組件是整個(gè)任務(wù)的主組件,在此組件中通過串口數(shù)據(jù)包負(fù)載部分的封裝以及發(fā)送,具體代碼如描述5.D.3BlinkToRadioC.nc所示?!久枋?.D.3】BlinkToRadioC.nc
#include<Timer.h>
#include"BlinkToRadio.h"
moduleBlinkToRadioC
{
uses
{
interfaceBoot;
interfaceLeds;
interfaceTimer<TMilli>asTimer0; interfacePacket;
interfaceAMPacket;
interfaceAMSend;
interfaceSplitControlasAMControl;
interfaceReceive;
interfacePacketAcknowledgements;
}
}
implementation
{
boolbusy=FALSE;
message_tpkt;
uint16_tcounter=0; /*程序啟動(dòng)*/
eventvoidBoot.booted()
{
busy=FALSE;
callAMControl.start();
}
/*開啟無(wú)線后開啟定時(shí)任務(wù)*/
eventvoidAMControl.startDone(error_terr)
{
if(err==SUCCESS)
{
callTimer0.startPeriodic(TIMER_PERIOD_MILLI);
}
else
{
callAMControl.start();
}
} eventvoidAMControl.stopDone(error_terr)
{
}
/*定時(shí)事件處理,發(fā)送數(shù)據(jù)*/
eventvoidTimer0.fired()
{
if(!busy)
{
BlinkToRadioMsg*btrpkt;
btrpkt=(BlinkToRadioMsg*)call Packet.getPayload(&pkt,sizeof(BlinkToRadioMsg));
btrpkt->nodeid=TOS_NODE_ID;
btrpkt->counter=counter++;
if(call AMSend.send(AM_BROADCAST_ADDR,&pkt,sizeof(BlinkToRadioMsg))==SUCCESS) {
busy=TRUE;
}
callLeds.led0Toggle();
}
}
/*發(fā)送完成后調(diào)用確認(rèn)幀回復(fù)命令,并開啟LED閃爍命令*/
eventvoidAMSend.sendDone(message_t*msg,error_terror)
{
if(&pkt==msg)
{
callPacketAcknowledgements.requestAck(msg);
callLeds.led1Toggle();
busy=FALSE;
}
} /*接收到數(shù)據(jù)后執(zhí)行LED閃爍命令*/
eventmessage_t*Receive.receive(message_t*msg,void*payload,uint8_tlen)
{
if(len==sizeof(BlinkToRadioMsg))
{
BlinkToRadioMsg*btrpkt=(BlinkToRadioMsg*)payload;
callLeds.led2Toggle();
}
returnmsg;
}
}
3.?BlinkToRadio.h
除了BlinkToRadioAppC組件和BlinkToRadioC組件之外,還需要編寫B(tài)linkToRadio.h。在BlinkToRadio.h文件中定義了串口傳送的周期以及要傳送消息的結(jié)構(gòu)體,其具體代碼如描述5.D.3BlinkToRadio.h所示?!久枋?.D.3】BlinkToRadio.h
#ifndef_BLINKTORADIO_H
#define_BLINKTORADIO_H
enum
{
//傳送消息的周期
TIMER_PERIOD_MILLI=2000
};
/*傳送消息的結(jié)構(gòu)體*/
typedefnx_structBlinkToRadioMsg
{
nx_uint16_tnodeid;
nx_uint16_tcounter;
}BlinkToRadioMsg;
#endif
4.?Makefile文件
在Makefile文件中指明任務(wù)的頂層配件,并規(guī)定編譯規(guī)則,其具體代碼如描述5.D.3Makefile所示。
【描述5.D.3】Makefile
COMPONENT=BlinkToRadioAppC
include$(MAKERULES)
5.實(shí)驗(yàn)結(jié)果
將程序編譯下載至兩個(gè)設(shè)備中,設(shè)備的LED1和LED2同時(shí)閃爍,表明數(shù)據(jù)發(fā)送成功;設(shè)備的LED3閃爍表明數(shù)據(jù)接收成功。如果關(guān)閉一臺(tái)設(shè)備,會(huì)發(fā)現(xiàn)另外一臺(tái)設(shè)備的LED3將不閃爍,這是因?yàn)榻邮詹坏綌?shù)據(jù)。在通信過程中,每成功發(fā)送一條數(shù)據(jù),都會(huì)有確認(rèn)幀確認(rèn)發(fā)送成功。使用ZigbeeSniffer捕獲數(shù)據(jù)幀如圖5-8所示。圖5-8捕獲的數(shù)據(jù)幀
5.5ADC信息采集
5.5.1相關(guān)組件及接口
在mytinyos平臺(tái)中,ADC的實(shí)現(xiàn)是通過一些ADC相關(guān)的組件來(lái)實(shí)現(xiàn)的,最主要的有兩個(gè)組件AdcC組件和AdcP組件。
1.?AdcC.nc
Adcc.nc組件位于cygwin\opt\mytinyos\tos\chips\cc2530\adc目錄下,在Adc組件中提供了兩個(gè)接口:AdcControl接口和Read接口。具體代碼如代碼5-17所示?!敬a5-17】AdcC.nc
genericconfigurationAdcC()
{
providesinterfaceAdcControl;
providesinterfaceRead<int16_t>;
}
implementation
{
componentsMainC,AdcP;
MainC.SoftwareInit->AdcP.Init;
enum{ID=unique("UNIQUE_ADC_PORT"),};
AdcControl=AdcP.AdcControl[ID];
Read=AdcP.Read[ID];
}
AdcControl接口:AdcC組件將AdcControl接口的實(shí)現(xiàn)綁定在AdcP組件上,由AdcP組件具體實(shí)現(xiàn)。
Read接口:此接口用于ADC信息的讀取,AdcC組件同樣將此組件綁定到AdcP組件,由AdcP組件具體實(shí)現(xiàn)。
2.?AdcP.nc
AdcP.nc組件位于cygwin\opt\mytinyos\tos\chips\cc2530\adc目錄下,此組件是一個(gè)硬件表示層組件,它的主要功能是實(shí)現(xiàn)了ADC的配置以及ADC采集信息的讀取,其主要代碼如代碼5-18所示。【代碼5-18】
moduleAdcP{
providesinterfaceInit;
providesinterfaceAdcControl[uint8_tid];
providesinterfaceRead<int16_t>[uint8_tid];
}
AdcControl接口有兩個(gè)命令,enable命令和disable命令。
enable命令:ADC相關(guān)的寄存器使能開始采集數(shù)據(jù)。
disable命令:關(guān)閉ADC相關(guān)寄存器,停止采集數(shù)據(jù)。
Read接口用于讀取ADC數(shù)據(jù),當(dāng)讀取完成之后將觸發(fā)ReadDone命令。5.5.2光敏信息采集
以下內(nèi)容將實(shí)現(xiàn)任務(wù)描述5.D.4,通過控制CC2530的ADC進(jìn)行光敏的采集,并通過串口傳輸?shù)絇C機(jī),需要完成以下工作:
首先在mytinyos/apps目錄下新建一個(gè)名為AdSensor的文件夾(參照任務(wù)5.D.1)。
其次在AdSensor文件夾創(chuàng)建頂層配件ADSensorAppC,主組件命名為ADSensorC.nc,并編寫程序。
編寫Makefile文件。
編譯程序,下載至設(shè)備中,連接串口,觀察現(xiàn)象并分析數(shù)據(jù)。
1.?ADSensorAppC.nc
ADSensorAppC.nc為整個(gè)任務(wù)的頂層配件組件,在此組件中實(shí)現(xiàn)了組件之間的綁定關(guān)系。其具體代碼如描述5.D.4ADSensorAppC.nc所示。【描述5.D.4】ADSensorAppC.nc
溫馨提示
- 1. 本站所有資源如無(wú)特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 資金動(dòng)賬提醒制度
- 診所急重癥搶救制度
- 解釋專制主義中央集權(quán)制度
- 融資擔(dān)保公司信息披露制度
- 養(yǎng)老院照護(hù)等級(jí)評(píng)估制度
- 2026北京西城區(qū)中國(guó)人民公安大學(xué)招聘94人備考考試試題附答案解析
- 2026山東濰坊市峽山區(qū)招聘中小學(xué)教師10人參考考試題庫(kù)附答案解析
- 2026中國(guó)科學(xué)院聲學(xué)研究所專項(xiàng)項(xiàng)目管理辦公室崗位招聘2人備考考試試題附答案解析
- 2026重慶兩江新區(qū)人民醫(yī)院宣傳科干事崗位招聘1人參考考試試題附答案解析
- 2026廣東佛山市順德區(qū)勒流新球初級(jí)中學(xué)語(yǔ)文、物理臨聘教師招聘參考考試試題附答案解析
- 加工中心操作工初級(jí)工考試試卷與答案
- 新生兒圍生期感染護(hù)理查房
- 內(nèi)蒙古呼和浩特市2025-2026學(xué)年高三上學(xué)期第一次質(zhì)量監(jiān)測(cè) 化學(xué)試卷
- 丈夫出軌婚內(nèi)協(xié)議書范本
- 厚型防火涂料施工規(guī)范及操作流程
- 婚姻家庭矛盾糾紛調(diào)解
- 中性粒細(xì)胞缺乏癥診療與管理體系
- 醫(yī)院行政管理體系介紹
- (新版)液氯安全標(biāo)簽
- GB/T 21649.2-2025粒度分析圖像分析法第2部分:動(dòng)態(tài)圖像分析法
- 南昌地鐵保護(hù)管理辦法
評(píng)論
0/150
提交評(píng)論