int main(void) { osal_int_disable( INTS_ALL ); //关闭所有中断 HAL_BOARD_INIT(); //初始化系统时钟 zmain_vdd_check(); //检查芯片电压是否正常 InitBoard( OB_COLD ); //初始化 I/O ,LED 、Timer 等 HalDriverInit(); //初始化芯片各硬件模块 osal_nv_init( NULL ); //初始化 Flash 存储器 ZMacInit(); //初始化 MAC 层 zmain_ext_addr(); //确定 IEEE 64 位地址 zgInit(); //初始化非易失变量 #ifndef NONWK // Since the AF isn't a task, call it's initialization routine afInit(); #endif osal_in it_system(); //初始化操作系统 osal_int_enable( INTS_ALL ); //使能全部中断 InitBoard( OB_READY ); //最终板载初始化 zmain_dev_info(); //显示设备信息 #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_st art_system();// No Re turn from here 执行操作系统,进去后不会返回 return 0; // Shouldn't get here. } // main() |
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++ ); //macT askInit(0) ,用户不需考虑 nwk_init( taskID++ ); //nwk_ init(1),用户不需考虑 Hal_Init( taskID++ ); //Hal_I nit(2) ,用户需考虑 #if defined( MT_TASK ) //如果定义 MT_TASK 则调用 MT_TaskIn it() MT_TaskInit( taskID++ ); #endif APS_Init( taskID++ ); //APS_I nit(3) ,用户不需考虑 #if defined ( ZIGBEE_FRAGMENTATION ) APSF_Init( taskID++ ); #endif ZDApp_Init( taskID++ ); //ZDApp _Init(4) ,用户需考虑 #if defined ( ZIGBEE_FREQ_AGILITY ) || defined ( ZIGBEE_PANID_CONFLICT ) ZDNwkMgr_Init( taskID++ ); #endif //用户创建的任务 SampleA pp_Init( taskID ); // SampleApp_Init _Init (5),用户需考虑。重要! |
void osal_st art_system( void ) { #if !defined ( ZBIT ) && !defined ( UBIT ) for(;;) // Forever Loop #endif { uint8 idx = 0; osalTimeUpdate(); //扫描哪个事 件被触发了,然后置相应的标志位 Hal_ProcessPoll(); //轮询 TIMER 与 UART do { if (tasksEvents[idx]) // Task is highest priorit y that is ready. { break; //得到待处理 的最高优先级任务索引号 idx } } while (++idx < tasksCnt); if (idx < tasksCnt) { uint16 events; halIntState_t intState; HAL_ENTER_CRITICAL_SECTION(intState);// 进入临界区,保护 events = tasksEvents[idx]; //提取需要处理的任务中的事件 tasksEvents[idx] = 0; //清除本次任务的事件 HAL_EXIT_CRITICAL_SECTION(intState); // 退出临界区 events = (tasksArr[idx])( idx, events );//通过指针调 用任务处理函数,关键 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 } } |
void SampleApp_Init( uint8 task_id ) { SampleApp_TaskID = task_id;//osal 分配的任务 ID 随着用户添加任务的增多而改变 SampleApp_NwkState = DEV_INIT;//设备状态设 定为 ZDO 层中定义的初始化状态、初始化应用设备的网络类型,设备类型的改变都要产生一个事件—ZD O_STATE_CHANGE,从字面理解为 ZDO 状态发生了改变。所以在设备初始化的时候一定要 把它初始化为什么状态都没有。那么它就要去检测整个环境,看是否能重新建立或者加入存在的网络。但是有一种情况例外,就是 当 NV_ RESTORE 被设置的候(NV_RESTORE 是 把信息保存在非易失存储器中),那么需要恢复其网络状 态,而不需要重新建立或者加入网络了.这里需要设置 NV_RESTORE宏定义。 SampleApp_TransID = 0; //消息发送 I D(多消息时有顺序之分) #if defined ( BUILD_ALL_DEVICES ) if ( readCoordinatorJumper() ) zgDeviceLogicalType = ZG_DEVICETYPE_COORDINATOR; else zgDeviceLogicalType = ZG_DEVICETYPE_ROUTER; #endif // BUILD_ALL_DEVICES //该段的意思是,如果设置了 HOLD_AUTO_START 宏定义,将会在启动芯片的 时候会暂停启动 流程,只有外部触发以后才会启动芯片。其实就是需要一个按钮触发它 的启动流程。 #if defined ( HOLD_AUTO_START ) ZDOInitDevice(0); #endif //设置发送数据的方式和目的地址寻址模式 //发送模式:广播发送 SampleApp_Periodic_DstAddr.addrMode = (afAddrMode_t)AddrBroadcast; //广播 SampleApp_Periodic_DstAddr.endPoint = SAMPLEAPP_ENDPOINT; //指定端点号 SampleApp_Periodic_DstAddr.addr.shortAddr = 0xFFFF; //指定目的网络地址为广播地址 //发送模式:组播发送 Setup for the flash command's destination address -Group 1 SampleApp_Flash_DstAddr.addrMode = (afAddrMode_t)afAddrGroup; //组寻址 SampleApp_Flash_DstAddr.endPoint = SAMPLEAPP_ENDPOINT; //指定端点号 SampleApp_Flash_DstAddr.addr.shortAddr = SAMPLEAPP_FLASH_GROUP; //组号 0 x0001 //定义本设 备用来通信的 APS 层端点描述 SampleApp_epDesc.endPoint = SAMPLEAPP_ENDPOINT; SampleApp_epDesc.task_id = &SampleApp_TaskID; //SampleApp 描述符的任务 ID SampleApp_epDesc.simpleDesc = (SimpleDescriptionFormat_t *)&SampleApp_SimpleDesc;//SampleApp 简单描述符 SampleApp_epDesc.latencyReq = noLatencyReqs; //延时策略 //向 AF 层登记描述符, 登记 endpoint description 到 AF,要对该应用进行初始化并在 AF 进行登记,告诉 应用层有这么一个 EP 已经开通可以使用,那么下层要是有关于该应用的信息或者应用要对下层做哪些操作,就自动得到下层的配合 afRegister( &SampleApp_epDesc ); //登记所有 的按键事件 RegisterForKeys( SampleApp_TaskID ); // By default, all devices start outin Group SampleApp_Group.ID = 0x0001; //组号 osal_memcpy( SampleApp_Group.name, "Group 1", 7 ); //设定组名 aps_AddGroup( SAMPLEAPP_ENDPOINT, &SampleApp_Group );//把该组登 记添加到 APS 中 #if defined ( LCD_SUPPORTED ) HalLcdWriteString( "SampleApp", HAL_LCD_LINE_1 );//如果支持 LCD,显示提示信息 #endif } |
uint16 SampleApp_ProcessEvent( uint8 task_id, uint16 events ) { afIncomingMSGPacket_t *MSGpkt; (void)task_id; // Intentionally unreferenced paramete if ( events & SYS_EVENT_MSG ) //接收系统消息再进行判断 {//接收属于本应用任务 SampleApp 的消息,以 SampleApp_TaskID 标记 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://接收数据事件,调用函数 AF_DataRequest()接收数据 SampleApp_MessageMSGCB( MSGpkt );//调用回调函数对收到的数据进行处理 break; // Received whenever the device changes state in the network case ZDO_STATE_CHANGE://只要网络状态发生改变,就通过 ZDO_STATE_CHANGE 事件通知所有的任务。同时 完成对协调器,路由器,终端的设置 SampleApp_NwkState = (devStates_t)(MSGpkt->hdr.status); //if ( (SampleApp_NwkState == DEV_ZB_COORD)//实验中协调器只接收数据所以取消发送事件 if ( (SampleApp_NwkState == DEV_ROUTER) || (SampleApp_NwkState == DEV_END_DEVICE) ) {//这个定时器只是为发送周期信息开启的,设备启动初始化后从这里开始触发第一个周期信息的发送,然后周而复始下去 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 );//指针指向下一个放在缓冲区的待处理的事件,返回 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_SendPeriodicMessage()处理完当前的周期性事件,然后启动定时器 开启下一个周期性事情,这样一种循环下去,也即是上面说的周期性事件了,可以做为传感器定时采集、上传任务 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; } |
//接收数据,参数为接收到的数据 void SampleApp_MessageMSGCB( afIncomingMSGPacket_t *pkt ) { uint16 flashTime; byte buf[3]; switch ( pkt->clusterId )//判断簇 ID { case SAMPLEAPP_PERIODIC_CLUSTERID://收到广播数据 osal_memset(buf, 0 , 3); osal_memcpy(buf, pkt->cmd.Data, 2);//复制数据到缓冲区中 if(buf[0]=='D' && buf[1]=='1')//判断收到的数据是否为“D1” { HalLedBlink(HAL_LED_1, 0, 50, 500);//如果是则 Led1 间隔 500ms 闪烁 #if defined(ZDO_COORDINATOR)//协调器收到"D1"后,返回"D1"给终端,让终端 Led1 也闪烁 SampleApp_SendPeriodicMessage(); #endif } else { HalLedSet(HAL_LED_1, HAL_LED_MODE_ON); } break; case SAMPLEAPP_FLASH_CLUSTERID: //收到组播数据 flashTime = BUILD_UINT16(pkt->cmd.Data[1], pkt->cmd.Data[2] ); HalLedBlink( HAL_LED_4, 4, 50, (flashTime / 4) ); break; } } |
void SampleApp_SendPeriodicMessage( void ) { byte SendData[3]="D1";// 调用 AF_DataRequest 将数据无线广播出去 if( AF_DataRequest( &SampleApp_Periodic_DstAddr, &SampleApp_epDesc, SAMPLEAPP_PERIODIC_CLUSTERID, 2, SendData, &SampleApp_TransID, AF_DISCV_ROUTE, AF_DEFAULT_RADIUS ) == afStatus_SUCCESS ) { } else { HalLedSet(HAL_LED_1, HAL_LED_MODE_ON);// Error occurred in request to send. } } |
AF_DataRequest( &SampleApp_Periodic_DstAddr,//发送目的地址+端点地址和传送模式 &SampleApp_epDesc,//源(答复或确认)终端的描述(比如操作系统中任务 ID 等)源 EP SAMPLEAPP_PERIODIC_CLUSTERID,//被 Profile 指定的有效的集群号 2, //发送数据长度 SendData,//发送数据缓冲区 &SampleApp_TransID,//任务ID 号 AF_DISCV_ROUTE,//有效位掩码的发送选项 AF_DEFAULT_RADIUS )//传送跳数,通常设置为AF_DEFAULT_RADIUS 好了,第一次就讲这么多吧,内容很多但非常重要,最好理解后再去做后面的实现,打好坚实的基础后,再去看后面的实验相对容易很多。 |