OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 31073|回复: 89

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

  [复制链接]

31

主题

1953

帖子

3

精华

论坛元老

Rank: 8Rank: 8

积分
4462
金钱
4462
注册时间
2018-5-11
在线时间
932 小时
发表于 2018-7-29 21:16:48 | 显示全部楼层 |阅读模式
本帖最后由 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并允许中断
}


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

哦,对了,
忘记提示一句: 使用库函数编程的同学,也是一样可用的。
直接替换掉原函数就可以了。
其实使用库函数编程还是有优势的,看到寄存器编的代码可以直接拿来就用,
而使用寄存器编程的同学,临时想调用库函数就真的不是那么容易了,哈哈。
我的开源链接 https://github.com/ShuifaHe/STM32.git  请关注,点赞支持哦。
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

31

主题

1953

帖子

3

精华

论坛元老

Rank: 8Rank: 8

积分
4462
金钱
4462
注册时间
2018-5-11
在线时间
932 小时
 楼主| 发表于 2018-7-29 21:46:47 | 显示全部楼层
本帖最后由 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下载后点个赞哦。


我的开源链接 https://github.com/ShuifaHe/STM32.git  请关注,点赞支持哦。
回复 支持 1 反对 0

使用道具 举报

31

主题

1953

帖子

3

精华

论坛元老

Rank: 8Rank: 8

积分
4462
金钱
4462
注册时间
2018-5-11
在线时间
932 小时
 楼主| 发表于 2018-7-29 21:30:14 | 显示全部楼层
本帖最后由 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就可以工作了。
我的开源链接 https://github.com/ShuifaHe/STM32.git  请关注,点赞支持哦。
回复 支持 1 反对 0

使用道具 举报

31

主题

1953

帖子

3

精华

论坛元老

Rank: 8Rank: 8

积分
4462
金钱
4462
注册时间
2018-5-11
在线时间
932 小时
 楼主| 发表于 2018-7-30 15:02:24 | 显示全部楼层
本帖最后由 warship 于 2018-7-30 15:17 编辑

搞完超级简单的delay_init(),
下面再贴一个超级复杂的,先声明一下,如果你的系统正常,就不要管下面的代码了,我是拿它排除某些系统迁移后出现的疑难杂症的。

这个代码其它没什么,只不过就是把系统复位、时钟初始化包括延时初始化写在一起了,
可以用于帮助解决或诊断时钟配置不对或延时变长等故障的原因的,
假如用它还不正常的话,十有八九是外部晶体停止振荡了。

void delay_init(void)
{
RCC->APB1RSTR = 0x00000000;//复位                        
RCC->APB2RSTR = 0x00000000;
         
RCC->AHBENR = 0x00000014;  //睡眠模式闪存和SRAM时钟使能.其他关闭.         
RCC->APB2ENR = 0x00000000; //外设时钟关闭.                           
RCC->APB1ENR = 0x00000000;   
RCC->CR |= 0x00000001;     //使能内部高速时钟HSION                                                                                                                                 
RCC->CFGR &= 0xF8FF0000;   //复位时钟配置                                         
RCC->CR &= 0xFEF6FFFF;     //复位HSEON,CSSON,PLLON
RCC->CR &= 0xFFFBFFFF;     //复位HSEBYP                     
RCC->CFGR &= 0xFF80FFFF;   //复位PLL等
RCC->CIR = 0x00000000;     //关闭所有中断
SCB->VTOR= 0x08000000;     //设置向量表位置,如从RAM启动则为0x20000000

RCC->CR|=0x00010000;  //外部高速时钟使能HSEON
while(!(RCC->CR>>17));//等待外部时钟就绪
RCC->CFGR=0X00000400; //配置各条总线时钟 APB1=DIV2;APB2=DIV1;AHB=DIV1;
RCC->CFGR|=7<<18;   //设置PLL值为9倍频,得到72M
RCC->CFGR|=1<<16;          //选择PLL作为时钟源
RCC->CR|=0x01000000;  //打开PLL
while(!(RCC->CR>>25));//等待PLL锁定
RCC->CFGR|=0x00000002;//PLL作为系统时钟
while((RCC->CFGR & 0x0C)!=8); //等待PLL作为系统时钟设置成功         
SysTick->LOAD=9000-1;    //装载值设定为9*1000-1=8999  即每ms中断一次
SysTick->CTRL|=3;        //开启SYSTICK并允许中断
}

