[STM32F4] 基本定时器做延时功能,急急急

[复制链接]
4285|46
xch 发表于 2023-2-25 11:22 | 显示全部楼层
liusheng1998 发表于 2023-2-24 21:24
谢谢 已经这么改了下,但是还是不对劲

啥不对劲?
 楼主| liusheng1998 发表于 2023-2-25 11:27 | 显示全部楼层
lvyunhua 发表于 2023-2-25 11:11
1.不知道你的CPU主频是多少,定时器最小计时一次是多少us?
2.不用中断,先定义一个全局变量global_tt=0, ...

好的 ,谢谢你的指点
1.我刚刚参考了多方资料, 在定时器中断10us的模式触发中断 确实行不通,
CPU主频是168Mhz。定时器最小计时是10us
2.不用中断的方式 我正在研究,先看看滴答定时器的模式,使用的写滴答定时器的
  1.         SysTick->LOAD=(u32)nms*fac_ms;                        //时间加载(SysTick->LOAD为24bit)
  2.         SysTick->VAL =0x00;                                   //清空计数器
  3.         SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ;

看来直接写寄存器,而非中断的方式是 大家的一致推荐,
但是之前我试过这种方案,没成。我就放弃了。
现在我觉得再试试
lvyunhua 发表于 2023-2-25 11:47 | 显示全部楼层
liusheng1998 发表于 2023-2-25 11:27
好的 ,谢谢你的指点
1.我刚刚参考了多方资料, 在定时器中断10us的模式触发中断 确实行不通,
CPU主频 ...

我记得STM32滴答定时器定时器最小分辨率是1ms哦   
 楼主| liusheng1998 发表于 2023-2-25 14:35 | 显示全部楼层
本帖最后由 liusheng1998 于 2023-2-26 20:33 编辑
lvyunhua 发表于 2023-2-25 11:47
我记得STM32滴答定时器定时器最小分辨率是1ms哦
  1. void delay_us(u32 nus)
  2. {               
  3.         u32 temp;                     
  4.         SysTick->LOAD=nus*fac_us;                                 //时间加载                           
  5.         SysTick->VAL=0x00;                                        //清空计数器
  6.         SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ; //开始倒数         
  7.         do
  8.         {
  9.                 temp=SysTick->CTRL;
  10.         }while((temp&0x01)&&!(temp&(1<<16)));        //等待时间到达   
  11.         SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk; //关闭计数器
  12.         SysTick->VAL =0X00;                                       //清空计数器
  13. }


这是正点原子的 滴答定时器us级别延迟,可用但只能做百微秒级别。
还在测试为啥。200us延时 很精准。300也还不错。但是250 就乱了具体乱在  200 300 反复横跳,不能是250等十微秒级别
        delay_us(250);
1    0000060B         8  17  50  C4  28  7C  EE  44  8F     757.706210 R           间隔300us
1    0000060B         8  17  50  C4  28  7C  EE  44  82     757.706520 R           间隔200us  
1    0000060B         8  17  50  C4  28  7C  EE  44  81     757.706720 R           间隔200us
1    0000060B         8  17  50  C4  28  7C  EE  44  8C     757.707030 R           间隔320us
1    0000060B         8  17  50  C4  28  7C  EE  44  8C     757.707240 R
-————————————————————————————————————————————
1    0000060B         8  17  50  C4  28  7C  EE  44  8F     771.714530 R
1    0000060B         8  17  50  C4  28  7C  EE  44  82     771.714740 R
1    0000060B         8  17  50  C4  28  7C  EE  44  81     771.715040 R
1    0000060B         8  17  50  C4  28  7C  EE  44  8C     771.715250 R
1    0000060B         8  17  50  C4  28  7C  EE  44  8C     771.715560 R
------------------------------------------------------------------------------------------------
 楼主| liusheng1998 发表于 2023-2-25 14:36 | 显示全部楼层

你好,不对劲的地方在于
没起到作用,卡住了。我反思原因出在  10us进入中断处理函数的频次太高了。
导致程序运行不起来
xch 发表于 2023-2-25 17:35 | 显示全部楼层
liusheng1998 发表于 2023-2-25 14:36
你好,不对劲的地方在于
没起到作用,卡住了。我反思原因出在  10us进入中断处理函数的频次太高了。
导致 ...

啥MCU 这么磨洋工? 一般运行在 32MHZ 主频的 ARM 也来得及

评论

xch
@Prry : 10us 跑大约320条指令 。中断服务干啥了?  发表于 2023-2-26 00:46
来得及跟有没有产生价值是两回事。cpu的资源全干中断去了,其他任务都不用干了。  发表于 2023-2-25 22:59
 楼主| liusheng1998 发表于 2023-2-25 19:15 | 显示全部楼层
