【STM32H7教程】第33章 STM32H7的定時器應用之TIM1-TIM17的中斷實現

完整教程下載地址:http://www.armbbs.cn/forum.php?mod=viewthread&tid=86980php

第33章       STM32H7的定時器應用之TIM1-TIM17的中斷實現

本章教程爲你們講解定時器應用之TIM1 – TIM17全部定時器的週期性中斷實現。實際項目中用到的地方較多,特別是週期性的事件查詢。框架

33.1 初學者重要提示函數

33.2 定時器中斷的驅動設計性能

33.3 定時器板級支持包(bsp_tim_pwm.c)學習

33.4 定時器驅動移植和使用測試

33.5 實驗例程設計框架優化

33.6 實驗例程說明(MDK)ui

33.7 實驗例程說明(IAR)spa

33.8 總結設計

 

33.1 初學者重要提示

  1.   學習本章節前,務必優先學習第32章,HAL庫的幾個經常使用API均做了講解和舉例。
  2.   STM32H7支持TIM1-TIM8,TIM12-TIM17共14個定時器,而中間的TIM9,TIM10,TIM11是不存在的,這點要注意。
  3.   STM32H7的進出中斷的速度能跑到12.5MHz,全部程序在TCM和Flash運行沒差異,詳情可看本章2.3小節。
  4.   實際應用中,中斷入口函數名稱不要寫錯,有些中斷的入口函數名稱比較特殊,詳情可看本章的2.2小節。

33.2 定時器中斷的驅動設計

定時器中斷的實現相對比較簡單,僅需一個函數便可實現TIM1-TIM17定時器的中斷更新配置。

33.2.1 定時器中斷初始化

實現代碼以下:

1.    /* 
2.    ******************************************************************************************************
3.    *    函 數 名: bsp_RCC_TIM_Enable
4.    *    功能說明: 使能TIM RCC 時鐘
5.    *    形    參: 無
6.    *    返 回 值: 無
7.    ******************************************************************************************************
8.    */
9.    void bsp_RCC_TIM_Enable(TIM_TypeDef* TIMx)
10.    {
11.        if (TIMx == TIM1) __HAL_RCC_TIM1_CLK_ENABLE();
12.        else if (TIMx == TIM2) __HAL_RCC_TIM2_CLK_ENABLE();
13.        else if (TIMx == TIM3) __HAL_RCC_TIM3_CLK_ENABLE();
14.        else if (TIMx == TIM4) __HAL_RCC_TIM4_CLK_ENABLE();
15.        else if (TIMx == TIM5) __HAL_RCC_TIM5_CLK_ENABLE();
16.        else if (TIMx == TIM6) __HAL_RCC_TIM6_CLK_ENABLE();
17.        else if (TIMx == TIM7) __HAL_RCC_TIM7_CLK_ENABLE();
18.        else if (TIMx == TIM8) __HAL_RCC_TIM8_CLK_ENABLE();
19.    //    else if (TIMx == TIM9) __HAL_RCC_TIM9_CLK_ENABLE();
20.    //    else if (TIMx == TIM10) __HAL_RCC_TIM10_CLK_ENABLE();
21.    //    else if (TIMx == TIM11) __HAL_RCC_TIM11_CLK_ENABLE();
22.        else if (TIMx == TIM12) __HAL_RCC_TIM12_CLK_ENABLE();
23.        else if (TIMx == TIM13) __HAL_RCC_TIM13_CLK_ENABLE();
24.        else if (TIMx == TIM14) __HAL_RCC_TIM14_CLK_ENABLE();
25.        else if (TIMx == TIM15) __HAL_RCC_TIM15_CLK_ENABLE();
26.        else if (TIMx == TIM16) __HAL_RCC_TIM16_CLK_ENABLE();
27.        else if (TIMx == TIM17) __HAL_RCC_TIM17_CLK_ENABLE();    
28.        else
29.        {
30.            Error_Handler(__FILE__, __LINE__);
31.        }    
32.    }
33.    
34.    /*
35.    ******************************************************************************************************
36.    *    函 數 名: bsp_SetTIMforInt
37.    *    功能說明: 配置TIM和NVIC,用於簡單的定時中斷,開啓定時中斷。另外注意中斷服務程序須要由用戶應
38.    *              用程序實現。
39.    *    形    參: TIMx : 定時器
40.    *             _ulFreq : 定時頻率 (Hz)。 0 表示關閉。
41.    *             _PreemptionPriority : 搶佔優先級
42.    *             _SubPriority : 子優先級
43.    *    返 回 值: 無
44.    ******************************************************************************************************
45.    */
46.    void bsp_SetTIMforInt(TIM_TypeDef* TIMx, uint32_t _ulFreq, uint8_t _PreemptionPriority, 
47.                          uint8_t _SubPriority)
48.    {
49.        TIM_HandleTypeDef   TimHandle = {0};
50.        uint16_t usPeriod;
51.        uint16_t usPrescaler;
52.        uint32_t uiTIMxCLK;
53.        
54.        /* 使能TIM時鐘 */
55.        bsp_RCC_TIM_Enable(TIMx);
56.        
57.        /*-----------------------------------------------------------------------
58.            bsp.c 文件中 void SystemClock_Config(void) 函數對時鐘的配置以下: 
59.    
60.            System Clock source       = PLL (HSE)
61.            SYSCLK(Hz)                = 400000000 (CPU Clock)
62.            HCLK(Hz)                  = 200000000 (AXI and AHBs Clock)
63.            AHB Prescaler             = 2
64.            D1 APB3 Prescaler         = 2 (APB3 Clock  100MHz)
65.            D2 APB1 Prescaler         = 2 (APB1 Clock  100MHz)
66.            D2 APB2 Prescaler         = 2 (APB2 Clock  100MHz)
67.            D3 APB4 Prescaler         = 2 (APB4 Clock  100MHz)
68.    
69.            由於APB1 prescaler != 1, 因此 APB1上的TIMxCLK = APB1 x 2 = 200MHz;
70.            由於APB2 prescaler != 1, 因此 APB2上的TIMxCLK = APB2 x 2 = 200MHz;
71.            APB4上面的TIMxCLK沒有分頻,因此就是100MHz;
72.    
73.            APB1 定時器有 TIM2, TIM3 ,TIM4, TIM5, TIM6, TIM7, TIM12, TIM13, TIM14,LPTIM1
74.            APB2 定時器有 TIM1, TIM8 , TIM15, TIM16,TIM17
75.    
76.            APB4 定時器有 LPTIM2,LPTIM3,LPTIM4,LPTIM5
77.        ----------------------------------------------------------------------- */
78.        if ((TIMx == TIM1) || (TIMx == TIM8) || (TIMx == TIM15) || (TIMx == TIM16) || (TIMx == TIM17))
79.        {
80.            /* APB2 定時器時鐘 = 200M */
81.            uiTIMxCLK = SystemCoreClock / 2;
82.        }
83.        else    
84.        {
85.            /* APB1 定時器 = 200M */
86.            uiTIMxCLK = SystemCoreClock / 2;
87.        }
88.    
89.        if (_ulFreq < 100)
90.        {
91.            usPrescaler = 10000 - 1;                    /* 分頻比 = 10000 */
92.            usPeriod =  (uiTIMxCLK / 10000) / _ulFreq  - 1;        /* 自動重裝的值 */
93.        }
94.        else if (_ulFreq < 3000)
95.        {
96.            usPrescaler = 100 - 1;                    /* 分頻比 = 100 */
97.            usPeriod =  (uiTIMxCLK / 100) / _ulFreq  - 1;        /* 自動重裝的值 */
98.        }
99.        else    /* 大於4K的頻率,無需分頻 */
100.        {
101.            usPrescaler = 0;                    /* 分頻比 = 1 */
102.            usPeriod = uiTIMxCLK / _ulFreq - 1;    /* 自動重裝的值 */
103.        }
104.    
105.        /* 
106.           定時器中斷更新週期 = TIMxCLK / usPrescaler + 1)/usPeriod + 1)
107.        */
108.        TimHandle.Instance = TIMx;
109.        TimHandle.Init.Prescaler         = usPrescaler;
110.        TimHandle.Init.Period            = usPeriod;    
111.        TimHandle.Init.ClockDivision     = 0;
112.        TimHandle.Init.CounterMode       = TIM_COUNTERMODE_UP;
113.        TimHandle.Init.RepetitionCounter = 0;
114.        TimHandle.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
115.        if (HAL_TIM_Base_Init(&TimHandle) != HAL_OK)
116.        {
117.            Error_Handler(__FILE__, __LINE__);
118.        }
119.    
120.        /* 使能定時器中斷  */
121.        __HAL_TIM_ENABLE_IT(&TimHandle, TIM_IT_UPDATE);
122.        
123.    
124.        /* 配置TIM定時更新中斷 (Update) */
125.        {
126.            uint8_t irq = 0;    /* 中斷號, 定義在 stm32h7xx.h */
127.            
128.            if (TIMx == TIM1) irq = TIM1_UP_IRQn;
129.            else if (TIMx == TIM2) irq = TIM2_IRQn;
130.            else if (TIMx == TIM3) irq = TIM3_IRQn;
131.            else if (TIMx == TIM4) irq = TIM4_IRQn;
132.            else if (TIMx == TIM5) irq = TIM5_IRQn;
133.            else if (TIMx == TIM6) irq = TIM6_DAC_IRQn;
134.            else if (TIMx == TIM7) irq = TIM7_IRQn;
135.            else if (TIMx == TIM8) irq = TIM8_UP_TIM13_IRQn;
136.            else if (TIMx == TIM12) irq = TIM8_BRK_TIM12_IRQn;
137.            else if (TIMx == TIM13) irq = TIM8_UP_TIM13_IRQn;
138.            else if (TIMx == TIM14) irq = TIM8_TRG_COM_TIM14_IRQn;
139.            else if (TIMx == TIM15) irq = TIM15_IRQn;
140.            else if (TIMx == TIM16) irq = TIM16_IRQn;
141.            else if (TIMx == TIM16) irq = TIM17_IRQn;
142.            else
143.            {
144.                Error_Handler(__FILE__, __LINE__);
145.            }    
146.            HAL_NVIC_SetPriority((IRQn_Type)irq, _PreemptionPriority, _SubPriority);
147.            HAL_NVIC_EnableIRQ((IRQn_Type)irq);        
148.        }
149.        
150.        HAL_TIM_Base_Start(&TimHandle);
151.    }

 

