发新帖本帖赏金 3.00元(功能说明)我要提问
返回列表
打印
[STM32F4]

基本定时器做延时功能,急急急

[复制链接]
楼主: liusheng1998
手机看帖
扫描二维码
随时随地手机跟帖
21
xch| | 2023-2-25 11:22 | 只看该作者 回帖奖励 |倒序浏览
liusheng1998 发表于 2023-2-24 21:24
谢谢 已经这么改了下,但是还是不对劲

啥不对劲?

使用特权

评论回复
22
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.不用中断的方式 我正在研究,先看看滴答定时器的模式,使用的写滴答定时器的
        SysTick->LOAD=(u32)nms*fac_ms;                        //时间加载(SysTick->LOAD为24bit)
        SysTick->VAL =0x00;                                   //清空计数器
        SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ;

看来直接写寄存器,而非中断的方式是 大家的一致推荐,
但是之前我试过这种方案,没成。我就放弃了。
现在我觉得再试试

使用特权

评论回复
23
lvyunhua| | 2023-2-25 11:47 | 只看该作者
liusheng1998 发表于 2023-2-25 11:27
好的 ,谢谢你的指点
1.我刚刚参考了多方资料, 在定时器中断10us的模式触发中断 确实行不通,
CPU主频 ...

我记得STM32滴答定时器定时器最小分辨率是1ms哦   

使用特权

评论回复
24
liusheng1998|  楼主 | 2023-2-25 14:35 | 只看该作者
本帖最后由 liusheng1998 于 2023-2-26 20:33 编辑
lvyunhua 发表于 2023-2-25 11:47
我记得STM32滴答定时器定时器最小分辨率是1ms哦
void delay_us(u32 nus)
{               
        u32 temp;                     
        SysTick->LOAD=nus*fac_us;                                 //时间加载                           
        SysTick->VAL=0x00;                                        //清空计数器
        SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ; //开始倒数         
        do
        {
                temp=SysTick->CTRL;
        }while((temp&0x01)&&!(temp&(1<<16)));        //等待时间到达   
        SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk; //关闭计数器
        SysTick->VAL =0X00;                                       //清空计数器
}


这是正点原子的 滴答定时器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
------------------------------------------------------------------------------------------------

使用特权

评论回复
25
liusheng1998|  楼主 | 2023-2-25 14:36 | 只看该作者

你好,不对劲的地方在于
没起到作用,卡住了。我反思原因出在  10us进入中断处理函数的频次太高了。
导致程序运行不起来

使用特权

评论回复
26
xch| | 2023-2-25 17:35 | 只看该作者
liusheng1998 发表于 2023-2-25 14:36
你好,不对劲的地方在于
没起到作用,卡住了。我反思原因出在  10us进入中断处理函数的频次太高了。
导致 ...

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

使用特权

评论回复
评论
Prry 2023-2-25 22:59 回复TA
来得及跟有没有产生价值是两回事。cpu的资源全干中断去了,其他任务都不用干了。 
27
liusheng1998|  楼主 | 2023-2-25 19:15 | 只看该作者
xch 发表于 2023-2-25 17:35
啥MCU 这么磨洋工? 一般运行在 32MHZ 主频的 ARM 也来得及

STM32F407
我见其他地方也说这么做10us中断太频繁了。

使用特权

评论回复
28
xch| | 2023-2-25 20:14 | 只看该作者
liusheng1998 发表于 2023-2-25 19:15
STM32F407
我见其他地方也说这么做10us中断太频繁了。

是频繁。不等于不能跑。
有一种办法,将定时器级联。主定时器产生10us 脉冲,不必产生中断。从定时器设定需要延时的拍数,产生捕获中断。甚至可以利用多路捕获通道产生多路延时。

使用特权

评论回复
29
liusheng1998|  楼主 | 2023-2-25 20:25 | 只看该作者
xch 发表于 2023-2-25 20:14
是频繁。不等于不能跑。
有一种办法,将定时器级联。主定时器产生10us 脉冲,不必产生中断。从定时器设定 ...

您这个思路 我还没想过,听起来确实高级。可以避免定时器频繁中断的问题。
我要做高精度延时 确实应该采取复杂一些的的方式来延时。
我去了解一下高级定时器的捕获中断功能先

使用特权

评论回复
30
xch| | 2023-2-25 20:28 | 只看该作者
liusheng1998 发表于 2023-2-25 20:25
您这个思路 我还没想过,听起来确实高级。可以避免定时器频繁中断的问题。
我要做高精度延时 确实应该采 ...

没准MCU 的工作时钟没搞对。使用默认的慢吞吞的MSI 时钟在跑。

使用特权

评论回复
31
liusheng1998|  楼主 | 2023-2-25 20:47 | 只看该作者
xch 发表于 2023-2-25 20:28
没准MCU 的工作时钟没搞对。使用默认的慢吞吞的MSI 时钟在跑。

啊? 我用的定时器应该还是正常配置的吧,根据时钟树的应该是APB1的X2的时钟来源。

使用特权

评论回复
32
xch| | 2023-2-25 20:51 | 只看该作者
liusheng1998 发表于 2023-2-25 20:47
啊? 我用的定时器应该还是正常配置的吧,根据时钟树的应该是APB1的X2的时钟来源。 ...

用定时器输出个方波,看看方波频率是否与想象的一样。

