原创 【原创】ZigBee学习之35——按键部分及系统调用时钟的分析2

2010-2-17 23:56 2818 4 4 分类: MCU/ 嵌入式

  /* Timer2 最为系统任务的时钟系统*/<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />


   OnboardTimerIntEnable = FALSE;


        HalTimerConfig (OSAL_TIMER,                        // 8bit timer2


                  HAL_TIMER_MODE_CTC,                 // Clear Timer on Compare


                  HAL_TIMER_CHANNEL_SINGLE,           // Channel 1 - default


                  HAL_TIMER_CH_MODE_OUTPUT_COMPARE,   // Output Compare mode


                  OnboardTimerIntEnable,              // Use interrupt


                  Onboard_TimerCallBack);             // Channel Mode


//函数执行后得到系统任务时钟(HAL_TIMER_2)的配置结构:


    halTimerRecord[hwtimerid].configured           = TRUE;


    halTimerRecord[hwtimerid].opMode        = HAL_TIMER_MODE_CTC;


    halTimerRecord[hwtimerid].channel         = HAL_TIMER_CHANNEL_SINGLE;


    halTimerRecord[hwtimerid].channelMode       = HAL_TIMER_CH_MODE_OUTPUT_COMPARE;


    halTimerRecord[hwtimerid].intEnable              = FALSE;


    halTimerRecord[hwtimerid].callBackFunc       = Onboard_TimerCallBack;


//Onboard_TimerCallBack()为处理系统时钟的回调函数,这个函数什么时候会被调用呢?是个问题


//一些相关宏的定义如下:


//#define HAL_TIMER_MODE_CTC        0x02    // Clear Timer On Compare


//#define HAL_TIMER_CHANNEL_SINGLE   0x01    // Single Channel - default


//#define HAL_TIMER_CH_MODE_OUTPUT_COMPARE  0x02    // Channel Mode Output_Compare


//现在系统任务时钟所需要使用的定时器已经配置好了,但是如何启动的呢?启动定时器必须要对TxCTL寄存器启动位置位才能启动啊!我们回到ZMain.c中的main()中,在InitBoard( OB_COLD );下面接着执行的是HalDriverInit()函数,在此函数中最开始就是初始化了定时器HalTimerInit();进去一看发现任然没有启动定时器!仅仅只是对定时器的寄存器进行了一个别名配置而已,增加了如下的配置:


  halTimerRecord[HW_TIMER_4].prescale    = HAL_TIMER4_8_PRESCALE;


  halTimerRecord[HW_TIMER_4].clock       = HAL_TIMER_32MHZ;


  halTimerRecord[HW_TIMER_4].prescaleVal = HAL_TIMER4_8_PRESCALE_VAL;


    /* Setup Timer4 Channel structure */


  halTimerChannel[HW_TIMER_4].TxCCTL =  TCHN_T4CCTL;


  halTimerChannel[HW_TIMER_4].TxCCL =   TCHN_T4CCL;


  halTimerChannel[HW_TIMER_4].TxCCH =   TCHN_T4CCH;


  halTimerChannel[HW_TIMER_4].TxOVF =   TCNH_T4OVF;


  halTimerChannel[HW_TIMER_4].ovfbit =  TCHN_T4OVFBIT;


  halTimerChannel[HW_TIMER_4].intbit =  TCHN_T4INTBIT;


那么是不是初始在main()中的osal_init_system();OSAL.c】函数中,好,那我们来看一下,是不是这里启动了系统时钟定时器。在这个函数中又调用了一个函数嫌疑最大:osalTimerInit();OSAL_Timers.c


void osalTimerInit( void )


{


//初始化了两个变量


//#define TICK_TIME   1000


//#define TIMER_DECR_TIME    1


  tmr_count = TICK_TIME;


  tmr_decr_time = TIMER_DECR_TIME;


 


  //这里是停止了系统时钟定时器OSAL_TIMER


  osal_timer_activate( false );


  timerActive = false;


 


  osal_systemClock = 0;


}


//看来在这个函数中也没有启动系统定时器,反而调用了停止系统时钟定时器的函数,莫非是黎明前的黑暗,呵呵!接着在main()函数中找嫌疑犯!再往下是打开了总中断osal_int_enable( INTS_ALL );剩下的可能在就是osal_start_system()中启动系统时钟了,我们来找一下。


//在此函数中调用了Hal_ProcessPoll ()hal_drivers.c


void Hal_ProcessPoll ()


{


  /* Timer Poll */


  HalTimerTick(); //这个函数又是个跟时钟相关的函数,会不会在这里面启动系统时钟呢?来看一下


  /* UART Poll */


#if (defined HAL_UART) && (HAL_UART == TRUE)


  HalUARTPoll();


#endif


}


//hal_timer.c


void HalTimerTick (void)


{


//前面调用的InitBoard()中已经设置halTimerRecord[hwtimerid].intEnable         = FALSE;


//再根据HAL_TIMER_2 --> HW Timer 4,所以会执行以下函数:


…………


  if (!halTimerRecord[HW_TIMER_4].intEnable)


  {


    halProcessTimer4 ();


  }


}


//继续跟踪。这个函数在定时器发生中断的时候就会执行,因为在定时器4中断中有调用此函数:


HAL_ISR_FUNCTION( halTimer4Isr, T4_VECTOR )


{halProcessTimer4 ();}


void halProcessTimer4 (void)


