OpenEdv-开源电子网

标题: FreeRTOS系统下us级延时如何实现? [打印本页]

作者: 强辉电子    时间: 2022-1-24 20:00
标题: FreeRTOS系统下us级延时如何实现?
请教各位大神,在FreeRTOS下,us级延时如何实现?us延时在模拟iic中用得最多,系统只提供了ms级延时函数,而原子提供的us、ms级延时函数似乎只能在裸机及ucos下使用。
作者: feng69635    时间: 2022-2-19 17:52
你应该是想问如何在FreeRTOS中实现模拟I2C吧,精确延迟我没有,我处理的方式是使用粗略的阻塞延迟实现us级延迟。I2C实现方式如下所示(仅供参考):
//微妙级延迟,非精准
static void delay_us(uint32_t us)
{
        while(us!=0){
                us--;
                __NOP();
        }
}

//FreeRTOS中I2C读取测试
uint8_t test(uint16_t ReadAddr,int NumToRead,uint8_t *rbuf)
{
        uint8_t i;
        uint8_t t=0;

        IIC_Start();  //开始  
        IIC_Send_Byte(0x14 | 0x00); //进入写模式               
        IIC_Wait_Ack();  
        delay_us(45);//大致延迟45us,时序需要
  
        IIC_Send_Byte(ReadAddr); //读数据地址                          
        IIC_Wait_Ack();           
        delay_us(45);//大致延迟45us,时序需要
   
        IIC_Start();  //重新开始
        IIC_Send_Byte(0x14 | 0x01); //进入读模式       
        IIC_Wait_Ack();   
  
        vTaskDelay(1);//RTOS延迟1ms,保证当前程序执行时间小于1ms
  
        for(i=0;i<NumToRead;i++)//读取数据
        {
                if(i!=(NumToRead-1))
                        t =IIC_Read_Byte(1);//回复
                else
                  t =IIC_Read_Byte(0);//不回复       
   
                rbuf[i] = t;       
                if(((i+1)%4)==0){ //每读4个,延迟1ms,保证当前程序执行时间小于1ms
                   vTaskDelay(1);
                }
        }  
  IIC_Stop();//产生一个停止条件
  
  return 1;
}  
作者: 强辉电子    时间: 2022-2-20 10:47
feng69635 发表于 2022-2-19 17:52
你应该是想问如何在FreeRTOS中实现模拟I2C吧,精确延迟我没有,我处理的方式是使用粗略的阻塞延迟实现us级 ...

谢谢哈,不过us级延时还是用的很广泛的,除了在模拟iic中,还有模拟spi中,都能用到。在freertos中,时基都是1ms的。us延时用阻塞方式,还是相对可取的,主要是时间短。
作者: 金钱猫撸金币    时间: 2022-6-30 13:14
楼主解决了吗?
作者: lovecomputer    时间: 2022-7-6 08:59
同问、同需求
作者: 霸王猫    时间: 2022-7-6 11:01
2楼的方法很好。
   对于IIC和SPI芯片的模拟时序操作,可以用自己写的延时函数(大致精确即可,也可以用示波器观察确认延时时间是否精确,然后进行调整),不必用系统的延时节拍函数。

   如果对时序要求很严格,而且不允许被中断打断,可以添加关中断措施。
作者: llpu    时间: 2022-8-5 08:46
通过timebase定时器 简单的us延时 测试还行 仅供参考
void delay_us(uint16_t Delay)
{   
    uint16_t tickstart = __HAL_TIM_GET_COUNTER(&htim7);
    uint16_t wait = Delay;

    while(((1000 + __HAL_TIM_GET_COUNTER(&htim7) - tickstart) % 1000) < wait)
    {
               
    }
}
作者: 1597685605    时间: 2022-10-9 16:06
NOP指令不精准延时
作者: 霸王猫    时间: 2022-10-13 19:57
正点原子提供了us的延时函数

