|
接我上面的:
上面这个函数是对key的配置函数,使能行的外部引脚中断,指定回调函数,使用中断方式检测按键,关于那两个启动和消除定时器的函数,也要注意他的作用。
上个程序中有个关键的回调函数,这个我们要分析下,注册回调函数是在main函数的倒数第二句程序,HalKeyConfig(RSA_KEY_INT_ENABLED, RSA_KeyCback);看后面这个RSA_KeyCback,这可不是个一般的参数,他是个函数,他的程序就不贴出来了,他的功能就是检测按键,检测到之后,然后调用:
RTI_SendDataReq( rsaDestIndex, profileId, vendorId, txOptions, len, pData);
从这个函数的表面意思就知道,他是个发送数据的函数,注意开头是RTI,现在只是发到RTI这层了,还要发到网络层,(不过这里我看他的结构框架,RemoTI的应用框架和网络层是写在一起的),然后发送到物理层,然后通过物理层向空中发射出去,这里的代码没办法贴了,因为他都封掉了,比较郁闷的一件事情,所以还是开源的好啊,因此非常支持outman现在搞开源的zigbee,题外话了。。。
写了这么多,看了是不是有很多问题,比如中断函数在哪里,他在里面做了什么,按键发送那个函数又是怎么调用的???等等一系列问题,好的 下面我们再从最上面的图开始整理思路,同时将没有涉及到的程序贴出来,
第一步:开始
第二步:按键的配置
第三步:产生中断,这里有程序没讲,贴出来,在hal_key,c这个文件中有个中断函数,HAL_ISR_FUNCTION,具体程序如下:
HAL_ISR_FUNCTION( halKeyPort0Isr, P0INT_VECTOR )
{
halProcessKeyInterrupt();//这里主要的作用是消抖
#if HAL_KEY
/* Make sure that we clear all enabled, but unused P0IFG bits.
* For P0 we can only enable or disable high or low nibble, not bit by
* bit. For P1 and P2 enabling of single bits are possible, therefore
* will not any unused pins generate interrupts on P1 or P2.
* We could have checked for low and high nibble in P0, but this
* isn't necessary as long as we only clear unused pin interrupts.
*/
P0IFG = (uint8) ~(HAL_KEY_P0INT_LOW_USED | HAL_KEY_POINT_HIGH_USED);
P0IF = 0;
CLEAR_SLEEP_MODE();
#endif
这里这是调用了一个函数halProcessKeyInterrupt,下面的程序不用管先,再贴这个函数的程序,看看他在做什么,
void halProcessKeyInterrupt (void)
{
#if (HAL_KEY == TRUE)
//首先通过中断标志位来看看是否真的有键按下
if (HAL_KEY_ROW_PXIFG & HAL_KEY_ROW_BITS)//如果有键按下进来
{
// Disable interrup 禁用行所有行端口的位中断
HAL_KEY_ROW_ICTL &= (uint8) ~HAL_KEY_ROW_ICTLBITS;
// interrupt flag has been set清除中断标志位
HAL_KEY_ROW_PXIFG = (uint8) (~HAL_KEY_ROW_BITS); // clear interrupt flag
//注意我们再key初始化函数中也有定义这个halKeyTimerRunning参数哦,为false
//也就是开始时没有处在运行状态的
if (!halKeyTimerRunning)//如果定时器没有处在运行状态,那么让定时器运行起来
{
halKeyTimerRunning = TRUE;
osal_start_timerEx (Hal_TaskID, HAL_KEY_EVENT, HAL_KEY_DEBOUNCE_VALUE);//启动定时器,为了消抖
}
// Enable interrupt 使能中断
HAL_KEY_ROW_ICTL |= HAL_KEY_ROW_ICTLBITS;
}
#endif /* HAL_KEY */
}
我想当你看到这个osal_start_timerEx (Hal_TaskID, HAL_KEY_EVENT, HAL_KEY_DEBOUNCE_VALUE);这句话的时候,就到了图中的第四步
第四步:启动消抖定时器
第五步:定时器溢出
他所做的事情,在定时器溢出之后,他会将相应的标志位置位(注意不是中断标志位),首先贴出osal_start_timerEx (Hal_TaskID, HAL_KEY_EVENT, HAL_KEY_DEBOUNCE_VALUE)的代码:
uint8 osal_start_timerEx( uint8 taskID, uint16 event_id, uint16 timeout_value )
{
halIntState_t intState;
osalTimerRec_t *newTimer;
HAL_ENTER_CRITICAL_SECTION( intState ); // Hold off interrupts.
// Add timer这个是我们要关注的地方,添加一个定时器
newTimer = osalAddTimer( taskID, event_id, timeout_value );
HAL_EXIT_CRITICAL_SECTION( intState ); // Re-enable interrupts.
return ( (newTimer != NULL) ? SUCCESS : NO_TIMER_AVAIL );
}
这个函数中我们关键是看osalAddTimer,到此我们就增加了一个key的定时器了,再往下的代码,就不贴了,定时器已经开始计时了,过了消抖的时间之后,下一步要怎么办呢,这个是最关键的了,这时我们看到了启动系统的函数:
void osal_start_system( void )
{
#if !defined ( ZBIT ) && !defined ( UBIT )
for(;;) // Forever Loop
#endif
{
uint8 idx = 0;
osalTimeUpdate(); //这里是在扫描哪个事件被触发了,然后置相应的标志位
Hal_ProcessPoll(); // This replaces MT_SerialPoll() and osal_check_timer().
/*通过这个tasksEvents可以知道是哪个层的事件发生了,接着就是调用相应的层处理
函数,在各层出来函数中还有小的事件,这就需要用events再进一步判断了*/
do {
if (tasksEvents[idx]) // Task is highest priority that is ready.
{
break;
}
} while (++idx < tasksCnt);
//判断是否有事件产生,如果有进来if
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); //恢复总中断
//调用相应的处理函数,返回的是未处理的事件
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
}
}
如果没有任何事件发生的时候,在for中一直死循环。
看到for这个死循环中的第一个函数osalTimeUpdate();,在上一步中我们讲到了定时器溢出,
溢出了再怎么办呢?osalTimeUpdate这个函数告诉你溢出之后该怎么办了,好了贴代码: |
|