STM32学习日志

   日期:2021-01-26     浏览:112    评论:0    
核心提示:STM32F4XX 学习日志:定时器中断模拟PWM波实现呼吸灯前言任务目标解决办法过程定时器配置标准库时钟主频配置出现问题中断服务函数主函数小结以上代码亲测有效。前言使用反客科技STM32F407VET6 M1的核心板,板载8M主时钟晶振(HSE),32.768kHz低速外部晶振(LSE)。含有一个用户LED以及一个用户按键。任务目标初学使用标准库开发,学长布置了使用定时器产生PWM波来实现呼吸灯的任务。但是这块板子上的LED灯接在PC13的引脚上。查询了最小原理图以及数据手册后发现,PC13并

STM32F4XX 学习日志:定时器中断模拟PWM波实现呼吸灯

  • 前言
    • 任务目标
    • 解决办法
    • 过程
    • 定时器配置
    • 标准库时钟主频配置出现问题
    • 中断服务函数
    • 主函数
    • 小结
    • 以上代码亲测有效。

前言

使用反客科技STM32F407VET6 M1的核心板,板载8M主时钟晶振(HSE),32.768kHz低速外部晶振(LSE)。含有一个用户LED以及一个用户按键。

任务目标

初学使用标准库开发,学长布置了使用定时器产生PWM波来实现呼吸灯的任务。
但是这块板子上的LED灯接在PC13的引脚上。查询了最小原理图以及数据手册后发现,PC13并没有定时器复用功能。

解决办法

使用更新中断以及输出比较中断实现模拟pwm波

过程

配置一个定时器两个中断,定时器设置为向上计数。设置TIM1_CC_IRQHandler(void)
TIM1_UP_TIM10_IRQHandler(void)
其中更新中断比较常用我就不说了。但是这一个TIM1_CC_IRQHandler中断服务函数在网上见的很少,我在网上多方查找没有结果之后,去翻了数据手册,看到这样的一段介绍。

以上为比较中断服务函数,当该位置1的时候表示定时器计数值与设定值相等,即

TIM_OCInitStructure.TIM_Pulse = 0;	

基数值等于该值的时候,也就是

TIM1->CNT=TIM1->CCR1

这两个寄存器的值相等时,发生中断。
对此就有了两个中断。
假设主频168MHZ设置预分频168-1
计数值100-1
该定定时器上溢中断发生的周期就为 168 000 000 / 168 =1us*100=100us
则将此周期视为pwm频率
而占空比可以通过控制输出比较中断触发的事件来设置。
即设定CCR1的值

TIM1->CCR1

该值与定时器重装载值的商即为占空比。通过在主函数里调整CCR1的值以此来模拟占空比可调的PWM波。

定时器配置

#include "tim.h"

void Tim_Init(void)
{   	
	TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
	TIM_OCInitTypeDef  TIM_OCInitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;

    
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1|RCC_APB2Periph_TIM8, ENABLE);

	//TIM_DeInit(TIM1); 

    
	TIM_TimeBaseStructure.TIM_Prescaler         = 168 - 1;                 
	TIM_TimeBaseStructure.TIM_Period            = 1000 - 1;                             
	TIM_TimeBaseStructure.TIM_ClockDivision     = TIM_CKD_DIV1;     
	TIM_TimeBaseStructure.TIM_CounterMode       = TIM_CounterMode_Up;     
	TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;                      
	TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure); 

	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;					//设置每次进入中断为电平翻转模式
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Disable;		//输出开
	TIM_OCInitStructure.TIM_Pulse = 0;											//设置最初CCR为0,这样一配置完就进去中断服务程序
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;			//设置最开始的电平为高电平
	TIM_OC1Init(TIM1, &TIM_OCInitStructure);									//载入寄存器 
	
// TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Disable); //这里就是参考手册里说的禁用预装载寄存器
	
    
	NVIC_InitStructure.NVIC_IRQChannel                   = TIM1_UP_TIM10_IRQn|TIM1_CC_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;  
	NVIC_InitStructure.NVIC_IRQChannelSubPriority        = 1;        
	NVIC_InitStructure.NVIC_IRQChannelCmd                = ENABLE;  
	NVIC_Init(&NVIC_InitStructure);

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

	TIM_ClearFlag(TIM1, TIM_FLAG_Update);
	TIM_ClearFlag(TIM1, TIM_FLAG_CC1);

	
	TIM_ITConfig(TIM1, TIM_IT_Update , ENABLE);
	TIM_ITConfig(TIM1, TIM_FLAG_CC1 , ENABLE);

	
	TIM_Cmd(TIM1, ENABLE); 
}  

标准库时钟主频配置出现问题

配置结束后测试时出现了一点问题,调试之后发现是时钟频率有问题导致分给定时器的时钟出现问题,TIM1挂载在APB2上,而库函数默认配置HSE作为系统时钟源,设置主频168MHz。但是当我获取PCLK2时钟频率后发现该线上的时钟频率是一个非常奇怪的数字,由此我判断是系统时钟出现问题。
对此我重新设置了高速内部时钟源作为系统时钟源。
下面贴出代码

#include "systemclk.h"
#define PLL_M 8
#define PLL_N 168

#define PLL_P 2
#define PLL_Q 7
  
