活到老,学到老!
分类: 嵌入式
2014-08-10 22:05:03
首先看一下hal_led.h头文件中的一些宏定义,其中定义了四个LED,分别是HAL_LED_1,HAL_LED_2,HAL_LED_3,HAL_LED_4,分别对应板子上的Green,Red,Yellow,Blue四个LED,然后定义了五种LED模式,HAL_LED_MODE_OFF,灯灭,HAL_LED_MODE_ON,灯亮,HAL_LED_MODE_BLINK,灯闪烁,HAL_LED_MODE_FLASH,灯闪亮,在这里,当调用HalLedSet (uint8 leds, uint8 mode)这个函数就会看到HAL_LED_MODE_BLINK和HAL_LED_MODE_FLASH的区别。HAL_LED_MODE_TOGGLE,灯状态切换。还定义了LED的一些默认参数,HAL_LED_DEFAULT_MAX_LEDS,LED最大个数为4个,HAL_LED_DEFAULT_DUTY_CYCLE,LED闪烁的默认亮灭的占空比,HAL_LED_DEFAULT_FLASH_COUNT,默认的闪烁次数,HAL_LED_DEFAULT_FLASH_TIME,默认的闪烁一次的时间为1000,这个是相对osal_systemClock这个系统tick的,具体单位时间是多少还要看用于tick的定时器,先不管,以后再分析。
再看hal_led.c这个源文件,其中定义了HalLedControl_t的结构体,这个结构体主要是对led控制的一些参数,
typedef struct {
uint8 mode; /* Operation mode */
uint8 todo; /* Blink cycles left */
uint8 onPct; /* On cycle percentage */
uint16 time; /* On/off cycle time (msec) */
uint32 next; /* Time for next change */
} HalLedControl_t;
看这个结构体,mode为led的操作模式,就是头文件中定义的那5种mode,todo即为LED剩余闪烁的次数,onPct为LED闪烁的亮的时间所占的比例,time即为LED每一次闪烁的时间,next为LED作出下一次转变的时间,其单位是相对于系统的tick即osal_systemClock这个系统变量。然后定义了HalLedStatus_t这个结构体,其中HalLedControl_t HalLedControlTable[HAL_LED_DEFAULT_MAX_LEDS]是对四个LED的控制情况的数组,sleepActive是指在系统睡眠时候是否启用LED,如果是则为true,否则为false。接下来看HalLedState这个全局变量记录的是LED上次更新时候的状态,通过后面的代码,我的理解是HalLedState的低四位分别表示四个LED,如果某一位为1,则它上次的状态为ON,否则为OFF。HalSleepLedState这个全局变量主要是记录了系统进入睡眠模式之前的四个LED的状态。preBlinkState这个全局变量记录了LED在进入闪烁模式之前的状态。然后定义了这个HalLedStatus_t结构体的全局变量HalLedStatusControl记录四个LED的控制状态。
HalLedInit这个函数式LED的初始化,调用HalLedSet (HAL_LED_ALL, HAL_LED_MODE_OFF)将四个LED置OFF,然后HalLedStatusControl.sleepActive = FALSE即在睡眠状态下不启用LED;下面看下HalLedSet这个驱动函数:
uint8 HalLedSet (uint8 leds, uint8 mode)
{
#if (defined (BLINK_LEDS)) && (HAL_LED == TRUE)
uint8 led;
HalLedControl_t *sts;
switch (mode)
{
case HAL_LED_MODE_BLINK:
/* Default blink, 1 time, D% duty cycle */
HalLedBlink (leds, 1, HAL_LED_DEFAULT_DUTY_CYCLE, HAL_LED_DEFAULT_FLASH_TIME);
break;
case HAL_LED_MODE_FLASH:
/* Default flash, N times, D% duty cycle */
HalLedBlink (leds, HAL_LED_DEFAULT_FLASH_COUNT, HAL_LED_DEFAULT_DUTY_CYCLE, HAL_LED_DEFAULT_FLASH_TIME);
break;
case HAL_LED_MODE_ON:
case HAL_LED_MODE_OFF:
case HAL_LED_MODE_TOGGLE:
led = HAL_LED_1;
leds &= HAL_LED_ALL;
sts = HalLedStatusControl.HalLedControlTable;
while (leds)
{
if (leds & led)
{
if (mode != HAL_LED_MODE_TOGGLE)
{
sts->mode = mode; /* ON or OFF */
}
else
{
sts->mode ^= HAL_LED_MODE_ON; /* Toggle */
}
HalLedOnOff (led, sts->mode);
leds ^= led; //上一个led处理完进入下一个
}
led <<= 1;
sts++;
}
break;
default:
break;
}
#elif (HAL_LED == TRUE)
HalLedOnOff(leds, mode);
#else
// HAL LED is disabled, suppress unused argument warnings
(void) leds;
(void) mode;
#endif /* BLINK_LEDS && HAL_LED */
return ( HalLedState );
}
在这个函数中描述了如何根据不同的mode实现对LED的控制,如果为mode为HAL_LED_MODE_BLINK或HAL_LED_MODE_FLASH,则相应调用HalLedBlink这个函数,不同的模式传进不同的参数。当然这个参数值是默认的。当mode为HAL_LED_MODE_ON、HAL_LED_MODE_OFF、HAL_LED_MODE_TOGGLE之一时,程序里面用一个while循环对四个LED进行相应的处理,其中leds ^= led表示上一个led已经处理完将其清零下次不再处理。在后面的led <<= 1; sts++;两句代码根据四个LED对应不同的低四位看,应该很容易明白。最后函数返回HalLedState即led的当前状态,在上面函数中调用了HalLedOnOff函数,该函数在最后
if (mode)
{
HalLedState |= leds;
}
else
{
HalLedState &= (leds ^ 0xFF);
}
即如果mode不为OFF时,则HalLedState将记录leds为ON,否则将leds中的某位置0,即为OFF状态。
回到HalLedSet这个函数,在mode为HAL_LED_MODE_BLINK或HAL_LED_MODE_FLASH时调用了HalLedBlink这个函数,下面看看它的实现代码
void HalLedBlink (uint8 leds, uint8 numBlinks, uint8 percent, uint16 period)
{
#if (defined (BLINK_LEDS)) && (HAL_LED == TRUE)
uint8 led;
HalLedControl_t *sts;
if (leds && percent && period)
{
if (percent < 100)
{
led = HAL_LED_1;
leds &= HAL_LED_ALL;
sts = HalLedStatusControl.HalLedControlTable;
while (leds)
{
if (leds & led)
{
/* Store the current state of the led before going to blinking */
preBlinkState |= (led & HalLedState);
sts->mode = HAL_LED_MODE_OFF; /* Stop previous blink */
sts->time = period; /* Time for one on/off cycle */
sts->onPct = percent; /* % of cycle LED is on */
sts->todo = numBlinks; /* Number of blink cycles */
if (!numBlinks) sts->mode |= HAL_LED_MODE_FLASH; /* Continuous */
sts->next = osal_GetSystemClock(); /* Start now */
sts->mode |= HAL_LED_MODE_BLINK; /* Enable blinking */
leds ^= led;
}
led <<= 1;
sts++;
}
osal_set_event (Hal_TaskID, HAL_LED_BLINK_EVENT);
}
else
{
HalLedSet (leds, HAL_LED_MODE_ON); /* >= 100%, turn on */
}
}
else
{
HalLedSet (leds, HAL_LED_MODE_OFF); /* No on time, turn off */
}
#elif (HAL_LED == TRUE)
percent = (leds & HalLedState) ? HAL_LED_MODE_OFF : HAL_LED_MODE_ON;
HalLedOnOff (leds, percent); /* Toggle */
#else
// HAL LED is disabled, suppress unused argument warnings
(void) leds;
(void) numBlinks;
(void) percent;
(void) period;
#endif /* BLINK_LEDS && HAL_LED */
}
这个函数中当percent小于100时先Store the current state of the led before going to blinking,将其保存在preBlinkState中,然后分别对sts指针变量中四个元素赋值,如果numBlinks为0,则表示LED持续不停的闪烁。将
sts->next赋值为osal_GetSystemClock(),即系统的tick值,后面会看到这个next的具体含义。最后调用osal_set_event这个函数将HAL_LED_BLINK_EVENT事件传给Hal_TaskID任务,当系统轮询任务时,HAL层任务则有事件要处理。在hal_drivers.c文件中Hal_ProcessEvent,即HAL层的事件处理函数,
if ( events & HAL_LED_BLINK_EVENT )
{
#if (defined (BLINK_LEDS)) && (HAL_LED == TRUE)
HalLedUpdate();
#endif /* BLINK_LEDS && HAL_LED */
return events ^ HAL_LED_BLINK_EVENT;
}
看这里的代码知道,当有LEDblink事件时调用了HalLedUpdate()这个函数,这个函数在hal_led.c文件里面,
void HalLedUpdate (void)
{
uint8 led;
uint8 pct;
uint8 leds;
HalLedControl_t *sts;
uint32 time;
uint16 next;
uint16 wait;
next = 0;
led = HAL_LED_1;
leds = HAL_LED_ALL;
sts = HalLedStatusControl.HalLedControlTable;
/* Check if sleep is active or not */
if (!HalLedStatusControl.sleepActive)
{
while (leds)
{
if (leds & led)
{
if (sts->mode & HAL_LED_MODE_BLINK)
{
time = osal_GetSystemClock();
if (time >= sts->next)//到了该闪烁的时间了
{
if (sts->mode & HAL_LED_MODE_ON)
{
pct = 100 - sts->onPct; /* Percentage of cycle for off */
sts->mode &= ~HAL_LED_MODE_ON; /* Say it's not on */
HalLedOnOff (led, HAL_LED_MODE_OFF); /* Turn it off */
if (!(sts->mode & HAL_LED_MODE_FLASH)) //不是无限闪烁
{
sts->todo--; /* Not continuous, reduce count */
if (!sts->todo) //闪烁次数到
{
sts->mode ^= HAL_LED_MODE_BLINK; /* No more blinks */
}
}
}
else
{
pct = sts->onPct; /* Percentage of cycle for on */
sts->mode |= HAL_LED_MODE_ON; /* Say it's on */
HalLedOnOff (led, HAL_LED_MODE_ON); /* Turn it on */
}
if (sts->mode & HAL_LED_MODE_BLINK)
{
wait = (((uint32)pct * (uint32)sts->time) / 100);
sts->next = time + wait;
}
else
{
/* no more blink, no more wait */
wait = 0;
/* After blinking, set the LED back to the state before it blinks */
HalLedSet (led, ((preBlinkState & led)!=0)?HAL_LED_MODE_ON:HAL_LED_MODE_OFF);
/* Clear the saved bit */
preBlinkState &= (led ^ 0xFF);
}
}
else
{
wait = sts->next - time; /* Time left */
}
if (!next || ( wait && (wait < next) ))
{
next = wait;
}
}
leds ^= led;
}
led <<= 1;
sts++;
}
if (next)
{
osal_start_timerEx(Hal_TaskID, HAL_LED_BLINK_EVENT, next); /* Schedule event */
}
}
}
这个函数只要理解了结构体中几个元素变量的含义,其实很好理解啦!当LED的mode为HAL_LED_MODE_BLINK时,首先time = osal_GetSystemClock();获取系统的tick值,然后比较time和sts->next,如果前者大则表明已经到了LED该闪烁的时间了,此时如果mode为ON(这里面有个技巧,即每次LED闪烁之后mode中记录的都是上次闪烁的LED的状态),则将mode置为OFF,然后调用HalLedOnOff将LED置OFF,如果sts->mode不为HAL_LED_MODE_FLASH,则LED不是无限闪烁模式,即有numBlinks次数的闪烁,在上一个函数中可以看到
if (!numBlinks) sts->mode |= HAL_LED_MODE_FLASH;这句,即numBlinks为0时,将其mode增加HAL_LED_MODE_FLASH,这就说明要无限闪烁了。看这句
else
{
pct = sts->onPct; /* Percentage of cycle for on */
sts->mode |= HAL_LED_MODE_ON; /* Say it's on */
HalLedOnOff (led, HAL_LED_MODE_ON); /* Turn it on */
}
即当mode为HAL_LED_MODE_OFF时,调整pct为ON的比例,然后mode反转,亮LED,如果mode中还有HAL_LED_MODE_BLINK,则说明LED还没有闪烁完,还要接着闪,此时将wait赋值为(((uint32)pct * (uint32)sts->time);sts->next = time + wait;wait为下一次要闪烁时候的等待时间,next为下一次要闪烁的tick值;如果mode中没有
HAL_LED_MODE_BLINK则说明LED已经闪烁完了,将wait清零,然后调用HalLedSet将LED置为闪烁之前的状态。
如果time小于sts->next则闪烁的时间还没到还要继续等待,wait = sts->next - time;将等待时间wait调整。
if (!next || ( wait && (wait < next) ))
{
next = wait;
}
如果next为0则说明是第一次闪烁,则将next置为wait值,如果( wait && (wait < next) )则是某一次闪烁且闪烁时间没到则重新将next赋值为wait。
如果next不为0即还需要下次的闪烁,此时调用osal_start_timerEx函数,此函数在经过next时间之后会向Hal_TaskID任务发送HAL_LED_BLINK_EVENT事件,LED需要继续闪烁。
以上是整个LED驱动的详细解析过程