我的开源链接 https://github.com/ShuifaHe/STM32.git  请关注,点赞支持哦。
回复 支持 反对

使用道具 举报

5

主题

17

帖子

0

精华

新手上路

积分
46
金钱
46
注册时间
2018-7-26
在线时间
11 小时
发表于 2018-7-31 06:36:52 | 显示全部楼层
学习了
回复 支持 反对

使用道具 举报

31

主题

1953

帖子

3

精华

论坛元老

Rank: 8Rank: 8

积分
4462
金钱
4462
注册时间
2018-5-11
在线时间
932 小时
 楼主| 发表于 2018-7-31 08:52:50 | 显示全部楼层

感谢支持
我的开源链接 https://github.com/ShuifaHe/STM32.git  请关注,点赞支持哦。
回复 支持 反对

使用道具 举报

20

主题

200

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
462
金钱
462
注册时间
2015-11-28
在线时间
89 小时
发表于 2018-7-31 09:27:09 | 显示全部楼层
warship 发表于 2018-7-29 21:46
好了,本该就此打住的,但既然说到延时了,就不得不吐槽一下原子的延时函数,
那个delay_ms(u16 nms)只 ...

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

使用道具 举报

31

主题

1953

帖子

3

精华

论坛元老

Rank: 8Rank: 8

积分
4462
金钱
4462
注册时间
2018-5-11
在线时间
932 小时
 楼主| 发表于 2018-7-31 10:27:49 | 显示全部楼层
森海有眼泉 发表于 2018-7-31 09:27
delay_ms  16位好像 涉及到 systick 函数的 24位 寄存器 最大值16777216  .在72mhz下 约为1.86秒.不能怪 ...

谢谢指教,硬件是死的,人是活的,我3楼提供的延时函数可轻松达到5分钟以上
我的开源链接 https://github.com/ShuifaHe/STM32.git  请关注,点赞支持哦。
回复 支持 反对

使用道具 举报

32

主题

300

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1049
金钱
1049
注册时间
2012-3-30
在线时间
321 小时
发表于 2018-7-31 11:40:27 | 显示全部楼层
楼主爱琢磨
回复 支持 反对

使用道具 举报

31

主题

1953

帖子

3

精华

论坛元老

Rank: 8Rank: 8

积分
4462
金钱
4462
注册时间
2018-5-11
在线时间
932 小时
 楼主| 发表于 2018-7-31 17:51:24 | 显示全部楼层

感谢支持,哈哈,没事瞎琢磨。
我的开源链接 https://github.com/ShuifaHe/STM32.git  请关注,点赞支持哦。
回复 支持 反对

使用道具 举报

3

主题

35

帖子

0

精华

初级会员

Rank: 2

积分
173
金钱
173
注册时间
2018-6-1
在线时间
20 小时
发表于 2018-8-1 01:07:00 | 显示全部楼层
喜欢看楼主的文章,每次都学习许多新的细的东西,谢谢分享
回复 支持 反对

使用道具 举报

31

主题

1953

帖子

3

精华

论坛元老

Rank: 8Rank: 8

积分
4462
金钱
4462
注册时间
2018-5-11
在线时间
932 小时
 楼主| 发表于 2018-8-6 22:11:30 | 显示全部楼层
本帖最后由 warship 于 2018-8-6 22:17 编辑