程序中的註釋已經比較詳細,這裏把幾個關鍵的地方再闡釋下:

  •   第9- 32行,函數bsp_RCC_TIM_Enable用於獲取要使能的定時器時鐘。
  •   第49行,HAL庫的定時器句柄變量要初始化爲0,這個問題在教程上一章的4.1小節有專門說明。
  •   第78 – 103行,計算出要配置的分頻和週期。這裏要注意一點,由於除了TIM2和TIM5,其它定時器都是16位的,相關寄存器大部分也都是16位的,配置的時候不能夠超出0 -65535。這裏分頻變量usPrescaler和週期變量usPeriod統一按照16位計算,因此有了這幾行代碼作頻率區分,防止超出範圍。
  •   第108 – 118行,經過函數HAL_TIM_Base_Init初始化定時器的基本功能。
  •   第125 – 148行,配置定時器中斷的優先級,並使能中斷。

33.2.2 定時器中斷服務程序

定時器初始化完畢了,定時器中斷服務程序不要忘了寫。好比使用定時器6的中斷。

/*
*********************************************************************************************************
*    函 數 名: TIM6_DAC_IRQHandler
*    功能說明: TIM6定時中斷服務程序
*    返 回 值: 無
*********************************************************************************************************
*/
void TIM6_DAC_IRQHandler(void)
{
    if((TIM6->SR & TIM_FLAG_UPDATE) != RESET)
    {
        /* 清除標誌 */
        TIM6->SR = ~ TIM_FLAG_UPDATE;
        /* 添加用戶程序 */
    }
}

 

使用定時器中斷不要把中斷入口函數的名字寫錯了,好比這個定時器6,很容易錯搞成TIM6__IRQHandler。

TIM1 – TIM17中斷入口名以下(在startup_stm32h743xx.s文件裏面有弱定義):

TIM1_BRK_IRQHandler             
TIM1_UP_IRQHandler              
TIM1_TRG_COM_IRQHandler        
TIM1_CC_IRQHandler                                                    
TIM2_IRQHandler                                           
TIM3_IRQHandler                                                 
TIM4_IRQHandler                 
TIM5_IRQHandler            
TIM6_DAC_IRQHandler                   
TIM7_IRQHandler 
TIM8_BRK_TIM12_IRQHandler         /* 注意這裏是TIM8 BRK和TIM12公用 */
TIM8_UP_TIM13_IRQHandler          /* 注意這裏是TIM8 UP和TIM13公用 */
TIM8_TRG_COM_TIM14_IRQHandler     /* 注意這裏是TIM8 TRG COM和TIM14公用 */
TIM8_CC_IRQHandler          
TIM15_IRQHandler 
TIM16_IRQHandler 
TIM17_IRQHandler

 