//延时nus
//nus:要延时的us数.      
//nus:0~204522252(最大值即2^32/fac_us@fac_us=168)                                                                              
void delay_us(u32 nus)
{               
        u32 ticks;
        u32 told,tnow,tcnt=0;
        u32 reload=SysTick->LOAD;                                //LOAD的值                     
        ticks=nus*fac_us;                                                 //需要的节拍数
        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;                        //时间超过/等于要延迟的时间,则退出.
                }  
        };                                                                                    
}  
作者: 海绵宝侠    时间: 2022-10-15 19:52
正点原子提供了us延时的函数,不过我认为需要在临界区里运行
作者: 35号技师    时间: 2022-10-17 09:05
用arm内核dwt外设延时呗
作者: zzr在这里    时间: 2022-10-23 18:24
可以用dwt外设来写嘞
作者: 霸王猫    时间: 2022-10-25 21:38
zzr在这里 发表于 2022-10-23 18:24
可以用dwt外设来写嘞
  1. /*
  2. *********************************************************************************************************
  3. *
  4. *        模块名称 : 数据观察点与跟踪(DWT)模块
  5. *        文件名称 : bsp_dwt.c
  6. *        版    本 : V1.0
  7. *        说    明 : 在CM3,CM4中可以有3种跟踪源:ETM, ITM 和DWT,本驱动主要实现
  8. *              DWT中的时钟周期(CYCCNT)计数功能,此功能非常重要,可以很方便的
  9. *              计算程序执行的时钟周期个数。
  10. *        修改记录 :
  11. *                版本号    日期        作者     说明
  12. *                V1.0    2015-08-18   Eric2013 正式发布
  13. *
  14. *        Copyright (C), 2015-2020, 安富莱电子 www.armfly.com
  15. *
  16. *********************************************************************************************************
  17. */

  18. #include "stm32f10x.h"
  19. #include "bsp_dwt.h"


  20. /*
  21. *********************************************************************************************************
  22. *                                             寄存器
  23. *********************************************************************************************************
  24. */
  25. #define  DWT_CYCCNT  *(volatile unsigned int *)0xE0001004
  26. #define  DWT_CR      *(volatile unsigned int *)0xE0001000
  27. #define  DEM_CR      *(volatile unsigned int *)0xE000EDFC
  28. #define  DBGMCU_CR   *(volatile unsigned int *)0xE0042004

  29. #define  DEM_CR_TRCENA               (1 << 24)
  30. #define  DWT_CR_CYCCNTENA            (1 <<  0)


  31. /*
  32. *********************************************************************************************************
  33. *        函 数 名: bsp_InitDWT
  34. *        功能说明: 初始化DWT. 该函数被 bsp_Init() 调用。
  35. *        形    参: 无
  36. *        返 回 值: 无
  37. *********************************************************************************************************
  38. */
  39. void bsp_InitDWT(void)
  40. {
  41.         DEM_CR         |= (unsigned int)DEM_CR_TRCENA;   /* Enable Cortex-M4's DWT CYCCNT reg.  */
  42.         DWT_CYCCNT      = (unsigned int)0u;
  43.         DWT_CR         |= (unsigned int)DWT_CR_CYCCNTENA;
  44. }



  45. /*
  46. *********************************************************************************************************
  47. *        函 数 名: bsp_DelayUS
  48. *        功能说明: 这里的延时采用CPU的内部计数实现,32位计数器
  49. *                     OSSchedLock(&err);
  50. *                                bsp_DelayUS(5);
  51. *                                OSSchedUnlock(&err); 根据实际情况看看是否需要加调度锁或选择关中断
  52. *        形    参: _ulDelayTime  延迟长度,单位1 us
  53. *        返 回 值: 无
  54. *   说    明: 1. 主频168MHz的情况下,32位计数器计满是2^32/168000000 = 25.565秒
  55. *                建议使用本函数做延迟的话,延迟在1秒以下。  
  56. *             2. 实际通过示波器测试,微妙延迟函数比实际设置实际多运行0.25us左右的时间。
  57. *             下面数据测试条件:
  58. *             (1). MDK5.15,优化等级0, 不同的MDK优化等级对其没有影响。
  59. *             (2). STM32F407IGT6
  60. *             (3). 测试方法:
  61. *                                 GPIOI->BSRRL = GPIO_Pin_8;
  62. *                                 bsp_DelayUS(10);
  63. *                                 GPIOI->BSRRH = GPIO_Pin_8;
  64. *             -------------------------------------------
  65. *                测试                 实际执行
  66. *             bsp_DelayUS(1)          1.2360us
  67. *             bsp_DelayUS(2)          2.256us
  68. *             bsp_DelayUS(3)          3.256us
  69. *             bsp_DelayUS(4)          4.256us
  70. *             bsp_DelayUS(5)          5.276us
  71. *             bsp_DelayUS(6)          6.276us
  72. *             bsp_DelayUS(7)          7.276us
  73. *             bsp_DelayUS(8)          8.276us
  74. *             bsp_DelayUS(9)          9.276us
  75. *             bsp_DelayUS(10)         10.28us
  76. *            3. 两个32位无符号数相减,获取的结果再赋值给32位无符号数依然可以正确的获取差值。
  77. *              假如A,B,C都是32位无符号数。
  78. *              如果A > B  那么A - B = C,这个很好理解,完全没有问题
  79. *              如果A < B  那么A - B = C, C的数值就是0xFFFFFFFF - B + A + 1。这一点要特别注意,正好用于本函数。
  80. *********************************************************************************************************
  81. */
  82. void bsp_DelayUS(uint32_t _ulDelayTime)
  83. {
  84.     uint32_t tCnt, tDelayCnt;
  85.         uint32_t tStart;
  86.                
  87.         tStart = DWT_CYCCNT;                                     /* 刚进入时的计数器值 */
  88.         tCnt = 0;
  89.         tDelayCnt = _ulDelayTime * (SystemCoreClock / 1000000);         /* 需要的节拍数 */                      

  90.         while(tCnt < tDelayCnt)
  91.         {
  92.                 tCnt = DWT_CYCCNT - tStart; /* 求减过程中,如果发生第一次32位计数器重新计数,依然可以正确计算 */       
  93.         }
  94. }



  95. /*
  96. *********************************************************************************************************
  97. *        函 数 名: bsp_DelayMS
  98. *        功能说明: 为了让底层驱动在带RTOS和裸机情况下有更好的兼容性
  99. *             专门制作一个阻塞式的延迟函数,在底层驱动中ms毫秒延迟主要用于初始化,并不会影响实时性。
  100. *        形    参: n 延迟长度,单位1 ms
  101. *        返 回 值: 无
  102. *********************************************************************************************************
  103. */
  104. void bsp_DelayMS(uint32_t _ulDelayTime)
  105. {
  106.         bsp_DelayUS(1000*_ulDelayTime);
  107. }
复制代码



作者: 霸王猫    时间: 2022-10-25 21:42
DWT可以完美的在FreeRTOS中做微秒延时

1、首先在main()中调用  bsp_InitDWT()
2、然后在程序中调用bsp_DelayUS(uint32_t _ulDelayTime)
作者: ZHANQIANKUN    时间: 2022-11-5 09:06
自己写一个了。
作者: 1240134740    时间: 2024-1-23 16:25
请问一下楼主为啥原子提供的us,ms级延时函数在freertos中不能使用,我现在在任务中读ds18B20的时候,延时函数直接失效,不明白是为啥
作者: xyzhu    时间: 2024-5-9 15:49
本帖最后由 xyzhu 于 2024-5-9 16:07 编辑
1240134740 发表于 2024-1-23 16:25
请问一下楼主为啥原子提供的us,ms级延时函数在freertos中不能使用,我现在在任务中读ds18B20的时候,延时 ...

freertos一般用的是systick 节拍器, 原子哥的裸机ms,us延时用的是systick,每次调用好像把计数器重载了。所以会造成错误。要调用为freertos改写的ms,us函数,原子哥好像也有示例代码的。




欢迎光临 OpenEdv-开源电子网 (http://47.111.11.73/) Powered by Discuz! X3.4