完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
一.ZigBee 协议栈简介
什么是ZigBee 协议栈呢?它和ZigBee 协议有什么关系呢?协议是一系列的通信标准,通信双方需要共同按照这一标准进行正常的数据发射和接收。协议栈是协议的具体实现形式,通俗点来理解就是协议栈是协议和用户之间的一个接口,开发人员通过使用协议栈来使用个协议的,进而实现无线数据收发。 ZigBee 的协议分为两部分,IEEE 802.15.4 定义了PHY(物理层)和MAC(介质访问层)技术规范;ZigBee 联盟定义了NWK(网络层)、APS(应用程序支持子层)、APL(应用层)技术规范。ZigBee 协议栈就是将各个层定义的协议都集合在一直,以函数的形式实现,并给用户提供API(应用层),用户可以直接调用。 Z-Stack协议栈体系结构 二.如何使用ZigBee 协议栈 协议栈是协议的实现,可以理解为代码,函数库,供上层应用调用,协议较底下的层与应用是相互独立的。你需要关心的就是你的应用逻辑,数据从哪里到哪里,怎么存储,处理;还有系统里的设备之间的通信顺序什么的.至于初始化等等工作不需要我们考虑。我们只需要调用相关的API函数就可以了。 三.了解zigbee协议栈的应用文件夹 安装好zigbee协议栈,打开目录Texas Instruments (一)Components:顾名思义这个是放我们的库的文件夹,里面放了一些我们用到的ZDO,driver,hal,zcl 等库的代码 (二)Documents:这里放的是TI 的开发文档的,里面很多都是讲述协议栈的API (三)Projects:这个文件夹放的是TI 协议栈的例子程序。 (四)Tools:这个文件夹是放TI 的例子程序的一些上位机之类的程序,作为工具使用。 接下来介绍的东西均需要打开示例工程在这里我们打开ZStack-CC25302.5.1aProjectszstackSamplesSampleAppCC2530DB进入zigbee的协议栈中 为了确保程序没问题我们在这里重新编译一下协议栈。 这是我们协议栈的汇总目录 这里是我们zigbee的文件夹,里面写好的代码都分为很多的group (一)APP:应用层目录,这里用户可以创建不同的工程目录,这里包含项目工程主要内容 (二)HAL:硬件层目录,包含有与硬件相关的配置和驱动及操作函数。 (三)MAC: MAC 层目录,包含了MAC 层的参数配置文件及其MAC 的LIB 库的函数接口文件。 (四)MT:实现通过串口可控各层,于各层进行直接交互。 (五)NWK:网络层目录,含网络层配置参数文件及网络层库的函数接口文件,APS 层库的函数接口 (六)OSAL:协议栈的操作系统。 (七)Profile: AF层目录,包含AF 层处理函数文件。 (八)Security:安全层目录,安全层处理函数,比如加密函数等。 (九)Services:地址处理函数目录,包括着地址模式的定义及地址处理函数。 (十)Tools:工程配置目录,包括空间划分及ZStack 相关配置信息。 (十一)ZDO: ZDO目录。 (十二)ZMac: MAC 层目录,包括MAC 层参数配置及MAC 层LIB 库函数回调处理函数。 (十三)Output:输出文件目录,这个EW8051 IDE 自动生成的。 点击DemoEB可以进行设备类型工作空间选择,必须要选好,不然不可以使用。 CoordinatorEB:为协调器的工作空间。 ROuterEB:为路由器的工作空间。 EndDeviceEB:为无线终端的设备选择。 四.zigbee协议栈的工作流程 在我们这个版本的来说在我们使用者的路径流程是:main()---> osal_init_system()---> osalInitTasks()---> SampleApp_Init() (一)打开ZMain.c 找到main 函数 学过C语言的都知道,C语言函数是在一直执行main文件里面的内容,首先我们先查看main.c的内容 int main( void ) { // Turn off interrupts osal_int_disable( INTS_ALL ); //关闭协议栈所有中断 // Initialization for board related stuff such as LEDs HAL_BOARD_INIT(); //初始化协议栈系统时钟 // Make sure supply voltage is high enough to run zmain_vdd_check(); //检查芯片电压是否正常 // Initialize board I/O InitBoard( OB_COLD ); //初始化I/O // Initialze HAL drivers HalDriverInit(); //初始化芯片硬件 // Initialize NV System osal_nv_init( NULL ); //初始化Flash 存储器 // Initialize the MAC ZMacInit(); //初始化MAC 层 // Determine the extended address zmain_ext_addr(); //确定IEEE 64位设备地址 // Initialize basic NV items zgInit(); //初始化非易失变量 #ifndef NONWK // Since the AF isn't a task, call it's initialization routine afInit(); #endif // Initialize the operating system osal_init_system(); //初始化协议栈操作系统 // Allow interrupts osal_int_enable( INTS_ALL ); //使能全部中断 // Final board initialization InitBoard( OB_READY ); //最终板载初始化 // Display information about this device zmain_dev_info(); //LCD显示设备信息 /* Display the device info on the LCD */ #ifdef LCD_SUPPORTED zmain_lcd_init(); //初始化LCD #endif #ifdef WDT_IN_PM1 /* If WDT is used, this is a good place to enable it. */ WatchDogEnable( WDTIMX ); #endif osal_start_system(); // No Return from here 执行操作系统,这里进入将不会退出,一直执行osal_start_system return 0; // Shouldn't get here. } // main() 我们接着看一下osal_start_system在这里我们可以点击选中然后goto到函数里面查看。 void osal_start_system( void ) { #if !defined ( ZBIT ) && !defined ( UBIT ) for(;;) // Forever Loop //这是个死循环 #endif { osal_run_system(); //协议栈一直执行这个函数 } } 这个是任务系统轮询的主要函数。他会查找发生的事件然后调用相应的事件执行函数, 如果没有事件登记要发生那就将进入睡眠模式。在协议栈中,所有将要处理的内容定义为事件,这个函数就是查找事件的函数,每个事件都有自己的事件号,根据事件号大小判断优先级,一个一个执行,例如按键按键,就触发按键事件,这个现在知道就可以,在后面我们会介绍。 在这里我们知道了协议栈一直执行事件扫面函数,那我们如何根据需求开发呢,我们要做的就是设置一个自己要监测的事件,然后写交互逻辑。 // 一个任务可以有多个事件 void osal_run_system( void ) { uint8 idx = 0; osalTimeUpdate();//更新事件 Hal_ProcessPoll(); do { if (tasksEvents[idx]) // Task is highest priority that is ready. { break; } } while (++idx < tasksCnt); if (idx < tasksCnt) { uint16 events; halIntState_t intState; HAL_ENTER_CRITICAL_SECTION(intState); events = tasksEvents[idx]; tasksEvents[idx] = 0; // Clear the Events for this task. HAL_EXIT_CRITICAL_SECTION(intState); activeTaskID = idx; events = (tasksArr[idx])( idx, events ); activeTaskID = TASK_NO_TASK; HAL_ENTER_CRITICAL_SECTION(intState); tasksEvents[idx] |= events; // Add back unprocessed events to the current task. HAL_EXIT_CRITICAL_SECTION(intState); } #if defined( POWER_SAVING ) else // Complete pass through all task events with no activity? { osal_pwrmgr_powerconserve(); // Put the processor/system into sleep } #endif /* Yield in case cooperative scheduling is being used. */ #if defined (configUSE_PREEMPTION) && (configUSE_PREEMPTION == 0) { osal_task_yield(); } #endif } 我们接下来进行事件的初始设置。在前面main函数中 osalInitTasks(); 为初始化系统任务,我们需要将自己的需求加入其中就可以达到目的。 goto一下进入函数 //osalInitTasks这个是设置任务的函数,然后任务里面也定义了很多事件 void osalInitTasks( void ) { uint8 taskID = 0; // 分配内存,返回指向缓冲区的指针 tasksEvents = (uint16 *)osal_mem_alloc( sizeof( uint16 ) * tasksCnt); // 设置所分配的内存空间单元值为0 osal_memset( tasksEvents, 0, (sizeof( uint16 ) * tasksCnt)); // 任务优先级由高向低依次排列,高优先级对应taskID 的值反而小 macTaskInit( taskID++ ); // taskID 0 nwk_init( taskID++ ); // taskID 1 Hal_Init( taskID++ ); //taskID 2 #if defined( MT_TASK ) MT_TaskInit( taskID++ ); #endif APS_Init( taskID++ ); //taskID 3 #if defined ( ZIGBEE_FRAGMENTATION ) APSF_Init( taskID++ ); #endif ZDApp_Init( taskID++ ); //taskID 4 #if defined ( ZIGBEE_FREQ_AGILITY ) || defined ( ZIGBEE_PANID_CONFLICT ) ZDNwkMgr_Init( taskID++ ); #endif //SampleApp_Init为用户创建任务,我们需要在这里进行任务的添加 现在进入函数我们查看一下 SampleApp_Init( taskID ); // taskID 5 } 在这里我们看一下用户应用任务的事件处理函数进入SampleApp_ProcessEvent函数在这里我们可以看到在协议栈初始的时候定义的事件,和处理函数,在后面我们再详细介绍如何使用。 uint16 SampleApp_ProcessEvent( uint8 task_id, uint16 events ) { afIncomingMSGPacket_t *MSGpkt; (void)task_id; // Intentionally unreferenced parameter if ( events & SYS_EVENT_MSG )//如果是SYS_EVENT_MSG 这个事件进入这里 { MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( SampleApp_TaskID );//类型转换 while ( MSGpkt ) { switch ( MSGpkt->hdr.event ) { // Received when a key is pressed case KEY_CHANGE: //如果是按键按下进入下面这个函数 SampleApp_HandleKeys( ((keyChange_t *)MSGpkt)->state, ((keyChange_t *)MSGpkt)->keys ); break; // Received when a messages is received (OTA) for this endpoint case AF_INCOMING_MSG_CMD://如果是接受到RF消息进入这里 SampleApp_MessageMSGCB( MSGpkt ); break; // Received whenever the device changes state in the network case ZDO_STATE_CHANGE: //如果网络状态改变,这个绝壁进入, SampleApp_NwkState = (devStates_t)(MSGpkt->hdr.status); if ( (SampleApp_NwkState == DEV_ZB_COORD) || (SampleApp_NwkState == DEV_ROUTER) || (SampleApp_NwkState == DEV_END_DEVICE) ) { // Start sending the periodic message in a regular interval. osal_start_timerEx( SampleApp_TaskID, SAMPLEAPP_SEND_PERIODIC_MSG_EVT, SAMPLEAPP_SEND_PERIODIC_MSG_TIMEOUT ); } else { // Device is no longer in the network } break; default: break; } // Release the memory释放消息占用的内存 osal_msg_deallocate( (uint8 *)MSGpkt ); // Next - if one is available // 返回while ( MSGpkt )重新处理事件,直到缓冲区没有等待处理事件为止 MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( SampleApp_TaskID ); } // return unprocessed events 返回未处理的事件 return (events ^ SYS_EVENT_MSG); } // Send a message out - This event is generated by a timer // (setup in SampleApp_Init()). if ( events & SAMPLEAPP_SEND_PERIODIC_MSG_EVT ) //如果是 SAMPLEAPP_SEND_PERIODIC_MSG_EVT 事件进入这里 这里是网络状态改变之后标志位值1的 { // Send the periodic message SampleApp_SendPeriodicMessage(); // Setup to send message again in normal period (+ a little jitter) osal_start_timerEx( SampleApp_TaskID, SAMPLEAPP_SEND_PERIODIC_MSG_EVT, (SAMPLEAPP_SEND_PERIODIC_MSG_TIMEOUT + (osal_rand() & 0x00FF)) ); // return unprocessed events return (events ^ SAMPLEAPP_SEND_PERIODIC_MSG_EVT); } // Discard unknown events return 0; } 了解以上的流程我们就可以了解到协议栈的整体运行机制了。并且大概的概念。 下面我们介绍本节涉及zigbee协议栈的函数; 函数名:osal_start_timerEx 函数声明uint8 osal_start_timerEx( uint8 taskID, uint16 event_id, uint16 timeout_value ) 这是一个定时器的函数,将在timeout_value毫秒之后将任务号为taskID的任务,事件号为event_id的事件标志位置为1.这个时候就可以通过evens&进行判断 |
|
|
|
只有小组成员才能发言,加入小组>>
4487个成员聚集在这个小组
加入小组3327 浏览 0 评论
航顺(HK)联合电子发烧友推出“近距离体验高性能Cortex-M3,免费申请价值288元评估板
4260 浏览 1 评论
4287 浏览 0 评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-18 16:26 , Processed in 0.588155 second(s), Total 77, Slave 60 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号