33.2.3 定時器中斷的最高頻率

有時候咱們但願定時器的中斷服務程序執行頻率越快越好,這樣能夠方便的在中斷裏面執行一些特定功能,好比控制引腳輸出指定個數的IO脈衝,使用定時器中斷就能夠方便的實現。

測試時開啓MDK的最高等級優化和時間優化。

測試下面狀況下,性能沒差異:

  •   程序在Flash運行,變量在DTCM,開啓Cache。
  •   程序和變量都在DTCM運行。

中斷部分的測試程序:

/*
*********************************************************************************************************
*        函 數 名: TIM6_DAC_IRQHandler
*        功能說明: TIM6定時中斷服務程序
*        返 回 值: 無
*********************************************************************************************************
*/
void TIM6_DAC_IRQHandler(void)
{
     TIM6->SR = ~TIM_FLAG_UPDATE;
     //GPIOB->ODR ^= GPIO_PIN_1;   /* 使用通用GPIO */
     HC574_TogglePin(GPIO_PIN_23); /* 使用的FMC擴展IO */
}

 

測試結果是STM32H7的進出中斷的速度能跑到12.5MHz,全部程序在TCM和Flash運行沒差異。

IO翻轉10MHz,方波頻率5MHz:

 

IO翻轉12.5MHz,方波頻率6.25MHz:

 

12.5Hz是最高頻率,實際應用中別跑這麼高,由於這個頻率下,程序基本一直在執行中斷服務程序。實際應用作個1MHz及其如下仍是沒問題的。

33.3 定時器板級支持包(bsp_tim_pwm.c)

定時器驅動文件bsp_tim_pwm.c主要實現了以下兩個API供用戶調用:

  •   bsp_SetTIMOutPWM
  •   bsp_SetTIMforInt

 

這兩個函數都是TIM1-TIM17全部定時器都支持,函數bsp_SetTIMOutPWM用於PWM,下個章節爲你們講解,本小節主要把函數bsp_SetTIMforInt作個說明。

33.3.1 函數bsp_SetTIMforInt

函數原型:

void bsp_SetTIMforInt(TIM_TypeDef* TIMx, uint32_t _ulFreq, uint8_t _PreemptionPriority, uint8_t _SubPriority)

 

函數描述:

此函數主要用配置定時器週期性中斷。

函數參數:

  •   第1個參數用於指定使用那個定時器,參數能夠是TIM1 – TIM17全部定時器(不含TIM9,TIM10和TIM11,由於STM32H7不支持這三個定時器)。
  •   第2個參數是要實現的定時器中斷頻率,單位Hz,若是填0的話,表示關閉。
  •   第3個參數是定時器搶佔式優先級,範圍0 – 15。
  •   第4個參數是定時器子優先級,範圍0 – 15。

注意事項:

  1. 定時器中斷頻率最好別超過10MHz,本章2.3小節有說明。
  2. 初始化後,別忘了寫對應的中斷服務程序。

使用舉例:

好比使用定時器6設置爲20Hz頻率, 週期0.05秒定時中斷:

bsp_SetTIMforInt(TIM6, 20, 2, 0); 

33.4 定時器驅動移植和使用

定時器的移植比較簡單:

  •   第1步:複製bsp_tim_pwm.c和bsp_tim_pwm.h到本身的工程目錄,並添加到工程裏面。
  •   第2步:這幾個驅動文件主要用到HAL庫的GPIO和TIM驅動文件,簡單省事些能夠添加全部HAL庫.C源文件進來。
  •   第3步:應用方法看本章節配套例子便可。

33.5 實驗例程設計框架

經過程序設計框架,讓你們先對配套例程有一個全面的認識,而後再理解細節,本次實驗例程的設計框架以下:

  第1階段,上電啓動階段:

  • 這部分在第14章進行了詳細說明。

  第2階段,進入main函數:

  •  第1步,硬件初始化,主要是MPU,Cache,HAL庫,系統時鐘,滴答定時器,LED和串口。
  •  第2步,按鍵應用程序設計部分。
  •  定時器中斷服務程序裏面實現翻轉LED4和FMC擴展引腳23。

