您的位置:首页 > 其它

3.关于延时函数的配置

2018-01-02 22:48 302 查看
接下来简单谈下如何配置延时函数(使用SysTick)
参考  http://blog.csdn.net/luodonghuan1/article/details/46573501 
关于延时函数有以下几种方案
1.不依赖于硬件,实现软件延时
2.利用SysTick,实现硬件演示,依赖于时钟配置

/***********************************************************************************************/

1.使用这种延时函数的情况大多是对时序要求不严格的情况,大多都是为了让单片机打发一些时间而已,
然后实现某种功能,比如,初学MCU,第二课,实现延时函数点灯。
以下是一些相对较准的软件延时函数,从来只有相对准确,而没有绝对准确的东西
//微秒延时函数,
void delay_us(u16 time)
{
u16 i=0;
while(time--)
{
i=10;  //自己定义
while(i--) ;
}
}

//毫秒延时函数
void delay_ms(u16 time)
{
u16 i=0;
while(time--)
{
i=12000;  //自己定义
while(i--) ;
}
}

/***********************************************************************************************/

2.此种情况大多应对时序比较严格的情况下,比如为了描述某个IC的时序,就必须要用到这种延时函数了,
当然这并不是绝对的,有些情况下使用SysTick也可能不如软件延时准确,使用软件延时就比较好,一切看需求
扯了这么多,接下来简单谈下怎么配置MS级的延时函数和US级的延时函数
首先说一下 ST中文参考手册中对SysTick介绍的很简单,如果不仔细查找,基本你获取不到很多有关他的信息
以下引用原话
/*
1.RCC 向 Cortex 系统定时器 (SysTick) 馈送 8 分频的 AHB 时钟 (HCLK)。 SysTick 可使用
此时钟作为时钟源,也可使用 HCLK 作为时钟源,具体可在 SysTick 控制和状态寄存器中配置。
2.SysTick 校准值设置为 18750。当 SysTick 时钟设置为 18.75 MHz(HCLK/8, HCLK 设为
150 MHz),会产生 1 ms 时间基准。
*/

好吧,第一句还有点用,看时钟树,意思就是说,SysTick时钟来源于HCLK,可以实现1分频或者8分频,
可以在SysTic寄存器里面配置.这里再简单提一下系统时钟,
有HSE (8M)|| HSI (16M)|| LSE (32.768K)|| LSI(32K)  (LSE && LSI 都可以用来做位RTC的时钟,但是LSI只能用来做看门狗时钟)
然后可以选择使用哪种时钟源(HSE || HSI),一般来说都是选择使用HSE最稳定,然后使用PLL实现倍频,
就是 PLL / M * N  / P / Q 配置这四个参数,之后就是配置AHB APB1 APB2,
然后不管是接外设还是使用定时器,时钟都来源于这几个,HCLK是来源于SYSTICK的,AHB分频系数一般设置为1
因此HCLK = SYSTICK

其实吧,很多ST官方手册上面都没有介绍,比如SysTick的寄存器,NVIC的寄存器,还有一些其他的东西
SysTick有四个寄存器

__IOM uint32_t CTRL;                   /*!< Offset: 0x000 (R/W)  SysTick Control and Status Register */
__IOM uint32_t LOAD;                   /*!< Offset: 0x004 (R/W)  SysTick Reload Value Register */
__IOM uint32_t VAL;                    /*!< Offset: 0x008 (R/W)  SysTick Current Value Register */
__IM  uint32_t CALIB;                  /*!< Offset: 0x00C (R/ )  SysTick Calibration Register */

第一个是控制和状态寄存器 (16位,一般只用最低位0,使能)
第二个是重装载寄存器     (24位)
第三个是存储当前值寄存器 (24位)
第四个是自校正寄存器(一般用不到)
以上寄存器具体可以去查下,这里就不给出了
然后就是配置的问题

思路很简单
1.给重装载寄存器装载需要计时的时间
2.把VAL寄存器中的值清零
3.CTRL使能计数
4.等待直到计时完毕
5.失能CTRL
6.清零VAL,为下次计时做准备

是吧,很简单吧,其实我更愿意称呼它为简单的定时器,
然后就是翻译成寄存器了。但是还是要注意几个问题的,

1.重装载需要的时间得根据当前HCLK的频率来设置
其实这一步也不是很懂,看了不管是HAL库还是ATK的配置都是HCLK / 8 * num,num为要延时的时间,
留一个参数入口,这样,LOAD就配置完成了,看下面这个例子,us级的延时函数,如果是ms的话
只需要*1000就行了,但是需要注意寄存器是24位的,使用ms的话168M只能延时798.915ms
然后可参照ATK的代码。
2.最好8分频(如ST官方手册,可以HCLK 8分频 也可以不分频)

/*******************************************************************************************/

/**
* @brief  : Use SysTick to enable delay_us
* @param  : MAX num : 2^24 * 8 / 168 = 798915 us
*
* @retval : none
*/
void
delay_us(uint32_t num)
{

#if   CLK_168         //168MHZ
SysTick->LOAD = num * 168 / 8 ;     //Reload
#elif CLK_160         //160MHZ
SysTick->LOAD = num * 160 / 8 ;     //Reload
#elif CLK_80          //80MHZ
SysTick->LOAD = num * 80  / 8 ;     //Reload
#elif CLK_72           //72MHZ
SysTick->LOAD = num * 72  / 8 ;     //Reload
#endif //<CLK_168>

SysTick->VAL = 0;                                            //CE
SysTick->CTRL |= 1<<0;                                       //Enable SysTick
while(!(SysTick->CTRL & 1<<16));
4000
//Till 0
SysTick->CTRL &= ~(1<<0);                                    //Disable SysTick
SysTick->VAL = 0;                                            //CE
}

/**
* @brief  : From ATK
* @param  : MAX num : 65535 ms
*
* @retval : none
*/
void
delay_ms(uint16_t nms)
{
uint16_t repeat=nms / 540;
uint16_t remain=nms % 540;
while(repeat)
{
delay(540);
repeat--;
}
if(remain)
delay(remain);
}

//Hide
/**
* @brief  : Use SysTick to enable delay_ms
* @param  : MAX num = 2^24 * 8 / 168 / 1000 = 798.915 ms
*
* @retval : none
*/
static void
delay(uint32_t num)
{

#if   CLK_168         //168MHZ
SysTick->LOAD = num * 168 * 1000 / 8 ;     //Reload
#elif CLK_160         //160MHZ
SysTick->LOAD = num * 160 * 1000 / 8 ;     //Reload
#elif CLK_80          //80MHZ
SysTick->LOAD = num * 80 *  1000 / 8 ;     //Reload
#elif CLK_72           //72MHZ
SysTick->LOAD = num * 72 *  1000 / 8 ;     //Reload
#endif //<CLK_168>

SysTick->VAL = 0;                                            //CE
SysTick->CTRL |= 1<<0;                                       //Enable SysTick
while(!(SysTick->CTRL & 1<<16));                             //Till 0
SysTick->CTRL &= ~(1<<0);                                    //Disable SysTick
SysTick->VAL = 0;                                            //CE
}

/***********************************************************************************************/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