ZigBee之ZStack协议移植(1)基本使用

  1. LEDApp_ProcessEvent()《LEDApp.c 240行》函数里面case ZDO_STATE_CHANGE:修改代码;后下载不同的代码 协调器CoordinatorEB、路由器RouterEB、终端EndDeviceEB到开发板后,会看的不同的效果(协调器 点亮LED1) (协调器 点亮LED21、LED2 )(协调器 点亮LED2 )。
    在这里插入图片描述
case ZDO_STATE_CHANGE:
          LEDApp_NwkState = (devStates_t)(MSGpkt->hdr.status);
          if ( (LEDApp_NwkState == DEV_ZB_COORD)//协调器
              || (LEDApp_NwkState == DEV_ROUTER)//路由器
              || (LEDApp_NwkState == DEV_END_DEVICE) )//终端
          {
            // Start sending "the" message in a regular interval.
//            osal_start_timerEx( LEDApp_TaskID,
//                                LEDApp_SEND_MSG_EVT,
//                                LEDApp_SEND_MSG_TIMEOUT );
            
          }
          if(LEDApp_NwkState == DEV_ZB_COORD)//协调器
          {
            P0SEL &=~0x12;//LED引脚为通用口 p0~1 4
            P0DIR |= 0x12; //输出模式
            P0_4 = 0;//点亮led1
          }
           if(LEDApp_NwkState == DEV_ROUTER)//路由器
          {
            P0SEL &=~0x12;//LED引脚为通用口 p0~1 4
            P0DIR |= 0x12; //输出模式
            P0_4 = 0;//点亮led1
            P0_1 = 0;//点亮led2
          }
           if(LEDApp_NwkState == DEV_END_DEVICE)//终端
          {
            P0SEL &=~0x12;//LED引脚为通用口 p0~1 4
            P0DIR |= 0x12; //输出模式
            P0_1 = 0;//点亮led2
          }
  1. 使用函数osal_set_event(LEDApp_TaskID,LEDApp_SEND_MSG_EVT);:处理LEDApp_TaskID的LEDApp_SEND_MSG_EVT事件函数《LEDApp.c 343行》。
    osal_start_timerEx(LEDApp_TaskID,LEDApp_MY_EVT,5000);:等待5000us处理LEDApp_TaskID的 LEDApp_SEND_MSG_EVT事件函数《LEDApp.c 343行》。
    注:我这做了修改 跳到这里是就是点亮点亮LED2,osal_set_event函数不会延时,osal_start_timerEx函数会有一定延时(更具自己设定时间,我这是5000us延时时间)
  if ( events & LEDApp_SEND_MSG_EVT )
  {
//    // Send "the" message
//    LEDApp_SendTheMessage();
//
//    // Setup to send message again
//    osal_start_timerEx( LEDApp_TaskID,
//                        LEDApp_SEND_MSG_EVT,
//                        LEDApp_SEND_MSG_TIMEOUT );
      P0SEL &=~0x12;//LED引脚为通用口 p0~1 4
      P0DIR |= 0x12; //输出模式
      P0_1 = 0;//点亮led2
    // return unprocessed events
    return (events ^ LEDApp_SEND_MSG_EVT);
  }
  1. 添加自己的事件
    官方函数只给了两个事件<LEDApp_SEND_MSG_EVT、LEDApp_RTOS_MSG_EVT>(不同ZStack版本有所不同);在《LEDApp.h 74行》定义。
    在这里插入图片描述
    注:这里的0x0001为 0000 0000 0000 0001 ;在定义事件值时必须是16位中一位为1其他必须为0;<#define LEDApp_MY_EVT 0x0004>我自己定义的事件(0000 0000 0000 0100);这里是定义事件值,那我们就可以在《LEDApp.c 345行左右的if ( events & LEDApp_SEND_MSG_EVT )》前后模仿写出基础格式
if ( events & LEDApp_MY_EVT )
  {
   //功能....
  return (events ^ LEDApp_MY_EVT);
  }

比如:我这一样还是点亮LED2,和第2点,使用方法一样osal_start_timerEx(LEDApp_TaskID,LEDApp_MY_EVT,000);

 if ( events & LEDApp_MY_EVT )
  {
    P0SEL &=~0x12;//LED引脚为通用口 p0~1 4
    P0DIR |= 0x12; //输出模式
    P0_1 = 0;//点亮led2
    return (events ^ LEDApp_MY_EVT);
  }
  1. 消息
    1)根据上一条可以得出,每个任务最多只能定义16个事件(0000 0000 0000 0000),而在系统运行的时候是远远有空的超过16条事件的,这样就完全不够用了,所以便引出了消息。
    消息的处理原理:
    在《comdef.h 122行》可以看到系统定义了一个系统事件#define SYS_EVENT_MSG 0x8000 // A message is waiting event
    比如当应用层任务来处理某个事务的时候,首先是给应用层发送一个消息,调用osal_set_event(LEDApp_TaskID,SYS_EVENT_MSG);,这样一来,应用层就会进入SYS_EVENT_MSG事件里进行处理,在这个事件里又将判断到底刚才引发产生SYS_EVENT_MSG事件是哪一种类型的消息,然后根据消息的类型做出相应的处理。
    然而消息的类型可以根据自己的需求随意定义数量,这样消息的类型就很多了,那么应用层处理的事件种类就很多了。
    我们可以看到在《ZComDef.h 376行》开始定义了很对消息类型;同时在《LEDApp.c uint16 LEDApp_ProcessEvent( uint8 task_id, uint16 events )》中就有处理消息的函数<case ZDO_CB_MSG:case KEY_CHANGE:case AF_DATA_CONFIRM_CMD:>等等,
    在这里插入图片描述2)现在我们自己设计个消息:
    我们在协调器里面定义个按钮KEY_CHANGE改变的消息:
if(LEDApp_NwkState == DEV_ZB_COORD)//协调器
          {
            P0SEL &=~0x12;//LED引脚为通用口 p0~1 4
            P0DIR |= 0x12; //输出模式
            P0_4 = 0;//LED1亮      
            keyChange_t *magPtr;
            //定义个按钮改变的消息
            magPtr = (keyChange_t *)osal_msg_allocate(sizeof(keyChange_t));
            if(magPtr)
            {
              //给这个消息填写相关的值,类型是按钮状态改变KEY_CHANGE
              magPtr->hdr.event = KEY_CHANGE;
              magPtr->keys = 3;//消息里面的内容是3
              //把发送给应用层LEDApp_TaskID的消息投到消息的队列,并且 osal_set_event( destination_task, SYS_EVENT_MSG );
               osal_msg_send(LEDApp_TaskID,(uint8 *)magPtr);
            }            
//            osal_set_event(LEDApp_TaskID,LEDApp_SEND_MSG_EVT);
//            //处理LEDApp_SEND_MSG_EVT事件函数(343)行
            osal_start_timerEx(LEDApp_TaskID,LEDApp_MY_EVT,2000);
            //等待2000us处理LEDApp_TaskID的 LEDApp_SEND_MSG_EVT事件函数(343)行
          }

注:其中在osal_msg_send(LEDApp_TaskID,(uint8 *)magPtr);《OSAL.c 493行》函数里,有一个osal_set_event( destination_task, SYS_EVENT_MSG );,也就是说运行到这,系统又会回到《LEDApp.c 239行》的uint16 LEDApp_ProcessEvent( uint8 task_id, uint16 events ),又因为是KEY_CHANGE事件,程序就会运行到《LEDApp.c 262行左右》case KEY_CHANGE:里面,LEDApp_HandleKeys( ((keyChange_t *)MSGpkt)->state, ((keyChange_t *)MSGpkt)->keys );这个函数就将处理对应的keys ,我这修改为:
static void LEDApp_HandleKeys( uint8 shift, uint8 keys ) { osal_start_timerEx(LEDApp_TaskID,LEDApp_MY_EVT,2000); //将运行等2000us到LEDApp_MY_EVT事件去。 }
通过前我自己写的LEDApp_MY_EVT事件处理函数,最后效果为LED1灭、LED2亮;
在这里插入图片描述
2. 生成.hex文件
在这里插入图片描述在这里插入图片描述
在这里插入图片描述OSAL原理
1、应用层是一个任务它有一个系统分配给他的唯一的编号叫任务ID
2、任务可以处理实践,处理事件的这些代码都在一个函数里,这个函数叫做任务事件处理函数。
3、应用层任务还有一个2字节的变量 任务事件变量
应用层任务事件变量和应用层定义的事件的关系:如果事件变量与上某个事件的宏值为1时,那么应用层任务将要处理这个事件。
而系统在运行的时候会不断的去读取应用层任务事件变量,当它发现这个变量为0时,就认为应用层任务当前没有事件需要处理;反之,任务应用层任务将要有事件需要被处理,它就会去调用应用层事件处理函数uint16 LEDApp_ProcessEvent( uint8 task_id, uint16 events ),并且把任务变量的值传给events ,在这个事件处理函数的,这个变量events会分别和这个应用层所定义的所有事件宏值进行与操作,发现结果为1,那么就去执行这个事件的处理函数代码。
几乎每个层都是一个任务 那么每一层都有一个任务ID 任务事件处理函数 任务事件变量
. 所有的任务事件处理函数—》放在数组里面 :tasksArr[]《OSAL_LEDApp.c 72行》
. 所有的任务事件变量—》放在变量数组里面 :uint16 *tasksEvents;《OSAL_LEDApp.c 72行》
. 任务ID系统分配规则:tasksArr[0] 就意味着0号事件处理函数ID 对应 变量数组[0]0号任务事件

const uint8 tasksCnt = sizeof( tasksArr ) / sizeof( tasksArr[0] );
//tasksCnt 为有多少任务

. osal_init_system();《ZMain.c 116行》初始化操作系统 -> osalInitTasks();《OSAL.c 999行》初始化任务函数-> 将分配了任务事件ID
. osal_start_system();《ZMain.c 140行》启动操作系统 -> 《OASL.c 1020行》这里将是个死循环函数,也就意味着整个系统都将在循环执行此处函数。
在这里插入图片描述–>osal_run_system();《OASL.c 1040行》

void osal_run_system( void )
{
  uint8 idx = 0;

  osalTimeUpdate();
  Hal_ProcessPoll();

  do {
    if (tasksEvents[idx])  // Task is highest priority that is ready.
    {
      break;//当有任务事件时(非0),就会跳出,此次的idx值就是任务ID号,
    }
  } while (++idx < tasksCnt);//从tasksEvents[0]--tasksEvents[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 );//找到任务事件不为0,将会转到对应的任务事件处理函数《LEDApp.c `uint16 LEDApp_ProcessEvent( uint8 task_id, uint16 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
}
  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值