完全改写自库函数SystemInit的版本(备查)
void delay_init(void)
{
  __IO uint32_t StartUpCounter = 0, HSEStatus = 0;
        
  /*!< RCC 系统复位(调试目的) */
  /*!< Set HSION bit */
  /*内部高速时钟使能*/
  RCC->CR |= (uint32_t)0x00000001;
  /*!< 复位 SW[1:0], HPRE[3:0], PPRE1[2:0], PPRE2[2:0], ADCPRE[1:0] 及 MCO[2:0] 等BIT位 */
  /*!<HIS被选作系统时钟,SYSCLK(系统时钟)未被分频,低速、高速总线时钟未被分频,ADC时钟被2分频,微控制器无时钟输出*/
  RCC->CFGR &= (uint32_t)0xF8FF0000;  
  /*!< 复位 HSEON, CSSON 及 PLLON 位 */
  /* PLL锁相环失能,CSS时钟安全系统失能,外部高速时钟失能*/
  RCC->CR &= (uint32_t)0xFEF6FFFF;
  /*!< 复位 HSEBYP  */
  /*清外部时钟可用标志*/
  RCC->CR &= (uint32_t)0xFFFBFFFF;
  /*!< 复位 PLLSRC, PLLXTPRE, PLLMUL[3:0] 及 USBPRE 等BIT位 */
  /* USB时钟为PLL 1.5分频,PLL倍频参数X2,HSE未被分频,HSI震荡时钟/2被当作PLL输入时钟 */
  RCC->CFGR &= (uint32_t)0xFF80FFFF;
  /*!使能所有时钟中断*/
  RCC->CIR = 0x00000000;
   
  /*!< 配置系统时钟频率, 系统总线(HCLK)与可编程时钟(PCLK)1、2  */
  /*!< 配置闪存延迟周期,使能预取缓存 */
    /*!< SYSCLK, HCLK, PCLK2 及 PCLK1 配置 ---------------------------*/   
  /*!< 使能 HSE */   
  RCC->CR |= ((uint32_t)RCC_CR_HSEON);

#define HSEStartUp_TimeOut   ((uint16_t)0x0500) /*!< HSE启动超时长度定义 */
  /*!< 等待 HSE 就绪,超时也跳出本循环 */
  do
  {
    HSEStatus = RCC->CR & RCC_CR_HSERDY;
    StartUpCounter++;  
  } while((HSEStatus == 0) && (StartUpCounter != HSEStartUp_TimeOut));
//到这里有两种情况: 一是HSE就绪,即HSEStatus为1;二是HSEStatus为0但超时
  if ((RCC->CR & RCC_CR_HSERDY) != RESET) //进一步确认HSE已就绪,置HSEStatus为1;
  {
    HSEStatus = (uint32_t)0x01;
  }
  else //HSE未就绪(超时),置HSEStatus为0;
  {
    HSEStatus = (uint32_t)0x00;
  }  

  if (HSEStatus == (uint32_t)0x01)  //在确认HSE已就绪的情况下,则:
  {
    /*!< 使能预取缓存 */
    FLASH->ACR |= FLASH_ACR_PRFTBE;

    /*!< Flash 2 wait state */
    FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);
    FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_2;   

    /*!< HCLK = SYSCLK */
    RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;
      
    /*!< PCLK2 = HCLK */
    RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;
   
    /*!< PCLK1 = HCLK */
    RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;
   
    /*!< PLLCLK = 8MHz * 9 = 72 MHz */
    RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLMULL));
    RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC | RCC_CFGR_PLLMULL9);

    /*!< 使能 PLL */
    RCC->CR |= RCC_CR_PLLON;

    /*!< 等待 PLL 就绪 */
    while((RCC->CR & RCC_CR_PLLRDY) == 0)
    {
    }

    /*!< 选择 PLL 作为系统时钟源 */
    RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
    RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;   

    /*!< 等待PLL 被用作系统时钟源成功 */
    while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08)
    {
    }
   SysTick->LOAD=9000-1;    //装载值设定为9*1000-1=8999  即每ms中断一次
   SysTick->CTRL|=3;        //开启SYSTICK并允许中断

  }
  else //HSE未就绪,等待超时(即上述第二种情况)   
  { /*!< 如果外部高速时钟失败,应用程序就会出现时钟配置错误,用户可在此添加代码处理这种错误 */   

    /*!< 进入死循环 */
    while (1)
    {
    }
  }

}






我的开源链接 https://github.com/ShuifaHe/STM32.git  请关注,点赞支持哦。
回复 支持 反对

使用道具 举报

0

主题

10

帖子

0

精华

新手入门

积分
16
金钱
16
注册时间
2018-8-8
在线时间
1 小时
发表于 2018-8-8 21:23:22 | 显示全部楼层
学习
回复 支持 反对

使用道具 举报

0

主题

23

帖子

0

精华

初级会员

Rank: 2

积分
82
金钱
82
注册时间
2018-8-9
在线时间
21 小时
发表于 2018-8-9 15:32:14 | 显示全部楼层
谢谢,学习了
回复 支持 反对

使用道具 举报

9

主题

165

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
251
金钱
251
注册时间
2018-4-6
在线时间
31 小时
发表于 2018-8-22 21:06:15 | 显示全部楼层
warship 发表于 2018-7-29 21:46
好了,本该就此打住的,但既然说到延时了,就不得不吐槽一下原子的延时函数,
那个delay_ms(u16 nms)只 ...

