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;
/* 1. 使能時鐘 */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1|RCC_APB2Periph_TIM8, ENABLE);
//TIM_DeInit(TIM1);
/* 2. 配置定時器引數 */
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); //這里就是參考手冊里說的禁用預裝載暫存器
/* 3. 配置定時器中斷優先級 */
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);
/* 4. 使能定時器中斷 */
TIM_ITConfig(TIM1, TIM_IT_Update , ENABLE);
TIM_ITConfig(TIM1, TIM_FLAG_CC1 , ENABLE);
/* 5. 使能定時器 */
TIM_Cmd(TIM1, ENABLE);
}
標準庫時鐘主頻配置出現問題
配置結束后測驗時出現了一點問題,除錯之后發現是時鐘頻率有問題導致分給定時器的時鐘出現問題,TIM1掛載在APB2上,而庫函式默認配置HSE作為系統時鐘源,設定主頻168MHz,但是當我獲取PCLK2時鐘頻率后發現該線上的時鐘頻率是一個非常奇怪的數字,由此我判斷是系統時鐘出現問題,
對此我重新設定了高速內部時鐘源作為系統時鐘源,
下面貼出代碼
#include "systemclk.h"
#define PLL_M 8
#define PLL_N 168
/* SYSCLK = PLL_VCO / PLL_P */
#define PLL_P 2
#define PLL_Q 7
/**
* @brief Configures HSI as the System clock source
**/
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)
{
/* Select regulator voltage output Scale 1 mode */
RCC->APB1ENR |= RCC_APB1ENR_PWREN;
PWR->CR |= PWR_CR_VOS;
// HCLK = SYSCLK / 1
RCC_HCLKConfig(RCC_SYSCLK_Div1);
/* HCLK = SYSCLK / 1*/
RCC->CFGR |= RCC_CFGR_HPRE_DIV1;
#if defined(STM32F40_41xxx) || defined(STM32F427_437xx) || defined(STM32F429_439xx) || defined(STM32F412xG) || defined(STM32F446xx) || defined(STM32F469_479xx)
/* PCLK2 = HCLK / 2*/
RCC->CFGR |= RCC_CFGR_PPRE2_DIV2;
/* PCLK1 = HCLK / 4*/
RCC->CFGR |= RCC_CFGR_PPRE1_DIV4;
#endif /* STM32F40_41xxx || STM32F427_437x || STM32F429_439xx || STM32F412xG || STM32F446xx || STM32F469_479xx */
#if defined(STM32F401xx) || defined(STM32F413_423xx)
/* PCLK2 = HCLK / 1*/
RCC->CFGR |= RCC_CFGR_PPRE2_DIV1;
/* PCLK1 = HCLK / 2*/
RCC->CFGR |= RCC_CFGR_PPRE1_DIV2;
#endif /* STM32F401xx || STM32F413_423xx */
#if defined(STM32F40_41xxx) || defined(STM32F427_437xx) || defined(STM32F429_439xx) || defined(STM32F401xx) || defined(STM32F469_479xx)
/* Configure the main PLL */
RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) |
(RCC_PLLCFGR_PLLSRC_HSI) | (PLL_Q << 24);
#endif /* STM32F40_41xxx || STM32F401xx || STM32F427_437x || STM32F429_439xx || STM32F469_479xx */
#if defined(STM32F412xG) || defined(STM32F413_423xx) || defined(STM32F446xx)
/* Configure the main PLL */
RCC->PLLCFGR = HSI_PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) |
(RCC_PLLCFGR_PLLSRC_HSI) | (PLL_Q << 24) | (PLL_R << 28);
#endif /* STM32F412xG || STM32F413_423xx || STM32F446xx */
/* Enable the main PLL */
RCC->CR |= RCC_CR_PLLON;
/* Wait till the main PLL is ready */
while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET) {
}
#if defined(STM32F427_437xx) || defined(STM32F429_439xx) || defined(STM32F446xx) || defined(STM32F469_479xx)
/* Enable the Over-drive to extend the clock frequency to 180 Mhz */
PWR->CR |= PWR_CR_ODEN;
while((PWR->CSR & PWR_CSR_ODRDY) == 0)
{
}
PWR->CR |= PWR_CR_ODSWEN;
while((PWR->CSR & PWR_CSR_ODSWRDY) == 0)
{
}
/* Configure Flash prefetch, Instruction cache, Data cache and wait state */
FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_5WS;
#endif /* STM32F427_437x || STM32F429_439xx || STM32F446xx || STM32F469_479xx */
#if defined(STM32F40_41xxx) || defined(STM32F412xG)
/* Configure Flash prefetch, Instruction cache, Data cache and wait state */
FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_5WS;
#endif /* STM32F40_41xxx || STM32F412xG */
#if defined(STM32F413_423xx)
/* Configure Flash prefetch, Instruction cache, Data cache and wait state */
FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_3WS;
#endif /* STM32F413_423xx */
#if defined(STM32F401xx)
/* Configure Flash prefetch, Instruction cache, Data cache and wait state */
FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_2WS;
#endif /* STM32F401xx */
/* Select the main PLL as system clock source */
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
RCC->CFGR |= RCC_CFGR_SW_PLL;
/* Wait till the main PLL is used as system clock source */
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中斷,定時器等配置,實際運用時由于不停的觸發中斷,造成系統處理效率極低,不宜使用,
**
以上代碼親測有效,
**
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/253168.html
標籤:其他
上一篇:6.1 現代計算機模型基礎
