6.1 實驗內容
通過本實驗主要學習以下內容:
? TIMER PWM輸出原理
? TIMER 定時中斷
6.2 實驗原理
6.2.1 IO口設置
本例程中,使用TIMER0輸出前三個通道的占空比,這三個通道分別為PA8、PA9和PA10,從datasheet中我們可以看到這三個引腳的定義:
所以需要將這三個引腳配置為AF模式并選擇正確的AF號:
6.2.2 TIMER輸出PWM原理
TIMER計數方式有兩種:邊沿計數和中央計數,其中邊沿計數分為向上計數和向下計數。
在向上計數模式下,需要配置TIMER的重載值,當TIMER開始工作后,計數值從0開始遞增,當達到重載值后計數值變?yōu)?重新開始計數;
向下計數模式和向上模式類似,只是計數值是遞減的,減到0后從重載數重新計數;
中央對齊模式的計數模式為從0開始計遞增到重載值,再從重載值遞減到0,從“0到0”為一次計數周期。
在0和重載值之間,用戶還可以設置一個比較值,PWM就是通過這個比較值來發(fā)出的,當計數值小于比較值時,IO口將會為高或者低,當計數值大于比較值時,IO將為輸出為另一個電平,即低或高,當TIMER連續(xù)計數時,就呈現出PWM波形。比較值的大小將決定PWM的占空比。以下為TIMER輸出PWM的示意圖:
圖中的OxCPRE為“輸出極性”,為高時為有效電平,為低時是無效電平,用戶可以設置通道口為有效電平時輸出高電平或者輸出低電平。比如,將PA8設置為高電平有效,那么當OxCPRE輸出為高時,PA8輸出高電平;如果設置PA8為低電平有效,那么當OxCPRE輸出為高時,則PA8輸出低電平。
本實驗采用TIMER5進行定時中斷,在中斷中改變TIMER0前三個通道的占空比,使用示波器或邏輯分析儀,可以測量TIMER0前三個通道PA8、PA9和PA10的波形。也可以通過飛線的方式將三個IO口分別接到紅綠藍三種不同顏色燈珠上,實現RGB彩燈的效果。
6.3 硬件設計
TIMER0的前三個通道分別為PA8、PA9和PA10,讀者直接對開發(fā)板上引出的排針進行測試即可。
6.4 代碼解析
本例程使用了兩個TIMER,其中TIMER5用來產生30ms的周期性中斷,在TIMER5的中斷中,對TIMER0的三個通道占空比進行調整,從而實現占空比可變的效果。
6.4.1 主函數代碼解析
主函數代碼如下所示,主要包括串口初始化、LED初始化、RGB燈珠初始化(即timer0的三個通道初始化)、timer驅動初始化(該timer用于調整RGB燈珠PWM驅動時間)。
C++
int main(void)
{
//延時和公共驅動部分初始化
driver_init();
//打印串口初始化
bsp_uart_init(&BOARD_UART);
//初始化LED組
bsp_led_group_init();
bsp_led_on(&LED2);
bsp_led_off(&LED1);
bsp_rgb_init(1000000,10);//
//注冊rgb_switch函數到timer定時中斷的回調函數
TIMER_INT.timer_updata_callback=rgb_switch;
//初始化定時器,默認計數器頻率100K,周期值3000,中斷頻率100K/3000= 33HZ(30ms)
bsp_timer_init(1000000,100);//
printf_log("\r\n RGB breathing lamp\r\n");
while(1)
{
}
}
6.4.2 RGB燈珠初始化函數解析
RGB燈珠初始化函數如下,在此定義了RGB_TIMER_R、RGB_TIMER_G、RGB_TIMER_B三個燈的控制結構體,并通過timer驅動進行配置。
C++
/* 定義注冊RGB對應PWM通道 */
TIMER_CH_DEF(RGB_TIMER_R,TIMER0,0,TIMER_CH_PWM_LOW,A,8,AF_PP,GPIO_AF_1);
TIMER_CH_DEF(RGB_TIMER_G,TIMER0,1,TIMER_CH_PWM_LOW,A,9,AF_PP,GPIO_AF_1);
TIMER_CH_DEF(RGB_TIMER_B,TIMER0,2,TIMER_CH_PWM_LOW,A,10,AF_PP,GPIO_AF_1);
/*!
* 說明 ????RGB初始化
* 輸入[1] ?counter_frequency 計數器頻率
* 輸入[2] ?period 周期值
* 返回值 ??無
*/
void bsp_rgb_init(uint32_t counter_frequency,uint16_t period)
{
driver_timer_multi_channel_init(&RGB_TIMER_R,&RGB_TIMER_G,&RGB_TIMER_B,NULL,counter_frequency,period);
driver_timer_pwm_on(&RGB_TIMER_R);
driver_timer_pwm_on(&RGB_TIMER_G);
6.4.3 基礎定時器初始化及中斷處理函數
基礎定時器初始化配置代碼如下,在此用一個定時器TIMER5,并使能了其溢出中斷。該定時器用于控制RGB PWM輸出時間。
C
/* 注冊定義定時器中斷使用的timer */
TIMER_BASE_DEF(TIMER_INT,TIMER5);
/*!
* 說明 ????定時器中斷初始化
* 輸入[1] ?counter_frequency:計數器頻率值
* 輸入[2] ?period:周期值
* 返回值 ??無
*/
void bsp_timer_init(uint32_t counter_frequency,uint16_t period)
{
driver_timer_base_int_init(&TIMER_INT,counter_frequency,period);
nvic_irq_enable(TIMER5_DAC_UDR_IRQn,0,0);
}
其中斷回調函數如下,通過該函數定時調整RGB三路PWM的占空比。
C
/*!
* 說明 ????定時器中斷服務函數
* 輸入[1] ?無
* 返回值 ??無
*/
void TIMER5_DAC_UDR_IRQHandler(void)
{
driver_timer_updata_int_handler(&TIMER_INT);
}
/*!
* 說明 ????RGB占空比切換函數(TIMER定時中斷回調)
* 輸入 ????無
* 輸出 ????無
* 返回值 ??無
*/
void rgb_switch(void)
{
static ?uint8_t r_duty=0,g_duty=0,b_duty=0;
//每輪中斷依次調整rgb占空比,將全部組合遍歷
bsp_rgb_duty_set(r_duty,g_duty,b_duty);
b_duty+=5;
if(b_duty>100)
{
b_duty=0;
g_duty+=5;
if(g_duty>100)
{
g_duty=0;
r_duty+=5;
if(r_duty>100)
{
r_duty=0;
bsp_led_toggle(&LED2);
bsp_led_toggle(&LED1);
}
}
}
}
6.5 實驗結果
將本例程代碼下載到海棠派開發(fā)板中,使用示波器測量PA8、PA9、PA10上,可以看到三個通道輸出PWM波,且占空比會周期性的變化。