除了膜拜,我还能说啥
回复 支持 反对

使用道具 举报

31

主题

1953

帖子

3

精华

论坛元老

Rank: 8Rank: 8

积分
4462
金钱
4462
注册时间
2018-5-11
在线时间
932 小时
 楼主| 发表于 2018-8-22 21:08:42 | 显示全部楼层
15353920254 发表于 2018-8-22 21:06
除了膜拜,我还能说啥

太谦虚了,
有事您说话哈。
我的开源链接 https://github.com/ShuifaHe/STM32.git  请关注,点赞支持哦。
回复 支持 反对

使用道具 举报

0

主题

2

帖子

0

精华

新手上路

积分
25
金钱
25
注册时间
2016-9-30
在线时间
3 小时
发表于 2018-8-22 23:36:40 | 显示全部楼层
好详细啊,受教了
顺便问个问题,上面写到9MHZ,计数9000次为1ms,那我如果要想做个1ms的标志位,就比如定义一个变量1msflag吧,这个我该怎么处理好呢?
回复 支持 反对

使用道具 举报

31

主题

1953

帖子

3

精华

论坛元老

Rank: 8Rank: 8

积分
4462
金钱
4462
注册时间
2018-5-11
在线时间
932 小时
 楼主| 发表于 2018-8-23 12:32:59 来自手机 | 显示全部楼层
deeric 发表于 2018-8-22 23:36
好详细啊,受教了;
顺便问个问题,上面写到9MHZ,计数9000次为1ms,那我如果要想做个1ms的标志位,就 ...

上面已经定义systick每ms中断一次了,你在中断服务程序里让这个变量等于1不就行了么
回复 支持 反对

使用道具 举报

4

主题

28

帖子

0

精华

高级会员

Rank: 4

积分
742
金钱
742
注册时间
2018-1-22
在线时间
59 小时
发表于 2018-8-23 17:23:57 | 显示全部楼层
学习一下。。。
回复 支持 反对

使用道具 举报

0

主题

2

帖子

0

精华

新手入门

积分
8
金钱
8
注册时间
2017-7-5
在线时间
2 小时
发表于 2018-8-30 01:55:59 | 显示全部楼层
膜拜大神,看了那么多帖子,也就这个最专业解决延时函数移植问题
回复 支持 反对

使用道具 举报

3

主题

39

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
309
金钱
309
注册时间
2013-4-5
在线时间
81 小时
发表于 2018-9-10 08:50:28 | 显示全部楼层
膜拜大神,好多天没来了,看到大神这么多帖子,够我看一阵了。
回复 支持 反对

使用道具 举报

31

主题

1953

帖子

3

精华

论坛元老

Rank: 8Rank: 8

积分
4462
金钱
4462
注册时间
2018-5-11
在线时间
932 小时
 楼主| 发表于 2018-9-10 10:16:04 | 显示全部楼层
deeric 发表于 2018-8-22 23:36
好详细啊,受教了;
顺便问个问题,上面写到9MHZ,计数9000次为1ms,那我如果要想做个1ms的标志位,就 ...

在systick中断处理函数中置这个标志就行了
我的开源链接 https://github.com/ShuifaHe/STM32.git  请关注,点赞支持哦。
回复 支持 反对

使用道具 举报

70

主题

275

帖子

0

精华

高级会员

Rank: 4

积分
728
金钱
728
注册时间
2017-6-20
在线时间
188 小时
发表于 2018-9-12 22:33:52 | 显示全部楼层
请大神讲讲这个  SysTick->LOAD=9000-1;    //装载值设定为9*1000-1=8999  即每ms中断一次 这里把,如果初始化给1ms中断一次,那我delay_us()函数是不是没法用了啊?麻烦给讲一下,这里不太明白
回复 支持 反对

使用道具 举报

31

主题

1953

帖子

3

精华

论坛元老

Rank: 8Rank: 8

积分
4462
金钱
4462
注册时间
2018-5-11
在线时间
932 小时
 楼主| 发表于 2018-9-13 21:40:26 | 显示全部楼层
本帖最后由 warship 于 2018-9-13 21:42 编辑
天天mdk 发表于 2018-9-12 22:33
请大神讲讲这个  SysTick->LOAD=9000-1;    //装载值设定为9*1000-1=8999  即每ms中断一次 这里把,如果初 ...

