×
嵌入式 > 嵌入式开发 > 详情

STM32F10x 学习笔记10(基本定时器)

发布时间:2020-09-01 发布时间:
|
大容量的STM32F101xx、STM32F103xx系列和互联型产品中包含了两个基本定时器,TIM6和TIM7。这两个定时器功能非常简单,基本上和SysTick定时器相当。

但是我在使用的时候确是费了一番周折才调试通过,所以还是应该将这两个定时器的使用方法好好的写一写。

基本定时器TIM6和TIM7各包含一个16位自动装载计数器,由各自的可编程分频器驱动。简单的说两个定时器是从0计数到N(由自动装载计数器来确定N的具体值),然后复位回0重新计数。每次复位到0的时候可以产生对应的中断信号,或者产生DMA请求,还可以触发DAC同步电路。不过这次笔记不讨论触发DAC的问题,等写到DAC的使用时在讲解如何用这两定时器驱动DAC。

基本定时器TIM6和TIM7挂载在APB1总线上,在使用之前需要先使能对应的时钟信号。对应的语句如下:

  1. RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6,ENABLE);
  2. RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM7,ENABLE);

APB1总线上的时钟信号在进入定时器之后第一件事情是被预分频器TIMx_PSC分频。程序中随时都可以更改TIMx_PSC的值,但是TIMx_PSC是有缓冲的,只有发生了更新事件时新的预分频值才会生效。

另外有一点必须要特别注意:如果我们想对CK_PSC时钟信号N分频的话,TIMx_PSC中应该写入M-1,而不是M。

对应的语句如下:

  1. TIMx->PSC=M-1;

如果我们希望立刻更新预分频器也是有办法的,那就是软件触发一次更新事件。TIM6和TIM7有个事件产生寄存器(TIMx_EGR)就是起这个作用的。TIMx_EGR只有最低位有用,称之为UG位,向这一位写入1则产生更新事件,定时器的计数器被归零。

对应的语句如下:

  1. TIMx->EGR=0x0001;

自动重装载寄存器TIMx_ARR决定了CNT计数器最高记到多少就会归零。自动重装载寄存器也是带缓存的。如果TIMx_CR1寄存器中的自动重装载预加载使能位(ARPE)为0,则写入自动重装载寄存器的值立即起作用。如果ARPE=1,则要等到发生了更新事件后才会起作用。举例来说,当前自动重装载寄存器的值为20000,CNT计数器的值为1000,ARPE=1,这时我们向自动重装载寄存器写个5000,CNT计数器记到5000时并不会归零,它还要继续直到记到20000然后归零,在归零的同时产生计数器溢出事件,计数器溢出事件可以产生更新事件,之后自动重装载寄存器的值才真的变为5000了。

这里出现了两个事件:计数器溢出事件和更新事件。这两个实际是不同的。每次当计数器溢出时都会产生计数器溢出事件,但是不一定产生更新事件。

TIM6和TIM7控制寄存器1(TIMx_CR1)有一位UDIS:禁止更新(Updatedisable)位。

如果这位被设置为1,则计数器溢出事件不会产生更新事件。不产生更新事件则预分频器的系数不能被更新,自动重装载寄存器的值也可能不能更新(ARPE=1)。

只是产生更新事件是没有用的,我们最终需要的是产生中断或DMA请求。这里先说中断的产生。

TIM6和TIM7DMA/中断使能寄存器(TIMx_DIER)有一位为UIE。只有这一位为1时才能产生更新中断。

对应的语句如下:

  1. TIMx->DIER|=0x0001;

TIM6和TIM7状态寄存器(TIMx_SR)中也只有一位是有用的,位于这个寄存器的最低位,称之为UIF位。这一位为1标志着产生了更新中断。什么时候这一位才能为1呢?简单的说就是产生更新事件这一位会被置位为1,不过也有特殊情况,我们知道有两种情况会产生更新事件:计数器溢出事件和UG=1。如果TIMx_CR1的URS位被设为了1,则UG=1产生的更新事件不会将UIF位置位1。

一般来说我们都不希望UG=1时产生中断,所以多数时间我们会设置URS位为1。

对应的语句如下:

  1. TIMx->CR1|=0x0004;

下面是一个例子程序,使用TIM6,产生一个5Hz的定时中断。时钟频率为72MHz。

  1. voidTIM6_Init(void)
  2. {
  3. NVIC_InitTypeDefNVIC_InitStructure;
  4. NVIC_InitStructure.NVIC_IRQChannel=TIM6_IRQn;
  5. NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;
  6. NVIC_InitStructure.NVIC_IRQChannelSubPriority=0;
  7. NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
  8. NVIC_Init(&NVIC_InitStructure);
  9. RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6,ENABLE);
  10. TIM6->PSC=7200-1;//分频之后的时钟频率为10KHz
  11. TIM6->ARR=2000-1;//5Hz定时频率
  12. TIM6->CR1=0x0004+0x0001;//URS=1CEN=1
  13. TIM6->DIER=0x0001;//使能更新中断
  14. }
  15. voidTIM6_IRQHandler(void)
  16. {
  17. LED_Flash(GPIO_LED2);
  18. TIM6->SR=0x0000;//清标志位
  19. }

还可以完全用STM32F10xStandardPeripheralsFirmwareLibrary来写这个程序。下面用TIM7实现类似的功能。

  1. voidTIM7_Init(void)
  2. {
  3. TIM_TimeBaseInitTypeDefTIM7_TimeBaseStructure;
  4. NVIC_InitTypeDefNVIC_InitStructure;
  5. NVIC_InitStructure.NVIC_IRQChannel=TIM7_IRQn;
  6. NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
  7. NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;
  8. NVIC_InitStructure.NVIC_IRQChannelSubPriority=0;
  9. NVIC_Init(&NVIC_InitStructure);
  10. RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM7,ENABLE);//RCC_APB1Periph_TIM7
  11. TIM_TimeBaseStructInit(&TIM7_TimeBaseStructure);
  12. TIM7_TimeBaseStructure.TIM_Prescaler=36000-1;//分频之后的时钟频率为2KHz
  13. TIM7_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;
  14. TIM7_TimeBaseStructure.TIM_Period=400-1;//5Hz定时频率
  15. TIM7_TimeBaseStructure.TIM_ClockDivision=0;
  16. TIM_TimeBaseInit(TIM7,&TIM7_TimeBaseStructure);
  17. TIM_UpdateRequestConfig(TIM7,TIM_UpdateSource_Regular);
  18. TIM_Cmd(TIM7,ENABLE);
  19. TIM_ITConfig(TIM7,TIM_IT_Update,ENABLE);
  20. }
  21. voidTIM7_IRQHandler(void)
  22. {
  23. if(TIM_GetITStatus(TIM7,TIM_IT_Update)==SET)
  24. {
  25. LED_Flash(GPIO_LED3);
  26. TIM_ClearITPendingBit(TIM7,TIM_FLAG_Update);
  27. }
  28. }

程序写完了,这里说几点注意事项。

(1)在对TIMx 进行设置之前一定要打开APB1总线上对应的时钟,否则所有的设置都不起作用。

(2)一定要设置NVIC,因为默认情况下这些外设的中断都是被禁用的。


『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
scsi接口