appwyp 2023-02-14 15:15 采纳率: 43.8%
浏览 155
已结题

STM32F4 计数器设计

要在STM32 F4上 测试算法 性能 (重点原子的开发板 180MHz 的频率)
1 要精确到us 不是 ms,裸机程序
2 在不加RTC的情况下如何记录系统运行的时间。一个32位 uint32_t (2^32=4,294,967,296) (大约可以表示1.19小时)
曾经用过定时器,每中断一次计算器加1. 1ms 中断一次程序可运行,但需要精确到us,如果是1us中断一次,程序就没法跑了,不停中断


volatile uint32_t T = 0;
volatile uint32_t T1 = 0;
volatile uint32_t T2 = 0;
volatile uint32_t reload = 0;
.....

reload = SysTick->LOAD;
T1 = SysTick->VAL;
algo();
T2 = SysTick->VAL;
if (T1 != T2)
{
       if (T2 < T1)
    {
        T = T1 - T2;
    }
    else
    {
        T = reload - T2 + T1;
    }
}

  • 写回答

18条回答 默认 最新

  • qiugs2020 2023-02-20 10:44
    关注

    当需要在没有RTC的情况下记录系统运行时间时,我们可以使用STM32的系统滴答定时器(SysTick)来实现。

    系统滴答定时器是一个24位的计数器,它可以按照预设的时间间隔(通常为1ms)自动递减,当计数器减为0时,就会产生一次SysTick中断。在中断服务程序中,我们可以记录系统的运行时间,并进行相应的处理。

    为了精确到us,我们需要根据SysTick定时器的时钟频率来计算每个SysTick定时器中断所表示的时间。在STM32F4上,SysTick定时器的时钟频率是AHB总线时钟频率(通常等于系统时钟频率)的1/8。因此,如果我们的系统时钟频率是180MHz,则SysTick定时器的时钟频率是180/8=22.5MHz。

    计算每个SysTick中断所表示的时间(即SysTick定时器的计数周期)的方法如下:

    由于SysTick定时器是一个24位的计数器,因此它的计数周期是2^24 = 16,777,216。
    SysTick定时器的时钟频率是22.5MHz,因此每个SysTick中断所表示的时间是16,777,216/22.5MHz ≈ 0.744ms。
    在中断服务程序中,我们可以记录系统的运行时间(以us为单位)的代码如下

    volatile uint32_t systick_count = 0;  // 系统运行时间(以us为单位)
    
    void SysTick_Handler(void)
    {
        systick_count += 744;  // 每个SysTick中断表示的时间是744us
    }
    
    uint32_t get_system_time_us(void)
    {
        uint32_t ticks;
        uint32_t cnt;
        do {
            ticks = systick_count;
            cnt = SysTick->VAL;
        } while (ticks != systick_count);
        return ticks + 744 - cnt / (SystemCoreClock / 22500000);
    }
    
    
    

    在上面的代码中,我们定义了一个全局变量systick_count来记录系统运行的时间(以us为单位),并在SysTick中断服务程序中每次增加744。这个数值是根据上面的计算得到的每个SysTick中断所表示的时间(即0.744ms)除以1000得到的,即744us。

    在get_system_time_us()函数中,我们先读取当前的systick_count值和SysTick定时器的当前计数值(cnt),如果在读取过程中SysTick中断发生了,我们就再次读取,直到两次读取得到的systick_count值相同。然后我们将这两个值相加,并减去cnt/(SystemCoreClock/22500000)的值,得到系统运行的时间(以us为单位)。

    这个差值的计算方法是根据SysTick计数器的减法计算方法得到的。当SysTick计数器减为0时,它会自动重载
    使用DWT(Dat Watchpoint and Trace)寄存器进行计时
    DWT寄存器是专门用来进行调试的寄存器,其中包括一个32位的计数器CYCCNT,可以实现精确计时。使用DWT寄存器需要开启调试功能,并且在编译时需要将调试信息加入代码中。

    具体的使用方法如下:

    在main函数中开启DWT寄存器,代码如下:

    CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
    DWT->CYCCNT = 0;
    DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
    
    
    

    在需要进行计时的地方使用DWT_CYCCNT寄存器获取当前计数值,代码如下:

    uint32_t start = DWT->CYCCNT;
    algo();
    uint32_t end = DWT->CYCCNT;
    uint32_t cycles = end - start;
    
    
    

    这样就可以使用DWT寄存器实现精确计时。

    需要注意的是,DWT寄存器只能在调试模式下使用,而且在初始化时需要先开启调试模式才能使用DWT寄存器,这会对系统的性能产生一定影响。

    总结:

    以上是几种常用的方法,在STM32 F4上实现精确计时。不同的应用场景可以选择不同的方法来实现计时。需要根据实际情况选择合适的方法,权衡计时的精度和系统的性能。

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(17条)

报告相同问题?

问题事件

  • 系统已结题 2月28日
  • 已采纳回答 2月20日
  • 赞助了问题酬金50元 2月14日
  • 创建了问题 2月14日

悬赏问题

  • ¥20 机器学习能否像多层线性模型一样处理嵌套数据
  • ¥20 西门子S7-Graph,S7-300,梯形图
  • ¥50 用易语言http 访问不了网页
  • ¥50 safari浏览器fetch提交数据后数据丢失问题
  • ¥15 matlab不知道怎么改,求解答!!
  • ¥15 永磁直线电机的电流环pi调不出来
  • ¥15 用stata实现聚类的代码
  • ¥15 请问paddlehub能支持移动端开发吗?在Android studio上该如何部署?
  • ¥20 docker里部署springboot项目,访问不到扬声器
  • ¥15 netty整合springboot之后自动重连失效