SysTick的默认时钟为系统时钟8分频,对于72M的系统来说,8分频后就是9MHz
即时间节拍为1/9M(秒)=1/9000(毫秒), 我们要每ms中断一次,当然就要计数9000次了。
所以设定装载值为9000。
中断是不会影响延时时,延时函数的具体实现过程已经考虑到这一点了。最新的delay请关注https://github.com/ShuifaHe/STM32/blob/delay/delay.c
我的开源链接 https://github.com/ShuifaHe/STM32.git  请关注,点赞支持哦。
回复 支持 反对

使用道具 举报

1

主题

41

帖子

0

精华

初级会员

Rank: 2

积分
57
金钱
57
注册时间
2018-9-11
在线时间
6 小时
发表于 2018-9-14 09:27:13 | 显示全部楼层
受教了!!
回复 支持 反对

使用道具 举报

10

主题

81

帖子

0

精华

初级会员

Rank: 2

积分
149
金钱
149
注册时间
2018-5-8
在线时间
27 小时
发表于 2018-9-14 10:22:45 | 显示全部楼层
炒冷饭炒了n次方才明白。。。。。
回复 支持 反对

使用道具 举报

10

主题

232

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
2279
金钱
2279
注册时间
2012-8-24
在线时间
247 小时
发表于 2018-10-30 09:49:56 | 显示全部楼层
大神,能不能说一下原子的延时中这几句是什么意思吗?尤其第夺句,谢谢
reload=SystemCoreClock/8000000;
reload*=1000000/delay_ostickspersec;
fac_ms=1000/delay_ostickspersec;
单片机技术交流请加127034610
回复 支持 反对

使用道具 举报

31

主题

1953

帖子

3

精华

论坛元老

Rank: 8Rank: 8

积分
4462
金钱
4462
注册时间
2018-5-11
在线时间
932 小时
 楼主| 发表于 2018-10-30 19:00:14 | 显示全部楼层
liushiming82 发表于 2018-10-30 09:49
大神,能不能说一下原子的延时中这几句是什么意思吗?尤其第夺句,谢谢
reload=SystemCoreClock/8000000;
...

没有看到这一句哦。
我的开源链接 https://github.com/ShuifaHe/STM32.git  请关注,点赞支持哦。
回复 支持 反对

使用道具 举报

10

主题

232

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
2279
金钱
2279
注册时间
2012-8-24
在线时间
247 小时
发表于 2018-10-31 13:15:49 | 显示全部楼层
liushiming82 发表于 2018-10-30 09:49
大神,能不能说一下原子的延时中这几句是什么意思吗?尤其第夺句,谢谢
reload=SystemCoreClock/8000000;
...

尤其第二句,不太明白  能否讲解一下
单片机技术交流请加127034610
回复 支持 反对

使用道具 举报

4

主题

30

帖子

0

精华

初级会员

Rank: 2

积分
195
金钱
195
注册时间
2016-12-28
在线时间
50 小时
发表于 2018-10-31 13:49:01 | 显示全部楼层
楼主好细
回复 支持 反对

使用道具 举报

31

主题

1953

帖子

3

精华

论坛元老

Rank: 8Rank: 8

积分
4462
金钱
4462
注册时间
2018-5-11
在线时间
932 小时
 楼主| 发表于 2018-11-2 20:45:53 | 显示全部楼层
liushiming82 发表于 2018-10-31 13:15
尤其第二句,不太明白  能否讲解一下

对你说的句子没有什么印象了,
能够多贴一些代码吗?
我的开源链接 https://github.com/ShuifaHe/STM32.git  请关注,点赞支持哦。
回复 支持 反对

使用道具 举报

10

主题

232

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
2279
金钱
2279
注册时间
2012-8-24
在线时间
247 小时
发表于 2018-11-3 14:48:47 | 显示全部楼层
                          
//初始化延迟函数
//当使用OS的时候,此函数会初始化OS的时钟节拍
//SYSTICK的时钟固定为HCLK时钟的1/8
//SYSCLK:系统时钟
void delay_init()
{
#if SYSTEM_SUPPORT_OS                                                          //如果需要支持OS.
        u32 reload;
#endif
        SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);        //选择外部时钟  HCLK/8
        fac_us=SystemCoreClock/8000000;                                //为系统时钟的1/8  
