STM32F103定时器输出频率测试

今天在调试STM32F103c8t6单片机定时器功能时,突然想看看定时器输出最大的频率是多少?为了方便验证在定时器中断中用LED灯翻转来判断定时器的频率。为了保证测试准确性,先测试测试LED直接用IO口驱动时的最大翻转速度。
测试代码如下:

#define LED PCout(13)     // PC13
void LED_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStucture;
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
    GPIO_InitStucture.GPIO_Pin = GPIO_Pin_13;
    GPIO_InitStucture.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStucture.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOC, &GPIO_InitStucture);	
	GPIO_SetBits(GPIOC,GPIO_Pin_13);
}
int main(void)
{
    LED_Init();         //初始化与LED连接的硬件接口
    while(1)
    {
	  LED = !LED;
    }
}

PC13口为LED控制口,低电平LED亮,高电平LED灭。在循环中翻转LED电平。用示波器测试LED波形如下:
在这里插入图片描述
LED的翻转频率为 1.38MHz,初始化的时候IO口频率设置的是50MHz,主程序中就一行代码,为什么LED翻转速度最快才1M多,什么原因造成的?会不会和代码有关系。将LED翻转改为直接给LED赋值试试。

while(1)
    {
         LED = 0;
 	    LED = 1;
    }

直接给IO口赋值,这时在看看LED的波形。
在这里插入图片描述
从波形可以看到LED的频率变成了3MHz多,看来指令不同,执行速度差别很大。
那还没不能再改快点,LED用的是位操作,要更快就直接操作寄存器。直接给输出寄存器赋值来控制PC13口的电平。
重新修改代码如下:

 while(1)
    {
		GPIOC->ODR=0x0000;
		GPIOC->ODR= 0x2000;
    }

测试波形如下:
在这里插入图片描述
LED翻转频率变成了4.24MHz,但是波形发生了变化,可以看到低电平的时间28ns,高电平的时间208ns。说明将PC13口置为高电平后,程序执行其他代码花费了180ns的时间。看来要提高LED的翻转速度,代码还有很大的优化空间。但是今天主要是测试定时器,所以在这块就不深究了。下来测试定时器代码。
这块用的是定时器3,在定时器3中断中翻转LED,然后测试波形。看看定时器的速度有多快。
定时器代码如下:


//APB1时钟分频为2  TIM2-7 时钟数为APB1 2倍
// Tout= (arr+1)*(psc+1) / Tclk 
void TIM3_Init(u16 arr, u16 psc)
{
    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
    
    TIM_TimeBaseInitStructure.TIM_Period = arr;
    TIM_TimeBaseInitStructure.TIM_Prescaler = psc;
    TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
    TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
    TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);

    TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);

    NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x01;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

    TIM_Cmd(TIM3, ENABLE);
}

void TIM3_IRQHandler(void)
{
    if(TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET)
    {
        TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
		LED = !LED;
    }
}

int main(void)
{
    LED_Init();         //初始化与LED连接的硬件接口
	TIM3_Init(4999,7199);  // 5000 * 7200 /72M =500ms
    while(1)
    {
    }
}

定时器3定时500ms,在定时中断中翻转LED电平。测试波形如下:
在这里插入图片描述
由波形可以看出LED的翻转频率为1K,周期500ms。说明定时器定时是比较准确的。
下来缩短定时器时间,定时器初始化代码改为:

TIM3_Init(1,7199);       // 2 * 72 /72M = 0.2ms

继续测试,波形如下:
在这里插入图片描述
频率为2.5K,周期为200us。下来将预分频值缩小百分之一。初始化改为:

TIM3_Init(1,71);    	 // 2* 72 / 72M =2us

测试波形如下:
在这里插入图片描述
频率为250K,周期为2us。看来设置理论计算的实际输出一样。
下来再将预分频值缩小十分之一:

TIM3_Init(1,7);  		 // 2* 9 / 72M = 200ns  

测试波形如下:
在这里插入图片描述
频率为313K,周期为1.6us,频率并不是刚才的10倍,什么原因引起的?根据刚才测试LED经验来看,应该是代码的问题引起的。那么在中断中将LED翻转改为寄存器操作看看。

void TIM3_IRQHandler(void)
{
    if(TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET)
    {
        TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
		GPIOC->ODR=0x0000;
		GPIOC->ODR= 0x2000;
    }
}

在这里插入图片描述
可以看出优化代码后,频率有提高,但是变化还是不大。继续优化代码,由于程序中只用了定时器3一个中断,所以在中断函数中就不判断标志位了,直接将标志位清0。清标志位代码也改为直接操作寄存器。

void TIM3_IRQHandler(void)
{
	    TIM3->SR=0x0000;
		GPIOC->ODR=0x0000;
		GPIOC->ODR= 0x2000;
}

测试波形如下:
在这里插入图片描述
可以看出,这次频率有了明显得提高,频率2.4MHz,高电平时间388ns,低电平时间28ns。低电平时间和刚测IO直接翻转测试的时间一样,说明将PC13口置高后程序执行其他代码花费了时间。

TIM3_Init(1,71);    	 // 2* 72 / 72M =2us	
TIM3_Init(1,7);  		 // 2* 9 / 72M = 200ns  

刚才预分频值为71的时候时候,频率为250K,我们将预分频值缩小为1/10,那么频率应该增大10倍。所以预分频值设置为7的时候,频率理论值应该为2.5MHz,实际测试值为2.4MHz,说明理论计算的值是正确的,定时器应该实际上也能输出这么高的频率,但是由于代码的原因导致不能正真观察到输出的频率。所以想要真正观察到实际输出频率,代码就得直接用汇编来实现了。
这块可以理论计算下最大输出频率,假如高电平的时间和低电平的时间一样是28ns,那么周期就是56ns,频率就为17.86MHz。说明理论上定时器输出频率可以达到十几MHz。但是由于代码原因我们不能验证这个,以后有机会了可以在验证下。
看来在实际应用中想要定时器输出更高频率,在写代码的时候就得好好优化.通过上面测试也发现,同样的功能,不同的操作方法对代码的执行效率影响很大。在以后写程序的时候不能仅仅实现功能就行,还要注意代码的执行效率。

发布了76 篇原创文章 · 获赞 30 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_20222919/article/details/100517967