void HSI_SetSysClock(void)
{ 
  __IO uint32_t HSIStartUpStatus = 0;
  
  RCC_DeInit();
 
  //set HSI
  RCC_HSICmd(ENABLE);
 
  HSIStartUpStatus = RCC->CR & RCC_CR_HSIRDY;
 
  if (HSIStartUpStatus == RCC_CR_HSIRDY)
  {     
    
     RCC->APB1ENR |= RCC_APB1ENR_PWREN;
     PWR->CR |= PWR_CR_VOS;
 
     // HCLK = SYSCLK / 1
     RCC_HCLKConfig(RCC_SYSCLK_Div1);
 
    
    RCC->CFGR |= RCC_CFGR_HPRE_DIV1;
 
#if defined(STM32F40_41xxx) || defined(STM32F427_437xx) || defined(STM32F429_439xx) || defined(STM32F412xG) || defined(STM32F446xx) || defined(STM32F469_479xx) 
    
    RCC->CFGR |= RCC_CFGR_PPRE2_DIV2;
    
    
    RCC->CFGR |= RCC_CFGR_PPRE1_DIV4;
#endif 
 
#if defined(STM32F401xx) || defined(STM32F413_423xx)
    
    RCC->CFGR |= RCC_CFGR_PPRE2_DIV1;
    
    
    RCC->CFGR |= RCC_CFGR_PPRE1_DIV2;
#endif 
 
    #if defined(STM32F40_41xxx) || defined(STM32F427_437xx) || defined(STM32F429_439xx) || defined(STM32F401xx) || defined(STM32F469_479xx) 
    
    RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) |
                   (RCC_PLLCFGR_PLLSRC_HSI) | (PLL_Q << 24);
#endif 
 
#if defined(STM32F412xG) || defined(STM32F413_423xx) || defined(STM32F446xx)
    
    RCC->PLLCFGR = HSI_PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) |
                   (RCC_PLLCFGR_PLLSRC_HSI) | (PLL_Q << 24) | (PLL_R << 28);
#endif 
    
    
    RCC->CR |= RCC_CR_PLLON;
    
    while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET) { 
    }
 
    #if defined(STM32F427_437xx) || defined(STM32F429_439xx) || defined(STM32F446xx) || defined(STM32F469_479xx)
    
    PWR->CR |= PWR_CR_ODEN;
    while((PWR->CSR & PWR_CSR_ODRDY) == 0)
    { 
    }
    PWR->CR |= PWR_CR_ODSWEN;
    while((PWR->CSR & PWR_CSR_ODSWRDY) == 0)
    { 
    }      
    
    FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_5WS;
#endif 
 
#if defined(STM32F40_41xxx) || defined(STM32F412xG) 
    
    FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_5WS;
#endif 
 
#if defined(STM32F413_423xx) 
    
    FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_3WS;
#endif 
 
#if defined(STM32F401xx)
    
    FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_2WS;
#endif 
 
    
    RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
    RCC->CFGR |= RCC_CFGR_SW_PLL;
 
    
    while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS ) != RCC_CFGR_SWS_PLL)
    { 
    }
  }
}

之后获取时钟频率,HCLK,PCLK2总线频率为168MHz,正常。
继续下面的步骤

中断服务函数

void TIM1_UP_TIM10_IRQHandler(void)
{ 
	GPIO_SetBits(GPIOC,GPIO_Pin_13);
// GPIO_ToggleBits(GPIOC,GPIO_Pin_13);
	TIM_ClearFlag(TIM1, TIM_FLAG_Update);  //清除标志位
}

void TIM1_CC_IRQHandler(void)
{ 	
	GPIO_ResetBits(GPIOC,GPIO_Pin_13);	
// GPIO_ToggleBits(GPIOC,GPIO_Pin_13);
   TIM_ClearFlag(TIM1, TIM_FLAG_CC1);  //清除标志位
}

主函数

#include "main.h"
#include "gpio.h"
#include "delay.h"
#include "systemclk.h"
static uint16_t count=0,flag=1;
int main(void)
{ 
	HSI_SetSysClock();
    delay_init();
	GPIO_init();
	Tim_Init();
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);// 设置中断优先级分组2
	while(1)
	{ 
	for(count=1;count<1000;count++)
	{ 
		TIM1->CCR1 = count;  	//设置占空比
		STD_Delay_ms(10);
	}
	for(count=999;count>0;count--)
	{ 
		TIM1->CCR1 = count;
		STD_Delay_ms(10);
	}
// RCC_ClocksTypeDef Get_RCC_Clocks;
	}
}

小结

本例子只用于学习熟悉了STM32,TIM1_CC_IRQHandler中断,定时器等配置。实际运用时由于不停的触发中断,造成系统处理效率极低。不宜使用。

**

以上代码亲测有效。

**

 
打赏
 本文转载自:网络 
所有权利归属于原作者,如文章来源标示错误或侵犯了您的权利请联系微信13520258486
更多>最近资讯中心
更多>最新资讯中心
0相关评论

推荐图文
推荐资讯中心
点击排行
最新信息
新手指南
采购商服务
供应商服务
交易安全
关注我们
手机网站:
新浪微博:
微信关注:

13520258486

周一至周五 9:00-18:00
(其他时间联系在线客服)

24小时在线客服