有不少初学者对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-21 20:49
森海有眼泉 发表于 2018-7-31 09:27
delay_ms  16位好像 涉及到 systick 函数的 24位 寄存器 最大值16777216  .在72mhz下 约为1.86秒.不能怪 ...

谢谢指教,硬件是死的,人是活的,我3楼提供的延时函数可轻松达到5分钟以上
czhaii
2楼-- · 2019-07-21 21:34
楼主爱琢磨
warship
3楼-- · 2019-07-22 02:13
 精彩回答 2  元偷偷看……
大力水手PP
4楼-- · 2019-07-22 02:14
喜欢看楼主的文章,每次都学习许多新的细的东西,谢谢分享
warship
5楼-- · 2019-07-22 02:56
本帖最后由 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)
    {
    }
  }

}






temp2
6楼-- · 2019-07-22 04:41
学习

一周热门 更多>