【STM32H7教程】第64章 STM32H7的高分辨率定時器HRTIM應用之PWM實現
- 2020 年 3 月 8 日
- 筆記
完整教程下載地址:http://www.armbbs.cn/forum.php?mod=viewthread&tid=86980
第64章 STM32H7的高分辨率定時器HRTIM應用之PWM實現
本章教程為大家講解高分辨率定時器HRTIM的PWM實現。
64.1 初學者重要提示
64.2 HRTIM的PWM驅動設計
64.3 HRTIM板級支持包(bsp_tim_pwm.c)
64.4 HRTIM驅動移植和使用
64.5 實驗例程設計框架
64.6 實驗例程說明(MDK)
64.7 實驗例程說明(IAR)
64.8 總結
64.1 初學者重要提示
- 學習本章節前,務必優先學習第63章,HAL庫的幾個常用API均作了講解和舉例。
- 設置PWM周期時,注意結構體HRTIM_TimeBaseCfgTypeDef中的Period周期參數範圍,至少3個HRTIM時鐘周期,最大值0xFFDF。
- HRTIM的輸出極性可以設置激活狀態Active和非激活狀態Inactive,這裡要注意一點,激活狀態既可以設置為高電平輸出,也可以設置為低電平輸出。
- HRTIM其它幾個例子執行效果展示,方便大家有個感性認識:
- STM32H7的HRTIM配置輸出5組不同頻率,不同占空比的波形,同時5組互補輸出也是沒問題的。http://www.armbbs.cn/forum.php?mod=viewthread&tid=89211 。
- STM32H7的HRTIM觸發ADC和DAC轉換 http://www.armbbs.cn/forum.php?mod=viewthread&tid=89233 。
- STM32H7的HRTIM Fault故障保護功能,可在輸出故障時禁止輸出 http://www.armbbs.cn/forum.php?mod=viewthread&tid=89232 。
- STM32H7的HRTIM生成任意波形 http://www.armbbs.cn/forum.php?mod=viewthread&tid=89220 。
64.2 HRTIM的PWM驅動設計
HRTIM的PWM實現相對比較簡單,只是涉及到的API比較多。
64.2.1 HRTIM時鐘設置
HRTIM支持兩種時鐘源,一個是來自CPU主頻時鐘,另一個是來自通用定時器。大家可以通過函數HAL_RCCEx_PeriphCLKConfig來設置使用那個時鐘。具體實現代碼如下:
1. RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0}; 2. 3. PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_HRTIM1; 4. PeriphClkInitStruct.Hrtim1ClockSelection = RCC_HRTIM1CLK_CPUCLK; 5. if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK) 6. { 7. Error_Handler(__FILE__, __LINE__); 8. }
這裡把幾個關鍵的地方再闡釋下:
- 第1行,這個變量務必要做0初始化,防止不必要的麻煩。
- 第4行,用於配置HRTIM使用的時鐘源,這裡有兩種選擇:
- 使用CPU主頻時鐘,對應參數RCC_HRTIM1CLK_CPUCLK。
- 使用通用定時器時鐘,對應參數RCC_HRTIM1CLK_TIMCLK。如果CPU主頻時鐘是400MHz的話,通用定時器時鐘就是200MHz。
64.2.2 HRTIM的PWM輸出引腳
HRTIM的涉及到的輸入輸出引腳如下:
FTL = FAULT INPUT Lines PA15 HRTIM_FLT1 PC11 HRTIM_FLT2 PD4 HRTIM_FLT3 PB3 HRTIM_FLT4 PG10 HRTIM_FLT5 EEV = EXTERN EVENT Lines PG13 HRTIM_EEV10 PB7 HRTIM_EEV9 PB6 HRTIM_EEV8 PB5 HRTIM_EEV7 PB4 HRTIM_EEV6 PG12 HRTIM_EEV5 PG11 HRTIM_EEV4 PD5 HRTIM_EEV3 PC12 HRTIM_EEV2 PC10 HRTIM_EEV1 PC6 HRTIM_CHA1 PC7 HRTIM_CHA2 PC8 HRTIM_CHB1 PA8 HRTIM_CHB2 PA9 HRTIM_CHC1 PA10 HRTIM_CHC2 PA11 HRTIM_CHD1 PA12 HRTIM_CHD2 PG6 HRTIM_CHE1 PG7 HRTIM_CHE2 PE0 HRTIM_SCIN PE1 HRTIM_SCOUT PB10 HRTIM_SCOUT PB11 HRTIM_SCIN
當前程序裏面使用的Timer D的HRTIM_CHD1和HRTIM_CHD2,即PA11和PA12引腳輸出PWM。程序配置如下:
GPIO_InitTypeDef GPIO_InitStruct; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_PULLUP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate = GPIO_AF2_HRTIM1; GPIO_InitStruct.Pin = GPIO_PIN_11; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); GPIO_InitStruct.Alternate = GPIO_AF2_HRTIM1; GPIO_InitStruct.Pin = GPIO_PIN_12; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
64.2.3 HRTIM初始化和時基配置
HRTIM的初始化和時基配置如下:
1. /*##- 初始化HRTIM ###################################################*/ 2. HrtimHandle.Instance = HRTIM1; /* 例化,使用的HRTIM1 */ 3. HrtimHandle.Init.HRTIMInterruptResquests = HRTIM_IT_NONE;/* 用於配置支持的中斷請求,當前配置無中斷 */ 4. HrtimHandle.Init.SyncOptions = HRTIM_SYNCOPTION_NONE; /* 配置HRTIM作為Master,發送同步信號,或者作 5. 為Slave,接收同步信號,當前配置沒有做同步功能 */ 6. 7. HAL_HRTIM_Init(&HrtimHandle); 8. 9. /*##- 配置HRTIM的TIMER D 時基 #########################################*/ 10. sConfig_time_base.Mode = HRTIM_MODE_CONTINUOUS; /* 連續工作模式 */ 11. sConfig_time_base.Period = HRTIM_TIMD_PERIOD; /* 設置周期 */ 12. sConfig_time_base.PrescalerRatio = HRTIM_PRESCALERRATIO_DIV1; /* 設置HRTIM分頻,當前設置的1分頻,也就 13. 是不分頻 */ 14. sConfig_time_base.RepetitionCounter = 0; /* 設置重複計數器為0,即不做重複計數 */ 15. 16. HAL_HRTIM_TimeBaseConfig(&HrtimHandle, HRTIM_TIMERINDEX_TIMER_D, &sConfig_time_base);
這裡把幾個關鍵的地方再闡釋下:
- 第2-4行,初始化HRTIM。
- 第10-16行,配置HRTIM的Timer D時基。
- 第11行,設置Timer D的周期。
比如HRTIM主頻是400MHz,HRTIM_TIMD_PERIOD = 4000,那麼Timer D的輸出頻率如下:
PWM的頻率 = 400MHz / HRTIM_TIMD_PERIOD
= 400000000 / 4000
= 100KHz
- 第12行,對於STM32H7系列,僅支持下面選項中最後三個參數,也就是1分頻,2分頻和4分頻。
#define HRTIM_PRESCALERRATIO_MUL32 (0x00000000U) #define HRTIM_PRESCALERRATIO_MUL16 (0x00000001U) #define HRTIM_PRESCALERRATIO_MUL8 (0x00000002U) #define HRTIM_PRESCALERRATIO_MUL4 (0x00000003U) #define HRTIM_PRESCALERRATIO_MUL2 (0x00000004U) #define HRTIM_PRESCALERRATIO_DIV1 (0x00000005U) #define HRTIM_PRESCALERRATIO_DIV2 (0x00000006U) #define HRTIM_PRESCALERRATIO_DIV4 (0x00000007U)
64.2.4 HRTIM的Timer D配置
Timer D的配置成員非常多,對於PWM輸出功能來說,這些成員的功能有個了解即可:
HRTIM_TimerCfgTypeDef sConfig_timerD; sConfig_timerD.DMARequests = HRTIM_TIM_DMA_NONE; /* 不使用DMA */ sConfig_timerD.HalfModeEnable = HRTIM_HALFMODE_DISABLED;/* 關閉HALF模式 */ sConfig_timerD.StartOnSync = HRTIM_SYNCSTART_DISABLED; /* 設置同步輸入端接收到上升沿信號後,不啟動定時器 */ sConfig_timerD.ResetOnSync = HRTIM_SYNCRESET_DISABLED; /* 設置同步輸入端接收到上升沿信號後,不複位定時器 */ sConfig_timerD.DACSynchro = HRTIM_DACSYNC_NONE; /* 不使用DAC同步事件 */ sConfig_timerD.PreloadEnable = HRTIM_PRELOAD_ENABLED; /* 使能寄存器預加載 */ sConfig_timerD.UpdateGating = HRTIM_UPDATEGATING_INDEPENDENT; /* 獨立更新,與DMA突發傳輸完成無關 */ sConfig_timerD.BurstMode = HRTIM_TIMERBURSTMODE_MAINTAINCLOCK; /* 在突發模式下,定時器正常運行 */ sConfig_timerD.RepetitionUpdate = HRTIM_UPDATEONREPETITION_ENABLED;/* 設置重計數器事件可以觸發寄存器更新 */ /* 當HRTIM TIMER的計數器複位時或者計數回滾到0時,不觸發寄存器更新 */ sConfig_timerD.ResetUpdate = HRTIM_TIMUPDATEONRESET_DISABLED; sConfig_timerD.InterruptRequests = HRTIM_TIM_IT_NONE; /* 不使用中斷 */ sConfig_timerD.PushPull = HRTIM_TIMPUSHPULLMODE_DISABLED; /* 不開啟推挽模式 */ sConfig_timerD.FaultEnable = HRTIM_TIMFAULTENABLE_NONE; /* 不使用HRTIM TIMER的Fault通道 */ sConfig_timerD.FaultLock = HRTIM_TIMFAULTLOCK_READWRITE; /* 不開啟HRTIM TIMER的異常使能狀態寫保護 */ sConfig_timerD.DeadTimeInsertion = HRTIM_TIMDEADTIMEINSERTION_DISABLED;/* 不開啟死區時間插入 */ /* 不開啟HRTIM TIMER的延遲保護模式 */ sConfig_timerD.DelayedProtectionMode = HRTIM_TIMER_D_E_DELAYEDPROTECTION_DISABLED; /* Master或TIMER(A到E)更新時,不同步更新寄存器 */ sConfig_timerD.UpdateTrigger= HRTIM_TIMUPDATETRIGGER_NONE; sConfig_timerD.ResetTrigger = HRTIM_TIMRESETTRIGGER_NONE; /* 無複位觸發 */ HAL_HRTIM_WaveformTimerConfig(&HrtimHandle, HRTIM_TIMERINDEX_TIMER_D, &sConfig_timerD);
注意,如果HRTIM_TimerCfgTypeDef sConfig_timerD做局部變量,務必記得清零。
64.2.5 Timer D的輸出比較配置
HRTIM用於PWM功能時,比較輸出用於設置PWM占空比:
HRTIM_CompareCfgTypeDef sConfig_compare; sConfig_compare.AutoDelayedMode = HRTIM_AUTODELAYEDMODE_REGULAR; /* 這裡使用標準模式,即未使用自動延遲 */ sConfig_compare.AutoDelayedTimeout = 0; /* 由於前面的參數未使用自動延遲模式,此參數無作用 */ /* 設置定時器比較單元的比較值: 最小值要大於等於3個HRTIM時鐘周期。 最大值要小於等於0xFFFF – 1 */ sConfig_compare.CompareValue = HRTIM_TIMD_PERIOD / 2; /* 占空比50% */ HAL_HRTIM_WaveformCompareConfig(&HrtimHandle, HRTIM_TIMERINDEX_TIMER_D, HRTIM_COMPAREUNIT_1, &sConfig_compare); sConfig_compare.CompareValue = HRTIM_TIMD_PERIOD / 4; /* 占空比25% */ HAL_HRTIM_WaveformCompareConfig(&HrtimHandle, HRTIM_TIMERINDEX_TIMER_D, HRTIM_COMPAREUNIT_2, &sConfig_compare);
注意事項:
- 如果HRTIM_CompareCfgTypeDef sConfig_compare做局部變量,務必記得清零。
- 配置占空比就是配置成員CompareValue,範圍是0到HRTIM_TIMD_PERIOD(這個參數就是前面配置的PWM周期)。比如配置為HRTIM_TIMD_PERIOD/2就表示占空比50%,配置為HRTIM_TIMD_PERIOD/4就表示占空比25%。
64.2.6 啟動PWM輸出和Timer D的計數
這部分的實現代碼如下:
1. HRTIM_OutputCfgTypeDef sConfig_output_config; 2. 3. sConfig_output_config.Polarity = HRTIM_OUTPUTPOLARITY_LOW; /* 設置定時器輸出極性 */ 4. sConfig_output_config.SetSource = HRTIM_OUTPUTRESET_TIMCMP1; /* 定時器比較事件1可以將輸出置位 */ 5. sConfig_output_config.ResetSource = HRTIM_OUTPUTSET_TIMPER; /* 定時器周期性更新事件可以將輸出清零 */ 6. sConfig_output_config.IdleMode = HRTIM_OUTPUTIDLEMODE_NONE; /* 輸出不受突發模式影響 */ 7. sConfig_output_config.IdleLevel = HRTIM_OUTPUTIDLELEVEL_INACTIVE; /* 設置空閑狀態輸出低電平 */ 8. sConfig_output_config.FaultLevel = HRTIM_OUTPUTFAULTLEVEL_NONE; /* 輸出不受異常輸入影響 */ 9. sConfig_output_config.ChopperModeEnable = HRTIM_OUTPUTCHOPPERMODE_DISABLED; /* 關閉Chopper模式 */ 10. sConfig_output_config.BurstModeEntryDelayed = HRTIM_OUTPUTBURSTMODEENTRY_REGULAR; /* 設置從突發模式切換 11. 到空閑模式,不插入死區時間 */ 12. 13. HAL_HRTIM_WaveformOutputConfig(&HrtimHandle, HRTIM_TIMERINDEX_TIMER_D, HRTIM_OUTPUT_TD1, 14. &sConfig_output_config); 15. 16. sConfig_output_config.SetSource = HRTIM_OUTPUTRESET_TIMCMP2; /* 定時器比較事件2可以將輸出置位 */ 17. HAL_HRTIM_WaveformOutputConfig(&HrtimHandle, HRTIM_TIMERINDEX_TIMER_D, HRTIM_OUTPUT_TD2, 18. &sConfig_output_config); 19. 20. /*##-9- 啟動PWM輸出 #############################################*/ 21. if (HAL_HRTIM_WaveformOutputStart(&HrtimHandle, HRTIM_OUTPUT_TD1 + HRTIM_OUTPUT_TD2) != HAL_OK) 22. { 23. Error_Handler(__FILE__, __LINE__); 24. } 25. 26. /*##-10- 啟動計數器 #############################################*/ 27. if (HAL_HRTIM_WaveformCounterStart(&HrtimHandle, HRTIM_TIMERID_TIMER_D) != HAL_OK) 28. { 29. Error_Handler(__FILE__, __LINE__); 30. }
這裡把幾個關鍵的地方再闡釋下:
- 第1行,如果HRTIM_OutputCfgTypeDef sConfig_output_config做局部變量,務必記得清零。
- 第3行,輸出極性是用來設置激活狀態Active對應的高電平還是低電平。
- 第4行,用來實現置位源(SetSource)設置,這裡是設置滿足比較事件1時,輸出置位。
- 第5行,用來實現複位源(ResetSource)設置,這裡是設置產生周期性更新事件時,輸出清零。
通過第4行和第5行,就實現了Timer D中通道1的高低電平輸出方式,
- 第16行,設置Timer D中通道2的置位源,即通道2的高低電平輸出方式。
64.3 HRTIM板級支持包(bsp_hrtim_pwm.c)
定時器驅動文件bsp_hrtim_pwm.c主要實現了如下一個API供用戶調用:
- bsp_SetHRTIMOutPWM
64.3.1 函數bsp_SetHRTIMforInt
函數原型:
void bsp_SetHRTIMOutPWM(void)
函數描述:
這個函數的源碼實現在本章64.2小節裏面已經進行了詳細說明。
當前這個函數通過配置HRTIM的TIMER D輸出兩路PWM,周期都是100KHz,PA11引腳輸出占空比50%,PA12引腳輸出的占空比25%。
64.4 HRTIM驅動移植和使用
定時器的移植比較簡單:
- 第1步:複製bsp_hrtim_pwm.c和bsp_hrtim_pwm.h到自己的工程目錄,並添加到工程裏面。
- 第2步:這幾個驅動文件主要用到HAL庫的GPIO和HRTIM驅動文件,簡單省事些可以添加所有HAL庫.C源文件進來。
- 第3步,應用方法看本章節配套例子即可。
64.5 實驗例程設計框架
通過程序設計框架,讓大家先對配套例程有一個全面的認識,然後再理解細節,本次實驗例程的設計框架如下:

第1階段,上電啟動階段:
- 這部分在第14章進行了詳細說明。
第2階段,進入main函數:
- 第1步,硬件初始化,主要是MPU,Cache,HAL庫,系統時鐘,滴答定時器,LED和串口。同時HRTIM也做了配置,將 HRTIM的TIMER D輸出兩路PWM,周期都是100KHz,PA11引腳輸出占空比50%,PA12引腳輸出的占空比25%。
- 第2步,按鍵應用程序設計部分。
64.6 實驗例程說明(MDK)
配套例子:
V7-045_高分辨率定時器HRTIM實現PWM輸出
實驗目的:
- 學習高分辨率定時器HRTIM的PWM實現。
實驗內容:
- 上電啟動了一個軟件定時器,每100ms翻轉一次LED2。
- 配置HRTIM的TIMER D輸出兩路PWM,周期都是100KHz,PA11引腳輸出占空比50%,PA12引腳輸出的占空比25%。
PWM輸出引腳PA11和PA12位置:

上電後串口打印的信息:
波特率 115200,數據位 8,奇偶校驗位無,停止位 1

程序設計:
系統棧大小分配:

RAM空間用的DTCM:

硬件外設初始化
硬件外設的初始化是在 bsp.c 文件實現:
/* ********************************************************************************************************* * 函 數 名: bsp_Init * 功能說明: 初始化所有的硬件設備。該函數配置CPU寄存器和外設的寄存器並初始化一些全局變量。只需要調用一次 * 形 參:無 * 返 回 值: 無 ********************************************************************************************************* */ void bsp_Init(void) { /* 配置MPU */ MPU_Config(); /* 使能L1 Cache */ CPU_CACHE_Enable(); /* STM32H7xx HAL 庫初始化,此時系統用的還是H7自帶的64MHz,HSI時鐘: - 調用函數HAL_InitTick,初始化滴答時鐘中斷1ms。 - 設置NVIV優先級分組為4。 */ HAL_Init(); /* 配置系統時鐘到400MHz - 切換使用HSE。 - 此函數會更新全局變量SystemCoreClock,並重新配置HAL_InitTick。 */ SystemClock_Config(); /* Event Recorder: - 可用於代碼執行時間測量,MDK5.25及其以上版本才支持,IAR不支持。 - 默認不開啟,如果要使能此選項,務必看V7開發板用戶手冊第xx章 */ #if Enable_EventRecorder == 1 /* 初始化EventRecorder並開啟 */ EventRecorderInitialize(EventRecordAll, 1U); EventRecorderStart(); #endif bsp_InitKey(); /* 按鍵初始化,要放在滴答定時器之前,因為按鈕檢測是通過滴答定時器掃描 */ bsp_InitTimer(); /* 初始化滴答定時器 */ bsp_InitUart(); /* 初始化串口 */ bsp_InitExtIO(); /* 初始化FMC總線74HC574擴展IO. 必須在 bsp_InitLed()前執行 */ bsp_InitLed(); /* 初始化LED */ }
MPU配置和Cache配置:
數據Cache和指令Cache都開啟。配置了AXI SRAM區(本例子未用到AXI SRAM)和FMC的擴展IO區。
/* ********************************************************************************************************* * 函 數 名: MPU_Config * 功能說明: 配置MPU * 形 參: 無 * 返 回 值: 無 ********************************************************************************************************* */ static void MPU_Config( void ) { MPU_Region_InitTypeDef MPU_InitStruct; /* 禁止 MPU */ HAL_MPU_Disable(); /* 配置AXI SRAM的MPU屬性為Write back, Read allocate,Write allocate */ MPU_InitStruct.Enable = MPU_REGION_ENABLE; MPU_InitStruct.BaseAddress = 0x24000000; MPU_InitStruct.Size = MPU_REGION_SIZE_512KB; MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS; MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE; MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE; MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE; MPU_InitStruct.Number = MPU_REGION_NUMBER0; MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1; MPU_InitStruct.SubRegionDisable = 0x00; MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE; HAL_MPU_ConfigRegion(&MPU_InitStruct); /* 配置FMC擴展IO的MPU屬性為Device或者Strongly Ordered */ MPU_InitStruct.Enable = MPU_REGION_ENABLE; MPU_InitStruct.BaseAddress = 0x60000000; MPU_InitStruct.Size = ARM_MPU_REGION_SIZE_64KB; MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS; MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE; MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE; MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE; MPU_InitStruct.Number = MPU_REGION_NUMBER1; MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0; MPU_InitStruct.SubRegionDisable = 0x00; MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE; HAL_MPU_ConfigRegion(&MPU_InitStruct); /*使能 MPU */ HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT); } /* ********************************************************************************************************* * 函 數 名: CPU_CACHE_Enable * 功能說明: 使能L1 Cache * 形 參: 無 * 返 回 值: 無 ********************************************************************************************************* */ static void CPU_CACHE_Enable(void) { /* 使能 I-Cache */ SCB_EnableICache(); /* 使能 D-Cache */ SCB_EnableDCache(); }
主功能:
主程序實現如下操作:
- 上電啟動了一個軟件定時器,每100ms翻轉一次LED2。
- 配置HRTIM的TIMER D輸出兩路PWM,周期都是100KHz,PA11引腳輸出占空比50%,PA12引腳輸出的占空比25%
/* ********************************************************************************************************* * 函 數 名: main * 功能說明: c程序入口 * 形 參: 無 * 返 回 值: 錯誤代碼(無需處理) ********************************************************************************************************* */ int main(void) { uint8_t ucKeyCode; /* 按鍵代碼 */ bsp_Init(); /* 硬件初始化 */ PrintfLogo(); /* 打印例程名稱和版本等信息 */ PrintfHelp(); /* 打印操作提示 */ bsp_SetHRTIMOutPWM(); bsp_StartAutoTimer(0, 100); /* 啟動1個100ms的自動重裝的定時器 */ while (1) { bsp_Idle(); /* 這個函數在bsp.c文件。用戶可以修改這個函數實現CPU休眠和喂狗 */ /* 判斷定時器超時時間 */ if (bsp_CheckTimer(0)) { /* 每隔100ms 進來一次 */ bsp_LedToggle(2); } /* 按鍵濾波和檢測由後台systick中斷服務程序實現,我們只需要調用bsp_GetKey讀取鍵值即可。 */ ucKeyCode = bsp_GetKey(); /* 讀取鍵值, 無鍵按下時返回 KEY_NONE = 0 */ if (ucKeyCode != KEY_NONE) { switch (ucKeyCode) { case KEY_DOWN_K1: /* K1鍵按下 */ break; default: /* 其它的鍵值不處理 */ break; } } } }
64.7 實驗例程說明(IAR)
配套例子:
V7-045_高分辨率定時器HRTIM實現PWM輸出
實驗目的:
- 學習高分辨率定時器HRTIM的PWM實現。
實驗內容:
- 上電啟動了一個軟件定時器,每100ms翻轉一次LED2。
- 配置HRTIM的TIMER D輸出兩路PWM,周期都是100KHz,PA11引腳輸出占空比50%,PA12引腳輸出的占空比25%。
PWM輸出引腳PA11和PA12位置:

上電後串口打印的信息:
波特率 115200,數據位 8,奇偶校驗位無,停止位 1

程序設計:
系統棧大小分配:

RAM空間用的DTCM:

硬件外設初始化
硬件外設的初始化是在 bsp.c 文件實現:
/* ********************************************************************************************************* * 函 數 名: bsp_Init * 功能說明: 初始化所有的硬件設備。該函數配置CPU寄存器和外設的寄存器並初始化一些全局變量。只需要調用一次 * 形 參:無 * 返 回 值: 無 ********************************************************************************************************* */ void bsp_Init(void) { /* 配置MPU */ MPU_Config(); /* 使能L1 Cache */ CPU_CACHE_Enable(); /* STM32H7xx HAL 庫初始化,此時系統用的還是H7自帶的64MHz,HSI時鐘: - 調用函數HAL_InitTick,初始化滴答時鐘中斷1ms。 - 設置NVIV優先級分組為4。 */ HAL_Init(); /* 配置系統時鐘到400MHz - 切換使用HSE。 - 此函數會更新全局變量SystemCoreClock,並重新配置HAL_InitTick。 */ SystemClock_Config(); /* Event Recorder: - 可用於代碼執行時間測量,MDK5.25及其以上版本才支持,IAR不支持。 - 默認不開啟,如果要使能此選項,務必看V7開發板用戶手冊第xx章 */ #if Enable_EventRecorder == 1 /* 初始化EventRecorder並開啟 */ EventRecorderInitialize(EventRecordAll, 1U); EventRecorderStart(); #endif bsp_InitKey(); /* 按鍵初始化,要放在滴答定時器之前,因為按鈕檢測是通過滴答定時器掃描 */ bsp_InitTimer(); /* 初始化滴答定時器 */ bsp_InitUart(); /* 初始化串口 */ bsp_InitExtIO(); /* 初始化FMC總線74HC574擴展IO. 必須在 bsp_InitLed()前執行 */ bsp_InitLed(); /* 初始化LED */ }
MPU配置和Cache配置:
數據Cache和指令Cache都開啟。配置了AXI SRAM區(本例子未用到AXI SRAM)和FMC的擴展IO區。
/* ********************************************************************************************************* * 函 數 名: MPU_Config * 功能說明: 配置MPU * 形 參: 無 * 返 回 值: 無 ********************************************************************************************************* */ static void MPU_Config( void ) { MPU_Region_InitTypeDef MPU_InitStruct; /* 禁止 MPU */ HAL_MPU_Disable(); /* 配置AXI SRAM的MPU屬性為Write back, Read allocate,Write allocate */ MPU_InitStruct.Enable = MPU_REGION_ENABLE; MPU_InitStruct.BaseAddress = 0x24000000; MPU_InitStruct.Size = MPU_REGION_SIZE_512KB; MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS; MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE; MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE; MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE; MPU_InitStruct.Number = MPU_REGION_NUMBER0; MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1; MPU_InitStruct.SubRegionDisable = 0x00; MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE; HAL_MPU_ConfigRegion(&MPU_InitStruct); /* 配置FMC擴展IO的MPU屬性為Device或者Strongly Ordered */ MPU_InitStruct.Enable = MPU_REGION_ENABLE; MPU_InitStruct.BaseAddress = 0x60000000; MPU_InitStruct.Size = ARM_MPU_REGION_SIZE_64KB; MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS; MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE; MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE; MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE; MPU_InitStruct.Number = MPU_REGION_NUMBER1; MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0; MPU_InitStruct.SubRegionDisable = 0x00; MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE; HAL_MPU_ConfigRegion(&MPU_InitStruct); /*使能 MPU */ HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT); } /* ********************************************************************************************************* * 函 數 名: CPU_CACHE_Enable * 功能說明: 使能L1 Cache * 形 參: 無 * 返 回 值: 無 ********************************************************************************************************* */ static void CPU_CACHE_Enable(void) { /* 使能 I-Cache */ SCB_EnableICache(); /* 使能 D-Cache */ SCB_EnableDCache(); }
主功能:
主程序實現如下操作:
- 上電啟動了一個軟件定時器,每100ms翻轉一次LED2。
- 配置HRTIM的TIMER D輸出兩路PWM,周期都是100KHz,PA11引腳輸出占空比50%,PA12引腳輸出的占空比25%
/* ********************************************************************************************************* * 函 數 名: main * 功能說明: c程序入口 * 形 參: 無 * 返 回 值: 錯誤代碼(無需處理) ********************************************************************************************************* */ int main(void) { uint8_t ucKeyCode; /* 按鍵代碼 */ bsp_Init(); /* 硬件初始化 */ PrintfLogo(); /* 打印例程名稱和版本等信息 */ PrintfHelp(); /* 打印操作提示 */ bsp_SetHRTIMOutPWM(); bsp_StartAutoTimer(0, 100); /* 啟動1個100ms的自動重裝的定時器 */ while (1) { bsp_Idle(); /* 這個函數在bsp.c文件。用戶可以修改這個函數實現CPU休眠和喂狗 */ /* 判斷定時器超時時間 */ if (bsp_CheckTimer(0)) { /* 每隔100ms 進來一次 */ bsp_LedToggle(2); } /* 按鍵濾波和檢測由後台systick中斷服務程序實現,我們只需要調用bsp_GetKey讀取鍵值即可。 */ ucKeyCode = bsp_GetKey(); /* 讀取鍵值, 無鍵按下時返回 KEY_NONE = 0 */ if (ucKeyCode != KEY_NONE) { switch (ucKeyCode) { case KEY_DOWN_K1: /* K1鍵按下 */ break; default: /* 其它的鍵值不處理 */ break; } } } }
64.8 總結
本章節就為大家講解這麼多,PWM是HRTIM裏面相對比較容易掌握,還有一些高級玩法,後續章節為大家做介紹。