{


  if (halTimerRecord[halTimerRemap(HAL_TIMER_2)].channelMode == HAL_TIMER_CH_MODE_OUTPUT_COMPARE)


  {


    if (TIMIF & TIMIF_T4CH0IF)


{//定时器4通道0产生中断


      TIMIF &= ~(TIMIF_T4CH0IF);    //清除中断标志


      halTimerSendCallBack (HAL_TIMER_2, HAL_TIMER_CHANNEL_A, HAL_TIMER_CH_MODE_OUTPUT_COMPARE);


//调用前面初始化的回调函数,对系统时钟+1


    }


    if (TIMIF & TIMIF_T4CH1IF)


    {


      TIMIF &= ~(TIMIF_T4CH1IF);


      halTimerSendCallBack (HAL_TIMER_2, HAL_TIMER_CHANNEL_B, HAL_TIMER_CH_MODE_OUTPUT_COMPARE);


    }


  }


…………


}


//貌似还没有看到启动系统时钟的定时器啊!呵呵别急,我们现在回过来看按键程序,我们接着分析这个函数:


byte osal_start_timerEx( byte taskID, UINT16 event_id, UINT16 timeout_value )


{


  halIntState_t intState;


  osalTimerRec_t *newTimer;


 


  HAL_ENTER_CRITICAL_SECTION( intState );  // Hold off interrupts.


 


  //为此任务和事件填充一个新定时器数据结构,这个结构中将包含计数时间,要传递的时间,接收事件的任务


  newTimer = osalAddTimer( taskID, event_id, timeout_value );


  if ( newTimer )


  {


#ifdef POWER_SAVING


    // Update timer registers


    osal_retune_timers();


    (void)timerActive;


#endif


   


    if ( timerActive == FALSE )


    {//这里要注意了,回想一下我们对系统时钟启动的分析,只发现停止了系统时钟,初始timerActive == FALSE,现在终于启动定时器了。而且处于开中断的状态下,这样的话当计时器溢出的时候当然会产生中断就去执行中断函数了。所以我们得出系统时钟也不是每时每刻都在运行的!


      osal_timer_activate( TRUE );


    }


  }


 


  HAL_EXIT_CRITICAL_SECTION( intState );   // Re-enable interrupts.


 


  return ( (newTimer != NULL) ? ZSUCCESS : NO_TIMER_AVAIL );


}


  }


//我们再来看一下中断服务函数,我的是用P1口:


HAL_ISR_FUNCTION( halKeyPort1Isr, P1INT_VECTOR )


{//刚开始是对芯片版本的判断,这个部重要了,可以去掉判断直接清除P1IF标志位


  if( CHVER <= REV_D )


  {


    P1IF = 0;


  }


//这个函数是清除端口每一位的子中断,然后继续进行先前的任务,即发送按键事件HAL_KEY_EVENT给指定的任务


  halProcessKeyInterrupt();


 


  if( CHVER >= REV_E )


  {//大于版本E的清除中断后进入睡眠模式


    P1IF = 0;


    CLEAR_SLEEP_MODE();


  }


}


//注意在ZStack<?xml:namespace prefix = st1 ns = "urn:schemas-microsoft-com:office:smarttags" />1.4.3-1.2.1中对于任务的管理是通过任务表来进行的,每个任务由初始化函数和事件处理函数构成,任务的初始化通过osalInitTasks()进行,然后OSAL利用任务表来调用任务函数,注意任务表中的顺序必须和任务初始化的顺序一致


//任务处理函数表,在后面可以添加自己的任务处理函数【sapi.c】


const pTaskEventHandlerFn tasksArr[] = {


  macEventLoop,


  nwk_event_loop,


  Hal_ProcessEvent,


#if defined( MT_TASK )


  MT_ProcessEvent,


#endif


  APS_event_loop,


  ZDApp_event_loop,


 


  SAPI_ProcessEvent


};


void osalInitTasks( void )


{


  uint8 taskID = 0;


 


  tasksEvents = (uint16 *)osal_mem_alloc( sizeof( uint16 ) * tasksCnt);


  osal_memset( tasksEvents, 0, (sizeof( uint16 ) * tasksCnt));


 


  macTaskInit( taskID++ );


  nwk_init( taskID++ );


  Hal_Init( taskID++ );


#if defined( MT_TASK )


  MT_TaskInit( taskID++ );


#endif


  APS_Init( taskID++ );


  ZDApp_Init( taskID++ );


  SAPI_Init( taskID );


}


//有一条主线:osal_set_event()将事件存入tasksEvents数组中【或者:通过HalTimerConfig()配置定时器的回调函数——对指定任务和事件调用osal_start_timerEx()等指定超时时间到达后通过调用回调函数来调用osal_set_event()】——系统主循环中检查到tasksEvents 数组中有事件——调用相应的接收事件的函数(tasksArr[idx])( idx, events ) ——Hal_ProcessEvent()检查是否是按键事件—— HalKeyPoll()得到按键值——调用按键回调函数OnBoard_KeyCallback(),回调函数在InitBoard()中通过调用HalKeyConfig()来配置——OnBoard_SendKeys()构造消息包,向应用发送按键信息,同时发送了KEY_CHANGE事件标志,【之前必须通过RegisterForKeys()注册接收按键事件的任务ID,此函数执行才有意义】——osal_msg_send()对对应任务发送消息——发送成功返回OnBoard_KeyCallback()进行相关按键的处理。这以上就是整个任务系统的执行流程。对于系统定时器的理解我认为系统时钟所用定时器并不是每时每刻都到运行的,而且它的作用是指定一个安全合适的系统时间间隔期。

PARTNER CONTENT

文章评论0条评论)

登录后参与讨论
EE直播间
更多
我要评论
0
4
关闭 站长推荐上一条 /3 下一条