#if SYSTEM_SUPPORT_OS                                                          //如果需要支持OS.
        reload=SystemCoreClock/8000000;                                //每秒钟的计数次数 单位为K          
        reload*=1000000/delay_ostickspersec;                //根据delay_ostickspersec设定溢出时间
                                                                                                //reload为24位寄存器,最大值:16777216,在72M下,约合1.86s左右       
        fac_ms=1000/delay_ostickspersec;                        //代表OS可以延时的最少单位          

        SysTick->CTRL|=SysTick_CTRL_TICKINT_Msk;           //开启SYSTICK中断
        SysTick->LOAD=reload;                                                 //每1/delay_ostickspersec秒中断一次       
        SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk;           //开启SYSTICK   

#else
        fac_ms=(u16)fac_us*1000;                                        //非OS下,代表每个ms需要的systick时钟数   
#endif
}                                                                    
单片机技术交流请加127034610
回复 支持 反对

使用道具 举报

31

主题

1953

帖子

3

精华

论坛元老

Rank: 8Rank: 8

积分
4462
金钱
4462
注册时间
2018-5-11
在线时间
932 小时
 楼主| 发表于 2018-11-3 20:22:31 | 显示全部楼层
本帖最后由 warship 于 2018-11-3 20:27 编辑
liushiming82 发表于 2018-11-3 14:48
//初始化延迟函数
//当使用OS的时候,此函数会初始化OS的时钟节拍
//SYSTICK的时钟固定为HCLK时钟 ...

这里首先要明白的是delay_ostickspersec
delay_ostickspersec是操作系统OS的心跳频率,也就是你想让每秒钟SYSTICK溢出中断的次数。
它的倒数,即1/delay_ostickspersec就是每次中断间隔的时间(单位是秒)
这个中断间隔时间,就是SYSTICK要定时的时间长度;
SYSTICK的时钟频率为系统8分频,即SystemCoreClock/8
时间长度*频率=周期数,即总计次数,即重装载数,即reload
时间长度=1/delay_ostickspersec      (单位为秒)
频率=SystemCoreClock/8                 (单位为HZ,即每秒周期数)
所以:reload=(1/delay_ostickspersec)*(SystemCoreClock/8)=(1000000/delay_ostickspersec)*(SystemCoreClock/8000000)


我的开源链接 https://github.com/ShuifaHe/STM32.git  请关注,点赞支持哦。
回复 支持 反对

使用道具 举报

42

主题

191

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
220
金钱
220
注册时间
2017-12-28
在线时间
62 小时
发表于 2018-12-1 14:47:15 | 显示全部楼层
断点测量100us延时,时间却一直在跑停不下来,为什么呢
搜狗截图20181201144318.png
搜狗截图20181201144406.png
回复 支持 反对

使用道具 举报

31

主题

1953

帖子

3

精华

论坛元老

Rank: 8Rank: 8

积分
4462
金钱
4462
注册时间
2018-5-11
在线时间
932 小时
 楼主| 发表于 2018-12-1 16:27:48 | 显示全部楼层
imbest 发表于 2018-12-1 14:47
断点测量100us延时,时间却一直在跑停不下来,为什么呢

不知道你为什么要在延时函数这里设断点,
你可以把断点设置在延时函数之后,
如果你怀疑延时不准确,
可以通过重复多次延时来累计检测时间,
比如延时100ms,  搞一个for(i=0;i<100;i++) delay_ms(100);
看是不是10秒就可以检验了。
我的开源链接 https://github.com/ShuifaHe/STM32.git  请关注,点赞支持哦。
回复 支持 反对

使用道具 举报

31

主题

1953

帖子

3

精华

论坛元老

Rank: 8Rank: 8

积分
4462
金钱
4462
注册时间
2018-5-11
在线时间
932 小时
 楼主| 发表于 2018-12-1 16:37:45 | 显示全部楼层
把延时函数那一行的断点先去掉
断点放在延时函数后面。
我的开源链接 https://github.com/ShuifaHe/STM32.git  请关注,点赞支持哦。
回复 支持 反对

使用道具 举报

42

主题

191

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
220
金钱
220
注册时间
2017-12-28
在线时间
62 小时
发表于 2018-12-1 16:38:43 | 显示全部楼层
warship 发表于 2018-12-1 16:27
不知道你为什么要在延时函数这里设断点,
你可以把断点设置在延时函数之后,
如果你怀疑延时不准确,

