初学stm32,分享TIMx定时器与TICK(滴答)定时器,与TIMx输出pwm波的一点心得。

2019-08-14 17:46发布

本人初学stm32,今天,昨天,前天分别做了三个实验。
分别是滴答定时器精确延迟,TIM定时器与pwm波,TIM定时器+串口通讯+led灯实现精确时间跳变;

先一个一个讲我的实验、
先贴出滴答定时器精确延迟的程序
这个是SysTick.c源程序
[mw_shl_code=cpp,true]#include "SysTick.h"
#include "main.h"

int TimingDelay;

void SysTick_Init(void)
{
        /* SystemFrequency / 1000    1ms中断一次
         * SystemFrequency / 100000         10us中断一次
         * SystemFrequency / 1000000 1us中断一次
         */
       
//对以下函数的解释
//SysTick_Config();是一个配置滴答计时器的函数
//我们打开其函数原型
//static __INLINE uint32_t SysTick_Config(uint32_t ticks)
//{
//  if (ticks > SysTick_LOAD_RELOAD_Msk)  return (1);            /* Reload value impossible */
//                                                               
//  SysTick->LOAD  = (ticks & SysTick_LOAD_RELOAD_Msk) - 1;      /* set reload register */
//  NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1);  /* set Priority for Cortex-M0 System Interrupts */
//  SysTick->VAL   = 0;                                          /* Load the SysTick Counter Value */
//  SysTick->CTRL  = SysTick_CTRL_CLKSOURCE_Msk |
//                   SysTick_CTRL_TICKINT_Msk   |
//                   SysTick_CTRL_ENABLE_Msk;                    /* Enable SysTick IRQ and SysTick Timer */
//  return (0);                                                  /* Function successful */
//}
//if (ticks > SysTick_LOAD_RELOAD_Msk)  return (1);  而其中这一句是判断传来的数据是否小于2的24次方(如果超过,则会处理不正常,因为STK_LOAD寄存器是24位的)。
//则可知,如果你的配置是正确的话,SysTick_Config(uint32_t ticks)的返回值是零,程序会跳过空循环,直接执行关闭滴答定时器。
//如果你的配置错误(即传来的数据是大于2的24次方),SysTick_Config(uint32_t ticks)的返回值是一,则程序if语句成立,程序会进入空循环,防止进一步出错。
//再解释SysTick_Config()的主要作用(自己理解,不标准请海涵):
//它使用芯片自带的滴答定时器记录时钟周期进行操作:
//将获取的参数传递给LOAD寄存器,LOAD寄存器检查后传递给STK_VAL寄存器
//然后每一个时钟周期就使STK_VAL寄存器的值减一
//当减到0的时候,就会触发中断。进入中断函数。

                //if(SysTick_Config(SystemFrequency / 1000))//ST3.0.0库版本
                if(SysTick_Config(SystemCoreClock / 1000))//ST3.5.0库版本
                {
                        while(1);
                }
               
                SysTick->CTRL &= ~ SysTick_CTRL_ENABLE_Msk;//关闭滴答定时器
}
//该函数的作用是有多少个ms
void Delay_ms(int nTime)
{
                TimingDelay=nTime;
                //使能滴答计时器
                SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk;
                while(TimingDelay!=0);
}

void         TimingDelay_Decrement(void)
{
                if(TimingDelay !=0)
                {
                                TimingDelay--;
                }
}
[/mw_shl_code]
这个是位于stm32f10x_it.c内的源程序
[mw_shl_code=applescript,true]extern void TimingDelay_Decrement(void);//采用的外部函数此处一定要写
void SysTick_Handler(void)
{
                if(TimingDelay!=1)
                TimingDelay_Decrement();
                if(TimingDelay==1)
                        Led_Usart(num++);
                        Delay_ms(1000);
       
}[/mw_shl_code]

请允许我大概总结一下,这个TICK的原理就是,时钟不分频,然后
通过SysTick_Config(SystemCoreClock / 1000))这句话分将用户需要的中断配置给STK_LOAD寄存器,
SystemCoreCLock:
uint32_t SystemCoreClock         = SYSCLK_FREQ_72MHz;        /*!< System Clock Frequency (Core Clock) */
即时钟的频率,也就是说滴答定时器只能配置STK_LOAD寄存器,无法配置定时器分频和重载周期值,
即:TIM_Prescaler和TIM_Period,(属于TIM定时器的)
而且由于STK_LOAD寄存器是24位的,也就是说STK_LOAD的最大值1677,7216
也就是说滴答定时器最多能撑到1677,7216个以72MHz为频率的时钟周期。72MHz=7200,0000;即不到一秒;
而滴答定时器采用的是向下减的方式,就是当STK_LOAD寄存器传给STK_VAL寄存器后,STK_VAL每经一个时钟周期进行一次自减运算。
直到STK_VAL减到零,引发中断。
综上可述:如果只凭滴答定时器的中断,是无法进行1秒的延迟的,所以,我的程序里有一个外部空循环函数,而且选择每1ms进入一次滴答定时器中断的方式进行1000向下的自减运算。当1000减到零时,跳出空循环,回到主函数。
这就是整个tick滴答定时器进行精确延迟的原理。





友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。