1.FreeRTOS提供的定时器函数会导致任务的切换,但是在实际的应用程序中可能需要不进行任务切换的延时函数。因此,本文根据FreeRTOS的时钟节拍来设置滴答定时器的计数周期。
2.首先,因为是要修改系统的滴答定时器中断服务函数,所以需要将如下的地方进行注释,负责会出现重复定义的错误。
然后重新修改滴答定时器的中断服务函数,在滴答定时器的中断服务里调用xPortSysTickHandler()。
3.初始化滴答定时器:
首先需要将滴答定时器的时钟频率设置为和FreeRTOS一致,并开启滴答定时器的中断。
前面我们说了 FreeRTOS 的系统时钟是由滴答定时器提供的,那么肯定要根据 FreeRTOS 的 系统时钟节拍来初始化滴答定时器了,delay_init()就是来完成这个功能的。FreeRTOS 的系统时 钟节拍由宏 configTICK_RATE_HZ 来设置,这个值我们可以自由设置,但是一旦设置好以后我 们就要根据这个值来初始化滴答定时器,其实就是设置滴答定时器的中断周期。在基础例程中 滴答定时器的时钟频率设置的是 AHB 的 1/8,这里为了兼容 FreeRTOS 将滴答定时器的时钟频 率改为了 AHB,也就是 72MHz!这一点一定要注意!
4.代码:
(1)delay.c:
#include "delay.h"
static uint16_t fac_ms = 8;
static u32 fac_us;
extern void xPortSysTickHandler(void);
//systickÖжϷþÎñº¯Êý
void SysTick_Handler(void)
{
if(xTaskGetSchedulerState()!=taskSCHEDULER_NOT_STARTED)//ϵͳÒѾÔËÐÐ
{
xPortSysTickHandler();
}
}
//
void delay_init(void)
{
u32 reload;
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK);//Ñ¡ÔñÍⲿʱÖÓ HCLK
fac_us=SystemCoreClock/1000000; //²»ÂÛÊÇ·ñʹÓÃOS,fac_us¶¼ÐèҪʹÓÃ
reload=SystemCoreClock/1000000; //ÿÃëÖӵļÆÊý´ÎÊý µ¥Î»ÎªM
reload*=1000000/configTICK_RATE_HZ; //¸ù¾ÝconfigTICK_RATE_HZÉ趨Òç³öʱ¼ä
//reloadΪ24λ¼Ä´æÆ÷,×î´óÖµ:16777216,ÔÚ72MÏÂ,Ô¼ºÏ0.233s×óÓÒ
fac_ms=1000/configTICK_RATE_HZ; //´ú±íOS¿ÉÒÔÑÓʱµÄ×îÉÙµ¥Î»
SysTick->CTRL|=SysTick_CTRL_TICKINT_Msk; //¿ªÆôSYSTICKÖжÏ
SysTick->LOAD=reload; //ÿ1/configTICK_RATE_HZÃëÖжÏÒ»´Î
SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk; //¿ªÆôSYSTICK
}
void delay_us(uint32_t nus)
{
u32 ticks;
u32 told,tnow,tcnt=0;
u32 reload=SysTick->LOAD; //LOADµÄÖµ
ticks=nus*fac_us; //ÐèÒªµÄ½ÚÅÄÊý
told=SysTick->VAL; //¸Õ½øÈëʱµÄ¼ÆÊýÆ÷Öµ
while(1)
{
tnow=SysTick->VAL;
if(tnow!=told)
{
if(tnow<told)tcnt+=told-tnow; //ÕâÀï×¢ÒâÒ»ÏÂSYSTICKÊÇÒ»¸öµÝ¼õµÄ¼ÆÊýÆ÷¾Í¿ÉÒÔÁË.
else tcnt+=reload-tnow+told;
told=tnow;
if(tcnt>=ticks)break; //ʱ¼ä³¬¹ý/µÈÓÚÒªÑÓ³ÙµÄʱ¼ä,ÔòÍ˳ö.
}
};
}
void delay_xms(uint32_t ms) //·â×°ÈÎÎñÇл»µÄÑÓʱº¯Êý
{
if(xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) //Èç¹ûϵͳÒѾÔÚÔËÐУ¬Ôò¿ªÊ¼ÑÓʱ
{
if(ms >= fac_ms)
{
vTaskDelay(ms / fac_ms);
}
ms %= fac_ms; //µ±OSÎÞ·¨ÌṩÕâôСµÄÑÓʱʱ£¬Ê¹ÓÃÆÕͨÑÓʱ
}
delay_ms((uint32_t)(ms*1000)); //ÆÕͨÑÓʱ
}
(2)delay.h:
#ifndef __DELAY_H
#define __DELAY_H
#include "stm32f10x.h"
#include "FreeRTOS.h"
#include "task.h"
void delay_init(void);
void delay_us(uint32_t us); //ÑÓʱ΢Ãë
void delay_ms(uint32_t ms); //ÑÓʱºÁÃë
void delay_xms(uint32_t ms); //·â×°ÈÎÎñÇл»µÄÑÓʱº¯Êý
#endif
5.总结:
使用如上的操作步骤就可以设好不进行任务切换的延时函数。需要注意的是将滴答定时器的时钟频率和FreeRTOS设置为一致,并在滴答定时器的中断服务函数里调用FreeRTOS的xPortSysTickHandler()。