就是进延时之前跟出延时之后,这之间的时间不就是延时的时间吗?现在是我的程序移植您给的延时函数一直卡在延时里出不来,请问为什么呢?
回复 支持 反对

使用道具 举报

51

主题

2166

帖子

2

精华

论坛元老

Rank: 8Rank: 8

积分
10653
金钱
10653
注册时间
2017-4-14
在线时间
2780 小时
发表于 2018-12-1 16:40:17 | 显示全部楼层
本帖最后由 275891381 于 2018-12-1 16:41 编辑
warship 发表于 2018-12-1 16:27
不知道你为什么要在延时函数这里设断点,
你可以把断点设置在延时函数之后,
如果你怀疑延时不准确,

正解,还可以延时前后翻转个io,示波器看一下就可以了,更准
再说这么多人经验的积累,没人怀疑他不准的,你为啥怀疑呢?

回复 支持 反对

使用道具 举报

42

主题

191

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
220
金钱
220
注册时间
2017-12-28
在线时间
62 小时
发表于 2018-12-1 16:40:43 | 显示全部楼层
warship 发表于 2018-12-1 16:27
不知道你为什么要在延时函数这里设断点,
你可以把断点设置在延时函数之后,
如果你怀疑延时不准确,

可以加您QQ或者微信吗?问题比较着急,这样太慢了,您可以私聊发给我号
回复 支持 反对

使用道具 举报

42

主题

191

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
220
金钱
220
注册时间
2017-12-28
在线时间
62 小时
发表于 2018-12-1 16:44:37 | 显示全部楼层
275891381 发表于 2018-12-1 16:40
正解,还可以延时前后翻转个io,示波器看一下就可以了,更准
再说这么多人经验的积累,没人怀疑他不准的 ...

我不是怀疑,我现在程序卡在了延时函数里出不来
回复 支持 反对

使用道具 举报

51

主题

2166

帖子

2

精华

论坛元老

Rank: 8Rank: 8

积分
10653
金钱
10653
注册时间
2017-4-14
在线时间
2780 小时
发表于 2018-12-1 16:46:05 | 显示全部楼层
本帖最后由 275891381 于 2018-12-1 17:58 编辑
imbest 发表于 2018-12-1 16:44
我不是怀疑,我现在程序卡在了延时函数里出不来

你是不是开滴答定时器中断了,中段函数没有写

static   u8  fac_us=0;                                                             //us延时倍乘数        
//SYSTICK的时钟固定为HCLK时钟的1/8
//中断时间time  =  ( SysTick->LOAD + 1 ) / f                        f = AHB或AHB/8            (9000-1+1)/9M=1ms
void delay_init(void)
{
        //NVIC_SetPriority (SysTick_IRQn, x);默认是NVIC_SetPriority (SysTick_IRQn,15);
        SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);        //选择外部时钟  HCLK/8  9M 计数器减1为1/9000000秒
        fac_us=SystemCoreClock/8000000;                                                //9  
        SysTick->CTRL|=SysTick_CTRL_TICKINT_Msk;                     //开启SYSTICK中断
        SysTick->LOAD=fac_us*1000-1;                                                               //每1/1000s中断一次        
        SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk;                     //开启SYSTICK           
}        

//nus:0~2^32/fac_us=477218588.444us=477s        (fac_us=9)                                                                  
void delay_us(u32 nus)
{               
        u32 ticks;
        u32 told,tnow,tcnt=0;
        u32 reload=SysTick->LOAD;                                                            //LOAD的值                     
        ticks=nus*fac_us;                                                                               //需要的节拍数                           
        tcnt=0;
        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;                                                      //时间超过/等于要延迟的时间,则退出.
                }  
        }        
}
//nms:0---2^32/fac_us/1000ms=477218.588ms=477s
void delay_ms(u32 nms)
{
          delay_us((u32)(nms*1000));//普通方式延时
}



//systick中断服务函数
void SysTick_Handler(void)//内部中断,硬件自动清除标志位
{
                //xitong_haomiao++;
}

回复 支持 反对

使用道具 举报

31

主题

1953

帖子

3

精华

论坛元老

Rank: 8Rank: 8