xch 发表于 2023-2-25 17:35
啥MCU 这么磨洋工? 一般运行在 32MHZ 主频的 ARM 也来得及

STM32F407
我见其他地方也说这么做10us中断太频繁了。
xch 发表于 2023-2-25 20:14 | 显示全部楼层
liusheng1998 发表于 2023-2-25 19:15
STM32F407
我见其他地方也说这么做10us中断太频繁了。

是频繁。不等于不能跑。
有一种办法,将定时器级联。主定时器产生10us 脉冲,不必产生中断。从定时器设定需要延时的拍数,产生捕获中断。甚至可以利用多路捕获通道产生多路延时。
 楼主| liusheng1998 发表于 2023-2-25 20:25 | 显示全部楼层
xch 发表于 2023-2-25 20:14
是频繁。不等于不能跑。
有一种办法,将定时器级联。主定时器产生10us 脉冲,不必产生中断。从定时器设定 ...

您这个思路 我还没想过,听起来确实高级。可以避免定时器频繁中断的问题。
我要做高精度延时 确实应该采取复杂一些的的方式来延时。
我去了解一下高级定时器的捕获中断功能先
xch 发表于 2023-2-25 20:28 | 显示全部楼层
liusheng1998 发表于 2023-2-25 20:25
您这个思路 我还没想过,听起来确实高级。可以避免定时器频繁中断的问题。
我要做高精度延时 确实应该采 ...

没准MCU 的工作时钟没搞对。使用默认的慢吞吞的MSI 时钟在跑。
 楼主| liusheng1998 发表于 2023-2-25 20:47 | 显示全部楼层
xch 发表于 2023-2-25 20:28
没准MCU 的工作时钟没搞对。使用默认的慢吞吞的MSI 时钟在跑。

啊? 我用的定时器应该还是正常配置的吧,根据时钟树的应该是APB1的X2的时钟来源。
xch 发表于 2023-2-25 20:51 | 显示全部楼层
liusheng1998 发表于 2023-2-25 20:47
啊? 我用的定时器应该还是正常配置的吧,根据时钟树的应该是APB1的X2的时钟来源。 ...

用定时器输出个方波,看看方波频率是否与想象的一样。
Prry 发表于 2023-2-25 22:57 | 显示全部楼层
lvyunhua 发表于 2023-2-25 11:47
我记得STM32滴答定时器定时器最小分辨率是1ms哦

时钟可以分频,可以做到纳秒级别。
Prry 发表于 2023-2-25 23:08 | 显示全部楼层
本帖最后由 Prry 于 2023-2-25 23:10 编辑

别整复杂,很简单的东西;17楼实现方案即可,任一定时器,配置时钟分频,1us计数一次,不用开启中断,延时函数取出定时器计数值比较即可。
void delay_us(uint32_t us)
{
    uint32_t cnt = 0;
    uint32_t last_cnt = 0;
     last_cnt = __HAL_TIM_GET_COUNTER(&htim1);
     while (cnt < us)
      {
                if (last_cnt != __HAL_TIM_GET_COUNTER(&htim1))
                {
                        last_cnt = __HAL_TIM_GET_COUNTER(&htim1);
                        cnt++;
                }
        }
}

打赏榜单

liusheng1998 打赏了 1.00 元 2023-02-26
理由:聊表谢意^^

mcu5i51 发表于 2023-2-26 08:39 | 显示全部楼层
为什么要比较值,设置定时器计数值,不开中断(精确请禁用全局中断),清中断标志,开始计时,时间溢出,检测溢出(中断位)完成;
优点:
不用中断功能,可以防止进入中断的几个到十几个的不确定周期,只剩下循环中的周期了,可以最大情况减少误差;
寄存器一般不用考虑优化
缺点:
禁用全局中断后和定周期的计数循环相仿,不禁用全局中断,误差为可能的中断运行周期;
另一个方法就是使用中断方式,主函数设定计时,中断中处理及时响应的代码,调整对应优先级,达到整体平衡
 楼主| liusheng1998 发表于 2023-2-26 10:04 | 显示全部楼层