33.6 實驗例程說明(MDK)

配套例子:

V7-018_定時器週期性中斷(驅動支持TIM1-TIM17)

實驗目的:

  1. 學習定時器週期性中斷實現,支持TIM1-TIM17全部定時器。

實驗內容:

  1. 系統上電後驅動了1個軟件定時器,每100ms翻轉一次LED2,同時啓動1個TIM6週期性中斷,每50ms執行一次,在中斷服務程序裏面翻轉LED4和FMC擴展引腳23。
  2. STM32H7支持TIM1-TIM8,TIM12-TIM17共14個定時器,而中間的TIM9,TIM10,TIM11是不存在的。
  3. STM32H7的進出中斷的速度能跑到12.5MHz,全部程序在TCM和Flash運行沒差異,實際應用中最好別超過1MHz。
  4. 中斷入口函數名稱不要寫錯,有些中斷的入口函數名稱比較特殊,詳情可看V7開發板用戶手冊。

實驗操做:

  1. K1按鍵按下,開啓TIM6的週期性中斷。
  2. K2按鍵按下,關閉TIM6的週期性中斷。

FMC擴展引腳23的位置:

 

上電後串口打印的信息:

波特率 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();
}

 

  定時器中斷服務程序:

定時器6的中斷服務程序以下,主要實現了LED4翻轉和FMC擴展引腳23的翻轉:

/*
*********************************************************************************************************
*    函 數 名: TIM6_DAC_IRQHandler
*    功能說明: TIM6定時中斷服務程序
*    返 回 值: 無
*********************************************************************************************************
*/
void TIM6_DAC_IRQHandler(void)
{
    if((TIM6->SR & TIM_FLAG_UPDATE) != RESET)
    {
        /* 清除更新標誌 */
        TIM6->SR = ~ TIM_FLAG_UPDATE;
        
        /* 翻轉LED4和FMC擴展引腳23 */
        bsp_LedToggle(4);
        HC574_TogglePin(GPIO_PIN_23);
    }
}

 

  主功能:

主程序實現以下操做:

  •   K1按鍵按下,開啓TIM6的週期性中斷。
  •   K2按鍵按下,關閉TIM6的週期性中斷。
/*
*********************************************************************************************************
*    函 數 名: main
*    功能說明: c程序入口
*    形    參: 無
*    返 回 值: 錯誤代碼(無需處理)
*********************************************************************************************************
*/
int main(void)
{
    uint8_t ucKeyCode;    /* 按鍵代碼 */
    

    bsp_Init();        /* 硬件初始化 */
    
    PrintfLogo();    /* 打印例程名稱和版本等信息 */
    PrintfHelp();    /* 打印操做提示 */

    bsp_StartAutoTimer(0, 100);    /* 啓動1個100ms的自動重裝的定時器 */
    
    bsp_SetTIMforInt(TIM6, 20, 2, 0);    /* 設置爲20Hz頻率, 週期0.05秒定時中斷*/    
    
    /* 進入主程序循環體 */
    while (1)
    {
        bsp_Idle();        /* 這個函數在bsp.c文件。用戶能夠修改這個函數實現CPU休眠和喂狗 */

        /* 判判定時器超時時間 */
        if (bsp_CheckTimer(0))    
        {
            /* 每隔50ms 進來一次 */  
            bsp_LedToggle(2);
        }

        /* 按鍵濾波和檢測由後臺systick中斷服務程序實現,咱們只須要調用bsp_GetKey讀取鍵值便可。 */
        ucKeyCode = bsp_GetKey();    /* 讀取鍵值, 無鍵按下時返回 KEY_NONE = 0 */
        if (ucKeyCode != KEY_NONE)
        {
            switch (ucKeyCode)
            {
                case KEY_DOWN_K1:            /* K1鍵按下 */
                    TIM6->DIER |= TIM_IT_UPDATE;
                    break;

                case KEY_DOWN_K2:            /* K2鍵按下 */
                    TIM6->DIER &= ~TIM_IT_UPDATE;
                    break;

                default:
                    /* 其它的鍵值不處理 */
                    break;
            }
        }
    }
}

 

