第71章 内核定时器控制流水灯

第七十一章 内核定时器控制流水灯

1. 硬件设计

LED方面参考之前的章节

2. 软件设计

2.1 编程大纲

  1. 初始化时间戳

  2. 延时函数

  3. 主函数测试

2.2 代码分析

2.2.1 初始化时间戳

#if USE_DWT_DELAY // 宏定义,如果没有定义,则不使用DWT延时函数

#define  DWT_CR      *(__IO uint32_t *)0xE0001000 // DWT控制寄存器地址
#define  DWT_CYCCNT  *(__IO uint32_t *)0xE0001004 // DWT计数器地址
#define  DEM_CR      *(__IO uint32_t *)0xE000EDFC // 调试监视器控制寄存器地址
#define  DEM_CR_TRCENA     (1 << 24) // 调试监视器控制寄存器的位24,DWT使能位
#define  DWT_CR_CYCCNTENA  (1 <<  0) // DWT控制寄存器的位0,CYCCNT使能位

// 初始化时间戳
void CPU_TS_TmrInit(void)
{
    DEM_CR |= (uint32_t)DEM_CR_TRCENA; // 使能DWT外设
    DWT_CYCCNT = (uint32_t)0u; // 清0计数器
    DWT_CR |= (uint32_t)DWT_CR_CYCCNTENA; // 使能CYCCNT计数器
}

// 读取当前时间戳
uint32_t CPU_TS_TmrRd(void)
{        
  return ((uint32_t)DWT_CYCCNT);
}

2.2.2 延时函数

/ 采用CPU的内部计数实现精确延时,32位计数器
void CPU_TS_Tmr_Delay_US(__IO uint32_t us)
{
  uint32_t ticks;
  uint32_t told,tnow,tcnt=0;

  /* 在函数内部初始化时间戳寄存器, */  
#if (CPU_TS_INIT_IN_DELAY_FUNCTION)  
  /* 初始化时间戳并清零 */
  CPU_TS_TmrInit();
#endif

  ticks = us * (GET_CPU_ClkFreq() / 1000000);  /* 需要的节拍数 */      
  tcnt = 0;
  told = (uint32_t)CPU_TS_TmrRd();         /* 刚进入时的计数器值 */
  while(1)
  {
    tnow = (uint32_t)CPU_TS_TmrRd();  
    if(tnow != told)
    { 
        /* 32位计数器是递增计数器 */    
      if(tnow > told)
      {
        tcnt += tnow - told;  
      }
      /* 重新装载 */
      else 
      {
        tcnt += UINT32_MAX - told + tnow; 
      } 
      told = tnow;
      /*时间超过/等于要延迟的时间,则退出 */
      if(tcnt >= ticks)break;
    }  
  }
}

#endif

2.2.3 主函数测试

#include "stm32f10x.h"
#include "led.h"
#include "core_delay.h"   

int main(void)
{    
    LED_Init();
    CPU_TS_TmrInit();
    while(1)
    {
        LED1_ON(); 
        Delay_us(100000); // 100000 * 10us = 1000ms
        LED1_OFF();
        LED2_ON();
        Delay_us(100000);        
        LED2_OFF();
        LED3_ON();
        Delay_us(100000);        
        LED3_OFF();
    } 
}

LED依次点亮,形成流水灯

posted @ 2025-03-13 13:58  hazy1k  阅读(18)  评论(0)    收藏  举报