本帖最后由 liusheng1998 于 2023-2-26 10:20 编辑
Prry 发表于 2023-2-25 23:08
别整复杂,很简单的东西;17楼实现方案即可,任一定时器,配置时钟分频,1us计数一次,不用开启中断,延时 ...
谢谢你的指教,给出的代码我研究了一下。
  1. while (cnt < us)
  2.       {
  3.                 if (last_cnt != __HAL_TIM_GET_COUNTER(&htim1))
  4.                 {
  5.                         last_cnt = __HAL_TIM_GET_COUNTER(&htim1);
  6.                         cnt++;
  7.                 }
我说一下我的理解: while循环是用来判断延时us数是否满足,接下来if判断的意思是,当前计数值last_cnt 是否等于向上计数的CNT 值,
如果不等于 说明 CNT 已经向上计数了一次。就读取CNT值到last_cnt,cnt就加一表明1us;
如果等于CNT,说明还没有向上计数一次。就不让cnt加一为过去1us。
  1. if (last_cnt != __HAL_TIM_GET_COUNTER(&htim1))
这个思路很棒,我来实际测试一下,看看效果如何!
 楼主| liusheng1998 发表于 2023-2-26 20:03 | 显示全部楼层
本帖最后由 liusheng1998 于 2023-2-26 20:37 编辑
Prry 发表于 2023-2-25 23:08
别整复杂,很简单的东西;17楼实现方案即可,任一定时器,配置时钟分频,1us计数一次,不用开启中断,延时 ...
  1. mbox=CAN_Transmit(CAN1,&TxMessage);
  2. MyDelay(250);
      
这就是我的延时函数。
  1. void MyDelay(int us)
  2.         {
  3.     int cnt=0;
  4.     int last_cnt=0;
  5.     last_cnt=TIM_GetCounter(TIM3);
  6.      while(cnt<us)
  7.       {
  8.           if(last_cnt != TIM_GetCounter(TIM3))  
  9.          {
  10.              last_cnt=TIM_GetCounter(TIM3);
  11.              cnt++;
  12.          }
  13.       }   
  14.         }
下面看出来 延迟的效果是 300us 200us 300us 200us。
1    0000060B         8  17  50  C4  28  7C  EE  44  81    1077.264156 R
1    0000060B         8  17  50  C4  28  7C  EE  44  82    1077.264466 R
1    0000060B         8  17  50  C4  28  7C  EE  44  83    1077.264666 R
1    0000060B         8  17  50  C4  28  7C  EE  44  84    1077.264976 R
1    0000060B         8  17  50  C4  28  7C  EE  44  85    1077.265176 R
不知道是为什么,跟抵达延时器的效果差不多,只能是200 300  不能是250根据我的数据接收显示,单论定时器存在的问题就是 为什么会有小于250us的延迟出现。就不考虑CAN报文发送是否需要时间。
延时的执行函数 应该会大于等于250us的接收间隔吧!我自己的分析:
虽然执行次数是对的,比如说参数us是250次 while判断,但是向上计数一次 耗时不是严格1us导致。
也就是说初始化配置定时器的1us不准确?。这个东西能不能设置准确呢?
  1. TIM3_Int_Init(5-1,84-1);




评论

可以的,检查定时器配置,时钟分频那部分,配置为1us计数一次。 你这样测试不准确,主循环有阻塞(比如你那个can发送函数),阻塞过程定时器也会计时;如果定时器配置没错,那就是的主循环函数50us执行一个周期,导致300/200的时间出现。  发表于 2023-2-26 23:17
 楼主| liusheng1998 发表于 2023-2-27 09:03 | 显示全部楼层
可以的,检查定时器配置,时钟分频那部分,配置为1us计数一次。 你这样测试不准确,主循环有阻塞(比如你那个can发送函数),阻塞过程定时器也会计时;如果定时器配置没错,那就是的主循环函数50us执行一个周期,导致300/200的时间出现。
请问一下,这个主循环函数50us执行一个周期是什么意思。我在调用延时函数的时候,只是用了一次
Mydealy(250)。
上面实验现象是  310  200 310 200us。时间间隔效果。
 楼主| liusheng1998 发表于 2023-2-27 09:46 | 显示全部楼层
不论是 通用定时器的200us 延时设计,还是滴答定时器的200us设计。实际接收效果 显示
都没有达到精准的200us。而是在200us 至 210us 这两个时间效果左右。
并且我的CAN报文验收设备的显示精度 只达到10us的显示级别。
因此无法验证微秒级别的延时效果。起码硬件不支持、
现在是否能提升到10us精度 ,是一个问题。
是你让我看见干枯沙漠开出花一朵。
 楼主| liusheng1998 发表于 2023-2-27 10:07 | 显示全部楼层
CPU执行中断时需要时间的,如入栈,出栈,以及其他处理,都需要时间!
一般情况下,STM32的中断性能不超过500Khz,也就是中断间隔达到2us一次时,
不管你中断函数多精简,基本上CPU就不会干其他什么事情了,因为它都在进出中断了。
单条指令执行时间:STM32F10X单片机在主频为72MHz下,C语言程序执行一条指令需要的时间可认为10ns~100ns。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 在线客服 返回列表 返回顶部