使用特权

评论回复
33
Prry| | 2023-2-25 22:57 | 只看该作者
lvyunhua 发表于 2023-2-25 11:47
我记得STM32滴答定时器定时器最小分辨率是1ms哦

时钟可以分频,可以做到纳秒级别。

使用特权

评论回复
34
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
理由:聊表谢意^^

35
mcu5i51| | 2023-2-26 08:39 | 只看该作者
为什么要比较值,设置定时器计数值,不开中断(精确请禁用全局中断),清中断标志,开始计时,时间溢出,检测溢出(中断位)完成;
优点:
不用中断功能,可以防止进入中断的几个到十几个的不确定周期,只剩下循环中的周期了,可以最大情况减少误差;
寄存器一般不用考虑优化
缺点:
禁用全局中断后和定周期的计数循环相仿,不禁用全局中断,误差为可能的中断运行周期;
另一个方法就是使用中断方式,主函数设定计时,中断中处理及时响应的代码,调整对应优先级,达到整体平衡

使用特权

评论回复
36
liusheng1998|  楼主 | 2023-2-26 10:04 | 只看该作者
本帖最后由 liusheng1998 于 2023-2-26 10:20 编辑
Prry 发表于 2023-2-25 23:08
别整复杂,很简单的东西;17楼实现方案即可,任一定时器,配置时钟分频,1us计数一次,不用开启中断,延时 ...
谢谢你的指教,给出的代码我研究了一下。
while (cnt < us)
      {
                if (last_cnt != __HAL_TIM_GET_COUNTER(&htim1))
                {
                        last_cnt = __HAL_TIM_GET_COUNTER(&htim1);
                        cnt++;
                }
我说一下我的理解: while循环是用来判断延时us数是否满足,接下来if判断的意思是,当前计数值last_cnt 是否等于向上计数的CNT 值,
如果不等于 说明 CNT 已经向上计数了一次。就读取CNT值到last_cnt,cnt就加一表明1us;
如果等于CNT,说明还没有向上计数一次。就不让cnt加一为过去1us。
 if (last_cnt != __HAL_TIM_GET_COUNTER(&htim1))
这个思路很棒,我来实际测试一下,看看效果如何!

使用特权

评论回复
37
liusheng1998|  楼主 | 2023-2-26 20:03 | 只看该作者
本帖最后由 liusheng1998 于 2023-2-26 20:37 编辑
Prry 发表于 2023-2-25 23:08
别整复杂,很简单的东西;17楼实现方案即可,任一定时器,配置时钟分频,1us计数一次,不用开启中断,延时 ...
mbox=CAN_Transmit(CAN1,&TxMessage);
MyDelay(250);
      
这就是我的延时函数。
void MyDelay(int us)
        {
    int cnt=0;
    int last_cnt=0;
    last_cnt=TIM_GetCounter(TIM3);
     while(cnt<us)
      {
          if(last_cnt != TIM_GetCounter(TIM3))  
         {
             last_cnt=TIM_GetCounter(TIM3);
             cnt++;
         }
      }   
        }
下面看出来 延迟的效果是 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不准确?。这个东西能不能设置准确呢?
TIM3_Int_Init(5-1,84-1);




使用特权

评论回复
评论
Prry 2023-2-26 23:17 回复TA
可以的,检查定时器配置,时钟分频那部分,配置为1us计数一次。 你这样测试不准确,主循环有阻塞(比如你那个can发送函数),阻塞过程定时器也会计时;如果定时器配置没错,那就是的主循环函数50us执行一个周期,导致300/200的时间出现。 
38
liusheng1998|  楼主 | 2023-2-27 09:03 | 只看该作者
可以的,检查定时器配置,时钟分频那部分,配置为1us计数一次。 你这样测试不准确,主循环有阻塞(比如你那个can发送函数),阻塞过程定时器也会计时;如果定时器配置没错,那就是的主循环函数50us执行一个周期,导致300/200的时间出现。
请问一下,这个主循环函数50us执行一个周期是什么意思。我在调用延时函数的时候,只是用了一次
Mydealy(250)。
上面实验现象是  310  200 310 200us。时间间隔效果。

使用特权

评论回复
39
liusheng1998|  楼主 | 2023-2-27 09:46 | 只看该作者
不论是 通用定时器的200us 延时设计,还是滴答定时器的200us设计。实际接收效果 显示
都没有达到精准的200us。而是在200us 至 210us 这两个时间效果左右。
并且我的CAN报文验收设备的显示精度 只达到10us的显示级别。
因此无法验证微秒级别的延时效果。起码硬件不支持、
现在是否能提升到10us精度 ,是一个问题。
是你让我看见干枯沙漠开出花一朵。

使用特权

评论回复
40
liusheng1998|  楼主 | 2023-2-27 10:07 | 只看该作者
CPU执行中断时需要时间的,如入栈,出栈,以及其他处理,都需要时间!
一般情况下,STM32的中断性能不超过500Khz,也就是中断间隔达到2us一次时,
不管你中断函数多精简,基本上CPU就不会干其他什么事情了,因为它都在进出中断了。
单条指令执行时间:STM32F10X单片机在主频为72MHz下,C语言程序执行一条指令需要的时间可认为10ns~100ns。

使用特权

评论回复
发新帖 本帖赏金 3.00元(功能说明)我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则