有不少初学者对delay_init()函数犯晕,其实这个函数可以简单到只有两行

2019-07-20 22:29发布

本帖最后由 warship 于 2018-7-29 22:30 编辑

有不少初学者对delay_init()函数犯晕,但每一个程序都绕不开,由于原子的例程里因为想兼容操作系统,搞了很多的宏条件,也难怪初学者难以读懂,
其实不光是初学者,说实在的,我没有用到OS,看着这个函数也头大(其实也是没有完全搞懂)
这两天看了一下,撇开对OS的支持(我想绝大多数的STM32初学者都不会上来就用OS的),
这个函数可以简单到只有两行。如下即可:

void delay_init(void)
{
  SysTick->LOAD=9000-1;    //装载值设定为9*1000-1=8999  即每ms中断一次
  SysTick->CTRL|=3;           //开启SYSTICK并允许中断
}


怎么样,简单吧?
你用它替换掉原子的函数,我保证能用。
楼下我会详细解释一下.

哦,对了,
忘记提示一句: 使用库函数编程的同学,也是一样可用的。
直接替换掉原函数就可以了。
其实使用库函数编程还是有优势的,看到寄存器编的代码可以直接拿来就用,
而使用寄存器编程的同学,临时想调用库函数就真的不是那么容易了,哈哈。
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
49条回答
warship
1楼-- · 2019-07-20 22:45
本帖最后由 warship 于 2018-9-21 10:47 编辑

好了,本该就此打住的,但既然说到延时了,就不得不吐槽一下原子的延时函数,
那个delay_ms(u16 nms)只能是16位的参数不说,还进一步限制最大只能延时1864ms,
如果初学者一不小心,想延时2秒,嘿嘿,不好意思,越界了!!!
所以建议索性把这个延时程序也换了,保证你可以一次延时5分钟以上,足够你闭目养神的了。

而且重要的是:延时函数仅反复读取SYSTICK的当前值,直到给定的延时时间到达, 不影响SYSTICK的自动重装,也不影响其中断

//微秒延时函数:
//nus:0~2^32/fac_us=4294967296/9=477,218,588 高达4.7亿微秒                                                                             
void delay_us(u32 nus)
{               
        u32 ticks;
        u32 told,tnow,tcnt=0;
        u32 reload=SysTick->LOAD;   //reload中保存原1ms装载的值                     
        ticks=nus*9;           //需要延时的节拍数                           
        tcnt=0;
        told=SysTick->VAL;          //刚进入时的计数器值
        while(1)
        {
                tnow=SysTick->VAL;        //当前计数值
                if(tnow!=told)            //如果计数值有变化, 则(这里注意一下SYSTICK是一个递减的计数器就可以了):
                {            
                        if(tnow<told)    //一般情况, 计数器递减了, 则累计经历的节拍数
                                tcnt+=told-tnow;               
                        else             //有溢出的情况, 计数值变大了, 则累计时要增加满载值  
                                tcnt+=reload-tnow+told;            
                        
                        told=tnow;      //每次累计后, 将当前值变成基础旧值
                        if(tcnt>=ticks)break;   //累计节拍数大于/等于需要延迟的节拍数,即延时时间到达, 则退出本函数.
                }  
        }        
}


//毫秒延时函数:
//将给定的延时毫秒数乘以1000后直接调用微秒延时函数
//nms:0---2^32/1000/fac_us=47万毫秒  
void delay_ms(u32 nms)
{                                    
  delay_us((u32)(nms*1000));            //直接调用delay_us函数进行延时  
}

后注:最新修改的delay函数可以确保SYSTICK中断不会影响延时精度,延时函数的具体实现过程已经考虑到延时过程中进入中断的情况了。最新的delay请关注https://github.com/ShuifaHe/STM32/blob/delay/delay.c,如果觉得对你有用的话,请帮忙在GITHUB下载后点个赞哦。


warship
2楼-- · 2019-07-21 03:10
本帖最后由 warship 于 2018-9-21 22:06 编辑

所谓的delay_init()即延时初始化,就是对系统滴答定时器的初始化,
初始化后就可以利用它来进行延时。
第一句就是设置计时器的装载值:SysTick->CTRL寄存器的第2位CLKSOURCE是用来控制输入SYSTICK的时钟源的。
定义为  0:FCLK/8,    1:FCLK。系统复位后,该位即为0,
也就是说,如果想让时钟源为FCLK/8时,无须做任何设置。
即:SysTick的默认时钟为系统时钟8分频,对于72M的系统来说,8分频后就是9MHz
即时间节拍为1/9M(秒)=1/9000(毫秒), 我们要每ms中断一次,当然就要计数9000次了。

第二句知道CTRL寄存器的定义就明白了,BIT0是使能位,BIT1是允许中断位,所以将此两位置1就可以工作了。
warship
3楼-- · 2019-07-21 05:35
 精彩回答 2  元偷偷看……
878738424
4楼-- · 2019-07-21 11:14
 精彩回答 2  元偷偷看……
warship
5楼-- · 2019-07-21 16:20
878738424 发表于 2018-7-31 06:36
学习了

感谢支持
森海有眼泉
6楼-- · 2019-07-21 17:16
warship 发表于 2018-7-29 21:46
好了,本该就此打住的,但既然说到延时了,就不得不吐槽一下原子的延时函数,
那个delay_ms(u16 nms)只 ...

delay_ms  16位好像 涉及到 systick 函数的 24位 寄存器 最大值16777216  .在72mhz下 约为1.86秒.不能怪原子~ 硬件  原因最大值是 1.86...

一周热门 更多>