精华内容
下载资源
问答
  • 最开始学习单片机时候,无论是51还是STM32等,都会在流水灯等示例中见到延时函数,刚开始我就弄不明白,我今天认真剖析一下. 首先是函数体 void Delay(__IO u32 nCount) { for(; nCount != 0; nCount--); } ...

    最开始学习单片机的时候,无论是51还是STM32等,都会在流水灯等示例中见到延时函数,刚开始我就弄不明白,我今天认真的剖析一下.

    首先是函数体

    void Delay(__IO u32 nCount)
    { 
    for(; nCount != 0; nCount--); 
     } 

    首先根据C语言的规范可以知道这是一个没有返回值的带形式参数的函数.

    C语言中的函数使用规范如下:

    return_type function_name( parameter list )
    {
       body of the function
    }
    
    
    所以可以知道第一个是:函数返回的数据类型

    第二个是:函数名

    第三个是:参数

    第四个是:函数主体

    所以再来看这个延时函数就比较容易理解了:

    void Delay(__IO u32 nCount)
    { 
    for(; nCount != 0; nCount--); 
     } 

    这个延时函数没有返回值,函数名称是Delay,同时函数的参数部分中的_IO是类型修饰符;u32是数据类型,同等于uint_32_t同等于unsigned int型

    函数的主体是for循环递减,大致的意思是32位的非负int型数据nCount一直递减,递减到0,就产生了一个不太精确的延时函数.

    其中_IO u32可以看作一个数据类型;具体可以在相关MCU头文件,例如"stm32f10x.h"中查看定义.大致等同32位无符号int类型

    使用的时候若

    void Delay(5000)
    则就是5000自减到0为止




    
    

    展开全文
  • STM32延时函数的四种方法

    万次阅读 2020-06-12 10:01:15
    这种延时方式应该是大家在51单片机时候,接触的延时函数。这个比较简单,让单片机做一些无关紧要的工作来打发时间,经常用循环来实现,在某些编译器下,代码会被优化,导致精度较低,用于一般的延时,对精度不...

    目录

    1、普通延时

    2、定时器中断

    3、查询定时器

    4、汇编指令


    单片机编程过程中经常用到延时函数,最常用的莫过于微秒级延时delay_us()和毫秒级delay_ms()。本文基于STM32F207介绍4种不同方式实现的延时函数。

    1、普通延时

    这种延时方式应该是大家在51单片机时候,接触最早的延时函数。这个比较简单,让单片机做一些无关紧要的工作来打发时间,经常用循环来实现,在某些编译器下,代码会被优化,导致精度较低,用于一般的延时,对精度不敏感的应用场景中。

    //微秒级的延时
    void delay_us(uint32_t delay_us)
    {    
      volatile unsigned int num;
      volatile unsigned int t;
    
      
      for (num = 0; num < delay_us; num++)
      {
        t = 11;
        while (t != 0)
        {
          t--;
        }
      }
    }
    //毫秒级的延时
    void delay_ms(uint16_t delay_ms)
    {    
      volatile unsigned int num;
      for (num = 0; num < delay_ms; num++)
      {
        delay_us(1000);
      }
    }

    上述工程源码仓库:https://github.com/strongercjd/STM32F207VCT6/tree/master/02-Template

    2、定时器中断

    定时器具有很高的精度,我们可以配置定时器中断,比如配置1ms中断一次,然后间接判断进入中断的次数达到精确延时的目的。这种方式精度可以得到保证,但是系统一直在中断,不利于在其他中断中调用此延时函数,有些高精度的应用场景不适合,比如其他外设正在输出,不允许任何中断打断的情况。

    STM32任何定时器都可以实现,下面我们以SysTick 定时器为例介绍:

    初始化SysTick 定时器:

    /* 配置SysTick为1ms */
    RCC_GetClocksFreq(&RCC_Clocks);
    SysTick_Config(RCC_Clocks.HCLK_Frequency / 1000);

    中断服务函数:

    void SysTick_Handler(void)
    {
      TimingDelay_Decrement();
    }
    void TimingDelay_Decrement(void)
    {
      if (TimingDelay != 0x00)
      { 
        TimingDelay--;
      }
    }

    延时函数:

    void Delay(__IO uint32_t nTime)
    {
      TimingDelay = nTime;
      while(TimingDelay != 0);
    }

    上述工程源码仓库:https://github.com/strongercjd/STM32F207VCT6/tree/master/02-Template

    3、查询定时器

    为了解决定时器频繁中断的问题,我们可以使用定时器,但是不使能中断,使用查询的方式去延时,这样既能解决频繁中断问题,又能保证精度。

    STM32任何定时器都可以实现,下面我们以SysTick 定时器为例介绍。

    STM32的CM3内核的处理器,内部包含了一个SysTick定时器,SysTick是一个24位的倒计数定时器,当计到0时,将从RELOAD寄存器中自动重装载定时初值。只要不把它在SysTick控制及状态寄存器中的使能位清除,就永不停息。

    SYSTICK的时钟固定为HCLK时钟的1/8,在这里我们选用内部时钟源120M,所以SYSTICK的时钟为(120/8)M,即SYSTICK定时器以(120/8)M的频率递减。SysTick 主要包含CTRL、LOAD、VAL、CALIB 等4 个寄存器。

                                           ▼CTRL:控制和状态寄存器

                                           ▼LOAD:自动重装载除值寄存器

                                            ▼VAL:当前值寄存器

                                     ▼CALIB:校准值寄存器

    使用不到,不再介绍

    示例代码

    void delay_us(uint32_t nus)
    {
      uint32_t temp;
      SysTick->LOAD = RCC_Clocks.HCLK_Frequency/1000000/8*nus;
      SysTick->VAL=0X00;//清空计数器
      SysTick->CTRL=0X01;//使能,减到零是无动作,采用外部时钟源
      do
      {
        temp=SysTick->CTRL;//读取当前倒计数值
      }while((temp&0x01)&&(!(temp&(1<<16))));//等待时间到达
      SysTick->CTRL=0x00; //关闭计数器
      SysTick->VAL =0X00; //清空计数器
    }
    void delay_ms(uint16_t nms)
    {
      uint32_t temp;
      SysTick->LOAD = RCC_Clocks.HCLK_Frequency/1000/8*nms;
      SysTick->VAL=0X00;//清空计数器
      SysTick->CTRL=0X01;//使能,减到零是无动作,采用外部时钟源
      do
      {
        temp=SysTick->CTRL;//读取当前倒计数值
      }while((temp&0x01)&&(!(temp&(1<<16))));//等待时间到达
      SysTick->CTRL=0x00; //关闭计数器
      SysTick->VAL =0X00; //清空计数器
    }

    上述工程源码仓库:https://github.com/strongercjd/STM32F207VCT6/tree/master/04-Delay

    4、汇编指令

    如果系统硬件资源紧张,或者没有额外的定时器提供,又不想方法1的普通延时,可以使用汇编指令的方式进行延时,不会被编译优化且延时准确。

    STM32F207在IAR环境下

    /*!
     *  @brief 	软件延时 
     *  @param	ulCount:延时时钟数
     *  @return none
     *	@note 	ulCount每增加1,该函数增加3个时钟
     */
    void SysCtlDelay(unsigned long ulCount)
    {
        __asm("    subs    r0, #1\n"
              "    bne.n   SysCtlDelay\n"
              "    bx      lr");
    }

    这3个时钟指的是CPU时钟,也就是系统时钟。120MHZ,也就是说1s有120M的时钟,一个时钟也就是1/120 us,也就是周期是1/120 us。3个时钟,因为执行了3条指令。

    使用这种方式整理ms和us接口,在Keil和IAR环境下都测试通过。

    /*120Mhz时钟时,当ulCount为1时,函数耗时3个时钟,延时=3*1/120us=1/40us*/
    /*
    SystemCoreClock=120000000
    
    us级延时,延时n微秒
    SysCtlDelay(n*(SystemCoreClock/3000000));
    
    ms级延时,延时n毫秒
    SysCtlDelay(n*(SystemCoreClock/3000));
    
    m级延时,延时n秒
    SysCtlDelay(n*(SystemCoreClock/3));
    */
    
    #if defined   (__CC_ARM) /*!< ARM Compiler */
    __asm void
    SysCtlDelay(unsigned long ulCount)
    {
        subs    r0, #1;
        bne     SysCtlDelay;
        bx      lr;
    }
    #elif defined ( __ICCARM__ ) /*!< IAR Compiler */
    void
    SysCtlDelay(unsigned long ulCount)
    {
        __asm("    subs    r0, #1\n"
           "    bne.n   SysCtlDelay\n"
           "    bx      lr");
    }
    
    #elif defined (__GNUC__) /*!< GNU Compiler */
    void __attribute__((naked))
    SysCtlDelay(unsigned long ulCount)
    {
        __asm("    subs    r0, #1\n"
           "    bne     SysCtlDelay\n"
           "    bx      lr");
    }
    
    #elif defined  (__TASKING__) /*!< TASKING Compiler */                           
    /*无*/
    #endif /* __CC_ARM */

    上述工程源码仓库:https://github.com/strongercjd/STM32F207VCT6/tree/master/03-ASM

     

    备注:

    理论上:汇编方式的延时也是不准确的,有可能被其他中断打断,最好使用us和ms级别的延时,采用for循环延时的函数也是如此。采用定时器延时理论上也可能不准确的,定时器延时是准确的,但是可能在判断语句的时候,比如if语句,判断延时是否到了的时候,就在判断的时候,被中断打断执行其他代码,返回时已经过了一小段时间。不过汇编方式和定时器方式,只是理论上不准确,在实际项目中,这两种方式的精度已经足够高了。

     

    点击查看本文所在的专辑,STM32F207教程

     

    关注公众号,第一时间收到文章更新。评论区不能及时看到,需要交流可以到公众号沟通

    展开全文
  • 想必各位嵌入式工程师对于Delay延时函数再也熟悉不过了~ ...从事嵌入式这一行的,想必大家在大学的时候一定上过C语言吧,上C语言的时候老师一定给大家写过Delay这个函数吧,给大家举个最简单的延时函数吧~ void De..

      想必各位嵌入式工程师对于Delay延时函数再也熟悉不过了~

    但对于各位刚入RTOS的小白来说,有操作系统的延时函数,真的和裸机中的延时函数一样吗?FreeRTOS的任务调度是怎么调度的?如何分配系统的CPU?

    今天小编就带大家来扒一下FreeRTOS中的延时函数相对延时vTaskDelay函数绝对延时vTaskDelayUntil函数。

    从事嵌入式这一行的,想必大家在大学的时候一定上过C语言吧,上C语言的时候老师一定给大家写过Delay这个函数吧,给大家举个最简单的延时函数吧~

    void Delay (u32 a)

    {

       while(a--);

    }

    那同学们是否记得老师讲过这样一句话,“在以后项目开发中,千万不要用Delay这种死循环的方式来延时,最好用定时器来代替Delay延时函数“。

    一般情况下,老师都会说过的对吧~

    这是因为Dealy的延时,是通过CPU做循环的方式来延时,CPU在延时中是做不了其他东西的,大大浪费了CPU的效率!而且非常危险!

    所以大家在裸机中如果要需要很长时间延时的话,建议用定时器来延时。但今天的重点不是裸机的延时函数,而是有操作系统的延时函数。

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

    刚开始学习FreeRTOS的时候看到FreeRTOS的API延时函数,不竟在想,实时操作系统不是讲究的是实时性吗,怎么也会有这种延时函数!给位大佬有没有共同的感受!

    后来深入了解FreeRTOS之后,才发现,原来这延时函数写的这么巧妙!

    我们先来看一下 vTaskDelay的源码。这是FreeRTOS中的延时API函数。

    void vTaskDelay( const TickType_t xTicksToDelay )
        {
        BaseType_t xAlreadyYielded = pdFALSE;
            if( xTicksToDelay > ( TickType_t ) 0U )
            {
                configASSERT( uxSchedulerSuspended == 0 );
                vTaskSuspendAll();
                {
                    traceTASK_DELAY();        
                    prvAddCurrentTaskToDelayedList( xTicksToDelay, pdFALSE );
                }
                xAlreadyYielded = xTaskResumeAll();
            }
            else
            {
                mtCOVERAGE_TEST_MARKER();
            }
            if( xAlreadyYielded == pdFALSE )
            {
                portYIELD_WITHIN_API();
            }
            else
            {
                mtCOVERAGE_TEST_MARKER();
            }
        }

     参数:const TickType_t xTicksToDelay 这是输入你要延时的时间

    我们看源码我们会发现, vTaskDelay中竟然有挂机函数vTaskSuspendAll();  和恢复函数xTaskResumeAll();

    原来在任务中调用延时函数,只是把任务挂起了,等延时时间到,在把任务恢复。

    举个例子:

    我这边有两个TASK,TASK1和TASK2;

    void Task1( void * pvParameters )
    {
        
        uint8_t i=0;
        
        while(1)
        {
            
            printf("TASK1 RUNNING%d\r\n",i);
            GPIO_SetBits(GPIOC,GPIO_Pin_2);    
            vTaskDelay(500);
            GPIO_ResetBits(GPIOC,GPIO_Pin_2);    
            i++;
            
            vTaskDelay(500);
        
        }
    }
     
     
    void Task2( void * pvParameters )
    {
            uint8_t j=0;
            while(1)
            {
                j++;
                GPIO_ResetBits(GPIOC,GPIO_Pin_3);    
                vTaskDelay(200);
                GPIO_SetBits(GPIOC,GPIO_Pin_3);    
                vTaskDelay(800);
                printf("TASK2 RUNNING%d\r\n",j);
                
            }

    }

    FreeRTOS这个任务执行是这样的。首先TASK1创建,然后在创建TASK2

    TASK先执行, 执行到GPIO_SetBits(GPIOC,GPIO_Pin_2);    下一句vTaskDelay(500);   延时500ms,其实就是任务挂起500ms,CPU此时不会执行TASK的任务,去执行

    处于就绪态的TASK2,   当TASK2的GPIO_ResetBits(GPIOC,GPIO_Pin_3);    执行好了之后执行下一条 vTaskDelay(200);此时TASK1延时500ms,TASK延时200ms。

    这时候FreeRTOS是没有执行处于就绪态的任务的,只有执行空闲任务 。此时由于TASK2是延时200ms,比TASK2延时的500ms要快,所以TASK2比TASK1更早进入

    就绪态,此时CPU执行  GPIO_SetBits(GPIOC,GPIO_Pin_3);    这一语句,执行好了之后TASK2又延时800ms,进入挂起态。当TASK1延时500ms到,TASK1进入就绪态,

    执行GPIO_ResetBits(GPIOC,GPIO_Pin_2);     i++;语句,执行完之后,TASK1又进入500ms的延时,进入挂起态~

    所以在FreeRTOS中的延时函数,只是任务挂起和任务恢复而已,就像创建二值信号量,其实就是创建队列~

    学习操作系统本来就是一件枯燥且乏味的事情~共勉

    绝对延时vTaskDelayUntil函数下次又机会在讲。

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

    展开全文
  • 单片机中的延时函数

    千次阅读 2017-06-12 21:50:43
    在单片机的设计中延时函数是常见,比如流水灯的时间控制等都需对时间进行控制,因此博主贴出一个简单的延时函数供参考./************************************************************/ // 通过延时函数实现数码管...

    在单片机的设计中延时函数最是常见,比如流水灯的时间控制等都需对时间进行控制,因此博主贴出一个简单的延时函数供参考.

    /************************************************************/
    // 通过延时函数实现数码管的显示
    /************************************************************/

    include

    define uchar unsigned char

    code seven_seg[] = {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};
    void delay(unsigned int delay_time) //延时函数
    {
    unsigned int j=0;
    for(;delay_time > 0;delay_time–)
    {
    for(j=0;j < 200;j++);
    }
    }
    void main(void)
    {
    uchar i; //声明一个循环变量
    P2 = 0xfe; //P2.0为0,经74HC04反相后,加在SEG0阳极上的电平为1
    while(1)
    {
    P0 = seven_seg[i]; //显示数组中对应的值
    delay(300);
    i++; //循环一次,i值增加1
    if(i >= 10)
    i = 0;
    }

    }

    注:先用双重嵌套定义延时函数,然后在调用的时候进行参数的设置和传递,单位为MS,可以用来设置流水灯流速,闹钟定时等功能的实现,仅供参考.

    展开全文
  • STM32延时函数的三种方法——最好掌握第三种

    万次阅读 多人点赞 2018-08-05 11:04:58
    单片机编程过程中经常用到延时函数常用莫过于微秒级延时delay_us( )和毫秒级delay_ms( )。 1.普通延时法 这个比较简单,让单片机做一些无关紧要工作来打发时间,经常用循环来实现,不过要做比较精准还是...
  • 单片机 延时函数

    2019-09-21 19:59:16
    在单片机的设计中延时函数是常见,比如流水灯的时间控制等都需对时间进行控制,因此博主贴出一个简单的延时函数供参考. /**********************************************************************/// 通过延时函数...
  • C语言里的延时函数

    万次阅读 2016-07-18 10:32:01
    在Windows下最简单的办法是调用系统函数Sleep(time),单位是ms,在windows.h中声明,注意大小写;不然就用中的函数获得当前时间,然后通过比较记录的时间和当前时间,决定作出的动作(不推荐用空循环,这样会占用CPU...
  • STM32延时函数的三种方法

    千次阅读 2020-01-06 12:17:07
    单片机编程过程中经常用到延时函数常用莫过于微秒级延时delay_us( )和毫秒级delay_ms( )。 1.普通延时法 这个比较简单,让单片机做一些无关紧要工作来打发时间,经常用循环来实现,不过要做比较精准还是...
  • 单片机编程过程中经常用到延时函数常用莫过于微秒级延时delay_us( )和毫秒级delay_ms( )。 1.普通延时法 (1)普通延时法1 这个比较简单,让单片机做一些无关紧要工作来打发时间,经常用循环来实现,不过...
  •  一开始简单的调用了sleep函数,后来调试发现不行。于是自定义了一个延时函数delay 2,那么,自定义延时函数和sleep函数区别究竟在哪呢  sleep在C库函数中,使用需加头文件 #include&lt;time.h&gt;  ...
  • 【STM32】SysTick滴答定时器(delay延时函数讲解)

    万次阅读 多人点赞 2018-04-09 13:51:56
    Systick定时器,是一个简单的定时器,对于CM3、CM4内核芯片,都有Systick定时器。Systick定时器常用来做延时,或者实时系统的心跳时钟。这样可以节省MCU资源,不用浪费一个定时器。比如UCOS中,分时复用,需要一个...
  • dotween仅仅只有300kb左右,但是能实现很多功能简单... 这样写要定义方法,一个最简单的需要4 5行 方法二:使用协程,要另起名,写方法,同样没有个5 6 7 8行写不下来 方法三,用dotween,dotween函数中提供了一...
  • Systick滴答定时器-延时函数

    千次阅读 2017-05-02 12:58:03
    1、参考资料  《STM32F1开发指南-库函数版本》-5.1小节 delay文件夹介绍 ... Systick定时器,是一个简单的定时器,对于CM3,CM4内核芯片,都有Systick定时器。  Systick定时器常用来做延时,或者
  • (一)Systick定时器,是一个简单的定时器(主要的),对于CM3,CM4内核芯片,都有Systick定时器。 Systick定时器常用来做延时,或者实时系统的心跳时钟。这样可以节省MCU资源,不用浪费一个定时器。比如UCOS中,...
  • 这是一个最简单的延时任务执行逻辑,有个问题来了,这样做的话,在等待期间,调用者线程会阻塞掉,因此并没什么实用价值,我们来稍微改进一下,这里会用到上一章讲到的异步函数知识 在这里我们稍微改进了一下,在...
  • 最简单的延时方法就是使用QThread类的sleep(n)、msleep(n)、usleep(n),这几个函数的不良后果就是,GUI会在延时的时间段内失去响应,界面卡死,所以,这三个函数一般用在非GUI线程中。 QThread::msleep(50);//阻塞...
  • STM32几种延时方法

    千次阅读 2018-08-05 16:33:19
    单片机编程过程中经常用到延时函数常用莫过于微秒级延时delay_us( )和毫秒级delay_ms( )。 1.普通延时法 这个比较简单,让单片机做一些无关紧要工作来打发时间,经常用循环来实现,不过要做比较精准...
  • STM32延时不同写法

    2020-12-14 14:23:13
    对于STM32系列的延时函数有着不同的写法,本章将给大家带来最简单的延时到最精准延时函数的各种写法及原理。 在STM32系列中要学会用好systick定时器,这很重要 一.普通延时函数 原理: 用C中累加或者累减的方法,到...
  • MATLAB画带延时系统伯德图

    千次阅读 2020-02-25 16:02:31
    最简单画Bode图就是bode(tf(num,den))就能解决,但是有些传递函数并不是线性,比如带有延时之类,Bode函数对于这类问题就无能为力 给定系统传递函数 w=logspace(-2,4,1000); G=(1-exp(-i*w)).^(2).*(i*w+1)./(-w....
  • 本文首先简单介绍冷启动对使用FaaS (Function as a service)开发者影响,并介绍函数计算冷启动流程和最佳实践。最后会分享函数计算冷启动延时优化现阶段成果,希望对于被冷启动延时所困扰开发者有所帮助。 ...
  • 单片机编程过程中经常用到延时函数常用莫过于微秒级延时delay_us( )和毫秒级delay_ms( )。 1.普通延时法 这个比较简单,让单片机做一些无关紧要工作来打发时间,经常用循环来实现,不过要做比较精准...
  • Qt之延时总结

    2019-03-08 10:36:03
    最简单的延时方法就是使用QThread类的sleep(n)、msleep(n)、usleep(n),这几个函数的不良后果就是,GUI会在延时的时间段内失去响应,界面卡死,所以,这三个函数一般用在非GUI线程中。 QThread::msleep(50);//阻塞...
  • 延时执行常用方法

    2016-11-30 14:09:00
    1、最简单的调用隐式函数方法 [self performSelector:@selector(deleyMethod) withObject:nil afterDelay:5.0]; 必须在主线程中执行,非阻塞线程方式。 2、NSThread [NSThread sleepForTimeInterval:6.0];...
  • 在上一期项目:最简单DIY51蓝牙遥控小车设计方案 访问地址是:https://www.cirmall.com/circuit/20328源码里面有舵机控制部分程序,但是被我注释掉了,由于舵机控制还是比较复杂,这里还是开一个专题来讲解51...
  • STM32延时方法分析

    2020-05-13 11:07:04
    介绍:单片机编程过程中经常用到延时函数常用莫过于微秒级延时delay_us()和毫秒级delay_ms()。 1.普通延时法 这个比较简单,让单片机做一些无关紧要工作来打发时间,经常用循环来实现,不过要做比较精准...

空空如也

空空如也

1 2 3 4 5 ... 10
收藏数 198
精华内容 79
关键字:

最简单的延时函数