积分
4462
金钱
4462
注册时间
2018-5-11
在线时间
932 小时
 楼主| 发表于 2018-12-1 16:50:39 | 显示全部楼层
imbest 发表于 2018-12-1 16:44
我不是怀疑,我现在程序卡在了延时函数里出不来

很可能是楼上所说的问题,
你先排除一下吧
我的开源链接 https://github.com/ShuifaHe/STM32.git  请关注,点赞支持哦。
回复 支持 反对

使用道具 举报

42

主题

191

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
220
金钱
220
注册时间
2017-12-28
在线时间
62 小时
发表于 2018-12-1 16:57:36 | 显示全部楼层
275891381 发表于 2018-12-1 16:46
你是不是开滴答定时器中断了,中段函数没有写

static   u8  fac_us=0;                               ...

滴答定时器中断函数里什么都不用写吗?
回复 支持 反对

使用道具 举报

31

主题

1953

帖子

3

精华

论坛元老

Rank: 8Rank: 8

积分
4462
金钱
4462
注册时间
2018-5-11
在线时间
932 小时
 楼主| 发表于 2018-12-1 16:58:17 | 显示全部楼层
imbest 发表于 2018-12-1 16:44
我不是怀疑,我现在程序卡在了延时函数里出不来

这部分代码加上了吗?

/*******************************************************************************
* Function Name  : SysTickHandler
* Description    : 系统每1毫秒产生一次中断,进入此服务程序
注意: 本函数与延时函数不冲突
*******************************************************************************/
//nTicks为一个32位的静态全局变量,用于累计SysTick总次数
static u32 nTicks = 0;  //静态全局变量只在本文件有作用
u32 GetTicks()
{
        return nTicks;
}

extern u8 Flag300ms;
/* SysTick中断服务函数 */
void SysTick_Handler(void)
{
        nTicks++;
}

我的开源链接 https://github.com/ShuifaHe/STM32.git  请关注,点赞支持哦。
回复 支持 反对

使用道具 举报

42

主题

191

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
220
金钱
220
注册时间
2017-12-28
在线时间
62 小时
发表于 2018-12-1 17:07:57 | 显示全部楼层
warship 发表于 2018-12-1 16:58
这部分代码加上了吗?

/************************************************************************* ...

确实是没有写滴答定时器中断函数,加上就好了,不过我还有一个疑问,在debug时keil右下角的时间t1是什么时间呢?什么作用呢?
回复 支持 反对

使用道具 举报

31

主题

1953

帖子

3

精华

论坛元老

Rank: 8Rank: 8

积分
4462
金钱
4462
注册时间
2018-5-11
在线时间
932 小时
 楼主| 发表于 2018-12-1 17:13:54 | 显示全部楼层
imbest 发表于 2018-12-1 17:07
确实是没有写滴答定时器中断函数,加上就好了,不过我还有一个疑问,在debug时keil右下角的时间t1是什么 ...

没有太注意这个,
可能是系统时钟计数?
解决就好了。
我的开源链接 https://github.com/ShuifaHe/STM32.git  请关注,点赞支持哦。
回复 支持 反对

使用道具 举报

42

主题

191

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
220
金钱
220
注册时间
2017-12-28
在线时间
62 小时
发表于 2018-12-1 17:16:18 | 显示全部楼层
warship 发表于 2018-12-1 17:13
没有太注意这个,
可能是系统时钟计数?
解决就好了。

好的,谢谢了
回复 支持 反对

使用道具 举报

0

主题

75

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
430
金钱
430
注册时间
2016-3-17
在线时间
95 小时
发表于 2018-12-15 17:08:15 | 显示全部楼层
楼主真能琢磨,佩服
长延时不错,短延时有问题。对时序要求比较严格的us用这个不太合适
回复 支持 反对

使用道具 举报

13

主题

633

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1331
金钱
1331
注册时间
2016-8-1
在线时间
229 小时
发表于 2018-12-15 20:37:48 | 显示全部楼层
学习了哈哈
回复 支持 反对

使用道具 举报

0

主题

13

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
282
金钱
282
注册时间
2017-1-8
在线时间
123 小时
发表于 2018-12-16 15:06:26 | 显示全部楼层
如果需要精确的延时,用定时器做。如果不需要精确的延时,软件延时就够了,for ...  nop...解决问题。反正我从来不用SysTick的延时,我用SysTick做定时器中断
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-2-26 09:39

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表