5.1.TIMER 基礎知識
TIMER分高級定時器,通用定時器L0,L1,L2和基本定時器。
5.2.硬件連接說明
TIMER 屬于片內外設,對于外部硬件設計,只需要單獨IO口外接信號線即可。
5.3.GD32 TIMER 外設原理簡介(以 GD32F30X 的高級定時器為例)
GD32 TIMER 主要特性
? 總通道數: 4;
? 計數器寬度: 16位;
? 定時器時鐘源可選:內部時鐘,內部觸發(fā),外部輸入,外部觸發(fā);
? 多種計數模式:向上計數,向下計數和中央計數;
? 可編程的預分頻器: 16位。運行時可以被改變;
? 每個通道可配置:輸入捕獲模式,輸出比較模式,可編程的PWM模式,單脈沖模式;
? 可編程的死區(qū)時間;
? 自動重裝載功能;
? 可編程的計數器重復功能;
? 中止輸入功能;
? 中斷輸出和DMA請求:更新事件,觸發(fā)事件,比較/捕獲事件和中止事件;
? 多個定時器的菊鏈使得一個定時器可以同時啟動多個定時器;
? 定時器的同步允許被選擇的定時器在同一個時鐘周期開始計數;
? 定時器主/從模式控制器。
TIMER 結構框圖介紹
5.4.軟件配置說明
定時中斷 TIMER4
通用定時器L0(TIMER1/2/3/4) 是4通道定時器,支持輸入捕獲,輸出比較,產生PWM信號控制電機和電源管理。通用定時器L0計數器是16位無符號計數器。通用定時器L0是可編程的,可以被用來計數,其外部事件可以驅動其他定時器。
這一章,將使用定時器產生中斷,然后在中斷服務函數里面翻轉 LED上的電平,來指示定時器中斷的產生。接下來我們以通用定時器 TIMER4 為實例,來說明要經過哪些步驟,才能達到這個要 求,并產生中斷。定時器配置步驟如下:
1)TIMER4 時鐘使能
rcu_periph_clock_enable(RCU_TIMER4);
2) 初始化定時器參數,設置自動重裝值,分頻系數,計數方式等
在庫函數中,定時器的初始化參數是通過初始化函數timer_parameter_struct 實現(xiàn)的:
void timer_init(uint32_t timer_periph, timer_parameter_struct* initpara);
第一個參數是確定是哪個定時器,這個比較容易理解。第二個參數是定時器初始化參數結構體指針,結構體類型為timer_parameter_struct ,下面我們看看這個結構體的定義:
/* TIMER init parameter struct definitions */ typedef struct { uint16_t prescaler; /*!
針對 TIMR4 初始化范例代碼格式
timer_initpara.prescaler = 5999; //30M/6000 =500Hz timer_initpara.alignedmode = TIMER_COUNTER_EDGE; timer_initpara.counterdirection = TIMER_COUNTER_UP; timer_initpara.period = 4000-1; //800ms timer_initpara.clockdivision = TIMER_CKDIV_DIV1; timer_init(TIMER4, &timer_initpara);
對于定時器定時周期的計算,設 TIMER4 的經過總線分頻后得到的時鐘為 30MHz,通過預分頻 5999,得到 TIMER4 每個計 數的時鐘為 1/(30MHz / (5999+1)) =0.2ms,4000 得到的周期為 0.2ms *4000 =800ms
3)設置 TIMER 允許更新中斷
因為我們要使用 TIMER4 的更新中斷,寄存器的相應位便可使能更新中斷。在庫函數里面定時器中斷使能是通過timer_interrupt_enable函數來實現(xiàn)的:
void timer_interrupt_enable(uint32_t timer_periph, uint32_t interrupt);
第一個參數是選擇定時器號,這個容易理解。
第二個參數非常關鍵,是用來指明我們使能的定時器中斷的類型。
4) TIMER4 中斷優(yōu)先級設置
在定時器中斷使能之后,因為要產生中斷,必不可少的要設置 NVIC 相關寄存器,設置中斷優(yōu)先級。通過nvic_irq_enable 函數實現(xiàn)中斷優(yōu)先級的設置。
針對 TIMR4 初始化范例代碼格式
nvic_irq_enable(TIMER4_IRQn, 1, 1);
5)允許 TIMER工作,也就是使能 TIMER
光配置好定時器還不行,沒有開啟定時器,照樣不能用。我們在配置完后要開啟定時器,在固件庫里面使能定時器的函數是通過timer_enable函數來實現(xiàn)的
void timer_enable(uint32_t timer_periph)
這個函數非常簡單,比如我們要使能TIMER4,方法為:
timer_enable(TIMER4);
6)編寫中斷服務函數
在最后,還是要編寫定時器中斷服務函數,通過該函數來處理定時器產生的相關中斷。中斷產生后,通過狀態(tài)寄存器的值來判斷此次產生的中斷屬于什么類型。然后執(zhí)行相關的操作,我們這里使用的是更新(溢出)中斷,在處理完中斷之后應來清除該中斷標志。
在固件庫函數里面,用來讀取中斷狀態(tài)寄存器的值判斷中斷類型的函數是:
FlagStatus timer_interrupt_flag_get(uint32_t timer_periph, uint32_t interrupt)
該函數的作用是,判斷定時器 TIMER 的中斷類型,并判斷是否發(fā)生中斷。
針對 TIMR4 中斷服務函數范例代碼:
void TIMER4_IRQHandler(void) { if(SET == timer_interrupt_flag_get(TIMER4, TIMER_INT_UP)){ /* clear channel 0 interrupt bit */ timer_interrupt_flag_clear(TIMER4, TIMER_INT_UP); gd_eval_led_toggle(LED2); } }
PWM 輸出 TIMER0
高級定時器(TIMER0和TIMER7)是四通道定時器,支持輸入捕獲和輸出比較。可以產生PWM信號控制電機和電源管理。高級定時器含有一個16位無符號計數器。高級定時器是可編程的,可以用來計數,其外部事件可以驅動其他定時器。高級定時器包含了一個死區(qū)時間插入模塊,非常適合電機控制。
本章,我們使用的是 TIMER0的通道0 輸出 PWM(脈沖寬度調制)。
下面我們介紹通過庫函數來配置該功能的步驟:
(1)開啟 TIMER0 和 GPIO 時鐘,配置 PA8復用功能輸出。
rcu_periph_clock_enable(RCU_TIMER0); rcu_periph_clock_enable(RCU_GPIOA); gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_8);
這里還需要說明一下, 對于定時器通道的引腳關系,引腳的IO口
這里補充說明下關于TIMER的相關GPIO口的命名
TIMERx_CHx : 定時器通道x
TIMERx_CHx_ON :定時器反向通道
TIMERx_BRKIN :剎車引腳
TIMERx_ETI:外部時鐘輸入
(2)初始化 TIMER0 ,設置 TIMER0 的預分頻和周期等參數, ,在上一節(jié)定時器中斷章節(jié)我們已經有講解,這里就不詳細講解,調用的格式為
timer_initpara.prescaler = 5999; timer_initpara.alignedmode = TIMER_COUNTER_EDGE; timer_initpara.counterdirection = TIMER_COUNTER_UP; timer_initpara.period = 4000; timer_initpara.clockdivision = TIMER_CKDIV_DIV1; timer_initpara.repetitioncounter = 0; timer_init(TIMER0, &timer_initpara);
3)設置 TIMER0_CH0 的 PWM 模式, 使能 TIMER0 的 CH0 輸出。 在庫函數中, PWM 通道設置是通過函數timer_channel_output_config來設置的
void timer_channel_output_config(uint32_t timer_periph, uint16_t channel, timer_oc_parameter_struct* ocpara)
我們直接來看看結構體timer_oc_parameter_struct的定義:
typedef struct { uint16_t outputstate; /*!< channel output state */ uint16_t outputnstate; /*!< channel complementary output state */ uint16_t ocpolarity; /*!< channel output polarity */ uint16_t ocnpolarity; /*!< channel complementary output polarity */ uint16_t ocidlestate; /*!< idle state of channel output */ uint16_t ocnidlestate; /*!< idle state of channel complementary output */ }timer_oc_parameter_struct;
針對 TIMR0 CH0 初始化范例代碼格式
/* CH0, CH1 and CH2 configuration in PWM mode */ timer_ocinitpara.outputstate = TIMER_CCX_ENABLE; timer_ocinitpara.outputnstate = TIMER_CCXN_DISABLE; timer_ocinitpara.ocpolarity = TIMER_OC_POLARITY_HIGH; timer_ocinitpara.ocnpolarity = TIMER_OCN_POLARITY_HIGH; timer_ocinitpara.ocidlestate = TIMER_OC_IDLE_STATE_LOW; timer_ocinitpara.ocnidlestate = TIMER_OCN_IDLE_STATE_LOW; timer_channel_output_config(TIMER0, TIMER_CH_0, &timer_ocinitpara);
4)設置PWM輸出以及脈沖寬度占空比
timer_channel_output_pulse_value_config(TIMER0, TIMER_CH_0, 2000); timer_channel_output_mode_config(TIMER0, TIMER_CH_0, TIMER_OC_MODE_PWM0); timer_channel_output_shadow_config(TIMER0, TIMER_CH_0, TIMER_OC_SHADOW_DISABLE); timer_primary_output_config(TIMER0,ENABLE);
5)使能 TIMER0
在完成以上設置了之后,我們需要使能 TIMER0。使能 TIMER0 的方法前面已經講解過:
timer_enable(TIMER0);
通過以上 5 個步驟,我們就可以控制 TIMER0的 CH0 輸出 PWM 波了。這里特別提醒一下大家,高級定時器雖然和通用定時器類似,但是高級定時器要想輸出 PWM,必須多額外加一條函數
void timer_primary_output_config(uint32_t timer_periph, ControlStatus newvalue);
輸入捕獲 TIMER2
通用定時器L0(TIMER1/2/3/4) 是4通道定時器,支持輸入捕獲,輸出比較,產生PWM信號控制電機和電源管理。通用定時器L0計數器是16位無符號計數器。通用定時器L0是可編程的,可以被用來計數,其外部事件可以驅動其他定時器。
本章要實現(xiàn)通過輸入捕獲,來獲取TIMER2_CH0(PA6)上面的下降沿,下面我們介紹庫函數配置上述功能輸入捕獲的步驟:
1)開啟 TIMER2 時鐘,配置 PA6為復用功能,并開啟上拉電阻。
rcu_periph_clock_enable(RCU_TIMER2); rcu_periph_clock_enable(RCU_GPIOA); gpio_init(GPIOA, GPIO_MODE_IPU, GPIO_OSPEED_50MHZ, GPIO_PIN_6); //INCUPTURE -TIMER2
跟上一講 PWM 輸出類似,這里我們使用的是定時器2的通道 0,所以我們從對應的數據手冊可以查看到對應的 IO 口為 PA6:
2) 初始化定時器參數,設置自動重裝值, 分頻系數,計數方式等
/* TIMER2 configuration */ timer_initpara.prescaler = 5999; timer_initpara.alignedmode = TIMER_COUNTER_EDGE; timer_initpara.counterdirection = TIMER_COUNTER_UP; timer_initpara.period = 4000; timer_initpara.clockdivision = TIMER_CKDIV_DIV1; timer_init(TIMER2, &timer_initpara);
3)設置 TIMER2 的輸入捕獲參數,開啟輸入捕獲
庫函數是通過 timer_input_capture_config 函數來初始化輸入比較參數的: timer_input_capture_config(TIMER2,TIMER_CH_0,&timer_icinitpara);
同樣,我們來看看參數設置結構體 TIM_ICInitTypeDef 的定義:
typedef struct { uint16_t icpolarity; /*!< channel input polarity */ uint16_t icselection; /*!< channel input mode selection */ uint16_t icprescaler; /*!< channel input capture prescaler */ uint16_t icfilter; /*!< channel input capture filter control */ }timer_ic_parameter_struct;
我們的配置代碼是:
/* initialize TIMER channel input parameter struct */ timer_channel_input_struct_para_init(&timer_icinitpara); /* TIMER2 CH0 input capture configuration */ timer_icinitpara.icpolarity = TIMER_IC_POLARITY_RISING; timer_icinitpara.icselection = TIMER_IC_SELECTION_DIRECTTI; timer_icinitpara.icprescaler = TIMER_IC_PSC_DIV1; timer_icinitpara.icfilter = 0x0; timer_input_capture_config(TIMER2,TIMER_CH_0,&timer_icinitpara);
4) 使能捕獲中斷和NVIC
timer_interrupt_enable(TIMER2,TIMER_INT_CH0); nvic_irq_enable(TIMER2_IRQn, 1, 1);
5) 編寫中斷服務函數
void TIMER2_IRQHandler(void){……}
6) 使能定時器
timer_enable(TIMER2);
通過以上 6 步設置,定時器 2 的通道 0 就可以開始輸入捕獲了
外部時鐘輸入 TIMER1
通用定時器L0(TIMER1/2/3/4) 是4通道定時器,支持輸入捕獲,輸出比較,產生PWM信號控制電機和電源管理。通用定時器L0計數器是16位無符號計數器。通用定時器L0是可編程的,可以被用來計數,其外部事件可以驅動其他定時器。
本章要實現(xiàn)使用TIMER1 PA0 作為時鐘輸入引腳,配置流程:
(1)使能GPIO,TIMER 時鐘和GPIO口復用配置
rcu_periph_clock_enable(RCU_GPIOA); rcu_periph_clock_enable(RCU_AF); rcu_periph_clock_enable(RCU_TIMER1); gpio_init(GPIOA,GPIO_MODE_IN_FLOATING,GPIO_OSPEED_50MHZ,GPIO_PIN_0);
(2)通過查看數據手冊,可以看到TIMER1_CH0_ETI,根據前面所講,是可以支持外部時鐘輸入的。
TIMER的結構體,初始化定時器參數,設置自動重裝值, 分頻系數,計數方式等
//ETI timer_initpara.prescaler = 1; // 2 分頻 timer_initpara.alignedmode = TIMER_COUNTER_EDGE; timer_initpara.counterdirection = TIMER_COUNTER_UP; timer_initpara.period = 65535; timer_initpara.clockdivision = TIMER_CKDIV_DIV1; timer_initpara.repetitioncounter = 0; timer_init(TIMER1,&timer_initpara); timer_enable(TIMER1);
(3)配置TIMER的時鐘來源和時鐘源處理的配置
timer_input_trigger_source_select(TIMER1,TIMER_SMCFG_TRGSEL_ETIFP); timer_external_clock_mode1_config(TIMER1, TIMER_EXT_TRI_PSC_OFF, TIMER_ETP_RISING, 0);
(4)使能TIMER
timer_enable(TIMER1);
5.5.TIMER 使用注意事項
TIMER 高級定時器 做定時用的時候(使用到UPDAT中斷),在產生中斷之后,高級定時器的其他所有的狀態(tài)標志位會被置位,但是不會置位中斷標志位.
本教程由GD32 MCU方案商聚沃科技原創(chuàng)發(fā)布,了解更多GD32 MCU教程,關注聚沃科技官網
-
單片機
+關注
關注
6039文章
44579瀏覽量
636462 -
開發(fā)板
+關注
關注
25文章
5081瀏覽量
97706 -
Timer
+關注
關注
1文章
64瀏覽量
12800 -
GD32
+關注
關注
7文章
404瀏覽量
24384
發(fā)布評論請先 登錄
相關推薦
評論