33.7 實驗例程說明(IAR)

配套例子:

V7-018_定時器週期性中斷(驅動支持TIM1-TIM17)

實驗目的:

  1. 學習定時器週期性中斷實現,支持TIM1-TIM17全部定時器。

實驗內容:

  1. 系統上電後驅動了1個軟件定時器,每100ms翻轉一次LED2,同時啓動1個TIM6週期性中斷,每50ms執行一次,在中斷服務程序裏面翻轉LED4和FMC擴展引腳23。
  2. STM32H7支持TIM1-TIM8,TIM12-TIM17共14個定時器,而中間的TIM9,TIM10,TIM11是不存在的。
  3. STM32H7的進出中斷的速度能跑到12.5MHz,全部程序在TCM和Flash運行沒差異,實際應用中最好別超過1MHz。
  4. 中斷入口函數名稱不要寫錯,有些中斷的入口函數名稱比較特殊,詳情可看V7開發板用戶手冊。

實驗操做:

  1. K1按鍵按下,開啓TIM6的週期性中斷。
  2. K2按鍵按下,關閉TIM6的週期性中斷。

FMC擴展引腳23的位置:

 

上電後串口打印的信息:

波特率 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();
}

 

  定時器中斷服務程序:

定時器6的中斷服務程序以下,主要實現了LED4翻轉和FMC擴展引腳23的翻轉:

/*
*********************************************************************************************************
*    函 數 名: TIM6_DAC_IRQHandler
*    功能說明: TIM6定時中斷服務程序
*    返 回 值: 無
*********************************************************************************************************
*/
void TIM6_DAC_IRQHandler(void)
{
    if((TIM6->SR & TIM_FLAG_UPDATE) != RESET)
    {
        /* 清除更新標誌 */
        TIM6->SR = ~ TIM_FLAG_UPDATE;
        
        /* 翻轉LED4和FMC擴展引腳23 */
        bsp_LedToggle(4);
        HC574_TogglePin(GPIO_PIN_23);
    }
}

 

 主功能:

主程序實現以下操做:

  •   K1按鍵按下,開啓TIM6的週期性中斷。
  •   K2按鍵按下,關閉TIM6的週期性中斷。
/*
*********************************************************************************************************
*    函 數 名: main
*    功能說明: c程序入口
*    形    參: 無
*    返 回 值: 錯誤代碼(無需處理)
*********************************************************************************************************
*/
int main(void)
{
    uint8_t ucKeyCode;    /* 按鍵代碼 */
    

    bsp_Init();        /* 硬件初始化 */
    
    PrintfLogo();    /* 打印例程名稱和版本等信息 */
    PrintfHelp();    /* 打印操做提示 */

    bsp_StartAutoTimer(0, 100);    /* 啓動1個100ms的自動重裝的定時器 */
    
    bsp_SetTIMforInt(TIM6, 20, 2, 0);    /* 設置爲20Hz頻率, 週期0.05秒定時中斷*/    
    
    /* 進入主程序循環體 */
    while (1)
    {
        bsp_Idle();        /* 這個函數在bsp.c文件。用戶能夠修改這個函數實現CPU休眠和喂狗 */

        /* 判判定時器超時時間 */
        if (bsp_CheckTimer(0))    
        {
            /* 每隔50ms 進來一次 */  
            bsp_LedToggle(2);
        }

        /* 按鍵濾波和檢測由後臺systick中斷服務程序實現,咱們只須要調用bsp_GetKey讀取鍵值便可。 */
        ucKeyCode = bsp_GetKey();    /* 讀取鍵值, 無鍵按下時返回 KEY_NONE = 0 */
        if (ucKeyCode != KEY_NONE)
        {
            switch (ucKeyCode)
            {
                case KEY_DOWN_K1:            /* K1鍵按下 */
                    TIM6->DIER |= TIM_IT_UPDATE;
                    break;

                case KEY_DOWN_K2:            /* K2鍵按下 */
                    TIM6->DIER &= ~TIM_IT_UPDATE;
                    break;

                default:
                    /* 其它的鍵值不處理 */
                    break;
            }
        }
    }
}

 

33.8 總結

本章節就爲你們講解這麼多,相對比較容易掌握,望初學者熟練運用。

相關文章
相關標籤/搜索